diff --git a/Program.cs b/Program.cs index d23767e..3bd12d3 100644 --- a/Program.cs +++ b/Program.cs @@ -1,6 +1,5 @@ -// See https://aka.ms/new-console-template for more information - -var window = new Window("ASDLteroids", 800, 600); +var window = new Window("ASDLteroids", 800, 600); var renderer = new Renderer(window); var scene = new Scene(renderer); + scene.Run(); diff --git a/dotnet-console.csproj b/asdlteroids.csproj similarity index 55% rename from dotnet-console.csproj rename to asdlteroids.csproj index c033c20..5524382 100644 --- a/dotnet-console.csproj +++ b/asdlteroids.csproj @@ -3,13 +3,20 @@ Exe net6.0 - dotnet_console + asdlteroids enable enable + + + + + + + diff --git a/assets/explode.wav b/assets/explode.wav new file mode 100644 index 0000000..0741f66 Binary files /dev/null and b/assets/explode.wav differ diff --git a/assets/shot.wav b/assets/shot.wav new file mode 100644 index 0000000..7de2c5f Binary files /dev/null and b/assets/shot.wav differ diff --git a/src/Controlls.cs b/src/Controlls.cs new file mode 100644 index 0000000..1a27b7c --- /dev/null +++ b/src/Controlls.cs @@ -0,0 +1,29 @@ +using static SDL2.SDL; + +enum Control +{ + THRUST, + LEFT, + RIGHT, + SHOOT +} + +static class ControlKeyExtension +{ + public static SDL_Keycode Key(this Control c) + { + switch (c) + { + case Control.THRUST: + return SDL_Keycode.SDLK_UP; + case Control.LEFT: + return SDL_Keycode.SDLK_LEFT; + case Control.RIGHT: + return SDL_Keycode.SDLK_RIGHT; + case Control.SHOOT: + return SDL_Keycode.SDLK_SPACE; + default: + throw new ArgumentException("Invalid control"); + } + } +} diff --git a/src/Scene.cs b/src/Scene.cs index 68181f6..0be4c91 100644 --- a/src/Scene.cs +++ b/src/Scene.cs @@ -12,6 +12,7 @@ class Scene public HashSet Asteroids; public int Score = 0; public int Level = 1; + public AudioPlayer AudioPlayer; public Scene(Renderer renderer) { @@ -19,6 +20,9 @@ class Scene this.Shots = new HashSet(); this.Asteroids = new HashSet(); this.renderer = renderer; + this.AudioPlayer = new AudioPlayer(); + this.AudioPlayer.Register(Sound.SHOT, "assets.shot.wav"); + this.AudioPlayer.Register(Sound.EXPLOSION, "assets.explode.wav"); instance = this; } diff --git a/src/engine/AudioPlayer.cs b/src/engine/AudioPlayer.cs new file mode 100644 index 0000000..5bbc7f2 --- /dev/null +++ b/src/engine/AudioPlayer.cs @@ -0,0 +1,32 @@ +enum Sound : int +{ + SHOT = 0, + EXPLOSION = 1, +} + +class AudioPlayer +{ + private Dictionary audioFiles = new(); + private string assemblyName; + + public AudioPlayer() + { + SDL2.SDL_mixer.Mix_OpenAudio(44100, SDL2.SDL_mixer.MIX_DEFAULT_FORMAT, 2, 2048); + this.assemblyName = this.GetType().Assembly.GetName().Name!; + } + + public void Register(Sound name, string path) + { + var stream = this.GetType().Assembly.GetManifestResourceStream($"{this.assemblyName}.{path}"); + var buffer = new byte[stream!.Length]; + stream.Read(buffer, 0, buffer.Length); + this.audioFiles.Add(name, buffer); + } + + public void Play(Sound name) + { + var buffer = this.audioFiles[name]; + var sound = SDL2.SDL_mixer.Mix_QuickLoad_WAV(buffer); + SDL2.SDL_mixer.Mix_PlayChannel((int)name, sound, 0); + } +} diff --git a/src/engine/KeyState.cs b/src/engine/KeyState.cs index 15032f0..5793a70 100644 --- a/src/engine/KeyState.cs +++ b/src/engine/KeyState.cs @@ -17,4 +17,9 @@ class KeyState byte scanCode = (byte)SDL_GetScancodeFromKey(keycode); return (this.keys[scanCode] == 1); } + + public bool isPressed(Control c) + { + return this.isPressed(c.Key()); + } } diff --git a/src/entities/Asteroid.cs b/src/entities/Asteroid.cs index b000814..7d7bef1 100644 --- a/src/entities/Asteroid.cs +++ b/src/entities/Asteroid.cs @@ -34,7 +34,6 @@ class Asteroid : Renderable, Logic public void Render(Renderer renderer, double dx) { renderer.setColor(255, 255, 255); - // renderer.DrawRect(X - (int)Size / 2, Y - (int)Size / 2, (int)Size, (int)Size); double[][] drawLines = new double[shape.Length + 1][]; for (int i = 0; i < shape.Length; i++) { @@ -65,7 +64,8 @@ class Asteroid : Renderable, Logic foreach (var shot in Scene.Instance.Shots) { - if (Point.Distance(shot.X, shot.Y, X, Y) < (int)Size / 2) + var halfSize = (int)Size / 2; + if (Point.Distance(shot.X, shot.Y, X - halfSize, Y - halfSize) < (int)Size / 2) { shot.Destroy(); this.Destroy(); @@ -88,6 +88,7 @@ class Asteroid : Renderable, Logic public void Destroy() { + Scene.Instance.AudioPlayer.Play(Sound.EXPLOSION); Scene.Instance.Score += (int)Size; Scene.Instance.Asteroids.Remove(this); Console.WriteLine("Asteroid destroyed"); diff --git a/src/entities/Ship.cs b/src/entities/Ship.cs index deaf974..39eddda 100644 --- a/src/entities/Ship.cs +++ b/src/entities/Ship.cs @@ -1,6 +1,3 @@ -using static SDL2.SDL; - - class Ship : Logic, Renderable { const double SPEED = 0.3; @@ -22,24 +19,25 @@ class Ship : Logic, Renderable public void Update(KeyState keyState, double dt) { thrust = false; - if (keyState.isPressed(SDL_Keycode.SDLK_LEFT)) + if (keyState.isPressed(Control.LEFT)) { rotation -= ROTATION_SPEED * dt; } - if (keyState.isPressed(SDL_Keycode.SDLK_RIGHT)) + if (keyState.isPressed(Control.RIGHT)) { rotation += ROTATION_SPEED * dt; } - if (keyState.isPressed(SDL_Keycode.SDLK_UP)) + if (keyState.isPressed(Control.THRUST)) { thrust = true; this.dx += Math.Cos(rotation) * SPEED * dt; this.dy += Math.Sin(rotation) * SPEED * dt; } - if (keyState.isPressed(SDL_Keycode.SDLK_SPACE) && (DateTime.Now - lastShot).TotalMilliseconds > 200) + if (keyState.isPressed(Control.SHOOT) && (DateTime.Now - lastShot).TotalMilliseconds > 200) { lastShot = DateTime.Now; var shot = new Shot(x, y, rotation); + Scene.Instance.AudioPlayer.Play(Sound.SHOT); Scene.Instance.Shots.Add(shot); } rotation = rotation % (2 * Math.PI); @@ -63,7 +61,8 @@ class Ship : Logic, Renderable } foreach (var asteroid in Scene.Instance.Asteroids) { - if (Point.Distance(x, y, asteroid.X, asteroid.Y) < (int)asteroid.Size / 2) + var halfAsteroidSize = (int)asteroid.Size / 2; + if (Point.Distance(x, y, asteroid.X - halfAsteroidSize, asteroid.Y - halfAsteroidSize) < halfAsteroidSize + 3) { Scene.Instance.Loose(); } @@ -74,20 +73,28 @@ class Ship : Logic, Renderable { renderer.setColor(255, 255, 255); renderer.DrawLines(new double[][] { - new double[]{x + Math.Cos(rotation) * 10, y + Math.Sin(rotation) * 10}, - new double[]{x + Math.Cos(rotation + Math.PI * 2 / 3) * 10, y + Math.Sin(rotation + Math.PI * 2 / 3) * 10}, - new double[]{x + Math.Cos(rotation + Math.PI * 4 / 3) * 10, y + Math.Sin(rotation + Math.PI * 4 / 3) * 10}, - new double[]{x + Math.Cos(rotation) * 10, y + Math.Sin(rotation) * 10} + new double[] { x + Math.Cos(rotation) * 10, y + Math.Sin(rotation) * 10 }, + new double[] { x + Math.Cos(rotation + (Math.PI * 2) / 3) * 10, y + Math.Sin(rotation + (Math.PI * 2) / 3) * 10 }, + new double[] { x + Math.Cos(rotation) * 10, y + Math.Sin(rotation) * 10 }, + new double[] { x + Math.Cos(rotation + (Math.PI * 2) / 3 * 2) * 10, y + Math.Sin(rotation + (Math.PI * 2) / 3 * 2) * 10 }, }); + renderer.DrawLines(new double[][] { + new double[] { x + Math.Cos(rotation + (Math.PI * 2) / 3) * 5, y + Math.Sin(rotation + (Math.PI * 2) / 3) * 5 }, + new double[] { x + Math.Cos(rotation + (Math.PI * 2) / 3 * 2) * 5, y + Math.Sin(rotation + (Math.PI * 2) / 3 * 2) * 5 }, + }); + if (thrust) { renderer.setColor(255, 0, 0); + var random = new Random(); // Draw flame behind ship renderer.DrawLines(new double[][] { - new double[]{x + Math.Cos(rotation + Math.PI * 2 / 3) * 10, y + Math.Sin(rotation + Math.PI * 2 / 3) * 10}, - new double[]{x + Math.Cos(rotation + Math.PI * 2 / 3) * 10 + Math.Cos(rotation + Math.PI) * 10, y + Math.Sin(rotation + Math.PI * 2 / 3) * 10 + Math.Sin(rotation + Math.PI) * 10}, - new double[]{x + Math.Cos(rotation + Math.PI * 4 / 3) * 10, y + Math.Sin(rotation + Math.PI * 4 / 3) * 10}, - new double[]{x + Math.Cos(rotation + Math.PI * 2 / 3) * 10, y + Math.Sin(rotation + Math.PI * 2 / 3) * 10} + new double[] { x + Math.Cos(rotation + (Math.PI * 2) / 3) * 10, y + Math.Sin(rotation + (Math.PI * 2) / 3) * 10 }, + new double[] { x + Math.Cos(rotation + (Math.PI * 2) / 3 * 1.2) * 5+random.Next(5), y + Math.Sin(rotation + (Math.PI * 2) / 3 * 1.2) * 5+random.Next(5) }, + new double[] { x + Math.Cos(rotation + (Math.PI * 2) / 3 * 1.4) * 10, y + Math.Sin(rotation + (Math.PI * 2) / 3 * 1.4) * 10 }, + new double[] { x + Math.Cos(rotation + (Math.PI * 2) / 3 * 1.6) * 6+random.Next(5), y + Math.Sin(rotation + (Math.PI * 2) / 3 * 1.6) * 5+random.Next(4) }, + new double[] { x + Math.Cos(rotation + (Math.PI * 2) / 3 * 1.8) * 10, y + Math.Sin(rotation + (Math.PI * 2) / 3 * 1.8) * 10 }, + new double[] { x + Math.Cos(rotation + (Math.PI * 2) / 3 * 2) * 5+random.Next(5), y + Math.Sin(rotation + (Math.PI * 2) / 3 * 2) * 5+random.Next(5) }, }); } }