A stealth-based 2D platformer where you don't have to kill anyone unless you want to. https://www.semicolin.games
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
4.8 KiB

  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Graphics;
  3. using Microsoft.Xna.Framework.Input;
  4. using System;
  5. namespace Jumpy {
  6. class Player {
  7. enum Facing { Left, Right };
  8. enum Pose { Walking, Standing, Crouching, Stretching, SwordSwing, Jumping };
  9. enum AirState { Jumping, Ground };
  10. private Texture2D texture;
  11. private const int spriteSize = 48;
  12. private const int spriteWidth = 7;
  13. private const int moveSpeed = 200;
  14. private const int jumpSpeed = 600;
  15. private const int gravity = 2000;
  16. private const int groundLevel = Camera.Height - spriteSize / 2;
  17. private Point position = new Point(Camera.Width / 2, groundLevel);
  18. private Facing facing = Facing.Right;
  19. private Pose pose = Pose.Standing;
  20. private AirState airState = AirState.Ground;
  21. private double swordSwingTime = 0;
  22. private double jumpTime = 0;
  23. private double ySpeed = 0;
  24. public Player(Texture2D texture) {
  25. this.texture = texture;
  26. }
  27. public void Update(GameTime time, History<GamePadState> gamePad) {
  28. if (gamePad[0].IsButtonDown(Buttons.A) && airState == AirState.Ground) {
  29. pose = Pose.Jumping;
  30. airState = AirState.Jumping;
  31. jumpTime = 0.5;
  32. ySpeed = -jumpSpeed;
  33. return;
  34. }
  35. // TODO: only swing the sword if button newly pressed (no turbosword)
  36. if (gamePad[0].IsButtonDown(Buttons.X) && swordSwingTime <= 0) {
  37. pose = Pose.SwordSwing;
  38. swordSwingTime = 0.3;
  39. return;
  40. }
  41. Vector2 leftStick = gamePad[0].ThumbSticks.Left;
  42. if (gamePad[0].IsButtonDown(Buttons.DPadLeft) || leftStick.X < -0.5) {
  43. facing = Facing.Left;
  44. pose = Pose.Walking;
  45. position.X -= (int) (moveSpeed * time.ElapsedGameTime.TotalSeconds);
  46. } else if (gamePad[0].IsButtonDown(Buttons.DPadRight) || leftStick.X > 0.5) {
  47. facing = Facing.Right;
  48. pose = Pose.Walking;
  49. position.X += (int) (moveSpeed * time.ElapsedGameTime.TotalSeconds);
  50. } else if (gamePad[0].IsButtonDown(Buttons.DPadDown) || leftStick.Y < -0.5) {
  51. pose = Pose.Crouching;
  52. } else if (gamePad[0].IsButtonDown(Buttons.DPadUp) || leftStick.Y > 0.5) {
  53. pose = Pose.Stretching;
  54. } else {
  55. pose = Pose.Standing;
  56. }
  57. if (jumpTime > 0) {
  58. jumpTime -= time.ElapsedGameTime.TotalSeconds;
  59. }
  60. if (swordSwingTime > 0) {
  61. swordSwingTime -= time.ElapsedGameTime.TotalSeconds;
  62. pose = Pose.SwordSwing;
  63. }
  64. if (airState == AirState.Jumping) {
  65. position.Y += (int) (ySpeed * time.ElapsedGameTime.TotalSeconds);
  66. ySpeed += gravity * (float) time.ElapsedGameTime.TotalSeconds;
  67. if (position.Y > groundLevel) {
  68. position.Y = groundLevel;
  69. ySpeed = 0;
  70. airState = AirState.Ground;
  71. }
  72. }
  73. if (airState == AirState.Jumping && pose != Pose.SwordSwing) {
  74. pose = Pose.Jumping;
  75. }
  76. position.X = Math.Min(Math.Max(position.X, 0 + spriteWidth), Camera.Width - spriteWidth);
  77. }
  78. private Point spritePosition(Pose pose, GameTime time) {
  79. int frameNum = (time.TotalGameTime.Milliseconds / 125) % 4;
  80. if (frameNum == 3) {
  81. frameNum = 1;
  82. }
  83. switch (pose) {
  84. case Pose.Walking:
  85. return new Point(spriteSize * frameNum + spriteSize * 6, 0);
  86. case Pose.Crouching:
  87. return new Point(spriteSize * 7, spriteSize * 2);
  88. case Pose.Stretching:
  89. return new Point(spriteSize * frameNum, spriteSize * 2);
  90. case Pose.Jumping:
  91. if (jumpTime > 0.25) {
  92. return new Point(spriteSize * 6, spriteSize);
  93. } else if (jumpTime > 0) {
  94. return new Point(spriteSize * 7, spriteSize);
  95. } else {
  96. return new Point(spriteSize * 8, spriteSize);
  97. }
  98. case Pose.SwordSwing:
  99. if (swordSwingTime > 0.2) {
  100. return new Point(spriteSize * 3, spriteSize * 0);
  101. } else if (swordSwingTime > 0.1) {
  102. return new Point(spriteSize * 4, spriteSize * 0);
  103. } else {
  104. return new Point(spriteSize * 5, spriteSize * 0);
  105. }
  106. case Pose.Standing:
  107. default:
  108. return new Point(spriteSize * 7, 0);
  109. }
  110. }
  111. public void Draw(GameTime time, SpriteBatch spriteBatch) {
  112. Point source = spritePosition(pose, time);
  113. Rectangle textureSource = new Rectangle(source.X, source.Y, spriteSize, spriteSize);
  114. Vector2 spriteCenter = new Vector2(spriteSize / 2, spriteSize / 2);
  115. SpriteEffects effect = facing == Facing.Right ?
  116. SpriteEffects.FlipHorizontally : SpriteEffects.None;
  117. Vector2 drawPos = new Vector2(position.X, position.Y);
  118. spriteBatch.Draw(texture, drawPos, textureSource, Color.White, 0f, spriteCenter,
  119. Vector2.One, effect, 0f);
  120. }
  121. }
  122. }