This commit is contained in:
2025-06-16 03:14:07 +01:00
parent 675ce0039a
commit 137c4a544b
26 changed files with 550 additions and 788 deletions

93
src/assets.cpp Normal file
View File

@@ -0,0 +1,93 @@
#include "assets.hpp"
AssetManager::AssetManager() {
}
AssetManager::~AssetManager() {
clearAssets();
}
void AssetManager::load(const std::string& name, const std::string& filePath) {
SDL_Surface* surface = IMG_Load(filePath.c_str());
if (!surface) {
SDL_Log("Failed to load image %s: %s", filePath.c_str(), SDL_GetError());
}
assets[name] = surface;
}
SDL_Surface* AssetManager::getAsset(const std::string& name) const {
auto it = assets.find(name);
if (it != assets.end()) {
return it->second;
}
SDL_Log("Asset %s not found", name.c_str());
return nullptr;
}
void AssetManager::unloadAsset(const std::string& name) {
auto it = assets.find(name);
if (it != assets.end()) {
SDL_DestroySurface(it->second);
assets.erase(it);
}
SDL_Log("Asset %s not found", name.c_str());
}
void AssetManager::clearAssets() {
for (auto& pair : assets) {
SDL_DestroySurface(pair.second);
}
assets.clear();
}
TileMap::TileMap(AssetManager& assetManager)
: assetManager(assetManager) {
}
TileMap::~TileMap() {
clear();
}
void TileMap::addTile(const std::string& name, const Tile& tile) {
tiles[name] = tile;
}
Tile TileMap::getTile(const std::string& name) const {
auto it = tiles.find(name);
if (it != tiles.end()) {
return it->second;
}
SDL_Log("Tile %s not found", name.c_str());
return Tile(); // Return an empty Tile
}
SDL_Surface* TileMap::getTileAsset(const std::string& name) const {
auto it = tiles.find(name);
if (it != tiles.end()) {
return assetManager.getAsset(it->second.assetName);
}
SDL_Log("Tile %s not found", name.c_str());
return nullptr;
}
Rect TileMap::getTileRect(const std::string& name) const {
auto it = tiles.find(name);
if (it != tiles.end()) {
return Rect(it->second.srcRect);
}
SDL_Log("Tile %s not found", name.c_str());
return Rect(); // Return an empty Rect
}
void TileMap::removeTile(const std::string& name) {
auto it = tiles.find(name);
if (it != tiles.end()) {
tiles.erase(it);
} else {
SDL_Log("Tile %s not found", name.c_str());
}
}
void TileMap::clear() {
tiles.clear();
}

View File

@@ -1,78 +1,138 @@
#include "engine.h"
#include "engine.hpp"
Engine::Engine(std::string title, int width, int height)
{
// convert title to char*
ctitle = title.c_str();
Engine::Engine(const char* windowTitle, int windowWidth, int windowHeight, int windowFlags) {
// Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
SDL_Log("SDL could not initialize! SDL_Error: %s", SDL_GetError());
return;
}
// Initialize SDL and TFF;
TTF_Init();
SDL_Init(SDL_INIT_EVERYTHING);
// Create the window
window = SDL_CreateWindow(windowTitle, windowWidth, windowHeight, windowFlags);
if (!window) {
SDL_Log("Window could not be created! SDL_Error: %s", SDL_GetError());
return;
}
// Create window and renderer
window = SDL_CreateWindow(
ctitle,
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
width,
height,
SDL_WINDOW_SHOWN
);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
// Create the renderer
renderer = SDL_CreateRenderer(window, nullptr);
if (!renderer) {
SDL_Log("Renderer could not be created! SDL_Error: %s", SDL_GetError());
return;
}
}
void Engine::initSound()
{
// Initialize sound
Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048);
soundInitialized = true;
Engine::~Engine() {
// Destroy the asset manager
assets.clearAssets();
// Destroy the renderer
if (renderer) {
SDL_DestroyRenderer(renderer);
}
// Destroy the window
if (window) {
SDL_DestroyWindow(window);
}
// Quit SDL subsystems
SDL_Quit();
}
void Engine::clear(SDL_Color color)
{
// Set color
void Engine::clearScreen(const Color& color) {
// Set the draw color
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
// Clear screen
// Clear the screen
SDL_RenderClear(renderer);
}
void Engine::startFrame()
{
// Start frame
frameStart = SDL_GetTicks();
}
void Engine::render()
{
// Render screen
void Engine::present() {
// Present the renderer
SDL_RenderPresent(renderer);
if (1000 / targetFrameRate > SDL_GetTicks() - frameStart)
{
SDL_Delay(1000 / targetFrameRate - (SDL_GetTicks() - frameStart));
// Calculate frame duration
frameEndTime = SDL_GetTicks();
frameDuration = frameEndTime - frameStartTime;
// Calculate delay to maintain target FPS
if (targetFPSValue > 0) {
Uint32 targetFrameTime = 1000 / targetFPSValue;
if (frameDuration < targetFrameTime) {
SDL_Delay(targetFrameTime - frameDuration);
}
}
}
void Engine::update()
{
// Update input
input.update();
}
Engine::~Engine()
{
// Free renderer and window
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
// If sound is initialized, quit Mix
if (soundInitialized)
{
Mix_Quit();
void Engine::draw(SDL_Surface* surface, Rect destRect) {
// Draw a surface to the renderer at the specified destination rectangle
if (!surface) {
SDL_Log("Cannot draw null surface");
return;
}
// Quit SDL and TTF
SDL_Quit();
TTF_Quit();
SDL_FRect sdlDestRect = {
static_cast<float>(destRect.x),
static_cast<float>(destRect.y),
static_cast<float>(destRect.width),
static_cast<float>(destRect.height)
};
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
if (!texture) {
SDL_Log("Failed to create texture from surface: %s", SDL_GetError());
return;
}
SDL_RenderTexture(renderer, texture, nullptr, &sdlDestRect);
SDL_DestroyTexture(texture);
}
void Engine::draw(SDL_Surface* surface, Rect srcRect, Rect destRect) {
// Draw a surface to the renderer with specified source and destination rectangles
if (!surface) {
SDL_Log("Cannot draw null surface");
return;
}
SDL_FRect sdlSrcRect = {
static_cast<float>(srcRect.x),
static_cast<float>(srcRect.y),
static_cast<float>(srcRect.width),
static_cast<float>(srcRect.height)
};
SDL_FRect sdlDestRect = {
static_cast<float>(destRect.x),
static_cast<float>(destRect.y),
static_cast<float>(destRect.width),
static_cast<float>(destRect.height)
};
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
if (!texture) {
SDL_Log("Failed to create texture from surface: %s", SDL_GetError());
return;
}
SDL_RenderTexture(renderer, texture, &sdlSrcRect, &sdlDestRect);
SDL_DestroyTexture(texture);
}
void Engine::draw(Tile tile, Rect destRect) {
// Draw a tile to the renderer at the specified destination rectangle
SDL_Surface* surface = assets.getAsset(tile.assetName);
if (!surface) {
SDL_Log("Tile asset %s not found", tile.assetName.c_str());
return;
}
draw(surface, tile.srcRect, destRect);
}
void Engine::startFrame() {
// Start the frame timer
frameStartTime = SDL_GetTicks();
}
void Engine::targetFPS(int fps) {
// Set the target frames per second
targetFPSValue = fps;
}

View File

@@ -1,133 +0,0 @@
// Includes
#include "engine.h"
// Variables
SDL_Surface* assets;
Music* music;
Engine *engine;
// Functions
// Quit function
void quit()
{
// Free assets
SDL_FreeSurface(assets);
delete engine;
// Exit program
exit(0);
}
// Main function
int main(int argc, char* argv[])
{
engine = new Engine("Game", 800, 600);
engine->initSound();
engine->targetFrameRate = 60;
// Load assets
assets = SDL_LoadBMP("example_assets/sprites.bmp");
music = new Music("example_assets/crystal_zone.mp3");
// frame map
std::map<std::string, SDL_Rect> idle = {
{ "idle", { 76, 456, 68, 128 } },
};
std::map<std::string, SDL_Rect> front = {
{ "front", { 4, 456, 68, 125 } },
{ "front2", { 76, 456, 68, 128 } },
{ "front3", { 148, 456, 68, 125 } }
};
std::map<std::string, SDL_Rect> back = {
{ "back", { 662, 456, 68, 125 } },
{ "back2", { 734, 456, 68, 128 } },
{ "back3", { 806, 456, 68, 125 } }
};
std::map<std::string, SDL_Rect> walk = {
{ "walk", { 220, 456, 68, 124 } },
{ "walk2", { 292, 456, 73, 127 } },
{ "walk3", { 369, 456, 68, 124 } }
};
std::map<std::string, SDL_Rect> test = {
{ "test", { 4, 2095, 68, 59 } },
{ "test2", { 76, 2095, 68, 59 } }
};
// Create sprite and animation
Sprite* sprite = new Sprite(engine->renderer, assets);
AnimationManager* animations = new AnimationManager(sprite);
animations->addAnimation("idle", idle, 10, false, true, false, false);
animations->addAnimation("walk_left", walk, 10, false, true, true, false);
animations->addAnimation("walk_right", walk, 10, true, true, true, false);
animations->addAnimation("walk_back", back, 10, false, true, true, false);
animations->addAnimation("walk_front", front, 10, false, true, true, true);
animations->addAnimation("test", test, 20, false, true, false, false);
animations->setAnimation("idle");
// Play music
music->play();
// Main loop
while (true)
{
// Start time
engine->startFrame();
// Update input
engine->update();
// Exit if window s closed
if (engine->input.exit || engine->input.activeKeys[SDLK_ESCAPE])
{
quit();
}
if (engine->input.activeKeys[SDLK_d] || engine->input.controllers[0].buttons[CBUTTONS::DPAD_RIGHT] || engine->input.controllers[0].leftStickX > 8000)
{
animations->setAnimation("walk_right");
sprite->move({ 1, 0 });
}
if (engine->input.activeKeys[SDLK_a] || engine->input.controllers[0].buttons[CBUTTONS::DPAD_LEFT] || engine->input.controllers[0].leftStickX < -8000)
{
animations->setAnimation("walk_left");
sprite->move({ -1, 0 });
}
if (engine->input.activeKeys[SDLK_w] || engine->input.controllers[0].buttons[CBUTTONS::DPAD_UP] || engine->input.controllers[0].leftStickY < -8000)
{
animations->setAnimation("walk_back");
sprite->move({ 0, -1 });
}
if (engine->input.activeKeys[SDLK_s] || engine->input.controllers[0].buttons[CBUTTONS::DPAD_DOWN] || engine->input.controllers[0].leftStickY > 8000)
{
animations->setAnimation("walk_front");
sprite->move({ 0, 1 });
}
if (engine->input.activeKeys[SDLK_SPACE] || engine->input.controllers[0].buttons[CBUTTONS::A])
{
animations->playAnimation("test");
}
if (!engine->input.keysPressed({ SDLK_w, SDLK_a, SDLK_s, SDLK_d }) && engine->input.controllers[0].leftStickX < 8000 && engine->input.controllers[0].leftStickX > -8000 &&
engine->input.controllers[0].leftStickY < 8000 && engine->input.controllers[0].leftStickY > -8000 &&
!engine->input.controllerPressed({ CBUTTONS::DPAD_UP, CBUTTONS::DPAD_DOWN, CBUTTONS::DPAD_LEFT, CBUTTONS::DPAD_RIGHT }))
{
animations->setAnimation("idle");
}
// Update animation
animations->update();
// Clear screen
engine->clear({ 100, 150, 255, 255 });
// Draw sprite
animations->draw(engine->renderer);
// Update screen
engine->render();
}
return 0;
}

View File

@@ -1,78 +1,112 @@
#include "input.h"
#include "input.hpp"
Input::Input() {
Input::Input()
{
SDL_Init(SDL_INIT_JOYSTICK);
exit = false;
}
void Input::update()
{
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_CONTROLLERBUTTONDOWN:
controllers[event.cbutton.which].buttons[event.cbutton.button] = true;
break;
case SDL_CONTROLLERBUTTONUP:
controllers[event.cbutton.which].buttons[event.cbutton.button] = false;
break;
case SDL_MOUSEBUTTONDOWN:
mouse.buttons[event.button.button] = true;
break;
case SDL_MOUSEBUTTONUP:
mouse.buttons[event.button.button] = false;
break;
case SDL_KEYDOWN:
activeKeys[event.key.keysym.sym] = true;
break;
case SDL_KEYUP:
activeKeys.erase(event.key.keysym.sym);
break;
case SDL_CONTROLLERDEVICEADDED:
controllers[SDL_NumJoysticks() - 1] = {
SDL_GameControllerOpen(SDL_NumJoysticks() - 1),
SDL_GameControllerName(SDL_GameControllerOpen(SDL_NumJoysticks() - 1))
};
printf("Controller added: %s\n", controllers[SDL_NumJoysticks() - 1].name.c_str());
break;
case SDL_QUIT:
exit = true;
break;
Input::~Input() {
}
void Input::handleEvents() {
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_EVENT_QUIT:
quitRequestedFlag = true;
break;
case SDL_EVENT_KEY_DOWN:
if (keyStates[event.key.scancode] == false) {
keyFallingEdgeStates[event.key.scancode] = true;
}
keyStates[event.key.scancode] = true;
break;
case SDL_EVENT_KEY_UP:
keyStates[event.key.scancode] = false;
keyFallingEdgeStates[event.key.scancode] = false;
break;
case SDL_EVENT_MOUSE_BUTTON_DOWN:
if (mouseButtonStates[event.button.button] == false) {
mouseButtonFallingEdgeStates[event.button.button] = true;
}
mouseButtonStates[event.button.button] = true;
break;
case SDL_EVENT_MOUSE_BUTTON_UP:
mouseButtonStates[event.button.button] = false;
mouseButtonFallingEdgeStates[event.button.button] = false;
break;
case SDL_EVENT_MOUSE_MOTION:
mousePosition.x = static_cast<int>(event.motion.x);
mousePosition.y = static_cast<int>(event.motion.y);
break;
}
for (auto& controller : controllers)
{
controller.second.leftStickX = SDL_GameControllerGetAxis(controller.second.controller, SDL_CONTROLLER_AXIS_LEFTX);
controller.second.leftStickY = SDL_GameControllerGetAxis(controller.second.controller, SDL_CONTROLLER_AXIS_LEFTY);
controller.second.rightStickX = SDL_GameControllerGetAxis(controller.second.controller, SDL_CONTROLLER_AXIS_RIGHTX);
controller.second.rightStickY = SDL_GameControllerGetAxis(controller.second.controller, SDL_CONTROLLER_AXIS_RIGHTY);
controller.second.leftTrigger = SDL_GameControllerGetAxis(controller.second.controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT);
controller.second.rightTrigger = SDL_GameControllerGetAxis(controller.second.controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
}
SDL_GetMouseState(&mouse.x, &mouse.y);
mouse.wheel = event.wheel.y;
}
}
bool Input::keysPressed(std::vector<SDL_Keycode> keys)
{
for (auto key : keys)
{
if (activeKeys[key])
{
bool Input::quitRequested() const {
return quitRequestedFlag;
}
bool Input::isKeyPressed(SDL_Scancode key) {
auto it = keyStates.find(key);
return it != keyStates.end() && it->second;
}
bool Input::isKeyPressed(std::vector<SDL_Scancode> keys) {
for (const auto& key : keys) {
if (isKeyPressed(key)) {
return true;
}
}
return false;
}
bool Input::controllerPressed(std::vector<Uint8> buttons, int controller)
{
for (auto button : buttons)
{
if (controllers[controller].buttons[button])
{
bool Input::isMouseButtonPressed(Uint8 button) {
auto it = mouseButtonStates.find(button);
return it != mouseButtonStates.end() && it->second;
}
bool Input::isMouseButtonPressed(std::vector<Uint8> buttons) {
for (const auto& button : buttons) {
if (isMouseButtonPressed(button)) {
return true;
}
}
return false;
}
Vector2 Input::getMousePosition() const {
return mousePosition;
}
bool Input::hasKeyBeenPressed(SDL_Scancode key) {
auto it = keyFallingEdgeStates.find(key);
if (it != keyFallingEdgeStates.end() && it->second) {
keyFallingEdgeStates[key] = false;
return true;
}
return false;
}
bool Input::hasKeyBeenPressed(std::vector<SDL_Scancode> keys) {
for (const auto& key : keys) {
if (hasKeyBeenPressed(key)) {
return true;
}
}
return false;
}
bool Input::hasMouseButtonBeenPressed(Uint8 button) {
auto it = mouseButtonFallingEdgeStates.find(button);
if (it != mouseButtonFallingEdgeStates.end() && it->second) {
mouseButtonFallingEdgeStates[button] = false;
return true;
}
return false;
}
bool Input::hasMouseButtonBeenPressed(std::vector<Uint8> buttons) {
for (const auto& button : buttons) {
if (hasMouseButtonBeenPressed(button)) {
return true;
}
}

57
src/main.cpp Normal file
View File

@@ -0,0 +1,57 @@
#include "engine.hpp"
// Main function
int main(int argc, char* argv[]) {
// Create the engine with a window title and dimensions
Engine engine("SDL3 Game Engine", 800, 600);
TileMap tileMap(engine.assets);
// Load bird asset
engine.assets.load("bird", "assets/bird.png");
tileMap.addTile("bird0", Tile{{0, 0, 34, 24}, "bird"});
tileMap.addTile("bird1", Tile{{34, 0, 34, 24}, "bird"});
tileMap.addTile("bird2", Tile{{68, 0, 34, 24}, "bird"});
int currentBirdIndex = 0;
// bird position
Vector2 birdPosition(0, 0);
while (!engine.input.quitRequested()) {
// Start a new frame
engine.startFrame();
// Handle input events
engine.input.handleEvents();
// check for movement keys
if (engine.input.isKeyPressed(SDL_SCANCODE_D)) {
birdPosition.x += 1; // Move right
}
if (engine.input.isKeyPressed(SDL_SCANCODE_A)) {
birdPosition.x -= 1; // Move left
}
if (engine.input.isKeyPressed(SDL_SCANCODE_W)) {
birdPosition.y -= 1; // Move up
}
if (engine.input.isKeyPressed(SDL_SCANCODE_S)) {
birdPosition.y += 1; // Move down
}
// Change bird sprite on space key press
if (engine.input.hasKeyBeenPressed(SDL_SCANCODE_SPACE)) {
currentBirdIndex = (currentBirdIndex + 1) % 3; // Cycle through bird sprites
}
// Clear the screen with a color
engine.clearScreen({0, 0, 0}); // Black color
// Draw the bird asset at a specific position
engine.draw(tileMap.getTile("bird" + std::to_string(currentBirdIndex)), birdPosition);
// Present the rendered frame
engine.present();
}
return 0;
}

View File

@@ -1,56 +0,0 @@
#include "sound.h"
Music::Music(const char* path)
{
music = Mix_LoadMUS(path);
}
void Music::play(int loops)
{
Mix_PlayMusic(music, loops);
}
void Music::pause()
{
Mix_PauseMusic();
}
void Music::stop()
{
Mix_HaltMusic();
}
void Music::resume()
{
Mix_ResumeMusic();
}
void Music::setVolume(int volume)
{
Mix_VolumeMusic(volume);
}
Music::~Music()
{
Mix_FreeMusic(music);
}
Effect::Effect(const char* path)
{
effect = Mix_LoadWAV(path);
}
void Effect::play(int loops, int channel)
{
Mix_PlayChannel(channel, effect, loops);
}
void Effect::setVolume(int volume)
{
Mix_VolumeChunk(effect, volume);
}
Effect::~Effect()
{
Mix_FreeChunk(effect);
}

View File

@@ -1,170 +0,0 @@
#include "sprite.h"
Sprite::Sprite(SDL_Renderer *renderer, SDL_Surface *surface)
{
Texture = SDL_CreateTextureFromSurface(renderer, surface);
dstrect = { 0, 0, surface->w, surface->h };
}
Sprite::~Sprite()
{
SDL_DestroyTexture(Texture);
}
void Sprite::draw(SDL_Renderer* renderer, std::string frame, bool autoRect, bool flip)
{
if (frames.find(frame) == frames.end())
{
printf("Frame not found\n");
return;
}
if (autoRect)
{
dstrect = { dstrect.x, dstrect.y, frames[frame].w, frames[frame].h };
}
SDL_SetTextureAlphaMod(Texture, 255);
dstrect.w *= scale.x;
dstrect.h *= scale.y;
SDL_RenderCopyEx(renderer, Texture, &frames[frame], &dstrect, angle, NULL, flip ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE);
}
void Sprite::addFrame(std::string name, SDL_Rect rect)
{
frames[name] = rect;
}
void Sprite::setPos(int_vec2 position)
{
dstrect.x = position.x;
dstrect.y = position.y;
}
void Sprite::move(int_vec2 position)
{
dstrect.x += position.x;
dstrect.y += position.y;
}
int_vec2 Sprite::getSize(std::string frame)
{
size = { frames[frame].w, frames[frame].h };
return size;
}
void Sprite::autorect(std::string frame)
{
dstrect = { dstrect.x, dstrect.y, frames[frame].w, frames[frame].h };
}
Animation::Animation(std::map<std::string, SDL_Rect> frames, Sprite* sprite, int frameDuration)
{
this->sprite = sprite;
this->frameDuration = frameDuration;
for (auto const& x : frames)
{
this->frames.push_back(x.first);
this->sprite->addFrame(x.first, x.second);
}
currentFrameName = this->frames[0];
}
void Animation::reset()
{
frameIndex = 0;
frameDirection = 1;
currentFrameName = frames[0];
end = false;
}
void Animation::update()
{
frameCounter++;
end = false;
if (frameCounter >= frameDuration)
{
frameCounter = 0;
if (pingpong)
{
frameIndex += frameDirection;
if (frameIndex >= frames.size() - 1 || frameIndex <= 0)
{
if (!loop)
{
frameDirection = 0;
end = true;
} else {
frameDirection *= -1;
}
}
}
else
{
frameIndex++;
if (frameIndex >= frames.size())
{
if (!loop)
{
frameIndex = frames.size() - 1;
end = true;
} else {
frameIndex = 0;
}
}
}
currentFrameName = frames[frameIndex];
}
}
void Animation::draw(SDL_Renderer* renderer, bool autoRect, bool flip)
{
sprite->draw(renderer, currentFrameName, autoRect, flip);
}
AnimationManager::AnimationManager(Sprite* sprite)
{
this->sprite = sprite;
}
void AnimationManager::addAnimation(std::string name, std::map<std::string, SDL_Rect> frames, int frameDuration, bool flip, bool autoRect, bool loop, bool pingpong)
{
animations[name] = new Animation(frames, sprite, frameDuration);
this->flip[name] = flip;
this->autoRect[name] = autoRect;
animations[name]->loop = loop;
animations[name]->pingpong = pingpong;
}
void AnimationManager::setAnimation(std::string name)
{
if (!playing) {
currentAnimation = name;
}
}
void AnimationManager::update()
{
animations[currentAnimation]->update();
if (playing && animations[currentAnimation]->end)
{
playing = false;
}
}
void AnimationManager::draw(SDL_Renderer* renderer)
{
animations[currentAnimation]->draw(renderer, autoRect[currentAnimation], flip[currentAnimation]);
}
void AnimationManager::playAnimation(std::string name)
{
if (!playing) {
animations[name]->loop = false;
animations[name]->reset();
setAnimation(name);
playing = true;
}
}

View File

@@ -1,17 +0,0 @@
#include "text.h"
Text::Text(TTF_Font* font, SDL_Color color)
{
this->font = font;
this->color = color;
}
void Text::draw(SDL_Renderer* renderer, std::string text, int x, int y)
{
surface = TTF_RenderText_Solid(font, text.c_str(), color);
texture = SDL_CreateTextureFromSurface(renderer, surface);
rect = { x, y, surface->w, surface->h };
SDL_RenderCopy(renderer, texture, NULL, &rect);
SDL_FreeSurface(surface);
SDL_DestroyTexture(texture);
}