commit 36cb6154d71c2baa0e36c7478ab2218669279235 Author: Sergio Valor Date: Wed Aug 21 10:42:37 2024 +0200 Primer commit la pilota no deixa de botar mai diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a5a6f96 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.exe +*.dll \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fd037cc --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +source := source/*.cpp +executable_name := pelota + +windows: + g++ $(source) -lmingw32 -lws2_32 -lSDL2main -lSDL2 -lSDL2_image -o $(executable_name).exe \ No newline at end of file diff --git a/resources/pelota.png b/resources/pelota.png new file mode 100644 index 0000000..f7b7411 Binary files /dev/null and b/resources/pelota.png differ diff --git a/source/ball.cpp b/source/ball.cpp new file mode 100644 index 0000000..da942fe --- /dev/null +++ b/source/ball.cpp @@ -0,0 +1,107 @@ +#include "ball.h" +#include "defines.h" + +// Constructor +Ball::Ball(float x, float vx, float vy, color_t color, Texture *texture) +{ + this->x = x; + this->y = 0.0f; + this->w = BALL_SIZE; + this->h = BALL_SIZE; + this->vx = vx; + this->vy = vy; + sprite = new Sprite(texture); + sprite->setPos({(int)x, (int)y}); + sprite->setSize(BALL_SIZE, BALL_SIZE); + sprite->setClip({0, 0, BALL_SIZE, BALL_SIZE}); + this->color = color; + g = GRAVITY; + onFloor = false; + stopped = false; +} + +// Destructor +Ball::~Ball() +{ + if (sprite) + { + delete sprite; + } +} + +// Actualiza la lógica de la clase +void Ball::update() +{ + if (stopped) + { + return; + } + + // Actualiza la posición + x += vx; + y += vy; + + // Aplica la gravedad + if (!onFloor) + { + vy += g; + } + + // Comprueba las colisiones con el lateral izquierdo + if (x < 0) + { + x = 0; + vx = -vx; + } + + // Comprueba las colisiones con el lateral derecho + if (x + w > SCREEN_WIDTH) + { + x = SCREEN_WIDTH - w; + vx = -vx; + } + + // Comprueba las colisiones con la parte superior + if (y < 0) + { + y = 0; + vy = -vy; + } + + // Comprueba las colisiones con la parte inferior + // if (y + h > SCREEN_HEIGHT) + if ((y + h > SCREEN_HEIGHT) && (vy > 0)) + { + // y = SCREEN_HEIGHT - h; + vy = -vy * LOSS; + std::cout << vy << std::endl; + if (abs(vy) < 0.5f) + { + vy = 0.0f; + onFloor = true; + } + } + + // Aplica rozamiento al rodar por el suelo + if (onFloor) + { + vx = vx * 0.97f; + if (abs(vx) < 0.1f) + { + vx = 0.0f; + stopped = true; + exit(0); + } + } + + // Actualiza la posición del sprite + sprite->setPos({(int)x, (int)y}); + sprite->update(); +} + +// Pinta la clase +void Ball::render() +{ + sprite->setColor(color.r, color.g, color.b); + sprite->render(); +} \ No newline at end of file diff --git a/source/ball.h b/source/ball.h new file mode 100644 index 0000000..7012231 --- /dev/null +++ b/source/ball.h @@ -0,0 +1,33 @@ +#pragma once + +#include "sprite.h" +#include "texture.h" +#include "defines.h" + +class Ball +{ +private: + Sprite *sprite; // Sprite para pintar la clase + float x; // Posición x + float y; // Posición y + int w; // Ancho + int h; // Alto + float vx, vy; // Velocidad + float g; // Gravedad + color_t color; // Color de la pelota + bool onFloor; // Indica si la pelota está ya en el suelo + bool stopped; // Indica si la pelota ha terminado de moverse; + +public: + // Constructor + Ball(float x, float vx, float vy, color_t color, Texture *texture); + + // Destructor + ~Ball(); + + // Actualiza la lógica de la clase + void update(); + + // Pinta la clase + void render(); +}; \ No newline at end of file diff --git a/source/defines.h b/source/defines.h new file mode 100644 index 0000000..f8e394b --- /dev/null +++ b/source/defines.h @@ -0,0 +1,12 @@ +#pragma once + +#define SCREEN_WIDTH 320 +#define SCREEN_HEIGHT 240 +#define BALL_SIZE 8 +#define GRAVITY 0.2f +#define LOSS 0.75f + +struct color_t +{ + int r,g,b; +}; \ No newline at end of file diff --git a/source/main.cpp b/source/main.cpp new file mode 100644 index 0000000..88818c2 --- /dev/null +++ b/source/main.cpp @@ -0,0 +1,185 @@ +#include +#include +#include "texture.h" +#include "ball.h" +#include "defines.h" +#include +#include + +SDL_Window *window = NULL; +SDL_Renderer *renderer = NULL; +SDL_Event *event; +Texture *texture = nullptr; +std::vector balls; +int test[5] = {1, 10, 100, 500, 1000}; + +bool shouldExit = false; +Uint32 ticks = 0; + +void initBalls() +{ + for (int i = 0; i < test[0]; ++i) + { + const int sign = ((rand() % 2) * 2) - 1;; + const float x = SCREEN_WIDTH / 2 - BALL_SIZE / 2; + const float vx = (((rand() % 20) + 10) * 0.1f) * sign; + const float vy = ((rand() % 40) - 20) * 0.1f; + const color_t color = {(rand() % 192) + 32, (rand() % 192) + 32, (rand() % 192) + 32}; + Ball *b = new Ball(x, vx, vy, color, texture); + balls.push_back(b); + } +} + +bool init() +{ + // Initialization flag + bool success = true; + + // Initialize SDL + if (SDL_Init(SDL_INIT_VIDEO) < 0) + { + printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError()); + success = false; + } + else + { + // Set texture filtering to linear + if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) + { + printf("Warning: Linear texture filtering not enabled!"); + } + + // Create window + window = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH * 2, SCREEN_HEIGHT * 2, SDL_WINDOW_SHOWN); + if (window == NULL) + { + printf("Window could not be created! SDL Error: %s\n", SDL_GetError()); + success = false; + } + else + { + // Create renderer for window + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + if (renderer == NULL) + { + printf("Renderer could not be created! SDL Error: %s\n", SDL_GetError()); + success = false; + } + else + { + // Initialize renderer color + SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF); + + // Initialize PNG loading + int imgFlags = IMG_INIT_PNG; + if (!(IMG_Init(imgFlags) & imgFlags)) + { + printf("SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError()); + success = false; + } + + SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT); + } + } + } + + event = new SDL_Event(); + + texture = new Texture(renderer, "resources/pelota.png"); + ticks = SDL_GetTicks(); + srand (time(NULL)); + initBalls(); + + return success; +} + +void close() +{ + // Destroy window + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + window = nullptr; + renderer = nullptr; + + if (event) + { + delete event; + event = nullptr; + } + + if (texture) + { + delete texture; + texture = nullptr; + } + + for (auto ball : balls) + { + if (ball) + { + delete ball; + ball = nullptr; + } + } + balls.clear(); + + // Quit SDL subsystems + IMG_Quit(); + SDL_Quit(); +} + +void checkEvents() +{ + // Comprueba los eventos que hay en la cola + while (SDL_PollEvent(event) != 0) + { + // Evento de salida de la aplicación + if (event->type == SDL_QUIT) + { + shouldExit = true; + break; + } + } +} + +void update() +{ + if (SDL_GetTicks() - ticks > 15) + { + ticks = SDL_GetTicks(); + + for (auto ball : balls) + { + ball->update(); + } + } +} + +void render() +{ + SDL_SetRenderDrawColor(renderer, 32, 32, 32, 255); + SDL_RenderClear(renderer); + + for (auto ball : balls) + { + ball->render(); + } + + SDL_RenderPresent(renderer); +} + +int main(int argc, char *args[]) +{ + init(); + + while (!shouldExit) + { + update(); + checkEvents(); + render(); + } + + close(); + + return 0; +} \ No newline at end of file diff --git a/source/sprite.cpp b/source/sprite.cpp new file mode 100644 index 0000000..7f89ebe --- /dev/null +++ b/source/sprite.cpp @@ -0,0 +1,52 @@ +#include "sprite.h" + +// Constructor +Sprite::Sprite(Texture *texture) +{ + this->texture = texture; + pos = {0, 0, 0, 0}; + clip = {0, 0, 0, 0}; +} + +// Destructor +Sprite::~Sprite() +{ +} + +// Establece la posición del sprite +void Sprite::setPos(SDL_Point pos) +{ + this->pos.x = pos.x; + this->pos.y = pos.y; +} + +// Pinta el sprite +void Sprite::render() +{ + texture->render(&clip, &pos); +} + +// Actualiza la lógica de la clase +void Sprite::update() +{ + +} + +// Establece el rectangulo de la textura que se va a pintar +void Sprite::setClip(SDL_Rect clip) +{ + this->clip = clip; +} + +// Establece el tamaño del sprite +void Sprite::setSize(int w, int h) +{ + this->pos.w = w; + this->pos.h = h; +} + +// Modulación de color +void Sprite::setColor(int r, int g, int b) +{ + texture->setColor(r, g, b); +} \ No newline at end of file diff --git a/source/sprite.h b/source/sprite.h new file mode 100644 index 0000000..b561e1b --- /dev/null +++ b/source/sprite.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include "texture.h" + +class Sprite +{ +private: + Texture *texture; // Textura con los gráficos del sprite + SDL_Rect pos; // Posición y tamaño del sprite + SDL_Rect clip; // Parte de la textura que se va a dibujar + +public: + // Constructor + Sprite(Texture *texture); + + // Destructor + ~Sprite(); + + // Establece la posición del sprite + void setPos(SDL_Point pos); + + // Pinta el sprite + void render(); + + // Actualiza la lógica de la clase + void update(); + + // Establece el rectangulo de la textura que se va a pintar + void setClip(SDL_Rect clip); + + // Establece el tamaño del sprite + void setSize(int w, int h); + + // Modulación de color + void setColor(int r, int g, int b); +}; \ No newline at end of file diff --git a/source/texture.cpp b/source/texture.cpp new file mode 100644 index 0000000..2469a17 --- /dev/null +++ b/source/texture.cpp @@ -0,0 +1,101 @@ +#include +#include +#include +#include "texture.h" + +Texture::Texture(SDL_Renderer *renderer) +{ + this->renderer = renderer; + texture = NULL; + width = 0; + height = 0; +} + +Texture::Texture(SDL_Renderer *renderer, std::string filepath) +{ + this->renderer = renderer; + texture = NULL; + width = 0; + height = 0; + loadFromFile(filepath); +} + +Texture::~Texture() +{ + free(); +} + +bool Texture::loadFromFile(std::string path) +{ + // Get rid of preexisting texture + free(); + + // The final texture + SDL_Texture *newTexture = NULL; + + // Load image at specified path + SDL_Surface *loadedSurface = IMG_Load(path.c_str()); + if (loadedSurface == NULL) + { + printf("Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError()); + } + else + { + // Color key image + SDL_SetColorKey(loadedSurface, SDL_TRUE, SDL_MapRGB(loadedSurface->format, 0, 0xFF, 0xFF)); + + // Create texture from surface pixels + newTexture = SDL_CreateTextureFromSurface(renderer, loadedSurface); + if (newTexture == NULL) + { + printf("Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError()); + } + else + { + // Get image dimensions + width = loadedSurface->w; + height = loadedSurface->h; + } + + // Get rid of old loaded surface + SDL_FreeSurface(loadedSurface); + } + + // Return success + texture = newTexture; + return texture != NULL; +} + +void Texture::free() +{ + // Free texture if it exists + if (texture != NULL) + { + SDL_DestroyTexture(texture); + texture = NULL; + width = 0; + height = 0; + } +} + +void Texture::render(SDL_Rect *src, SDL_Rect *dst) +{ + // Render to screen + SDL_RenderCopy(renderer, texture, src, dst); +} + +int Texture::getWidth() +{ + return width; +} + +int Texture::getHeight() +{ + return height; +} + +// Modulación de color +void Texture::setColor(int r, int g, int b) +{ + SDL_SetTextureColorMod(texture, r, g, b); +} diff --git a/source/texture.h b/source/texture.h new file mode 100644 index 0000000..efc85ab --- /dev/null +++ b/source/texture.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +// Texture wrapper class +class Texture +{ +private: + SDL_Renderer *renderer; + SDL_Texture *texture; + + // Image dimensions + int width; + int height; + +public: + // Initializes variables + Texture(SDL_Renderer *renderer); + Texture(SDL_Renderer *renderer, std::string filepath); + + // Deallocates memory + ~Texture(); + + // Loads image at specified path + bool loadFromFile(std::string path); + + // Deallocates texture + void free(); + + // Renders texture at given point + void render(SDL_Rect *src = nullptr, SDL_Rect *dst = nullptr); + + // Gets image dimensions + int getWidth(); + int getHeight(); + + // Modulación de color + void setColor(int r, int g, int b); +};