public bool Update(int direction, int lingerCounter, Chunk targetChunk) { float dt = Game1.DeltaT; Controller.Update(); Sprite.Update(dt); if (0 < DeathTimer) { DeathTimer -= dt; if (DeathTimer <= 0) { targetChunk.Die(this); Respawn(targetChunk); return(true); } if (Grounded) { Velocity.X = 0; } } switch (direction) { case Chunk.Left: if (lingerCounter > 0) { if (Grounded) { Velocity.X = 0; } else { if (-AccelRate * 0.5F * dt > Velocity.X) { Velocity.X += AccelRate * 0.5F * dt; } else { Velocity.X = 0; } } } else if (-MaxVel < Velocity.X) { if (0 < Velocity.X && Grounded) { Velocity.X = 0; } Velocity.X -= AccelRate * dt; } break; case Chunk.Right: if (lingerCounter > 0) { if (Grounded) { Velocity.X = 0; } else { if (AccelRate * 0.5F * dt < Velocity.X) { Velocity.X -= AccelRate * 0.5F * dt; } else { Velocity.X = 0; } } } else if (Velocity.X < MaxVel) { if (Velocity.X < 0 && Grounded) { Velocity.X = 0; } Velocity.X += AccelRate * dt; } break; case Chunk.Down: break; case Chunk.Up: break; } Velocity.Y -= dt * Gravity; if (State == PlayerState.CrashDoor) { if (Sprite.Frame == 6) { State = PlayerState.Normal; TargetEntity = null; } } HandleCollisions(dt, targetChunk, false); if (0 < Velocity.Y) { Sprite.Play("jump"); } else if (Velocity.Y < 0) { Sprite.Play("fall"); } else if (Velocity.X != 0) { Sprite.Play("run"); } else { Sprite.Play("idle"); } // Base direction on movement if (Velocity.X < 0) { Sprite.Direction = -1; } if (0 < Velocity.X) { Sprite.Direction = +1; } return(false); }
public override void Update(Chunk chunk) { float dt = Game1.DeltaT; Controller.Update(); Sprite.Update(dt); if (Controller.Pause) { Game.Paused = true; } if (0 < DeathTimer) { DeathTimer -= dt; if (DeathTimer <= 0) { chunk.Die(this); } if (Grounded) { Velocity.X = 0; } } if (Controller.Crouch && !Controller.Was.Crouch) { IsCrouched = !IsCrouched; } bool hide = Controller.Hide && !Controller.Was.Hide; bool jump = Controller.Jump && !Controller.Was.Jump; //// Perform movement stepping. //// !! This code should never change Position !! // Check for neighbors Object down = chunk.CollidePoint(new Vector2(Position.X, Position.Y - Size.Y - 1)); Object left = chunk.CollidePoint(new Vector2(Position.X - Size.X - 1, Position.Y)); Object right = chunk.CollidePoint(new Vector2(Position.X + Size.X + 1, Position.Y)); Object leftCorner = chunk.CollidePoint(new Vector2(Position.X - Size.X - 1, Position.Y - Size.Y - 1)); Object rightCorner = chunk.CollidePoint(new Vector2(Position.X + Size.X + 1, Position.Y - Size.Y - 1)); // Apply gravity Velocity.Y -= dt * Gravity; chunk.ForEachCollidingTile(this, (tile, pos) => { if (tile is TileSpike && State != PlayerState.Dying) { Kill(); } else if (tile is TileGoal) { Game.SoundEngine.Play("win"); Game.ShowScore(); } }); switch (State) { case PlayerState.Climbing: case PlayerState.Normal: chunk.ForEachCollidingEntity(this, (entity) => { if (entity is Pickup && !chunk.Level.Alarm.IsRaised) { Vector2 buttonPos = Game.TextEngine.TranslateToWindow(entity.Position + new Vector2(0, 36)); Game.TextEngine.QueueButton(TextEngine.Button.Y, buttonPos); if (Controller.Interact) { if (chunk.NextItem < chunk.StoryItems.Length) { State = PlayerState.QueueInCall; ItemDialog = true; } chunk.Die(entity); } } else if (entity is HidingSpot) { Vector2 buttonPos = Game.TextEngine.TranslateToWindow(entity.Position + new Vector2(0, 36)); Game.TextEngine.QueueButton(TextEngine.Button.Y, buttonPos); if (hide) { TargetSpot = entity.Position; hide = false; State = PlayerState.QueueHide; } } else if (entity is Door && ((Door)entity).State == Door.EState.Closed) { if (entity.GetBoundingBox().Bottom <= GetBoundingBox().Bottom) { float dir = Math.Sign(Position.X - entity.Position.X); if (-Sprite.Direction == dir) { Vector2 buttonPos = Game.TextEngine.TranslateToWindow(entity.Position + new Vector2(dir * 1.1F * Chunk.TileSize, 32)); Game.TextEngine.QueueButton(TextEngine.Button.Y, buttonPos); if (entity == TargetEntity) { if (Controller.Interact && !IsCrouched) { InteractTimer -= Game1.DeltaT; if (InteractTimer <= 0) { State = PlayerState.QueueCrash; TargetSpot = entity.Position + new Vector2(dir * (0.5F * Chunk.TileSize + 1), 0); } } else { State = PlayerState.QueueDoor; TargetSpot = entity.Position + new Vector2(dir * (0.5F * Chunk.TileSize + 1), 0); } } else { if (Controller.Interact) { TargetEntity = entity; InteractTimer = InteractHold; } } } } } else if (entity is ButtonPrompt) { Vector2 buttonPos = Game.TextEngine.TranslateToWindow(entity.Position + new Vector2(0, 36)); ((ButtonPrompt)entity).DrawPrompt(); } else if (entity is DialogTrigger) { if (chunk.Level.NextTrigger < chunk.Level.TriggeredDialogs.Length) { State = PlayerState.QueueInCall; ItemDialog = false; } chunk.Die(entity); } else if (entity is AlarmTrigger) { ((AlarmTrigger)entity).Triggered = true; chunk.Level.Alarm.Detected = true; chunk.Level.Alarm.Alert(Position, chunk); } }); if (State == PlayerState.QueueHide || State == PlayerState.QueueDoor || State == PlayerState.QueueCrash || State == PlayerState.QueueInCall) { break; } if (left != null || right != null || (State == PlayerState.Climbing && (leftCorner != null || rightCorner != null))) { HasWallJumped = false; State = PlayerState.Normal; if (Controller.Climb) { State = PlayerState.Climbing; if (Controller.MoveUp && Velocity.Y < ClimbSpeed) { Velocity.Y = +ClimbSpeed; } else if (Controller.MoveDown) { Velocity.Y = -ClimbSpeed; } else if (Velocity.Y <= ClimbSpeed) { Velocity.Y = 0; } if (Velocity.X != 0) { State = PlayerState.Normal; } // Push over corners if (leftCorner != null && left == null && Sprite.Direction == -1) { Velocity.X = -150; Velocity.Y = ClimbSpeed; } if (rightCorner != null && right == null && Sprite.Direction == +1) { Velocity.X = +150; Velocity.Y = ClimbSpeed; } } else if (Velocity.Y < 0) { Velocity.Y *= WallSlideFriction; } if (jump && (!HasWallJumped || CanRepeatWallJump)) { if (right != null && (!Grounded)) { MakeSound(chunk, "walljump"); Velocity.X = -WallJumpVelocity.X; Velocity.Y = WallJumpVelocity.Y; HasWallJumped = true; jump = false; } else if (left != null && (!Grounded)) { MakeSound(chunk, "walljump"); Velocity.X = WallJumpVelocity.X; Velocity.Y = WallJumpVelocity.Y; HasWallJumped = true; jump = false; } } } else { State = PlayerState.Normal; } if (Grounded) { SoundFrame = -1; HasWallJumped = false; if (jump) { IsCrouched = false; MakeSound(chunk, "jump"); jump = false; Velocity.Y = JumpSpeed; LongJump = LongJumpTime * dt; } else if (!chunk.ChunkAlarmState && Controller.Call && !Controller.Was.Call) { State = PlayerState.QueueOutCall; } } if (State == PlayerState.Normal || Grounded) { float max = (IsCrouched) ? CrouchSpeed : MaxVel; if (Controller.MoveRight && Velocity.X < max) { // Allow quick turns on the ground if (Velocity.X < 0 && Grounded) { Velocity.X = 0; } Velocity.X += AccelRate * dt; } else if (Controller.MoveLeft && -max < Velocity.X) { // Allow quick turns on the ground if (0 < Velocity.X && Grounded) { Velocity.X = 0; } Velocity.X -= AccelRate * dt; } else if (!Controller.MoveLeft && !Controller.MoveRight) { // Deaccelerate in the air to accomodate wall jumps if (Grounded || Math.Abs(Velocity.X) < DeaccelRate * dt) { Velocity.X = 0; } else { Velocity.X -= Math.Sign(Velocity.X) * DeaccelRate * dt; } } else if (IsCrouched && max < Math.Abs(Velocity.X)) { Velocity.X = Math.Sign(Velocity.X) * max; } } if (Controller.Jump && 0 < LongJump) { Velocity.Y += AccelRate * dt; } else { LongJump = 0; } break; case PlayerState.QueueHide: if (Position.X < TargetSpot.X && Velocity.X < MaxVel) { // Allow quick turns on the ground if (Velocity.X < 0 && Grounded) { Velocity.X = 0; } Velocity.X += AccelRate * dt; } else if (Position.X > TargetSpot.X && -MaxVel < Velocity.X) { // Allow quick turns on the ground if (0 < Velocity.X && Grounded) { Velocity.X = 0; } Velocity.X -= AccelRate * dt; } if (Math.Abs(Position.X - TargetSpot.X) <= MaxVel * dt) { HasWallJumped = false; State = PlayerState.Hiding; Position = TargetSpot + new Vector2(0, Size.Y - Chunk.TileSize / 2); Velocity.X = 0; } if (Position.Y - Size.Y < TargetSpot.Y - Chunk.TileSize) { State = PlayerState.Normal; } break; case PlayerState.Hiding: Velocity.X = 0; Velocity.Y = 0; if (hide) { State = PlayerState.Normal; } break; case PlayerState.QueueDoor: if (Position.X < TargetSpot.X && Velocity.X < MaxVel) { // Allow quick turns on the ground if (Velocity.X < 0 && Grounded) { Velocity.X = 0; } Velocity.X += AccelRate * dt; } else if (Position.X > TargetSpot.X && -MaxVel < Velocity.X) { // Allow quick turns on the ground if (0 < Velocity.X && Grounded) { Velocity.X = 0; } Velocity.X -= AccelRate * dt; } if (Math.Abs(Position.X - TargetSpot.X) <= MaxVel * dt) { HasWallJumped = false; State = PlayerState.OpeningDoor; Position.X = TargetSpot.X; Velocity.X = 0; } if (Position.Y - Size.Y < TargetSpot.Y - Chunk.TileSize) { State = PlayerState.Normal; } break; case PlayerState.OpeningDoor: Velocity.X = 0; Velocity.Y = 0; if (Sprite.Frame == 78) { ((Door)TargetEntity).Interact(chunk, false, TargetEntity.Position.X < Position.X); } if (Sprite.Frame == 0) { State = PlayerState.Normal; TargetEntity = null; } break; case PlayerState.QueueCrash: if (Position.X < TargetSpot.X && Velocity.X < MaxVel) { // Allow quick turns on the ground if (Velocity.X < 0 && Grounded) { Velocity.X = 0; } Velocity.X += AccelRate * dt; } else if (Position.X > TargetSpot.X && -MaxVel < Velocity.X) { // Allow quick turns on the ground if (0 < Velocity.X && Grounded) { Velocity.X = 0; } Velocity.X -= AccelRate * dt; } if (Math.Abs(Position.X - TargetSpot.X) <= MaxVel * (dt + 0.6F / 4)) { HasWallJumped = false; State = PlayerState.CrashDoor; TargetSpot = TargetSpot + 999 * Vector2.UnitX * Math.Sign(TargetEntity.Position.X - Position.X); Velocity.X = MaxVel * Math.Sign(TargetSpot.X - Position.X); } break; case PlayerState.CrashDoor: Velocity.Y = 0; if (Sprite.Frame >= 88 && Sprite.Frame <= 91) { if (Velocity.X < 0 && Grounded) { Velocity.X = 0; } if (Velocity.X < MaxVel) { Velocity.X += Math.Sign(TargetSpot.X - Position.X) * 0.5F * AccelRate * dt; } } else { if (Velocity.X < 0 && Grounded) { Velocity.X = 0; } if (Velocity.X < MaxVel) { Velocity.X += Math.Sign(TargetSpot.X - Position.X) * AccelRate * dt; } } if (Sprite.Frame == 88) { ((Door)TargetEntity).Interact(chunk, true, TargetEntity.Position.X < Position.X); } if (Sprite.Frame == 6) { State = PlayerState.Normal; TargetEntity = null; } break; case PlayerState.QueueInCall: Velocity.X = 0; if (Sprite.Frame == 75) { CallTimer -= dt; if (CallTimer == float.PositiveInfinity) { State = PlayerState.Normal; CallTimer = 0; break; } if (CallTimer < 0) { if (ItemDialog) { chunk.Level.OpenDialogBox(chunk.StoryItems[chunk.NextItem++]); } else { chunk.Level.OpenDialogBox(chunk.Level.TriggeredDialogs[chunk.Level.NextTrigger++]); } CallTimer = float.PositiveInfinity; } } else { CallTimer = CallDuration; } break; case PlayerState.QueueOutCall: Velocity.X = 0; if (Sprite.Frame == 75) { CallTimer -= dt; if (CallTimer == float.PositiveInfinity) { State = PlayerState.Normal; CallTimer = 0; break; } if (CallTimer < 0) { chunk.Level.OpenDialogBox(Level.RandomDialogs[chunk.Level.NextRandomDialog++]); CallTimer = float.PositiveInfinity; } } else { CallTimer = CallDuration; } break; case PlayerState.Dying: break; } if (0 < LongJump) { LongJump -= dt; if (Velocity.Y < 0) { LongJump = 0; } } bool HardFall = (Velocity.Y < HardFallVelocity); // Now that all movement has been updated, check for collisions HandleCollisions(dt, chunk, true); if (Grounded && HardFall) { MakeSound(chunk, "land", 80); } // Animations StopSoundLoop = true; switch (State) { case PlayerState.QueueInCall: case PlayerState.QueueOutCall: if (CallTimer == CallDuration) { Sprite.Play("call"); LoopSound("call"); } break; case PlayerState.QueueDoor: case PlayerState.QueueHide: case PlayerState.Normal: if ((Velocity.Y < 0 && (left != null || right != null))) { Sprite.Play("slide"); LoopSound("slide"); // Force direction to face wall if (left != null) { Sprite.Direction = -1; } if (right != null) { Sprite.Direction = +1; } } else { if (0 < Velocity.Y) { Sprite.Play("jump"); } else if (Velocity.Y < 0) { Sprite.Play("fall"); } else if (Velocity.X != 0) { if (IsCrouched) { Sprite.Play("crouchwalk"); if (Sprite.Frame == 58 || Sprite.Frame == 63) { MakeSound(chunk, chunk.IsOutside ? "crouch_outside" : "crouch_inside", 5); } } else { Sprite.Play("run"); if (Sprite.Frame == 10 || Sprite.Frame == 18) { MakeSound(chunk, chunk.IsOutside ? "run_outside" : "run_inside", 70); } } } else { SoundFrame = 0; if (IsCrouched) { Sprite.Play("crouch"); } else { Sprite.Play("idle"); } } } break; case PlayerState.Climbing: Sprite.Play("climb"); if (Sprite.Frame == 26 || Sprite.Frame == 31) { MakeSound(chunk, "climb", 20); } if (Velocity.Y < 0) { Sprite.FrameStep = -1; } else { Sprite.FrameStep = +1; } // Force direction to face wall if (left != null) { Sprite.Direction = -1; } if (right != null) { Sprite.Direction = +1; } if (Velocity.Y == 0 || !Controller.Climb) { Sprite.Reset(); } break; case PlayerState.Hiding: Sprite.Play("hide"); if (Sprite.Frame == 34) { MakeSound(chunk, "hide", 5); } break; case PlayerState.OpeningDoor: Sprite.Play("open"); break; case PlayerState.CrashDoor: Sprite.Play("crash"); break; case PlayerState.Dying: Sprite.Play("die"); break; } if (StopSoundLoop) { StopSound(); } // Base direction on movement if (Velocity.X < 0) { Sprite.Direction = -1; } if (0 < Velocity.X) { Sprite.Direction = +1; } Game.SoundEngine.Update(Position); }