From a1fa102c4a209fa6fadb6a1c33dc1ee415b675dd Mon Sep 17 00:00:00 2001 From: PoliEcho Date: Sun, 24 Aug 2025 10:21:20 +0200 Subject: [PATCH] add enemies and fix angles --- src/const.hpp | 1 + src/enemies.cpp | 74 ++++++++++++++++++++++++++++++++++ src/enemies.hpp | 6 +++ src/game_logic.cpp | 20 ++++++++- src/main.cpp | 2 + src/meth.cpp | 28 ++++++------- src/meth.hpp | 3 +- src/misc.cpp | 26 ++++++++++++ src/misc.hpp | 4 ++ src/projectiles.cpp | 20 ++------- src/types.hpp | 98 +++++++++++++++++++++++++++++++++++++-------- 11 files changed, 230 insertions(+), 52 deletions(-) create mode 100644 src/enemies.cpp create mode 100644 src/enemies.hpp create mode 100644 src/misc.cpp create mode 100644 src/misc.hpp diff --git a/src/const.hpp b/src/const.hpp index 3fc2d7b..028167c 100644 --- a/src/const.hpp +++ b/src/const.hpp @@ -12,3 +12,4 @@ constexpr Uint64 TARGET_FRAME_TIME_NS = 1'000'000'000 / TARGET_FPS; #define HEIGHT_RATIO 41.53846153846154 #define MIN_INPUT_DELAY_MOVEMENT 0 #define MIN_INPUT_DELAY_FIRE 200 +#define NORMAL_PROJECTILE_SPEED 3 diff --git a/src/enemies.cpp b/src/enemies.cpp new file mode 100644 index 0000000..2b6aa43 --- /dev/null +++ b/src/enemies.cpp @@ -0,0 +1,74 @@ +#include "const.hpp" +#include "main.hpp" +#include "meth.hpp" +#include "misc.hpp" +#include "projectiles.hpp" +#include "types.hpp" +#include +#include + +enemy_type spawn_enemy(enemy_ai_type ai_type, Uint32 reload_time) { + enemy_type enemy; + enemy.ship.texture = texture_from_SVG_file("assets/enemy_1.svg", 1); + enemy.type = ai_type; + enemy.reload_time = reload_time; + + enemy.ship.rect = { + static_cast(mode->w), + static_cast(get_random_num(0, mode->h - enemy.ship.texture->h)), + static_cast(enemy.ship.texture->w), + static_cast(enemy.ship.texture->h)}; + + enemy.ship.gun_offset.x = 0; + enemy.ship.gun_offset.y = 0.5f * enemy.ship.texture->h; + enemy.size_multiplier = 1; + return enemy; +} + +void step_enemy(enemy_type &e, ship_type &player, + std::vector &projectiles) { + switch (e.type) { + case RANDOM: + switch (get_random_num(0, 3)) { + case 0: + e.ship.rect.x++; + break; + case 1: + e.ship.rect.x -= 2; + break; + case 2: + e.ship.rect.y++; + break; + case 3: + e.ship.rect.y--; + break; + } + if (get_random_num(0, 1000) == 0 && + SDL_GetTicks() - e.last_shot > e.reload_time) { + projectiles.push_back( + spawn_projectile({e.ship.rect.x + e.ship.gun_offset.x, + e.ship.rect.y + e.ship.gun_offset.y}, + e.size_multiplier, 270, NORMAL_PROJECTILE_SPEED, + "assets/basic_projectile.svg", nullptr)); + } + break; + case FLYER: + if (e.ship.rect.x != e.target.x && e.ship.rect.y != e.target.y) { + if (e.ship.rect.y < mode->h / 2) { + e.target.y = 0; + } else { + e.target.y = mode->h - e.ship.rect.h; + } + e.target.x = e.ship.rect.x - (e.ship.rect.w / 2); + } + break; + case GUNNER: + break; + case ACE: + break; + case BOSS: + break; + } + SDL_RenderTexture(main_sdl_session.renderer, e.ship.texture, nullptr, + &e.ship.rect); +} \ No newline at end of file diff --git a/src/enemies.hpp b/src/enemies.hpp new file mode 100644 index 0000000..094b181 --- /dev/null +++ b/src/enemies.hpp @@ -0,0 +1,6 @@ +#pragma once +#include "types.hpp" +#include +enemy_type spawn_enemy(enemy_ai_type ai_type, Uint32 reload_time); +void step_enemy(enemy_type &e, ship_type &player, + std::vector &projectiles); \ No newline at end of file diff --git a/src/game_logic.cpp b/src/game_logic.cpp index c77d891..d869577 100644 --- a/src/game_logic.cpp +++ b/src/game_logic.cpp @@ -1,7 +1,10 @@ #include "const.hpp" +#include "enemies.hpp" #include "main.hpp" +#include "meth.hpp" #include "projectiles.hpp" #include "types.hpp" +#include #include #include @@ -37,7 +40,7 @@ bool play_level() { Uint8 player_ship_speed = 1; std::vector projectiles; - std::vector enemies; + std::vector enemies; while (running) { const Uint64 frameStart = SDL_GetTicksNS(); @@ -97,14 +100,26 @@ bool play_level() { projectiles.push_back( spawn_projectile({player_ship.rect.x + player_ship.gun_offset.x, player_ship.rect.y + player_ship.gun_offset.y}, - 1, 0, 3, "assets/basic_projectile.svg", nullptr)); + 1, 90, NORMAL_PROJECTILE_SPEED, + "assets/basic_projectile.svg", nullptr)); last_fire = SDL_GetTicks(); } } + // chance to spawn enemy every frame + if (get_random_num(0, 10) == 0) { + enemies.push_back(spawn_enemy( + // static_cast(get_random_num(RANDOM, GUNNER)), + RANDOM, get_random_num(200, 1000))); + } + SDL_SetRenderDrawColor(main_sdl_session.renderer, 0, 0, 0, 255); SDL_RenderClear(main_sdl_session.renderer); + for (enemy_type &e : enemies) { + step_enemy(e, player_ship, projectiles); + } + for (projectile &p : projectiles) { if (p.rect.x > mode->w || p.rect.y > mode->h) { projectiles.erase(projectiles.begin() + (&p - projectiles.data())); @@ -133,4 +148,5 @@ bool play_level() { } SDL_DestroyTexture(player_ship.texture); + return true; } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index f8690c3..5e2349d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,5 @@ #include "game_logic.hpp" +#include "meth.hpp" #include "types.hpp" #include #include @@ -11,6 +12,7 @@ #include #include #include +#include sdl_session main_sdl_session; const SDL_DisplayMode *mode; diff --git a/src/meth.cpp b/src/meth.cpp index 0c08cf5..4fc9309 100644 --- a/src/meth.cpp +++ b/src/meth.cpp @@ -1,27 +1,25 @@ #include "types.hpp" #include +#include SDL_FPoint find_dst_point_with_angle_and_distance(SDL_FPoint start, Angle angle, float distance) { - float angle_rad = (angle - 90) * M_PI / 180.0f; + float angle_degrees = static_cast(angle); + float angle_rad = (angle_degrees - 90.0f) * M_PI / 180.0f; float dx = std::cos(angle_rad) * distance; float dy = std::sin(angle_rad) * distance; - float calculated_distance = std::sqrt(dx * dx + dy * dy); - SDL_FPoint result; - - if (calculated_distance > 0) { - dx /= calculated_distance; - dy /= calculated_distance; - - result.x = start.x + dx * distance; - result.y = start.y + dy * distance; - } else { - result.x = start.x; - result.y = start.y; - } - + result.x = start.x + dx; + result.y = start.y + dy; return result; } + +int get_random_num(int min, int max) { + static std::random_device dev; + static std::mt19937 rng(dev()); + + std::uniform_int_distribution dist(min, max); + return dist(rng); +} diff --git a/src/meth.hpp b/src/meth.hpp index 6e42dcc..0c64cbf 100644 --- a/src/meth.hpp +++ b/src/meth.hpp @@ -2,4 +2,5 @@ #include "types.hpp" #include SDL_FPoint find_dst_point_with_angle_and_distance(SDL_FPoint start, Angle angle, - float distance); \ No newline at end of file + float distance); +int get_random_num(int min, int max); \ No newline at end of file diff --git a/src/misc.cpp b/src/misc.cpp new file mode 100644 index 0000000..f712351 --- /dev/null +++ b/src/misc.cpp @@ -0,0 +1,26 @@ +#include "main.hpp" +#include +#include +#include + +SDL_Texture *texture_from_SVG_file(const char *file_name, + float size_multiplier) { + SDL_IOStream *texture_file = SDL_IOFromFile(file_name, "r"); + std::array texture_base_size; + { + SDL_Surface *tmp_surface = IMG_LoadSVG_IO(texture_file); + texture_base_size = {tmp_surface->w, tmp_surface->h}; + SDL_DestroySurface(tmp_surface); + } + SDL_SeekIO(texture_file, 0, SDL_IO_SEEK_SET); // reset to top of the file + SDL_Surface *projectile_surface = + IMG_LoadSizedSVG_IO(texture_file, texture_base_size[0] * size_multiplier, + texture_base_size[1] * size_multiplier); + + SDL_CloseIO(texture_file); + + SDL_Texture *texture = SDL_CreateTextureFromSurface(main_sdl_session.renderer, + projectile_surface); + SDL_DestroySurface(projectile_surface); + return texture; +} \ No newline at end of file diff --git a/src/misc.hpp b/src/misc.hpp new file mode 100644 index 0000000..3be6022 --- /dev/null +++ b/src/misc.hpp @@ -0,0 +1,4 @@ +#include +#include +SDL_Texture *texture_from_SVG_file(const char *file_name, + float size_multiplier); \ No newline at end of file diff --git a/src/projectiles.cpp b/src/projectiles.cpp index 83ac3c5..7a4cc62 100644 --- a/src/projectiles.cpp +++ b/src/projectiles.cpp @@ -1,6 +1,7 @@ #include "macro.hpp" #include "main.hpp" #include "meth.hpp" +#include "misc.hpp" #include "types.hpp" #include #include @@ -15,23 +16,8 @@ projectile spawn_projectile(SDL_FPoint position, float size_multiplier, SDL_FRect *target) { projectile p; - SDL_IOStream *texture_file = SDL_IOFromFile(texture_file_name, "r"); - std::array texture_base_size; - { - SDL_Surface *tmp_surface = IMG_LoadSVG_IO(texture_file); - texture_base_size = {tmp_surface->w, tmp_surface->h}; - SDL_DestroySurface(tmp_surface); - } - SDL_SeekIO(texture_file, 0, SDL_IO_SEEK_SET); // reset to top of the file - SDL_Surface *projectile_surface = - IMG_LoadSizedSVG_IO(texture_file, texture_base_size[0] * size_multiplier, - texture_base_size[1] * size_multiplier); - - SDL_CloseIO(texture_file); - - p.texture = SDL_CreateTextureFromSurface(main_sdl_session.renderer, - projectile_surface); - SDL_DestroySurface(projectile_surface); + p.texture = + texture_from_SVG_file("assets/basic_projectile.svg", size_multiplier); p.angle = angle; p.rect = {position.x, position.y, static_cast(p.texture->w), diff --git a/src/types.hpp b/src/types.hpp index 7489a3a..b789e57 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -16,7 +16,6 @@ enum enemy_ai_type { struct Angle { private: float value{0}; - void normalize() { value = std::fmod(value, 360); if (value < 0) @@ -24,77 +23,140 @@ private: } public: - // Constructor - Angle(int val = 0) : value(val) { normalize(); } + // Constructors + Angle(int val = 0) : value(static_cast(val)) { normalize(); } + Angle(float val) : value(val) { normalize(); } + Angle(double val) : value(static_cast(val)) { normalize(); } - // Assignment operator + // Assignment operators Angle &operator=(int val) { + value = static_cast(val); + normalize(); + return *this; + } + + Angle &operator=(float val) { value = val; normalize(); return *this; } + Angle &operator=(double val) { + value = static_cast(val); + normalize(); + return *this; + } + // Compound assignment Angle &operator+=(int rhs) { - value += rhs; + value += static_cast(rhs); normalize(); return *this; } Angle &operator-=(int rhs) { + value -= static_cast(rhs); + normalize(); + return *this; + } + + Angle &operator+=(float rhs) { + value += rhs; + normalize(); + return *this; + } + + Angle &operator-=(float rhs) { value -= rhs; normalize(); return *this; } + // Binary operators for int Angle operator+(int rhs) const { - return Angle(static_cast(value) + rhs); + Angle result; + result.value = value + static_cast(rhs); + result.normalize(); + return result; } Angle operator-(int rhs) const { - return Angle(static_cast(value) - rhs); + Angle result; + result.value = value - static_cast(rhs); + result.normalize(); + return result; } Angle operator*(int rhs) const { - return Angle(static_cast(value * rhs)); + Angle result; + result.value = value * static_cast(rhs); + result.normalize(); + return result; } Angle operator/(int rhs) const { - return Angle(static_cast(value / rhs)); + Angle result; + result.value = value / static_cast(rhs); + result.normalize(); + return result; } // Binary operators for double Angle operator+(double rhs) const { - return Angle(static_cast(value + rhs)); + Angle result; + result.value = value + static_cast(rhs); + result.normalize(); + return result; } Angle operator-(double rhs) const { - return Angle(static_cast(value - rhs)); + Angle result; + result.value = value - static_cast(rhs); + result.normalize(); + return result; } Angle operator*(double rhs) const { - return Angle(static_cast(value * rhs)); + Angle result; + result.value = value * static_cast(rhs); + result.normalize(); + return result; } Angle operator/(double rhs) const { - return Angle(static_cast(value / rhs)); + Angle result; + result.value = value / static_cast(rhs); + result.normalize(); + return result; } // Binary operators for float Angle operator+(float rhs) const { - return Angle(static_cast(value + rhs)); + Angle result; + result.value = value + rhs; + result.normalize(); + return result; } Angle operator-(float rhs) const { - return Angle(static_cast(value - rhs)); + Angle result; + result.value = value - rhs; + result.normalize(); + return result; } Angle operator*(float rhs) const { - return Angle(static_cast(value * rhs)); + Angle result; + result.value = value * rhs; + result.normalize(); + return result; } Angle operator/(float rhs) const { - return Angle(static_cast(value / rhs)); + Angle result; + result.value = value / rhs; + result.normalize(); + return result; } // Type conversion @@ -124,6 +186,8 @@ struct enemy_type { enemy_ai_type type; Uint32 last_shot; Uint32 reload_time; + SDL_FPoint target; + float size_multiplier; }; struct projectile {