From 93c0623fe4b24b44499f0d3bdc5de37f2366a4f3 Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Sat, 3 Feb 2018 23:39:49 +0100 Subject: [PATCH] Implemented a simple particle engine. --- CMakeLists.txt | 3 +- src/gui.c | 3 + src/main.c | 17 +++++ src/monster.c | 6 ++ src/particle_engine.c | 155 ++++++++++++++++++++++++++++++++++++++++++ src/particle_engine.h | 24 +++++++ src/player.c | 5 ++ src/pointer.c | 3 +- src/vector2d.h | 9 +++ 9 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 src/particle_engine.c create mode 100644 src/particle_engine.h create mode 100644 src/vector2d.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b5519a..ffb4360 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ if (NOT WIN32) ) endif (NOT WIN32) -set(CMAKE_C_FLAGS_DEBUG "-DDEBUG") +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG") # PROGRAMS: add_executable(breakhack @@ -70,6 +70,7 @@ add_executable(breakhack src/item_builder src/pointer src/gui_button + src/particle_engine ) target_link_libraries(breakhack diff --git a/src/gui.c b/src/gui.c index 7c6fb95..1676a93 100644 --- a/src/gui.c +++ b/src/gui.c @@ -465,6 +465,9 @@ gui_destroy(Gui *gui) for (int i = 0; i < LOG_LINES_COUNT; ++i) texture_destroy(gui->log_lines[i]); + for (int i = 0; i < LABEL_COUNT; ++i) + sprite_destroy(gui->labels[i]); + ht_destroy_custom(gui->textures, (void (*)(void*)) &texture_destroy); free(gui); } diff --git a/src/main.c b/src/main.c index 4de82bb..d3a86a7 100644 --- a/src/main.c +++ b/src/main.c @@ -18,6 +18,7 @@ #include "item_builder.h" #include "pointer.h" #include "gui_button.h" +#include "particle_engine.h" static SDL_Window *gWindow = NULL; static SDL_Renderer *gRenderer = NULL; @@ -27,6 +28,7 @@ static RoomMatrix *gRoomMatrix = NULL; static Gui *gGui = NULL; static Pointer *gPointer = NULL; static unsigned int cLevel = 1; +static float deltaTime = 1.0; static double renderScale = 1.0; static GameState gGameState; static Camera gCamera; @@ -135,6 +137,7 @@ bool init(void) gGui = gui_create(gRenderer); item_builder_init(gRenderer); gPointer = pointer_create(gRenderer); + particle_engine_init(); } gGameState = PLAYING; @@ -213,6 +216,7 @@ run_game(void) roommatrix_build_lightmap(gRoomMatrix); gui_update_player_stats(gGui, gPlayer, gMap, gRenderer); + particle_engine_update(deltaTime); if (gPlayer->steps >= gPlayer->stats.speed) { player_reset_steps(gPlayer); @@ -224,6 +228,7 @@ run_game(void) SDL_RenderSetViewport(gRenderer, &gameViewport); map_render(gMap, &gCamera); + particle_engine_render(&gCamera); player_render(gPlayer, &gCamera); roommatrix_render_lightmap(gRoomMatrix, &gCamera); @@ -249,6 +254,9 @@ run_game(void) static void run(void) { + static int oldTime = 0; + static int currentTime = 0; + bool quit = false; Timer* fpsTimer = timer_create(); @@ -281,6 +289,14 @@ void run(void) if (ticks < 1000/60) SDL_Delay((1000/60) - ticks); timer_stop(fpsTimer); + + if (currentTime == 0) + currentTime = SDL_GetTicks(); + else { + oldTime = currentTime; + currentTime = SDL_GetTicks(); + deltaTime = (currentTime - oldTime) / 1000.0; + } } timer_destroy(fpsTimer); @@ -295,6 +311,7 @@ void close(void) gui_destroy(gGui); pointer_destroy(gPointer); item_builder_close(); + particle_engine_close(); SDL_DestroyRenderer(gRenderer); SDL_DestroyWindow(gWindow); gWindow = NULL; diff --git a/src/monster.c b/src/monster.c index 7e672d7..5447b53 100644 --- a/src/monster.c +++ b/src/monster.c @@ -10,6 +10,7 @@ #include "item.h" #include "item_builder.h" #include "map.h" +#include "particle_engine.h" static void monster_load_texts(Monster *m, SDL_Renderer *renderer) @@ -231,6 +232,11 @@ monster_hit(Monster *monster, unsigned int dmg) if (dmg > 0) { monster->hitText->active = true; monster->missText->active = false; + Position p = monster->sprite->pos; + p.x += 8; + p.y += 8; + Dimension d = { 8, 8 }; + particle_engine_bloodspray(p, d); } else { monster->missText->active = true; monster->hitText->active = false; diff --git a/src/particle_engine.c b/src/particle_engine.c new file mode 100644 index 0000000..a48ff10 --- /dev/null +++ b/src/particle_engine.c @@ -0,0 +1,155 @@ +#include +#include "particle_engine.h" +#include "linkedlist.h" +#include "util.h" +#include "defines.h" +#include "vector2d.h" + +typedef struct Particle_t { + Position pos; + Vector2d velocity; + Dimension dim; + unsigned int movetime; + unsigned int lifetime; + SDL_Color color; +} Particle; + +typedef struct Engine_t { + LinkedList *particles; +} Engine; + +static Engine *engine = NULL; + +static void +check_engine(void) +{ + if (!engine) + fatal("Particle engine not initiated"); +} + +void +particle_engine_init(void) +{ + if (engine != NULL) + fatal("Engine already initiated"); + + engine = ec_malloc(sizeof(Engine)); + engine->particles = linkedlist_create(); +} + +void +particle_engine_bloodspray(Position pos, Dimension dim) +{ + int x, y, xv, yv, w, h, i; + unsigned int mt, lt; + Particle *p; + + check_engine(); + + for (i = 0; i < 15; ++i) { + x = (rand() % dim.width) + pos.x; + y = (rand() % dim.height) + pos.y; + + xv = (rand() % 200) - 100; + yv = (rand() % 200) - 100; + + mt = (rand() % 10) + 10; + lt = (rand() % 120) + 60; + + w = (rand() % 3) + 2; + h = (rand() % 3) + 2; + + p = ec_malloc(sizeof(Particle)); + p->pos = (Position) { x, y }; + p->velocity = (Vector2d) { xv, yv }; + p->movetime = mt; + p->lifetime = lt; + p->dim = (Dimension) { w, h }; + p->color = (SDL_Color) { 255, 0, 0, 255 }; + linkedlist_append(&engine->particles, p); + } +} + +static void +move_particle(Particle *particle, float deltaTime) +{ + if (!particle->movetime) + return; + + particle->pos.x += particle->velocity.x * deltaTime; + particle->pos.y += particle->velocity.y * deltaTime; +} + +void +particle_engine_update(float deltaTime) +{ + check_engine(); + LinkedList *current, *last; + Particle *particle; + + current = engine->particles; + last = NULL; + + while (current) { + particle = current->data; + + if (particle->movetime) + particle->movetime--; + + if (particle->lifetime > 0) { + particle->lifetime--; + move_particle(current->data, deltaTime); + last = current; + current = current->next; + } else { + if (!last) { + engine->particles = current->next; + free(current->data); + free(current); + current = engine->particles; + } else { + last->next = current->next; + free(current->data); + free(current); + current = last->next; + } + } + } +} + +static void +render_particle(Particle *p, Camera *cam) +{ + Position pos = camera_to_camera_position(cam, &p->pos); + SDL_Rect box = { pos.x, pos.y, p->dim.width, p->dim.height }; + SDL_SetRenderDrawColor(cam->renderer, + p->color.r, + p->color.b, + p->color.g, + p->color.a); + SDL_RenderFillRect(cam->renderer, &box); +} + +void +particle_engine_render(Camera *cam) +{ + check_engine(); + LinkedList *particles = engine->particles; + + while (particles) { + render_particle(particles->data, cam); + particles = particles->next; + } +} + +void +particle_engine_close(void) +{ + check_engine(); + + while (engine->particles) + free(linkedlist_pop(&engine->particles)); + + free(engine); + engine = NULL; +} diff --git a/src/particle_engine.h b/src/particle_engine.h new file mode 100644 index 0000000..c232c56 --- /dev/null +++ b/src/particle_engine.h @@ -0,0 +1,24 @@ +#ifndef PARTICLE_ENGINE_H_ +#define PARTICLE_ENGINE_H_ + +#include +#include "position.h" +#include "dimension.h" +#include "camera.h" + +void +particle_engine_init(void); + +void +particle_engine_bloodspray(Position, Dimension); + +void +particle_engine_update(float deltatime); + +void +particle_engine_render(Camera*); + +void +particle_engine_close(void); + +#endif // PARTICLE_ENGINE_H_ diff --git a/src/player.c b/src/player.c index 194d972..c801adb 100644 --- a/src/player.c +++ b/src/player.c @@ -7,6 +7,7 @@ #include "util.h" #include "gui.h" #include "item.h" +#include "particle_engine.h" #define ENGINEER_STATS { 12, 12, 5, 7, 2, 1, 1 } #define MAGE_STATS { 12, 12, 5, 7, 2, 1, 1 } @@ -309,6 +310,10 @@ player_hit(Player *p, unsigned int dmg) if (dmg > 0) { p->hitText->active = true; p->missText->active = false; + Position pos = p->sprite->pos; + pos.x += 8; + pos.y += 8; + particle_engine_bloodspray(pos, (Dimension) { 8, 8 }); } else { p->missText->active = true; p->hitText->active = false; diff --git a/src/pointer.c b/src/pointer.c index 2acb754..5733cd9 100644 --- a/src/pointer.c +++ b/src/pointer.c @@ -2,6 +2,7 @@ #include #include "pointer.h" #include "util.h" +#include "particle_engine.h" Pointer * pointer_create(SDL_Renderer *renderer) @@ -25,7 +26,7 @@ pointer_handle_event(Pointer *p, SDL_Event *event) if (event->type == SDL_MOUSEMOTION) { p->sprite->pos.x = event->motion.x; p->sprite->pos.y = event->motion.y; - debug("Pointer pos: %dx%d", p->sprite->pos.x, p->sprite->pos.y); + // debug("Pointer pos: %dx%d", p->sprite->pos.x, p->sprite->pos.y); } } diff --git a/src/vector2d.h b/src/vector2d.h new file mode 100644 index 0000000..ed455c6 --- /dev/null +++ b/src/vector2d.h @@ -0,0 +1,9 @@ +#ifndef VECTOR2D_H_ +#define VECTOR2D_H_ + +typedef struct Vector2d_t { + float x; + float y; +} Vector2d; + +#endif // VECTOR2D_H_