public static void PlayDamageSound(string damageType, float damage, PhysicsBody body) { Vector2 bodyPosition = body.DrawPosition; PlayDamageSound(damageType, damage, bodyPosition, 800.0f); }
public LevelTrigger(XElement element, Vector2 position, float rotation, float scale = 1.0f, string parentDebugName = "") { TriggererPosition = new Dictionary <Entity, Vector2>(); worldPosition = position; if (element.Attributes("radius").Any() || element.Attributes("width").Any() || element.Attributes("height").Any()) { PhysicsBody = new PhysicsBody(element, scale) { CollisionCategories = Physics.CollisionLevel, CollidesWith = Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionProjectile | Physics.CollisionWall }; PhysicsBody.FarseerBody.OnCollision += PhysicsBody_OnCollision; PhysicsBody.FarseerBody.OnSeparation += PhysicsBody_OnSeparation; PhysicsBody.FarseerBody.SetIsSensor(true); PhysicsBody.FarseerBody.BodyType = BodyType.Static; PhysicsBody.FarseerBody.BodyType = BodyType.Kinematic; ColliderRadius = ConvertUnits.ToDisplayUnits(Math.Max(Math.Max(PhysicsBody.radius, PhysicsBody.width / 2.0f), PhysicsBody.height / 2.0f)); PhysicsBody.SetTransform(ConvertUnits.ToSimUnits(position), rotation); } cameraShake = element.GetAttributeFloat("camerashake", 0.0f); InfectIdentifier = element.GetAttributeString("infectidentifier", null); InfectionChance = element.GetAttributeFloat("infectionchance", 0.05f); triggerOnce = element.GetAttributeBool("triggeronce", false); stayTriggeredDelay = element.GetAttributeFloat("staytriggereddelay", 0.0f); randomTriggerInterval = element.GetAttributeFloat("randomtriggerinterval", 0.0f); randomTriggerProbability = element.GetAttributeFloat("randomtriggerprobability", 0.0f); UseNetworkSyncing = element.GetAttributeBool("networksyncing", false); unrotatedForce = element.Attribute("force") != null && element.Attribute("force").Value.Contains(',') ? element.GetAttributeVector2("force", Vector2.Zero) : new Vector2(element.GetAttributeFloat("force", 0.0f), 0.0f); ForceFluctuationInterval = element.GetAttributeFloat("forcefluctuationinterval", 0.01f); ForceFluctuationStrength = Math.Max(element.GetAttributeFloat("forcefluctuationstrength", 0.0f), 0.0f); ForceFalloff = element.GetAttributeBool("forcefalloff", true); ForceVelocityLimit = ConvertUnits.ToSimUnits(element.GetAttributeFloat("forcevelocitylimit", float.MaxValue)); string forceModeStr = element.GetAttributeString("forcemode", "Force"); if (!Enum.TryParse(forceModeStr, out forceMode)) { DebugConsole.ThrowError("Error in LevelTrigger config: \"" + forceModeStr + "\" is not a valid force mode."); } CalculateDirectionalForce(); string triggeredByStr = element.GetAttributeString("triggeredby", "Character"); if (!Enum.TryParse(triggeredByStr, out triggeredBy)) { DebugConsole.ThrowError("Error in LevelTrigger config: \"" + triggeredByStr + "\" is not a valid triggerer type."); } UpdateCollisionCategories(); TriggerOthersDistance = element.GetAttributeFloat("triggerothersdistance", 0.0f); var tagsArray = element.GetAttributeStringArray("tags", new string[0]); foreach (string tag in tagsArray) { tags.Add(tag.ToLower()); } if (triggeredBy.HasFlag(TriggererType.OtherTrigger)) { var otherTagsArray = element.GetAttributeStringArray("allowedothertriggertags", new string[0]); foreach (string tag in otherTagsArray) { allowedOtherTriggerTags.Add(tag.ToLower()); } } foreach (XElement subElement in element.Elements()) { switch (subElement.Name.ToString().ToLowerInvariant()) { case "statuseffect": statusEffects.Add(StatusEffect.Load(subElement, string.IsNullOrEmpty(parentDebugName) ? "LevelTrigger" : "LevelTrigger in " + parentDebugName)); break; case "attack": case "damage": var attack = new Attack(subElement, string.IsNullOrEmpty(parentDebugName) ? "LevelTrigger" : "LevelTrigger in " + parentDebugName); if (!triggerOnce) { var multipliedAfflictions = attack.GetMultipliedAfflictions((float)Timing.Step); attack.Afflictions.Clear(); foreach (Affliction affliction in multipliedAfflictions) { attack.Afflictions.Add(affliction, null); } } attacks.Add(attack); break; } } forceFluctuationTimer = Rand.Range(0.0f, ForceFluctuationInterval); randomTriggerTimer = Rand.Range(0.0f, randomTriggerInterval); }
public void Update(float deltaTime) { if (ParentTrigger != null && !ParentTrigger.IsTriggered) { return; } triggerers.RemoveWhere(t => t.Removed); if (PhysicsBody != null) { //failsafe to ensure triggerers get removed when they're far from the trigger float maxExtent = Math.Max(ConvertUnits.ToDisplayUnits(PhysicsBody.GetMaxExtent() * 5), 5000.0f); triggerers.RemoveWhere(t => { return(Vector2.Distance(t.WorldPosition, WorldPosition) > maxExtent); }); } bool isNotClient = true; #if CLIENT isNotClient = GameMain.Client == null; #endif if (!UseNetworkSyncing || isNotClient) { if (ForceFluctuationStrength > 0.0f) { //no need for force fluctuation (or network updates) if the trigger limits velocity and there are no triggerers if (forceMode != TriggerForceMode.LimitVelocity || triggerers.Any()) { forceFluctuationTimer += deltaTime; if (forceFluctuationTimer > ForceFluctuationInterval) { NeedsNetworkSyncing = true; currentForceFluctuation = Rand.Range(1.0f - ForceFluctuationStrength, 1.0f); forceFluctuationTimer = 0.0f; } } } if (randomTriggerProbability > 0.0f) { randomTriggerTimer += deltaTime; if (randomTriggerTimer > randomTriggerInterval) { if (Rand.Range(0.0f, 1.0f) < randomTriggerProbability) { NeedsNetworkSyncing = true; triggeredTimer = stayTriggeredDelay; } randomTriggerTimer = 0.0f; } } } if (stayTriggeredDelay > 0.0f) { if (triggerers.Count == 0) { triggeredTimer -= deltaTime; } else { triggeredTimer = stayTriggeredDelay; } } if (triggerOnce) { if (triggeredOnce) { return; } if (triggerers.Count > 0) { triggeredOnce = true; } } foreach (Entity triggerer in triggerers) { foreach (StatusEffect effect in statusEffects) { Vector2?position = null; if (effect.HasTargetType(StatusEffect.TargetType.This)) { position = WorldPosition; } if (triggerer is Character character) { effect.Apply(effect.type, deltaTime, triggerer, character, position); if (effect.HasTargetType(StatusEffect.TargetType.Contained) && character.Inventory != null) { foreach (Item item in character.Inventory.AllItemsMod) { if (item.ContainedItems == null) { continue; } foreach (Item containedItem in item.ContainedItems) { effect.Apply(effect.type, deltaTime, triggerer, containedItem.AllPropertyObjects, position); } } } } else if (triggerer is Item item) { effect.Apply(effect.type, deltaTime, triggerer, item.AllPropertyObjects, position); } if (effect.HasTargetType(StatusEffect.TargetType.NearbyItems) || effect.HasTargetType(StatusEffect.TargetType.NearbyCharacters)) { var targets = new List <ISerializableEntity>(); effect.GetNearbyTargets(worldPosition, targets); effect.Apply(effect.type, deltaTime, triggerer, targets); } } if (triggerer is IDamageable damageable) { foreach (Attack attack in attacks) { attack.DoDamage(null, damageable, WorldPosition, deltaTime, false); } } else if (triggerer is Submarine submarine) { foreach (Attack attack in attacks) { float structureDamage = attack.GetStructureDamage(deltaTime); if (structureDamage > 0.0f) { Explosion.RangedStructureDamage(worldPosition, attack.DamageRange, structureDamage, levelWallDamage: 0.0f); } } if (!string.IsNullOrWhiteSpace(InfectIdentifier)) { submarine.AttemptBallastFloraInfection(InfectIdentifier, deltaTime, InfectionChance); } } if (Force.LengthSquared() > 0.01f) { if (triggerer is Character character) { ApplyForce(character.AnimController.Collider, deltaTime); foreach (Limb limb in character.AnimController.Limbs) { if (limb.IsSevered) { continue; } ApplyForce(limb.body, deltaTime); } } else if (triggerer is Submarine submarine) { ApplyForce(submarine.SubBody.Body, deltaTime); } } if (triggerer == Character.Controlled || triggerer == Character.Controlled?.Submarine) { GameMain.GameScreen.Cam.Shake = Math.Max(GameMain.GameScreen.Cam.Shake, cameraShake); } } }
public Limb(Ragdoll ragdoll, Character character, LimbParams limbParams) { this.ragdoll = ragdoll; this.character = character; this.Params = limbParams; wearingItems = new List <WearableSprite>(); dir = Direction.Right; body = new PhysicsBody(limbParams); type = limbParams.Type; if (limbParams.IgnoreCollisions) { body.CollisionCategories = Category.None; body.CollidesWith = Category.None; ignoreCollisions = true; } else { //limbs don't collide with each other body.CollisionCategories = Physics.CollisionCharacter; body.CollidesWith = Physics.CollisionAll & ~Physics.CollisionCharacter & ~Physics.CollisionItem & ~Physics.CollisionItemBlocking; } body.UserData = this; pullJoint = new FixedMouseJoint(body.FarseerBody, ConvertUnits.ToSimUnits(limbParams.PullPos * Scale)) { Enabled = false, //MaxForce = ((type == LimbType.LeftHand || type == LimbType.RightHand) ? 400.0f : 150.0f) * body.Mass // 150 or even 400 is too low if the joint is used for moving the character position from the mainlimb towards the collider position MaxForce = 1000 * Mass }; GameMain.World.Add(pullJoint); var element = limbParams.Element; body.BodyType = BodyType.Dynamic; foreach (XElement subElement in element.Elements()) { switch (subElement.Name.ToString().ToLowerInvariant()) { case "attack": attack = new Attack(subElement, (character == null ? "null" : character.Name) + ", limb " + type); if (attack.DamageRange <= 0) { switch (body.BodyShape) { case PhysicsBody.Shape.Circle: attack.DamageRange = body.radius; break; case PhysicsBody.Shape.Capsule: attack.DamageRange = body.height / 2 + body.radius; break; case PhysicsBody.Shape.Rectangle: attack.DamageRange = new Vector2(body.width / 2.0f, body.height / 2.0f).Length(); break; } attack.DamageRange = ConvertUnits.ToDisplayUnits(attack.DamageRange); } break; case "damagemodifier": DamageModifiers.Add(new DamageModifier(subElement, character.Name)); break; } } SerializableProperties = SerializableProperty.GetProperties(this); InitProjSpecific(element); }
public SubmarineBody(Submarine sub, bool showWarningMessages = true) { this.submarine = sub; Body farseerBody = null; if (!Hull.hullList.Any()) { farseerBody = BodyFactory.CreateRectangle(GameMain.World, 1.0f, 1.0f, 1.0f); if (showWarningMessages) { DebugConsole.ThrowError("WARNING: no hulls found, generating a physics body for the submarine failed."); } } else { List <Vector2> convexHull = GenerateConvexHull(); HullVertices = convexHull; for (int i = 0; i < convexHull.Count; i++) { convexHull[i] = ConvertUnits.ToSimUnits(convexHull[i]); } Vector2 minExtents = Vector2.Zero, maxExtents = Vector2.Zero; farseerBody = BodyFactory.CreateBody(GameMain.World, this); foreach (Structure wall in Structure.WallList) { if (wall.Submarine != submarine) { continue; } Rectangle rect = wall.Rect; FixtureFactory.AttachRectangle( ConvertUnits.ToSimUnits(wall.BodyWidth), ConvertUnits.ToSimUnits(wall.BodyHeight), 50.0f, -wall.BodyRotation, ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2) + wall.BodyOffset), farseerBody, this); minExtents.X = Math.Min(rect.X, minExtents.X); minExtents.Y = Math.Min(rect.Y - rect.Height, minExtents.Y); maxExtents.X = Math.Max(rect.Right, maxExtents.X); maxExtents.Y = Math.Max(rect.Y, maxExtents.Y); } foreach (Hull hull in Hull.hullList) { if (hull.Submarine != submarine) { continue; } Rectangle rect = hull.Rect; FixtureFactory.AttachRectangle( ConvertUnits.ToSimUnits(rect.Width), ConvertUnits.ToSimUnits(rect.Height), 100.0f, ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2)), farseerBody, this); minExtents.X = Math.Min(rect.X, minExtents.X); minExtents.Y = Math.Min(rect.Y - rect.Height, minExtents.Y); maxExtents.X = Math.Max(rect.Right, maxExtents.X); maxExtents.Y = Math.Max(rect.Y, maxExtents.Y); } foreach (Item item in Item.ItemList) { if (item.StaticBodyConfig == null || item.Submarine != submarine) { continue; } float radius = item.StaticBodyConfig.GetAttributeFloat("radius", 0.0f) * item.Scale; float width = item.StaticBodyConfig.GetAttributeFloat("width", 0.0f) * item.Scale; float height = item.StaticBodyConfig.GetAttributeFloat("height", 0.0f) * item.Scale; Vector2 simPos = ConvertUnits.ToSimUnits(item.Position); float simRadius = ConvertUnits.ToSimUnits(radius); float simWidth = ConvertUnits.ToSimUnits(width); float simHeight = ConvertUnits.ToSimUnits(height); if (width > 0.0f && height > 0.0f) { FixtureFactory.AttachRectangle(simWidth, simHeight, 5.0f, simPos, farseerBody, this).UserData = item; minExtents.X = Math.Min(item.Position.X - width / 2, minExtents.X); minExtents.Y = Math.Min(item.Position.Y - height / 2, minExtents.Y); maxExtents.X = Math.Max(item.Position.X + width / 2, maxExtents.X); maxExtents.Y = Math.Max(item.Position.Y + height / 2, maxExtents.Y); } else if (radius > 0.0f && width > 0.0f) { FixtureFactory.AttachRectangle(simWidth, simRadius * 2, 5.0f, simPos, farseerBody, this).UserData = item; FixtureFactory.AttachCircle(simRadius, 5.0f, farseerBody, simPos - Vector2.UnitX * simWidth / 2, this).UserData = item; FixtureFactory.AttachCircle(simRadius, 5.0f, farseerBody, simPos + Vector2.UnitX * simWidth / 2, this).UserData = item; minExtents.X = Math.Min(item.Position.X - width / 2 - radius, minExtents.X); minExtents.Y = Math.Min(item.Position.Y - radius, minExtents.Y); maxExtents.X = Math.Max(item.Position.X + width / 2 + radius, maxExtents.X); maxExtents.Y = Math.Max(item.Position.Y + radius, maxExtents.Y); } else if (radius > 0.0f && height > 0.0f) { FixtureFactory.AttachRectangle(simRadius * 2, height, 5.0f, simPos, farseerBody, this).UserData = item; FixtureFactory.AttachCircle(simRadius, 5.0f, farseerBody, simPos - Vector2.UnitY * simHeight / 2, this).UserData = item; FixtureFactory.AttachCircle(simRadius, 5.0f, farseerBody, simPos + Vector2.UnitX * simHeight / 2, this).UserData = item; minExtents.X = Math.Min(item.Position.X - radius, minExtents.X); minExtents.Y = Math.Min(item.Position.Y - height / 2 - radius, minExtents.Y); maxExtents.X = Math.Max(item.Position.X + radius, maxExtents.X); maxExtents.Y = Math.Max(item.Position.Y + height / 2 + radius, maxExtents.Y); } else if (radius > 0.0f) { FixtureFactory.AttachCircle(simRadius, 5.0f, farseerBody, simPos, this).UserData = item; minExtents.X = Math.Min(item.Position.X - radius, minExtents.X); minExtents.Y = Math.Min(item.Position.Y - radius, minExtents.Y); maxExtents.X = Math.Max(item.Position.X + radius, maxExtents.X); maxExtents.Y = Math.Max(item.Position.Y + radius, maxExtents.Y); } } Borders = new Rectangle((int)minExtents.X, (int)maxExtents.Y, (int)(maxExtents.X - minExtents.X), (int)(maxExtents.Y - minExtents.Y)); } farseerBody.BodyType = BodyType.Dynamic; farseerBody.CollisionCategories = Physics.CollisionWall; farseerBody.CollidesWith = Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionCharacter | Physics.CollisionProjectile | Physics.CollisionWall; farseerBody.Restitution = Restitution; farseerBody.Friction = Friction; farseerBody.FixedRotation = true; farseerBody.Awake = true; farseerBody.SleepingAllowed = false; farseerBody.IgnoreGravity = true; farseerBody.OnCollision += OnCollision; farseerBody.UserData = submarine; Body = new PhysicsBody(farseerBody); }
public Limb(Character character, XElement element, float scale = 1.0f) { this.character = character; WearingItems = new List <WearableSprite>(); dir = Direction.Right; DoesFlip = element.GetAttributeBool("flip", false); Scale = scale; body = new PhysicsBody(element, scale); if (element.GetAttributeBool("ignorecollisions", false)) { body.CollisionCategories = Category.None; body.CollidesWith = Category.None; ignoreCollisions = true; } else { //limbs don't collide with each other body.CollisionCategories = Physics.CollisionCharacter; body.CollidesWith = Physics.CollisionAll & ~Physics.CollisionCharacter & ~Physics.CollisionItem; } body.UserData = this; RefJointIndex = -1; Vector2 pullJointPos = Vector2.Zero; if (element.Attribute("type") != null) { try { type = (LimbType)Enum.Parse(typeof(LimbType), element.Attribute("type").Value, true); } catch { type = LimbType.None; DebugConsole.ThrowError("Error in " + element + "! \"" + element.Attribute("type").Value + "\" is not a valid limb type"); } pullJointPos = element.GetAttributeVector2("pullpos", Vector2.Zero) * scale; pullJointPos = ConvertUnits.ToSimUnits(pullJointPos); stepOffset = element.GetAttributeVector2("stepoffset", Vector2.Zero) * scale; stepOffset = ConvertUnits.ToSimUnits(stepOffset); RefJointIndex = element.GetAttributeInt("refjoint", -1); } else { type = LimbType.None; } pullJoint = new FixedMouseJoint(body.FarseerBody, pullJointPos); pullJoint.Enabled = false; pullJoint.MaxForce = ((type == LimbType.LeftHand || type == LimbType.RightHand) ? 400.0f : 150.0f) * body.Mass; GameMain.World.AddJoint(pullJoint); SteerForce = element.GetAttributeFloat("steerforce", 0.0f); if (element.Attribute("mouthpos") != null) { MouthPos = ConvertUnits.ToSimUnits(element.GetAttributeVector2("mouthpos", Vector2.Zero)); } body.BodyType = BodyType.Dynamic; body.FarseerBody.AngularDamping = LimbAngularDamping; damageModifiers = new List <DamageModifier>(); foreach (XElement subElement in element.Elements()) { switch (subElement.Name.ToString().ToLowerInvariant()) { case "sprite": string spritePath = subElement.Attribute("texture").Value; string spritePathWithTags = spritePath; if (character.Info != null) { spritePath = spritePath.Replace("[GENDER]", (character.Info.Gender == Gender.Female) ? "f" : ""); spritePath = spritePath.Replace("[HEADID]", character.Info.HeadSpriteId.ToString()); if (character.Info.HeadSprite != null && character.Info.SpriteTags.Any()) { string tags = ""; character.Info.SpriteTags.ForEach(tag => tags += "[" + tag + "]"); spritePathWithTags = Path.Combine( Path.GetDirectoryName(spritePath), Path.GetFileNameWithoutExtension(spritePath) + tags + Path.GetExtension(spritePath)); } } if (File.Exists(spritePathWithTags)) { sprite = new Sprite(subElement, "", spritePathWithTags); } else { sprite = new Sprite(subElement, "", spritePath); } break; case "damagedsprite": string damagedSpritePath = subElement.Attribute("texture").Value; if (character.Info != null) { damagedSpritePath = damagedSpritePath.Replace("[GENDER]", (character.Info.Gender == Gender.Female) ? "f" : ""); damagedSpritePath = damagedSpritePath.Replace("[HEADID]", character.Info.HeadSpriteId.ToString()); } damagedSprite = new Sprite(subElement, "", damagedSpritePath); break; case "attack": attack = new Attack(subElement); break; case "damagemodifier": damageModifiers.Add(new DamageModifier(subElement)); break; } } InitProjSpecific(element); }
public SubmarineBody(Submarine sub) { this.submarine = sub; Body farseerBody = null; if (!Hull.hullList.Any()) { Body = new PhysicsBody(1, 1, 1, 1); farseerBody = Body.FarseerBody; DebugConsole.ThrowError("WARNING: no hulls found, generating a physics body for the submarine failed."); } else { List <Vector2> convexHull = GenerateConvexHull(); HullVertices = convexHull; for (int i = 0; i < convexHull.Count; i++) { convexHull[i] = ConvertUnits.ToSimUnits(convexHull[i]); } convexHull.Reverse(); //get farseer 'vertices' from vectors Vertices shapevertices = new Vertices(convexHull); AABB hullAABB = shapevertices.GetAABB(); Borders = new Rectangle( (int)ConvertUnits.ToDisplayUnits(hullAABB.LowerBound.X), (int)ConvertUnits.ToDisplayUnits(hullAABB.UpperBound.Y), (int)ConvertUnits.ToDisplayUnits(hullAABB.Extents.X * 2.0f), (int)ConvertUnits.ToDisplayUnits(hullAABB.Extents.Y * 2.0f)); farseerBody = BodyFactory.CreateBody(GameMain.World, this); foreach (Structure wall in Structure.WallList) { if (wall.Submarine != submarine) { continue; } Rectangle rect = wall.Rect; FixtureFactory.AttachRectangle( ConvertUnits.ToSimUnits(rect.Width), ConvertUnits.ToSimUnits(rect.Height), 50.0f, ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2)), farseerBody, this); } foreach (Hull hull in Hull.hullList) { if (hull.Submarine != submarine) { continue; } Rectangle rect = hull.Rect; FixtureFactory.AttachRectangle( ConvertUnits.ToSimUnits(rect.Width), ConvertUnits.ToSimUnits(rect.Height), 5.0f, ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2)), farseerBody, this); } } farseerBody.BodyType = BodyType.Dynamic; farseerBody.CollisionCategories = Physics.CollisionWall; farseerBody.CollidesWith = Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionCharacter | Physics.CollisionProjectile | Physics.CollisionWall; farseerBody.Restitution = Restitution; farseerBody.Friction = Friction; farseerBody.FixedRotation = true; //mass = Body.Mass; farseerBody.Awake = true; farseerBody.SleepingAllowed = false; farseerBody.IgnoreGravity = true; farseerBody.OnCollision += OnCollision; farseerBody.UserData = submarine; Body = new PhysicsBody(farseerBody); }
public LevelObject(LevelObjectPrefab prefab, Vector3 position, float scale, float rotation = 0.0f) { ActivePrefab = Prefab = prefab; Position = position; Scale = scale; Rotation = rotation; spriteIndex = ActivePrefab.Sprites.Any() ? Rand.Int(ActivePrefab.Sprites.Count, Rand.RandSync.Server) : -1; if (Sprite != null && prefab.SpriteSpecificPhysicsBodyElements.ContainsKey(Sprite)) { PhysicsBody = new PhysicsBody(prefab.SpriteSpecificPhysicsBodyElements[Sprite], ConvertUnits.ToSimUnits(new Vector2(position.X, position.Y)), Scale); } else if (prefab.PhysicsBodyElement != null) { PhysicsBody = new PhysicsBody(prefab.PhysicsBodyElement, ConvertUnits.ToSimUnits(new Vector2(position.X, position.Y)), Scale); } if (PhysicsBody != null) { PhysicsBody.SetTransformIgnoreContacts(PhysicsBody.SimPosition, -Rotation); PhysicsBody.BodyType = BodyType.Static; PhysicsBody.CollisionCategories = Physics.CollisionLevel; PhysicsBody.CollidesWith = Physics.CollisionWall | Physics.CollisionCharacter; } foreach (XElement triggerElement in prefab.LevelTriggerElements) { Triggers ??= new List <LevelTrigger>(); Vector2 triggerPosition = triggerElement.GetAttributeVector2("position", Vector2.Zero) * scale; if (rotation != 0.0f) { var ca = (float)Math.Cos(rotation); var sa = (float)Math.Sin(rotation); triggerPosition = new Vector2( ca * triggerPosition.X + sa * triggerPosition.Y, -sa * triggerPosition.X + ca * triggerPosition.Y); } var newTrigger = new LevelTrigger(triggerElement, new Vector2(position.X, position.Y) + triggerPosition, -rotation, scale, prefab.Name); int parentTriggerIndex = prefab.LevelTriggerElements.IndexOf(triggerElement.Parent); if (parentTriggerIndex > -1) { newTrigger.ParentTrigger = Triggers[parentTriggerIndex]; } Triggers.Add(newTrigger); } if (spriteIndex == -1) { foreach (var overrideProperties in prefab.OverrideProperties) { if (overrideProperties == null) { continue; } if (overrideProperties.Sprites.Count > 0) { spriteIndex = Rand.Int(overrideProperties.Sprites.Count, Rand.RandSync.Server); break; } } } NeedsUpdate = NeedsNetworkSyncing || (Triggers != null && Triggers.Any()) || Prefab.PhysicsBodyTriggerIndex > -1; InitProjSpecific(); }