public void Draw(Renderer renderer, SpatialData spatial, float depth) { Point textureDim = TextureDim; if (textureDim == Point.Zero) { textureDim = Texture.Bounds.Size; } Rectangle sourceRect = new Rectangle { Location = TextureOffset, Size = textureDim }; renderer.DrawSprite( position: spatial.Position, rotation: spatial.Rotation, scale: Scale, depth: depth, texture: Texture, hotspot: Hotspot, sourceRectangle: sourceRect, tint: Tint, spriteEffects: SpriteEffects); }
public override void Draw(Renderer renderer) { base.Draw(renderer); if (Health.IsAlive) { int currentHP = Health.CurrentHealth; int cols = Math.Min(currentHP, NumIconsPerRow); Vector2 healthIconDim = Conversion.ToMeters(HealthIcon.ScaledDim); Vector2 spacing = healthIconDim + IconPadding; SpatialData anchor = this.GetWorldSpatialData(); anchor.Position.X -= 0.5f * (cols * spacing.X); float left = anchor.Position.X; int hpIndex = 0; while (true) { for (int x = 0; x < cols; x++) { if (hpIndex++ >= currentHP) { goto DONE; } HealthIcon.Draw(renderer, anchor); anchor.Position.X += spacing.X; } anchor.Position.X = left; anchor.Position.Y += spacing.Y; } DONE :; } }
public void CopyFrom(SpatialData other) { Parent = other.Parent; Position = other.Position; Rotation = other.Rotation; LocalAABB = other.LocalAABB; }
public SpatialData GetCopy() { SpatialData result = new SpatialData(); result.CopyFrom(this); return(result); }
/// <summary> /// Gets the world position and rotation for this spatial object. /// The result has the same LocalAABB, i.e. it is not inherited. /// The result will have no parent. /// </summary> public static SpatialData GetWorldSpatialData(this ISpatial self) { Vector2 position = Vector2.Zero; float radians = 0.0f; ISpatial parent = self; while (parent != null) { SpatialData spatial = parent.Spatial; position += spatial.Position; radians += spatial.Rotation.Radians; Debug.Assert(spatial.Parent != parent); parent = spatial.Parent; } SpatialData result = new SpatialData { Position = position, Rotation = new Angle { Radians = radians }, LocalAABB = self.Spatial.LocalAABB, }; return(result); }
public override void Initialize() { SpatialData spatial = this.GetWorldSpatialData(); Body body = BodyFactory.CreateBody( world: Global.Game.World, position: spatial.Position, rotation: spatial.Rotation.Radians); FixtureFactory.AttachRectangle( body: body, offset: Conversion.ToMeters(0, -50), width: Conversion.ToMeters(330), height: Conversion.ToMeters(100), density: Global.OwliverDensity); FixtureFactory.AttachRectangle( body: body, offset: Conversion.ToMeters(0, -160), width: Conversion.ToMeters(280), height: Conversion.ToMeters(150), density: Global.OwliverDensity); BodyComponent.Body = body; base.Initialize(); }
public float CalcDepth(SpatialData spatial, GameLayer layer) { // Note(manu): 0 means front, 1 means back. float maxY = Level.SCREEN_DIMENSION * CurrentLevel.ScreenTileHeight; float y = MathHelper.Clamp(spatial.Position.Y, 0, maxY); float alpha = y / maxY; float depth; switch (layer) { case GameLayer.CloseToTheScreen: depth = MathHelper.Lerp(0.0999f, 0.0f, alpha); break; case GameLayer.SomewhereInTheMiddle: depth = MathHelper.Lerp(0.9f, 0.1f, alpha); break; case GameLayer.Background: depth = 1.0f; break; default: throw new ArgumentException("layer"); } return(depth); }
public override void Update(float deltaSeconds) { SpatialData s = this.GetWorldSpatialData(); Body.SetTransform(ref s.Position, s.Rotation.Radians); base.Update(deltaSeconds); }
public override void Draw(Renderer renderer) { base.Draw(renderer); SpatialData worldSpatial = this.GetWorldSpatialData(); Sprite.Draw(renderer, worldSpatial, RenderDepth); }
public override void Draw(Renderer renderer) { base.Draw(renderer); SpatialData worldSpatial = this.GetWorldSpatialData(); ActiveAnimation.Draw(renderer, worldSpatial, RenderDepth, AdditionalScale, Tint); }
public override void Initialize() { Debug.Assert(Orientation != SpikeTrapOrientation.None); SpatialData s = this.GetWorldSpatialData(); FixedOrigin.Spatial.CopyFrom(s); float halfThickness = 0.5f * SensorThickness; float halfReach = 0.5f * SensorReach; switch (Orientation) { case SpikeTrapOrientation.Horizontal: { TargetSensor.RectangleSensorLocalAABB = new AABB { LowerBound = new Vector2(-halfReach, -halfThickness), UpperBound = new Vector2(halfReach, halfThickness), }; } break; case SpikeTrapOrientation.Vertical: { TargetSensor.RectangleSensorLocalAABB = new AABB { LowerBound = new Vector2(-halfThickness, -halfReach), UpperBound = new Vector2(halfThickness, halfReach), }; } break; default: throw new ArgumentException(nameof(Orientation)); } { Body body = BodyFactory.CreateRectangle( world: Global.Game.World, bodyType: BodyType.Kinematic, position: s.Position, rotation: s.Rotation.Radians, width: 1, height: 1, density: Global.OwliverDensity); body.FixedRotation = true; body.CollisionCategories = CollisionCategory.Enemy | CollisionCategory.EnemyWeapon; body.OnCollision += MovingBody_OnCollision; MovingBodyComponent.Body = body; } base.Initialize(); TargetSensorAABB = TargetSensor.Body.ComputeAABB(); }
public static void SetWorldRotation(this ISpatial self, Angle worldRotation) { if (self.Spatial.Parent != null) { SpatialData parent = self.Spatial.Parent.GetWorldSpatialData(); self.Spatial.Rotation = worldRotation - parent.Rotation; } else { self.Spatial.Rotation = worldRotation; } }
public static void SetWorldPosition(this ISpatial self, Vector2 worldPosition) { if (self.Spatial.Parent != null) { SpatialData parent = self.Spatial.Parent.GetWorldSpatialData(); self.Spatial.Position = worldPosition - parent.Position; } else { self.Spatial.Position = worldPosition; } }
public override void Initialize() { { SpatialData s = this.GetWorldSpatialData(); Body body = new Body( world: Global.Game.World, position: s.Position, rotation: s.Rotation.Radians, bodyType: BodyType.Dynamic, userdata: BodyComponent); float radius = Conversion.ToMeters(80 * Global.SlurpScale.X); float density = Global.OwliverDensity; FixtureFactory.AttachCircle( radius: radius, density: density, body: body, offset: Conversion.ToMeters(0, -25) * Global.SlurpScale); FixtureFactory.AttachCircle( radius: radius, density: density, body: body, offset: Conversion.ToMeters(0, 25) * Global.SlurpScale); body.FixedRotation = true; body.LinearDamping = 5.0f; body.OnCollision += OnCollision; body.CollisionCategories = CollisionCategory.Enemy; BodyComponent.Body = body; } base.Initialize(); // Disable chasing when we are invincible. Health.OnInvincibilityGained += () => { Homing.TargetSensor.Body.Enabled = false; }; Health.OnInvincibilityLost += () => { Homing.TargetSensor.Body.Enabled = true; }; }
public override void Update(float deltaSeconds) { base.Update(deltaSeconds); if (DepthReference != null) { SpatialData spatial = DepthReference.GetWorldSpatialData(); RenderDepth = Global.Game.CalcDepth(spatial, Owner.Layer); if (DebugDrawingEnabled) { Global.Game.DebugDrawCommands.Add(view => { view.DrawPoint(spatial.Position, Conversion.ToMeters(3), Color.Navy); }); } } }
public override void Initialize() { SpatialData s = BodyComponent.GetWorldSpatialData(); BodyComponent.Body = BodyFactory.CreateCircle( world: Global.Game.World, radius: 0.2f, density: 0.5f * Global.OwliverDensity, position: s.Position); BodyComponent.Body.IsSensor = true; BodyComponent.Body.CollidesWith = CollisionCategory.Friendly; SpriteAnimationType animType = SpriteAnimationType.Bonbon_Gold + (int)BonbonType; Animation.AnimationTypes.Add(animType); base.Initialize(); }
/// <summary> /// Returns the SpatialData instance representing the offset. /// </summary> public static SpatialData AttachWithOffsetTo(this ISpatial self, ISpatial newParent, Vector2 positionOffset, Angle rotationOffset) { SpatialData result = null; if (newParent != self) { result = new SpatialData() { Position = positionOffset, Rotation = rotationOffset }; result.AttachTo(newParent); self.AttachTo(result); } return(result); }
public override void Initialize() { Debug.Assert(TargetCollisionCategories != 0, "You should have set target collision categories by now."); SpatialData s = this.GetWorldSpatialData(); switch (SensorType) { case TargetSensorType.Unknown: throw new NotImplementedException(); case TargetSensorType.Circle: { Debug.Assert(CircleSensorRadius > 0.0f); Body = BodyFactory.CreateCircle( world: Global.Game.World, bodyType: BodyType.Static, position: s.Position, radius: CircleSensorRadius, density: 0); } break; case TargetSensorType.Rectangle: { Body = BodyFactory.CreateRectangle( world: Global.Game.World, bodyType: BodyType.Static, position: RectangleSensorLocalAABB.Center, width: RectangleSensorLocalAABB.Width, height: RectangleSensorLocalAABB.Height, density: 0); } break; default: throw new ArgumentException(nameof(SensorType)); } base.Initialize(); Body.IsSensor = true; Body.CollidesWith = TargetCollisionCategories; Body.OnCollision += OnCollision; Body.OnSeparation += OnSeparation; }
public override void Update(float deltaSeconds) { base.Update(deltaSeconds); SpriteAnimationPlaybackState oldPlaybackState = ActiveAnimation.State.PlaybackState; ActiveAnimation.Update(deltaSeconds); SpriteAnimationPlaybackState newPlaybackState = ActiveAnimation.State.PlaybackState; if (newPlaybackState != oldPlaybackState) { OnAnimationPlaybackStateChanged?.Invoke(ActiveAnimationType, oldPlaybackState, newPlaybackState); } Global.Game.DebugDrawCommands.Add(view => { SpatialData worldSpatial = this.GetWorldSpatialData(); view.DrawAABB(worldSpatial.AbsoluteAABB, new Color(0xdd, 0x99, 0x44)); }); }
public override void Initialize() { SpatialData s = this.GetWorldSpatialData(); MyBody = new Body( world: Global.Game.World, position: s.Position, rotation: s.Rotation.Radians, bodyType: BodyType.Dynamic, userdata: BodyComponent); float radius = Conversion.ToMeters(60) * Global.OwliverScale.X; float density = Global.OwliverDensity; Fixture lowerFixture = FixtureFactory.AttachCircle( radius: radius, density: density, body: MyBody); Fixture upperFixture = FixtureFactory.AttachCircle( radius: radius, density: density, body: MyBody, offset: Conversion.ToMeters(0, -70) * Global.OwliverScale); upperFixture.CollidesWith = CollisionCategory.EnemyWeapon; MyBody.CollisionCategories = CollisionCategory.Friendly | CollisionCategory.Owliver; MyBody.FixedRotation = true; MyBody.SleepingAllowed = false; MyBody.LinearDamping = 15.0f; MyBody.OnCollision += OnCollision; MyBody.OnSeparation += OnSeparation; BodyComponent.Body = MyBody; Animation.OnAnimationPlaybackStateChanged += OnAnimationLoopFinished; base.Initialize(); }
public override void Initialize() { { float halfWidth = Conversion.ToMeters(80) * Global.SingerScale.X; SpatialData s = this.GetWorldSpatialData(); Body body = BodyFactory.CreateCapsule( world: Global.Game.World, bodyType: BodyType.Dynamic, position: s.Position, rotation: s.Rotation.Radians, height: Conversion.ToMeters(240) * Global.SingerScale.Y - 2.0f * halfWidth, endRadius: halfWidth, density: Global.OwliverDensity); body.LinearDamping = 10.0f; body.FixedRotation = true; body.CollisionCategories = CollisionCategory.Enemy; BodyComponent.Body = body; } base.Initialize(); }
public override void Initialize() { SpatialData s = this.GetWorldSpatialData(); Body body = BodyFactory.CreateCapsule( world: Global.Game.World, endRadius: Conversion.ToMeters(9), height: Conversion.ToMeters(50), position: s.Position, rotation: s.Rotation.Radians + new Angle { Degrees = 90.0f + new Random().NextBilateralFloat() * 2 }.Radians, density: 1000 * Global.OwliverDensity, bodyType: BodyType.Dynamic); body.CollisionCategories = CollisionCategories; body.CollidesWith = CollidesWith; body.IsBullet = true; body.OnCollision += OnCollision; BodyComponent.Body = body; base.Initialize(); }
public override void Initialize() { SpatialData s = this.GetWorldSpatialData(); Vector2 dim = Conversion.ToMeters(350, 400) * Global.TanktonScale; Body body = BodyFactory.CreateRoundedRectangle( world: Global.Game.World, position: s.Position, rotation: s.Rotation.Radians, bodyType: BodyType.Dynamic, width: dim.X, height: dim.Y, xRadius: 0.5f, yRadius: 0.5f, density: 2 * Global.OwliverDensity, segments: 0); body.FixedRotation = true; body.LinearDamping = 20.0f; body.CollisionCategories = CollisionCategory.Enemy; BodyComponent.Body = body; base.Initialize(); }
public void Draw(Renderer renderer, float deltaSeconds) { CrossAnimation.Update(deltaSeconds); foreach (SpriteAnimationInstance anim in DigitAnimations) { anim.Update(deltaSeconds); } foreach (SpriteAnimationInstance anim in KeyAnimations) { anim.Update(deltaSeconds); } if (HealthIconAnimation != null) { HealthIconAnimation.Update(deltaSeconds); int hp = Owliver.Health.MaxHealth; SpatialData spatial = HealthIconAnchor.GetWorldSpatialData(); const float spacing = 3; for (int healthIndex = 0; healthIndex < hp; healthIndex++) { Color tint = healthIndex < Owliver.Health.CurrentHealth ? FullHealthTint : NoHealthTint; HealthIconAnimation.Draw(renderer, spatial.GetWorldSpatialData(), tint: tint); spatial.Position.X += HealthIconAnimation.ScaledDim.X + spacing; } } if (Owliver.MoneyBag != null) { MoneyBagIconAnimation.Update(deltaSeconds); SpatialData spatial = MoneyBagIconAnchor.GetWorldSpatialData(); MoneyBagIconAnimation.Draw(renderer, MoneyBagIconAnchor); const float spacing = 3; float previousAnimWidth = MoneyBagIconAnimation.ScaledDim.X; spatial.Position.X -= 0.5f * CrossAnimation.ScaledDim.X + 0.5f * previousAnimWidth + spacing; CrossAnimation.Draw(renderer, spatial); previousAnimWidth = CrossAnimation.ScaledDim.X; int value = Owliver.MoneyBag.CurrentAmount; while (true) { int digit = value % 10; SpriteAnimationInstance digitAnim = DigitAnimations[digit]; spatial.Position.X -= 0.5f * previousAnimWidth + 0.5f * digitAnim.ScaledDim.X + spacing; digitAnim.Draw(renderer, spatial); value /= 10; if (value == 0) { break; } previousAnimWidth = digitAnim.ScaledDim.X; } } if (Owliver.KeyRing != null) { SpatialData anchor = KeyRingAnchor.GetWorldSpatialData(); for (int keyTypeIndex = 0; keyTypeIndex < (int)KeyType.COUNT; keyTypeIndex++) { KeyType keyType = (KeyType)keyTypeIndex; int keyAmount = Owliver.KeyRing[keyType]; SpriteAnimationInstance keyAnim = KeyAnimations[keyTypeIndex]; SpatialData spatial = anchor.GetWorldSpatialData(); for (int keyIndex = 0; keyIndex < keyAmount; keyIndex++) { keyAnim.Draw(renderer, spatial); spatial.Position.X += 0.6f * keyAnim.ScaledDim.X; } anchor.Position.Y += 0.8f * keyAnim.ScaledDim.Y; } } }
public override void Update(float deltaSeconds) { base.Update(deltaSeconds); switch (TrapState) { case SpikeTrapState.Searching: { Body target = TargetSensor.CurrentMainTarget; if (target != null) { SpatialData originSpatial = FixedOrigin.GetWorldSpatialData(); Vector2 attackDir; switch (Orientation) { case SpikeTrapOrientation.Horizontal: { float deltaX = target.Position.X - originSpatial.Position.X; attackDir = new Vector2(Math.Sign(deltaX), 0); } break; case SpikeTrapOrientation.Vertical: { float deltaY = target.Position.Y - originSpatial.Position.Y; attackDir = new Vector2(0, Math.Sign(deltaY)); } break; default: throw new ArgumentException(nameof(Orientation)); } MovingBody.LinearVelocity = attackDir * AttackSpeed; EnterState(SpikeTrapState.Attacking); } } break; case SpikeTrapState.Attacking: { Vector2 movementDir = MovingBody.LinearVelocity.GetNormalizedSafe(); SpatialData originSpatial = FixedOrigin.GetWorldSpatialData(); Vector2 attackPosition = originSpatial.Position + movementDir * SensorReach; bool isAtEnd; switch (Orientation) { case SpikeTrapOrientation.Horizontal: { if (movementDir.X > 0) { isAtEnd = MovingBody.Position.X >= attackPosition.X; } else { isAtEnd = MovingBody.Position.X <= attackPosition.X; } } break; case SpikeTrapOrientation.Vertical: { if (movementDir.Y > 0) { isAtEnd = MovingBody.Position.Y >= attackPosition.Y; } else { isAtEnd = MovingBody.Position.Y <= attackPosition.Y; } } break; default: throw new ArgumentException(nameof(Orientation)); } if (isAtEnd) { EnterState(SpikeTrapState.WaitingAfterAttacking); MovingBody.Position = attackPosition; } } break; case SpikeTrapState.WaitingAfterAttacking: { CurrentWaitTime += TimeSpan.FromSeconds(deltaSeconds); if (CurrentWaitTime >= DelayBeforeReturning) { EnterState(SpikeTrapState.Returning); Vector2 originDelta = FixedOrigin.GetWorldSpatialData().Position - MovingBody.Position; Vector2 originDir = originDelta.GetNormalizedSafe(); MovingBody.LinearVelocity = originDir * ReturnSpeed; } } break; case SpikeTrapState.Returning: { Vector2 movementDir = MovingBody.LinearVelocity.GetNormalizedSafe(); SpatialData originSpatial = FixedOrigin.GetWorldSpatialData(); bool isAtEnd; switch (Orientation) { case SpikeTrapOrientation.Horizontal: { if (movementDir.X > 0) { isAtEnd = MovingBody.Position.X >= originSpatial.Position.X; } else { isAtEnd = MovingBody.Position.X <= originSpatial.Position.X; } } break; case SpikeTrapOrientation.Vertical: { if (movementDir.Y > 0) { isAtEnd = MovingBody.Position.Y >= originSpatial.Position.Y; } else { isAtEnd = MovingBody.Position.Y <= originSpatial.Position.Y; } } break; default: throw new ArgumentException(nameof(Orientation)); } if (isAtEnd) { EnterState(SpikeTrapState.Searching); MovingBody.Position = originSpatial.Position; MovingBody.Awake = false; } } break; default: throw new ArgumentException(nameof(TrapState)); } if (CurrentHitCooldown > TimeSpan.Zero) { CurrentHitCooldown -= TimeSpan.FromSeconds(deltaSeconds); if (CurrentHitCooldown <= TimeSpan.Zero) { CurrentHitCooldown = TimeSpan.Zero; } } { Global.Game.DebugDrawCommands.Add(view => { view.DrawString(20, 400, $"{TrapState}"); }); } }
public override void Initialize() { float outerLeft = Conversion.ToMeters(310); float innerLeft = Conversion.ToMeters(79); float inner = Conversion.ToMeters(80); float innerRight = Conversion.ToMeters(79); float outerRight = Conversion.ToMeters(222); float width = Conversion.ToMeters(768); float height = Conversion.ToMeters(128); float barrierHeight = Conversion.ToMeters(20); float density = Global.OwliverDensity; // // Inner body // { // TODO(manu): Set InnerBodyComponent.Spatial.LocalAABB. SpatialData s = InnerBodyComponent.GetWorldSpatialData(); InnerBodyComponent.Body = BodyFactory.CreateRectangle( world: Global.Game.World, width: innerLeft + inner + innerRight, height: barrierHeight, density: density, position: s.Position + new Vector2(outerLeft + innerLeft + 0.5f * inner, 0.0f), rotation: s.Rotation.Radians, bodyType: BodyType.Static); } // // Outer body // { // TODO(manu): Set OuterBodyComponent.Spatial.LocalAABB. SpatialData s = OuterBodyComponent.GetWorldSpatialData(); OuterBodyComponent.Body = BodyFactory.CreateBody( world: Global.Game.World, position: s.Position, rotation: s.Rotation.Radians, bodyType: BodyType.Static); Vector2 offsetRight = Conversion.ToMeters(300, 0); FixtureFactory.AttachRectangle( body: OuterBodyComponent.Body, width: outerLeft, height: barrierHeight, offset: new Vector2(0.5f * outerLeft, 0.0f), density: density); FixtureFactory.AttachRectangle( body: OuterBodyComponent.Body, width: outerRight, height: barrierHeight, offset: new Vector2(width - 0.5f * outerRight, 0.0f), density: density); } // // Trigger body // { Vector2 dim = Conversion.ToMeters(60, 80); Trigger.Spatial.LocalAABB = new AABB { LowerBound = -0.5f * dim, UpperBound = 0.5f * dim, }; SpatialData s = Trigger.GetWorldSpatialData(); s.Position.Y -= Conversion.ToMeters(20); //s.Position.Y -= Conversion.ToMeters((0.5f * 128) - 10); Trigger.Body = BodyFactory.CreateRectangle( world: Global.Game.World, width: s.LocalAABB.Width, height: s.LocalAABB.Height, density: 0, position: s.Position, rotation: s.Rotation.Radians, bodyType: BodyType.Static); Trigger.Body.IsSensor = true; Trigger.Body.CollidesWith = CollisionCategory.Friendly; Trigger.Body.OnCollision += OnCollisionWithTrigger; } base.Initialize(); }
public void PerformChase(float deltaSeconds) { IsHoming = false; Body body = MyBody; if (Target != null) { SpatialData worldSpatial = this.GetWorldSpatialData(); SpatialData targetSpatial = Target.GetWorldSpatialData(); Vector2 targetDelta = targetSpatial.Position - worldSpatial.Position; targetDelta.GetDirectionAndLength(out Vector2 targetDir, out float targetDistance); if (targetDistance > TargetRange) { // Don't do anything. } else if (targetDistance > TargetInnerRange) { IsHoming = true; Vector2 velocity = targetDir * Speed; switch (HomingType) { case HomingType.ConstantSpeed: { if (body != null) { if (body.IsStatic) { Vector2 deltaPosition = velocity * deltaSeconds; body.Position += deltaPosition; } else { body.LinearVelocity = velocity; } } else { Vector2 deltaPosition = velocity * deltaSeconds; Vector2 newPosition = worldSpatial.Position + deltaPosition; Spatial.SetWorldPosition(newPosition); } } break; case HomingType.ConstantAcceleration: { if (body != null) { Vector2 impulse = body.Mass * velocity; body.ApplyLinearImpulse(ref impulse); } else { throw new NotImplementedException(); } } break; default: throw new ArgumentException(nameof(HomingType)); } } } if (DebugDrawingEnabled) { Global.Game.DebugDrawCommands.Add(view => { Vector2 p = this.GetWorldSpatialData().Position; view.DrawPoint(p, Conversion.ToMeters(3.0f), Color.Turquoise); view.DrawCircle(p, TargetInnerRange, Color.Yellow); view.DrawCircle(p, TargetRange, Color.Blue); }); } }