From af6fd5fc4532ed4c81b0356f2d29c5cacfe54c7b Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Sat, 31 May 2025 13:26:21 +0200 Subject: [PATCH] Add physics and level module --- CMakeLists.txt | 1 + src/assets.cpp | 2 +- src/definitions.hpp | 17 ++++ src/level.hpp | 111 +++++++++++++++++++++++++ src/main.cpp | 191 ++------------------------------------------ src/physics.cpp | 81 +++++++++++++++++++ src/physics.hpp | 36 +++++++++ src/sdl_types.hpp | 9 --- 8 files changed, 253 insertions(+), 195 deletions(-) create mode 100644 src/definitions.hpp create mode 100644 src/level.hpp create mode 100644 src/physics.cpp create mode 100644 src/physics.hpp delete mode 100644 src/sdl_types.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index abd6030..e96b398 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ find_package(spdlog CONFIG REQUIRED) add_executable(HansTheGatherer src/main.cpp src/assets.cpp + src/physics.cpp ) target_link_libraries(HansTheGatherer SDL3::SDL3 flecs::flecs spdlog::spdlog) diff --git a/src/assets.cpp b/src/assets.cpp index 2de8f8b..61f237f 100644 --- a/src/assets.cpp +++ b/src/assets.cpp @@ -1,6 +1,6 @@ #include "assets.hpp" #include "audio.hpp" -#include "sdl_types.hpp" +#include "definitions.hpp" #include #include diff --git a/src/definitions.hpp b/src/definitions.hpp new file mode 100644 index 0000000..4a6b8c4 --- /dev/null +++ b/src/definitions.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +static constexpr int WINDOW_WIDTH = 400; +static constexpr int WINDOW_HEIGHT = 240; + +struct SdlHandles +{ + SDL_Window* window; + SDL_Renderer* renderer; +}; + +struct Game +{ + uint32_t ticks; +}; diff --git a/src/level.hpp b/src/level.hpp new file mode 100644 index 0000000..ac1d30e --- /dev/null +++ b/src/level.hpp @@ -0,0 +1,111 @@ +#pragma once + +#include "definitions.hpp" +#include "input.hpp" +#include "physics.hpp" +#include "sprite.hpp" + +#include + +struct Fruit +{ +}; + +struct Basket +{ +}; + +struct LevelModule +{ + LevelModule(flecs::world& world) + { + auto const* texture_assets = world.get(); + + world.entity("Background") + .set(Position{.x = 0, .y = 0}) + .set(Sprite{.texture = &texture_assets->background, .texture_atlas_index = 0}) + .set(Size{.w = WINDOW_WIDTH, .h = WINDOW_HEIGHT}); + + auto basket = + world.entity("Basket") + .add() + .set(Position{.x = WINDOW_WIDTH / 2 - 32, .y = WINDOW_HEIGHT - 32}) + .set(Sprite{.texture = &texture_assets->basket, .texture_atlas_index = 0}) + .set(Size{.w = 64, .h = 32}) + .add(); + + world.entity() + .child_of(basket) + .add() + .set(Position{.x = 0, .y = 0}) + .set(Size{.w = 64, .h = 32}) + .add(); + + world.system("SpawnFruits") + .term_at(0) + .singleton() + .term_at(1) + .singleton() + .each( + [](flecs::iter& it, + size_t index, + Game const& game, + TextureAssets const& texture_assets) + { + if ((game.ticks % 100) == 0) + { + auto fruit = + it.world() + .entity() + .add() + .add() + .set(Position{ + .x = static_cast(game.ticks % WINDOW_WIDTH), .y = -16}) + .set(Velocity{.x = 0, .y = 1}) + .set(Sprite{.texture = &texture_assets.fruits, + .texture_atlas_index = + static_cast(game.ticks % 228)}) + .set(Size{.w = 32, .h = 32}); + + it.world() + .entity("CollisionBox") + .child_of(fruit) + .add() + .set(Position{.x = 0, .y = 0}) + .set(Size{.w = 32, .h = 32}) + .add(); + } + }); + + // world.system("DespawnFruits") + // .each( + // [](flecs::entity e, WorldPosition const& pos, Fruit) + // { + // if (pos.y >= WINDOW_HEIGHT) + // e.destruct(); + // }); + + world.system("MoveBasket") + .term_at(0) + .singleton() + .each( + [](ButtonInput const& input, + Position& pos, + Size const& size, + Sprite const& sprite, + Basket) + { + if (input.pressed.contains(SDLK_LEFT)) + { + pos.x -= 5; + } + if (input.pressed.contains(SDLK_RIGHT)) + { + pos.x += 5; + } + + pos.x = pos.x < 0 ? 0 : pos.x; + pos.x = pos.x > WINDOW_WIDTH - size.w ? WINDOW_WIDTH - size.w : pos.x; + }); + } +}; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index f003f52..cea1357 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,8 @@ #include "assets.hpp" +#include "definitions.hpp" #include "input.hpp" -#include "sdl_types.hpp" +#include "level.hpp" +#include "physics.hpp" #include "sprite.hpp" #include @@ -12,38 +14,6 @@ #include #include -static constexpr int WINDOW_WIDTH = 400; -static constexpr int WINDOW_HEIGHT = 240; - -struct WorldPosition -{ - int x; - int y; -}; - -struct Position -{ - int x; - int y; -}; - -struct Velocity -{ - int x; - int y; -}; - -struct Size -{ - int w; - int h; -}; - -struct Game -{ - uint32_t ticks; -}; - int main() { spdlog::info("Initialize SDL..."); @@ -69,137 +39,19 @@ int main() } flecs::world world; + world.set(Game{.ticks = 0}); world.set(ButtonInput{}); world.set(SdlHandles{.window = window, .renderer = renderer}); init_assets(world); - auto* texture_assets = world.get(); - - world.entity("Background") - .set(Position{.x = 0, .y = 0}) - .set(Sprite{.texture = &texture_assets->background, .texture_atlas_index = 0}) - .set(Size{.w = WINDOW_WIDTH, .h = WINDOW_HEIGHT}); - - struct Fruit - { - }; - struct Basket - { - }; - struct CollisionBox - { - }; + world.import (); + world.import (); world.system("IncrementTicks") .term_at(0) .singleton() .each([](Game& game_ticks) { game_ticks.ticks += 1; }); - auto basket = - world.entity("Basket") - .add() - .set(Position{.x = WINDOW_WIDTH / 2 - 32, .y = WINDOW_HEIGHT - 32}) - .set(Sprite{.texture = &texture_assets->basket, .texture_atlas_index = 0}) - .set(Size{.w = 64, .h = 32}) - .add(); - - world.entity("CollisionBox") - .child_of(basket) - .add() - .set(Position{.x = 0, .y = 0}) - .set(Size{.w = 64, .h = 32}) - .add(); - - world.system("DrawBoxes") - .term_at(0) - .singleton() - .each( - [](SdlHandles const& sdl_handles, - WorldPosition const& pos, - Size const& size, - CollisionBox) - { - SDL_FRect rect{static_cast(pos.x), - static_cast(pos.y), - static_cast(size.w), - static_cast(size.h)}; - SDL_SetRenderDrawColor(sdl_handles.renderer, 0, 0, 255, 255); - SDL_RenderRect(sdl_handles.renderer, &rect); - }); - - world.system("SpawnFruits") - .term_at(0) - .singleton() - .term_at(1) - .singleton() - .each( - [](flecs::iter& it, size_t index, Game const& game, TextureAssets const& texture_assets) - { - if ((game.ticks % 100) == 0) - { - auto fruit = - it.world() - .entity() - .add() - .set(Position{ - .x = static_cast(game.ticks % WINDOW_WIDTH), .y = -16}) - .set(Velocity{.x = 0, .y = 1}) - .set(Sprite{.texture = &texture_assets.fruits, - .texture_atlas_index = - static_cast(game.ticks % 228)}) - .set(Size{.w = 32, .h = 32}); - - it.world() - .entity("CollisionBox") - .child_of(fruit) - .add() - .set(Position{.x = 0, .y = 0}) - .set(Size{.w = 32, .h = 32}) - .add(); - } - }); - - world.system("PropagatePosition") - .kind(flecs::PostUpdate) - .each( - [](flecs::entity e, WorldPosition& world_pos, Position const& local_pos) - { - if (e.parent() == flecs::entity::null()) - { - world_pos.x = local_pos.x; - world_pos.y = local_pos.y; - } - else - { - auto parent_world_pos = e.parent().get(); - world_pos.x = parent_world_pos->x + local_pos.x; - world_pos.y = parent_world_pos->y + local_pos.y; - } - }); - - world.system("CollisionCheck") - .each( - [](flecs::iter& it, - size_t index, - WorldPosition const& world_pos, - Size const& size, - CollisionBox) - { - auto basket_box = it.world().lookup("Basket::CollisionBox"); - if (it.entity(index) == basket_box) - return; - - auto basket_box_pos = basket_box.get(); - auto basket_box_size = basket_box.get(); - - if (basket_box_pos->x + basket_box_size->w >= world_pos.x && - basket_box_pos->x <= world_pos.x + size.w && - basket_box_pos->y + basket_box_size->h >= world_pos.y && - basket_box_pos->y <= world_pos.y + size.h) - { - spdlog::info("collision"); - } - }); world.system("RenderSprites") .kind(flecs::PreUpdate) .term_at(0) @@ -227,37 +79,6 @@ int main() sdl_handles.renderer, sprite.texture->sdl_texture, &srcrect, &dstrect); }); - world.system("MoveBasket") - .term_at(0) - .singleton() - .each( - [](ButtonInput const& input, - Position& pos, - Size const& size, - Sprite const& sprite, - Basket) - { - if (input.pressed.contains(SDLK_LEFT)) - { - pos.x -= 5; - } - if (input.pressed.contains(SDLK_RIGHT)) - { - pos.x += 5; - } - - pos.x = pos.x < 0 ? 0 : pos.x; - pos.x = pos.x > WINDOW_WIDTH - size.w ? WINDOW_WIDTH - size.w : pos.x; - }); - - world.system("MoveSprites") - .each( - [](Position& pos, Velocity const& vel) - { - pos.x += vel.x; - pos.y += vel.y; - }); - auto* audio_assets = world.get(); auto* stream = SDL_OpenAudioDeviceStream( SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &audio_assets->background_music.spec, NULL, NULL); diff --git a/src/physics.cpp b/src/physics.cpp new file mode 100644 index 0000000..909d0cb --- /dev/null +++ b/src/physics.cpp @@ -0,0 +1,81 @@ +#include "physics.hpp" +#include "definitions.hpp" +#include "level.hpp" + +#include + +PhysicsModule::PhysicsModule(flecs::world& world) +{ + world.system("TranslatePhysicsObject") + .each( + [](Position& pos, Velocity const& vel) + { + pos.x += vel.x; + pos.y += vel.y; + }); + + // world.system("PropagatePosition") + // .kind(flecs::PostUpdate) + // .each( + // [](flecs::entity e, WorldPosition& world_pos, Position const& local_pos) + // { + // if (e.parent() == flecs::entity::null()) + // { + // world_pos.x = local_pos.x; + // world_pos.y = local_pos.y; + // } + // else + // { + // auto parent_world_pos = e.parent().get(); + // world_pos.x = parent_world_pos->x + local_pos.x; + // world_pos.y = parent_world_pos->y + local_pos.y; + // } + // }); + + world.system("DrawBoxes") + .term_at(0) + .singleton() + .each( + [](SdlHandles const& sdl_handles, + WorldPosition const& pos, + Size const& size, + CollisionBox) + { + SDL_FRect rect{static_cast(pos.x), + static_cast(pos.y), + static_cast(size.w), + static_cast(size.h)}; + SDL_SetRenderDrawColor(sdl_handles.renderer, 0, 0, 255, 255); + SDL_RenderRect(sdl_handles.renderer, &rect); + }); + + auto basket_query = world.query(); + + world.system("CollisionCheck") + .kind(flecs::OnValidate) + .each( + [basket_query]( + flecs::entity e, WorldPosition const& world_pos, Size const& size, CollisionBox) + { + if (e.parent().has()) + return; + + basket_query.first().children( + [world_pos, size](flecs::entity basket_child) + { + if (!basket_child.has()) + return; + + auto basket_child_pos = basket_child.get(); + auto basket_child_size = basket_child.get(); + + if (basket_child_pos->x + basket_child_size->w >= world_pos.x && + basket_child_pos->x <= world_pos.x + size.w && + basket_child_pos->y + basket_child_size->h >= world_pos.y && + basket_child_pos->y <= world_pos.y + size.h) + { + spdlog::info("collision"); + } + }); + }); +} \ No newline at end of file diff --git a/src/physics.hpp b/src/physics.hpp new file mode 100644 index 0000000..d81e969 --- /dev/null +++ b/src/physics.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include + +struct WorldPosition +{ + int x; + int y; +}; + +struct Position +{ + int x; + int y; +}; + +struct Velocity +{ + int x; + int y; +}; + +struct Size +{ + int w; + int h; +}; + +struct CollisionBox +{ +}; + +struct PhysicsModule +{ + PhysicsModule(flecs::world& world); +}; diff --git a/src/sdl_types.hpp b/src/sdl_types.hpp deleted file mode 100644 index 2dcd34c..0000000 --- a/src/sdl_types.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include - -struct SdlHandles -{ - SDL_Window* window; - SDL_Renderer* renderer; -};