Nicer action texts

This commit is contained in:
Linus Probert 2018-05-15 11:16:56 +02:00
parent 4e5e3e515c
commit d6daf7b798
14 changed files with 221 additions and 103 deletions

2
.vimrc
View File

@ -3,4 +3,4 @@ nnoremap <F2> :Make clean<cr>
nnoremap <F3> :Make lint test<cr>
nnoremap <F4> :!./_build/breakhack<cr>
let g:syntastic_c_include_dirs = [ 'build', '/usr/include/SDL2' ]
let g:syntastic_c_include_dirs = [ '_build', '/usr/include/SDL2' ]

View File

@ -165,6 +165,7 @@ add_executable(breakhack
src/sqlite3
src/db
src/settings
src/actiontextbuilder
)
# Sqlite has some warnings that I we don't need to see
@ -244,6 +245,7 @@ if (NOT DEBUG_BUILD)
"maproombuilder.lua"
"menumapgen.lua"
"monstergen.lua"
"pitlayouts.dat"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data
)
if (WIN32)

View File

@ -19,54 +19,49 @@
#include <stdlib.h>
#include "actiontext.h"
#include "util.h"
#include "update_data.h"
ActionText*
actiontext_create()
actiontext_create(Sprite *sprite)
{
ActionText *t = ec_malloc(sizeof(ActionText));
t->pos = (Position) { 0, 0 };
t->texture = texture_create();
t->sprite = sprite;
t->timer = timer_create();
t->active = false;
t->dead = false;
t->velocity = (Vector2d) { 100, -100 };
t->color = (SDL_Color) { 255, 255, 255, 255 };
return t;
}
void
actiontext_load_font(ActionText *t, const char *path, unsigned int size)
actiontext_update(ActionText *t, UpdateData *data)
{
texture_load_font(t->texture, path, size);
}
void
actiontext_set_text(ActionText *t, const char *text, SDL_Renderer *renderer)
{
texture_load_from_text(t->texture, text, t->color, renderer);
t->sprite->pos.x += (int) (t->velocity.x * data->deltatime);
t->sprite->pos.y += (int) (t->velocity.y * data->deltatime);
}
void
actiontext_render(ActionText *t, Camera *cam)
{
if (!t->active)
if (t->dead)
return;
if (t->active && !timer_started(t->timer))
if (!t->dead && !timer_started(t->timer))
timer_start(t->timer);
Position cameraPos = camera_to_camera_position(cam, &t->pos);
SDL_Rect box = { cameraPos.x, cameraPos.y, t->texture->dim.width, t->texture->dim.height };
if (timer_get_ticks(t->timer) < 300) {
texture_render(t->texture, &box, cam);
if (timer_get_ticks(t->timer) < 500) {
sprite_render(t->sprite, cam);
} else {
timer_stop(t->timer);
t->active = false;
t->dead = true;
}
}
void
actiontext_destroy(ActionText *t)
{
texture_destroy(t->texture);
sprite_destroy(t->sprite);
timer_destroy(t->timer);
free(t);
}

View File

@ -23,22 +23,24 @@
#include <stdbool.h>
#include "position.h"
#include "texture.h"
#include "sprite.h"
#include "timer.h"
#include "vector2d.h"
struct UpdateData_t;
typedef struct {
Position pos;
Texture *texture;
bool active;
Sprite *sprite;
bool dead;
Timer *timer;
Vector2d velocity;
SDL_Color color;
} ActionText;
ActionText* actiontext_create(void);
ActionText* actiontext_create(Sprite*);
void actiontext_load_font(ActionText*, const char *path, unsigned int size);
void actiontext_set_text(ActionText*, const char *text, SDL_Renderer*);
void actiontext_update(ActionText*, struct UpdateData_t*);
void actiontext_render(ActionText*, Camera*);

77
src/actiontextbuilder.c Normal file
View File

@ -0,0 +1,77 @@
/*
* BreakHack - A dungeone crawler RPG
* Copyright (C) 2018 Linus Probert <linus.probert@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "actiontextbuilder.h"
#include "util.h"
#include "linkedlist.h"
static SDL_Renderer *gRenderer = NULL;
static LinkedList *actiontexts;
void
actiontextbuilder_init(SDL_Renderer *renderer)
{
gRenderer = renderer;
actiontexts = linkedlist_create();
}
void
actiontextbuilder_create_text(const char *msg, SDL_Color color, Position *p)
{
assert (gRenderer != NULL);
Sprite *sprite = sprite_create();
sprite->pos = *p;
sprite_load_text_texture(sprite, "GUI/SDS_8x8.ttf", 0, 14);
texture_load_from_text(sprite->textures[0], msg, color, gRenderer);
sprite->dim = sprite->textures[0]->dim;
linkedlist_push(&actiontexts, actiontext_create(sprite));
}
void
actiontextbuilder_update(UpdateData *data)
{
LinkedList *remaining = linkedlist_create();
while (actiontexts) {
ActionText *text = linkedlist_pop(&actiontexts);
if (text->dead) {
actiontext_destroy(text);
} else {
actiontext_update(text, data);
linkedlist_push(&remaining, text);
}
}
actiontexts = remaining;
}
void
actiontextbuilder_render(Camera *cam)
{
LinkedList *actiontext = actiontexts;
while (actiontext) {
actiontext_render(actiontext->data, cam);
actiontext = actiontext->next;
}
}
void
actiontextbuilder_close(void)
{
while (actiontexts)
actiontext_destroy(linkedlist_pop(&actiontexts));
}

43
src/actiontextbuilder.h Normal file
View File

@ -0,0 +1,43 @@
/*
* BreakHack - A dungeone crawler RPG
* Copyright (C) 2018 Linus Probert <linus.probert@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ACTIONTEXTBUILDER_H_
#define ACTIONTEXTBUILDER_H_
#include <SDL.h>
#include "actiontext.h"
#include "camera.h"
#include "update_data.h"
void
actiontextbuilder_init(SDL_Renderer*);
void
actiontextbuilder_update(UpdateData*);
void
actiontextbuilder_render(Camera*);
void
actiontextbuilder_create_text(const char *msg, SDL_Color, Position*);
void
actiontextbuilder_close(void);
#endif // ACTIONTEXTBUILDER_H_

View File

@ -47,6 +47,7 @@
#include "texturecache.h"
#include "update_data.h"
#include "settings.h"
#include "actiontextbuilder.h"
typedef enum Turn_t {
PLAYER,
@ -196,6 +197,7 @@ initGame(void)
gPointer = pointer_create(gRenderer);
particle_engine_init();
menuTimer = timer_create();
actiontextbuilder_init(gRenderer);
return true;
}
@ -482,6 +484,9 @@ run_game(void)
gui_update_player_stats(gGui, gPlayer, gMap, gRenderer);
camera_update(gCamera, updateData.deltatime);
particle_engine_update(deltaTime);
actiontextbuilder_update(&updateData);
map_update(&updateData);
player_update(&updateData);
roommatrix_update_with_player(gRoomMatrix, gPlayer);
@ -501,6 +506,7 @@ run_game(void)
SDL_RenderSetViewport(gRenderer, &gameViewport);
map_render(gMap, gCamera);
actiontextbuilder_render(gCamera);
particle_engine_render_game(gCamera);
if (!is_player_dead())
@ -639,6 +645,7 @@ void close(void)
gui_destroy(gGui);
skillbar_destroy(gSkillBar);
pointer_destroy(gPointer);
actiontextbuilder_close();
item_builder_close();
particle_engine_close();
timer_destroy(menuTimer);

View File

@ -24,6 +24,7 @@
#include "item_builder.h"
#include "gui.h"
#include "particle_engine.h"
#include "update_data.h"
static
Room* create_room(void)
@ -230,6 +231,18 @@ void map_tile_render(Map *map, MapTile *tile, Position *pos, Camera *cam)
}
void
map_update(UpdateData *data)
{
Map *map = data->map;
LinkedList *monster = map->monsters;
while (monster) {
Monster *m = monster->data;
monster = monster->next;
monster_update(m, data);
}
}
void map_render(Map *map, Camera *cam)
{
unsigned int i, j;

View File

@ -32,6 +32,8 @@
#include "player.h"
#include "map_room_modifiers.h"
struct UpdateData_t;
typedef struct MapTile_t {
int textureIndex0;
int textureIndex1;
@ -86,6 +88,9 @@ map_clear_dead_monsters(Map*, Player*);
void
map_clear_collected_items(Map*);
void
map_update(struct UpdateData_t*);
void
map_render(Map*, Camera*);

View File

@ -285,10 +285,8 @@ l_add_monster(lua_State *L)
const char *texture_path_1, *texture_path_2, *tmp_label;
char *label;
Texture *texture1, *texture2;
SDL_Renderer *renderer;
Stats stats;
renderer = luaL_checksdlrenderer(L);
map = luaL_checkmap(L, 1);
x = (int) luaL_checkinteger(L, 2);
y = (int) luaL_checkinteger(L, 3);
@ -325,7 +323,7 @@ l_add_monster(lua_State *L)
lua_pop(L, 8);
monster = monster_create(renderer);
monster = monster_create();
monster->sprite->clip = (SDL_Rect) { clip_x, clip_y, 16, 16 };
monster_update_pos(monster, (Position) { x, y });
sprite_set_texture(monster->sprite, texture1, 0);

View File

@ -30,27 +30,11 @@
#include "map.h"
#include "particle_engine.h"
#include "defines.h"
static void
monster_load_texts(Monster *m, SDL_Renderer *renderer)
{
ActionText *t = actiontext_create();
actiontext_load_font(t, "GUI/SDS_6x6.ttf", 14);
t->color = (SDL_Color) { 255, 100, 0, 255 };
actiontext_set_text(t, "HIT", renderer);
t->pos = m->sprite->pos;
m->hitText = t;
t = actiontext_create();
actiontext_load_font(t, "GUI/SDS_6x6.ttf", 14);
t->color = (SDL_Color) { 255, 255, 0, 255 };
actiontext_set_text(t, "MISS", renderer);
t->pos = m->sprite->pos;
m->missText = t;
}
#include "update_data.h"
#include "actiontextbuilder.h"
Monster*
monster_create(SDL_Renderer *renderer)
monster_create(void)
{
Monster *m = ec_malloc(sizeof(Monster));
m->sprite = sprite_create();
@ -74,8 +58,6 @@ monster_create(SDL_Renderer *renderer)
m->lclabel = NULL;
m->steps = 0;
monster_load_texts(m, renderer);
return m;
}
@ -86,8 +68,6 @@ monster_update_pos(Monster *m, Position pos)
Position textPos = pos;
textPos.y += 10;
m->hitText->pos = textPos;
m->missText->pos = textPos;
}
static bool
@ -276,23 +256,38 @@ monster_move(Monster *m, RoomMatrix *rm)
m->steps = 0;
return true;
}
return false;
}
void
monster_update(Monster *m, UpdateData *data)
{
UNUSED(m);
UNUSED(data);
}
void
monster_hit(Monster *monster, unsigned int dmg)
{
static SDL_Color c_red = { 255, 0, 0, 255 };
static SDL_Color c_yellow = { 255, 255, 0, 255 };
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, dmg);
char msg[5];
m_sprintf(msg, 5, "-%d", dmg);
actiontextbuilder_create_text(msg,
c_red,
&monster->sprite->pos);
} else {
monster->missText->active = true;
monster->hitText->active = false;
actiontextbuilder_create_text("Dodged",
c_yellow,
&monster->sprite->pos);
}
monster->state.current = monster->state.challenge;
@ -363,10 +358,6 @@ void
monster_render(Monster *m, Camera *cam)
{
sprite_render(m->sprite, cam);
if (m->hitText)
actiontext_render(m->hitText, cam);
if (m->missText)
actiontext_render(m->missText, cam);
}
void
@ -377,9 +368,5 @@ monster_destroy(Monster *m)
free(m->label);
if (m->lclabel)
free(m->lclabel);
if (m->hitText)
actiontext_destroy(m->hitText);
if (m->missText)
actiontext_destroy(m->missText);
free(m);
}

View File

@ -24,6 +24,9 @@
#include "stats.h"
#include "actiontext.h"
#include "player.h"
#include "linkedlist.h"
struct UpdateData_t;
typedef enum { PASSIVE, AGRESSIVE, SCARED } StateType;
@ -37,14 +40,12 @@ typedef struct Monster_t {
char *label;
char *lclabel;
Sprite *sprite;
ActionText *hitText;
ActionText *missText;
Stats stats;
State state;
unsigned int steps;
} Monster;
Monster* monster_create(SDL_Renderer*);
Monster* monster_create(void);
void
monster_update_pos(Monster*, Position);
@ -61,6 +62,9 @@ monster_hit(Monster*, unsigned int dmg);
void
monster_update_stats_for_level(Monster*, unsigned int level);
void
monster_update(Monster*, struct UpdateData_t*);
void
monster_drop_loot(Monster*, Map*, Player*);

View File

@ -32,6 +32,7 @@
#include "projectile.h"
#include "texturecache.h"
#include "vector2d.h"
#include "actiontextbuilder.h"
#define ENGINEER_STATS { 12, 12, 5, 7, 2, 2, 1 }
#define MAGE_STATS { 12, 12, 5, 7, 1, 2, 1 }
@ -73,11 +74,17 @@ next_level_threshold(unsigned int current_level)
static void
player_gain_xp(Player *player, unsigned int xp_gain)
{
static SDL_Color c_green = { 0, 255, 0, 255 };
char msg[10];
m_sprintf(msg, 5, "+%dxp", xp_gain);
actiontextbuilder_create_text(msg, c_green, &player->sprite->pos);
player->xp += xp_gain;
if (player->xp >= next_level_threshold(player->stats.lvl)) {
player_levelup(player);
gui_log("You have reached level %u", player->stats.lvl);
gui_event_message("You reached level %u", player->stats.lvl);
actiontextbuilder_create_text("Level up", c_green, &player->sprite->pos);
}
}
@ -97,8 +104,6 @@ static void
player_step(Player *p)
{
action_spent(p);
p->missText->pos = p->sprite->pos;
p->hitText->pos = p->sprite->pos;
}
static bool
@ -335,24 +340,6 @@ handle_player_input(Player *player, RoomMatrix *matrix, SDL_Event *event)
handle_movement_input(player, matrix, event);
}
static void
player_load_texts(Player *p, SDL_Renderer *renderer)
{
ActionText *t = actiontext_create();
actiontext_load_font(t, "GUI/SDS_6x6.ttf", 14);
t->color = (SDL_Color) { 255, 100, 0, 255 };
actiontext_set_text(t, "HIT", renderer);
t->pos = p->sprite->pos;
p->hitText = t;
t = actiontext_create();
actiontext_load_font(t, "GUI/SDS_6x6.ttf", 14);
t->color = (SDL_Color) { 255, 255, 0, 255 };
actiontext_set_text(t, "MISS", renderer);
t->pos = p->sprite->pos;
p->missText = t;
}
Player*
player_create(class_t class, SDL_Renderer *renderer)
{
@ -410,7 +397,6 @@ player_create(class_t class, SDL_Renderer *renderer)
player->sprite->dim = GAME_DIMENSION;
player->sprite->clip = (SDL_Rect) { 0, 0, 16, 16 };
player->handle_event = &handle_player_input;
player_load_texts(player, renderer);
return player;
}
@ -444,35 +430,42 @@ player_monster_kill_check(Player *player, Monster *monster)
void
player_hit(Player *p, unsigned int dmg)
{
static SDL_Color c_red = { 255, 0, 0, 255 };
static SDL_Color c_yellow = { 255, 255, 0, 255 };
if (p->stats.hp <= 0) {
dmg = 200;
}
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 }, dmg);
mixer_play_effect(PLAYER_HIT0 + get_random(2));
char msg[5];
m_sprintf(msg, 5, "-%d", dmg);
actiontextbuilder_create_text(msg,
c_red,
&p->sprite->pos);
} else {
p->missText->active = true;
p->hitText->active = false;
actiontextbuilder_create_text("Dodged",
c_yellow,
&p->sprite->pos);
}
}
void
player_render(Player *player, Camera *cam)
{
sprite_render(player->sprite, cam);
actiontext_render(player->hitText, cam);
actiontext_render(player->missText, cam);
LinkedList *projectile = player->projectiles;
while (projectile) {
projectile_render(projectile->data, cam);
projectile = projectile->next;
}
}
void
@ -506,11 +499,7 @@ void player_update(UpdateData *data)
}
}
if (!player->projectiles)
return;
LinkedList *remaining = linkedlist_create();
while (player->projectiles) {
Projectile *p = linkedlist_pop(&player->projectiles);
projectile_update(p, data);
@ -531,8 +520,6 @@ player_destroy(Player *player)
{
if (player->sprite)
sprite_destroy(player->sprite);
actiontext_destroy(player->hitText);
actiontext_destroy(player->missText);
timer_destroy(player->animationTimer);

View File

@ -52,8 +52,6 @@ typedef struct ExperienceData_t {
typedef struct Player_t {
Sprite *sprite;
ActionText *hitText;
ActionText *missText;
Stats stats;
unsigned int daggers;
LinkedList *projectiles;