You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
4.8 KiB
C++
185 lines
4.8 KiB
C++
3 months ago
|
#include <chrono>
|
||
|
#include <cstdlib>
|
||
|
#include <iostream>
|
||
|
#include <string_view>
|
||
|
#include <thread>
|
||
|
|
||
|
#include <entt/entt.hpp>
|
||
|
#include <SDL2/SDL.h>
|
||
|
#include <SDL2/SDL_image.h>
|
||
|
|
||
|
static constexpr auto WINDOW_WIDTH = 640;
|
||
|
static constexpr auto WINDOW_HEIGHT = 480;
|
||
|
|
||
|
static SDL_Window *window = nullptr;
|
||
|
static SDL_Renderer *renderer = nullptr;
|
||
|
|
||
|
static int sdl2Initialize();
|
||
|
static SDL_Texture *sdl2LoadTexture(const char *path);
|
||
|
|
||
|
struct Player {
|
||
|
char unused = 0;
|
||
|
};
|
||
|
|
||
|
struct Vec2 {
|
||
|
float x, y;
|
||
|
|
||
|
auto& operator+=(const Vec2& o) noexcept {
|
||
|
x += o.x;
|
||
|
y += o.y;
|
||
|
return *this;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct Point : public Vec2 {};
|
||
|
struct Velocity : public Vec2 {};
|
||
|
|
||
|
class Texture
|
||
|
{
|
||
|
public:
|
||
|
Texture(const char *path) {
|
||
|
tex = sdl2LoadTexture(path);
|
||
|
}
|
||
|
|
||
|
~Texture() {
|
||
|
if (tex != nullptr)
|
||
|
SDL_DestroyTexture(tex);
|
||
|
}
|
||
|
|
||
|
void operator()(SDL_Renderer *rend, Point p) const noexcept {
|
||
|
const int x = static_cast<int>(p.x);
|
||
|
const int y = static_cast<int>(p.y);
|
||
|
SDL_Rect rect {x, y, 0, 0};
|
||
|
|
||
|
/* TODO err check */
|
||
|
SDL_QueryTexture(tex, nullptr, nullptr, &rect.w, &rect.h);
|
||
|
SDL_RenderCopy(rend, tex, nullptr, &rect);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
SDL_Texture *tex;
|
||
|
};
|
||
|
|
||
|
int main()
|
||
|
{
|
||
|
if (auto err = sdl2Initialize(); err)
|
||
|
return err;
|
||
|
|
||
|
entt::registry registry;
|
||
|
|
||
|
const auto ent = registry.create();
|
||
|
registry.emplace<Player>(ent);
|
||
|
registry.emplace<Point>(ent, 0.f, WINDOW_HEIGHT - 100.f);
|
||
|
registry.emplace<Velocity>(ent, 0.f, 0.f);
|
||
|
registry.emplace<Texture>(ent, "img/player.png");
|
||
|
|
||
|
SDL_Event e;
|
||
|
bool quit = false;
|
||
|
while (!quit) {
|
||
|
const auto nextFrame = std::chrono::high_resolution_clock::now() +
|
||
|
std::chrono::microseconds(1'000'000 / 60);
|
||
|
|
||
|
SDL_RenderClear(renderer);
|
||
|
registry.view<Texture, Point>().each(
|
||
|
[](Texture& tex, Point& p) { tex(renderer, p); });
|
||
|
SDL_RenderPresent(renderer);
|
||
|
|
||
|
registry.view<Velocity, Point>().each(
|
||
|
[](Velocity& v, Point& p) { p += v; });
|
||
|
|
||
|
while (SDL_PollEvent(&e)) {
|
||
|
if (e.type == SDL_QUIT) {
|
||
|
quit = true;
|
||
|
} else if (e.type == SDL_KEYDOWN) {
|
||
|
auto view = registry.view<Player, Velocity>();
|
||
|
|
||
|
if (e.key.repeat) {
|
||
|
// do nothing
|
||
|
} else if (e.key.keysym.sym == SDLK_d) {
|
||
|
view.each([](Player& p, Velocity& v) { v.x += 1.5f; });
|
||
|
} else if (e.key.keysym.sym == SDLK_a) {
|
||
|
view.each([](Player& p, Velocity& v) { v.x -= 1.5f; });
|
||
|
}
|
||
|
} else if (e.type == SDL_KEYUP) {
|
||
|
auto view = registry.view<Player, Velocity>();
|
||
|
|
||
|
if (e.key.repeat) {
|
||
|
// do nothing
|
||
|
} else if (e.key.keysym.sym == SDLK_d) {
|
||
|
view.each([](Player& p, Velocity& v) { v.x -= 1.5f; });
|
||
|
} else if (e.key.keysym.sym == SDLK_a) {
|
||
|
view.each([](Player& p, Velocity& v) { v.x += 1.5f; });
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std::this_thread::sleep_until(nextFrame);
|
||
|
}
|
||
|
|
||
|
SDL_DestroyWindow(window);
|
||
|
SDL_Quit();
|
||
|
}
|
||
|
|
||
|
int sdl2Initialize()
|
||
|
{
|
||
|
if (auto err = SDL_Init(SDL_INIT_VIDEO); err < 0) {
|
||
|
std::cerr << "SDL error: " << SDL_GetError() << std::endl;
|
||
|
return EXIT_FAILURE;
|
||
|
} else {
|
||
|
atexit(SDL_Quit);
|
||
|
}
|
||
|
|
||
|
if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG)) {
|
||
|
std::cerr << "IMG error: " << IMG_GetError() << std::endl;
|
||
|
return EXIT_FAILURE;
|
||
|
} else {
|
||
|
atexit(IMG_Quit);
|
||
|
}
|
||
|
|
||
|
window = SDL_CreateWindow("game",
|
||
|
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||
|
WINDOW_WIDTH, WINDOW_HEIGHT,
|
||
|
SDL_WINDOW_SHOWN);
|
||
|
|
||
|
if (window == nullptr) {
|
||
|
std::cerr << "SDL error: " << SDL_GetError() << std::endl;
|
||
|
return EXIT_FAILURE;
|
||
|
} else {
|
||
|
atexit([] { SDL_DestroyWindow(window); });
|
||
|
}
|
||
|
|
||
|
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
||
|
|
||
|
if (renderer == nullptr) {
|
||
|
std::cerr << "SDL error: " << SDL_GetError() << std::endl;
|
||
|
return EXIT_FAILURE;
|
||
|
} else {
|
||
|
atexit([] { SDL_DestroyRenderer(renderer); });
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
SDL_Texture *sdl2LoadTexture(const char *path)
|
||
|
{
|
||
|
SDL_Texture *tex = nullptr;
|
||
|
|
||
|
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;
|
||
|
} else {
|
||
|
tex = SDL_CreateTextureFromSurface(renderer, surface);
|
||
|
|
||
|
if (tex == nullptr) {
|
||
|
std::cerr << "Unable to create texture for " << path << '!' << std::endl;
|
||
|
std::cerr << "SDL error: " << SDL_GetError() << std::endl;
|
||
|
} else {
|
||
|
SDL_FreeSurface(surface);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return tex;
|
||
|
}
|
||
|
|