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.

105 lines
3.3 KiB

  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Graphics;
  3. using System;
  4. using System.Collections.Generic;
  5. namespace SemiColinGames {
  6. public sealed class ShmupWorld : IWorld {
  7. public class ShmupPlayer {
  8. public TextureRef Texture = Textures.Yellow2;
  9. // Center of player sprite.
  10. public Vector2 Position = new Vector2(48, 1080 / 8);
  11. public Vector2 HalfSize = new Vector2(16, 10);
  12. private float speed = 150f;
  13. private float shotCooldown = 0f;
  14. private ProfilingList<Shot> shots = new ProfilingList<Shot>(10, "playerShots");
  15. public ProfilingList<Shot> Update(
  16. float modelTime, History<Input> input, Rectangle worldBounds) {
  17. // Movement update.
  18. Vector2 motion = Vector2.Multiply(input[0].Motion, modelTime * speed);
  19. Position = Vector2.Add(Position, motion);
  20. Position.X = Math.Max(Position.X, HalfSize.X);
  21. Position.X = Math.Min(Position.X, worldBounds.Size.X - HalfSize.X);
  22. Position.Y = Math.Max(Position.Y, HalfSize.Y);
  23. Position.Y = Math.Min(Position.Y, worldBounds.Size.Y - HalfSize.Y);
  24. // Check whether we need to add new shots.
  25. shotCooldown -= modelTime;
  26. shots.Clear();
  27. if (input[0].Attack && shotCooldown <= 0) {
  28. shotCooldown = 0.2f;
  29. Vector2 shotOffset = new Vector2(12, 2);
  30. Vector2 shotPosition = Vector2.Add(Position, shotOffset);
  31. shots.Add(new Shot(shotPosition, new Vector2(300, 0)));
  32. }
  33. return shots;
  34. }
  35. }
  36. public class Shot {
  37. static int color = 0;
  38. public TextureRef Texture;
  39. public Vector2 Position;
  40. public Vector2 HalfSize = new Vector2(11, 4);
  41. public Rectangle Bounds;
  42. public Vector2 Velocity;
  43. public Shot(Vector2 position, Vector2 velocity) {
  44. Texture = (color % 5) switch {
  45. 0 => Textures.Projectile1,
  46. 1 => Textures.Projectile2,
  47. 2 => Textures.Projectile3,
  48. 3 => Textures.Projectile4,
  49. _ => Textures.Projectile5
  50. };
  51. color++;
  52. Position = position;
  53. Velocity = velocity;
  54. Update(0); // set Bounds
  55. }
  56. public void Update(float modelTime) {
  57. Position = Vector2.Add(Position, Vector2.Multiply(Velocity, modelTime));
  58. Bounds = new Rectangle(
  59. (int) (Position.X - HalfSize.X),
  60. (int) (Position.Y - HalfSize.Y),
  61. (int) HalfSize.X * 2,
  62. (int) HalfSize.Y * 2);
  63. }
  64. }
  65. public readonly Rectangle Bounds;
  66. public readonly ShmupPlayer Player;
  67. public readonly ProfilingList<Shot> Shots;
  68. public ShmupWorld() {
  69. Bounds = new Rectangle(0, 0, 1920 / 4, 1080 / 4);
  70. Player = new ShmupPlayer();
  71. Shots = new ProfilingList<Shot>(100, "shots");
  72. }
  73. ~ShmupWorld() {
  74. Dispose();
  75. }
  76. public void Dispose() {
  77. GC.SuppressFinalize(this);
  78. }
  79. public void Update(float modelTime, History<Input> input) {
  80. ProfilingList<Shot> newPlayerShots = Player.Update(modelTime, input, Bounds);
  81. foreach (Shot shot in Shots) {
  82. shot.Update(modelTime);
  83. }
  84. Shots.AddRange(newPlayerShots);
  85. // TODO: inflate bounds rectangle
  86. Shots.RemoveAll(shot => !Bounds.Intersects(shot.Bounds));
  87. Debug.AddToast("shots: " + Shots.Count);
  88. }
  89. }
  90. }