From 456ef376530fc4644732d499c862f1413b9987d9 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Mon, 5 Aug 2024 15:47:55 -0400 Subject: [PATCH] level solid; basic collision/gravity --- img/level.png | Bin 0 -> 7392 bytes include/components/solid.hpp | 56 +++++++++++++++++++++++++++++++++ include/components/texture.hpp | 12 +++++-- include/vec2.hpp | 4 +++ include/window.hpp | 1 + main.cpp | 41 +++++++++++++++++++++--- window.cpp | 12 +++++++ 7 files changed, 118 insertions(+), 8 deletions(-) create mode 100644 img/level.png create mode 100644 include/components/solid.hpp diff --git a/img/level.png b/img/level.png new file mode 100644 index 0000000000000000000000000000000000000000..bb28633a35030887f7bc36e64f0b829c3e01dc70 GIT binary patch literal 7392 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 +#include + +class Solid { +public: + Solid(const char *path) { + bitmap = sdl2LoadSolid(path); + } + + ~Solid() { + if (bitmap != nullptr) + SDL_FreeSurface(bitmap); + } + + float collision(Vec2 p) const noexcept { + float dy = 0.f; + + if (at(p)) { + auto up = p; + while (up.y > 0 && at(up)) + up.y--; + + auto down = p; + while (down.y < bitmap->h && at(down)) + down.y++; + + if (down.y - p.y > p.y - up.y) + dy = -(p.y - up.y); + else + dy = down.y - p.y; + } + + return dy; + } + +private: + SDL_Surface *bitmap; + + bool at(Vec2 p) const noexcept { + const auto bm = reinterpret_cast(bitmap->pixels); + const int x = std::clamp(static_cast(p.x), 0, bitmap->w); + const int y = std::clamp(static_cast(p.y), 0, bitmap->h); + const int i = y * bitmap->w + x; + const auto val = bm[i * bitmap->format->BytesPerPixel]; + return val > 0; + } +}; + +#endif // COMPONENTS_SOLID_HPP + diff --git a/include/components/texture.hpp b/include/components/texture.hpp index f4d414e..14253f1 100644 --- a/include/components/texture.hpp +++ b/include/components/texture.hpp @@ -1,6 +1,7 @@ #ifndef COMPONENTS_TEXTURE_HPP #define COMPONENTS_TEXTURE_HPP +#include "components/point.hpp" #include "window.hpp" class Texture @@ -8,6 +9,8 @@ class Texture public: Texture(const char *path) { tex = sdl2LoadTexture(path); + if (tex) + SDL_QueryTexture(tex, nullptr, nullptr, &w, &h); } ~Texture() { @@ -18,15 +21,18 @@ public: void operator()(SDL_Renderer *rend, Point p) const noexcept { const int x = static_cast(p.x); const int y = static_cast(p.y); - SDL_Rect rect {x, y, 0, 0}; + SDL_Rect rect {x, y, w, h}; - /* TODO err check */ - SDL_QueryTexture(tex, nullptr, nullptr, &rect.w, &rect.h); SDL_RenderCopy(rend, tex, nullptr, &rect); } + Point dim() const noexcept { + return Point {static_cast(w), static_cast(h)}; + } + private: SDL_Texture *tex; + int w, h; }; #endif // COMPONENTS_TEXTURE_HPP diff --git a/include/vec2.hpp b/include/vec2.hpp index dcd4b93..6b3c30a 100644 --- a/include/vec2.hpp +++ b/include/vec2.hpp @@ -4,6 +4,10 @@ struct Vec2 { float x, y; + auto operator+(const Vec2& o) const noexcept { + return Vec2 {x + o.x, y + o.y}; + } + auto& operator+=(const Vec2& o) noexcept { x += o.x; y += o.y; diff --git a/include/window.hpp b/include/window.hpp index d245b33..ad8392c 100644 --- a/include/window.hpp +++ b/include/window.hpp @@ -11,6 +11,7 @@ extern SDL_Renderer *renderer; int sdl2Initialize(); SDL_Texture *sdl2LoadTexture(const char *path); +SDL_Surface *sdl2LoadSolid(const char *path); #endif // WINDOW_HPP diff --git a/main.cpp b/main.cpp index 09b55f4..c137cc1 100644 --- a/main.cpp +++ b/main.cpp @@ -1,10 +1,12 @@ #include "components/point.hpp" #include "components/player.hpp" +#include "components/solid.hpp" #include "components/texture.hpp" #include "components/velocity.hpp" #include "window.hpp" #include +#include #include #include @@ -21,11 +23,20 @@ int main() entt::registry registry; - const auto ent = registry.create(); - registry.emplace(ent); - registry.emplace(ent, 0.f, WINDOW_HEIGHT - 100.f); - registry.emplace(ent, 0.f, 0.f); - registry.emplace(ent, "img/player.png"); + { + const auto ent = registry.create(); + registry.emplace(ent); + registry.emplace(ent, 0.f, WINDOW_HEIGHT - 200.f); + registry.emplace(ent, 0.f, 0.f); + registry.emplace(ent, "img/player.png"); + } + + { + const auto ent = registry.create(); + registry.emplace(ent, 0.f, 0.f); + registry.emplace(ent, "img/level.png"); + registry.emplace(ent, "img/level.png"); + } do { const auto now = std::chrono::high_resolution_clock::now(); @@ -36,6 +47,23 @@ int main() registry.view().each([](auto& v, auto& p) { p += v; }); + registry.view().each( + [®istry](auto& s, auto& p) { + registry.view().each( + [&s, &p](auto& _, auto& pp, auto& pv, auto& t) { + const auto c = s.collision(pp + t.dim()); + + if (c) { + if (std::abs(c) > 1.f) + pv.y = c * 0.5f; + else + pv.y = 0.f; + } else { + pv.y += 0.1f; + } + }); + }); + std::this_thread::sleep_until(now + FRAME_TIME); } while (handleInputs(registry)); } @@ -57,6 +85,9 @@ bool handleInputs(entt::registry& registry) case SDLK_a: view.each([](Player& p, Velocity& v) { v.x -= 1.5f; }); break; + case SDLK_SPACE: + view.each([](Player& p, Velocity& v) { if (v.y <= 0.f) v.y -= 3.f; }); + break; } } else if (e.type == SDL_KEYUP && !e.key.repeat) { auto view = registry.view(); diff --git a/window.cpp b/window.cpp index 3813a3c..e8677a8 100644 --- a/window.cpp +++ b/window.cpp @@ -70,3 +70,15 @@ SDL_Texture *sdl2LoadTexture(const char *path) return tex; } +SDL_Surface *sdl2LoadSolid(const char *path) +{ + auto surface = IMG_Load(path); + + if (surface == nullptr) { + std::cerr << "Unable to load image " << path << '!' << std::endl; + std::cerr << "SDL error: " << IMG_GetError() << std::endl; + } + + return surface; +} +