Implemented the sword swing effect.

This adds the animation type for future use.
Not super happy with the animation png. Will look over it in the future.
This commit is contained in:
Linus Probert 2018-07-09 19:26:06 +02:00
parent 79b0869974
commit 988d6c5cac
12 changed files with 264 additions and 10 deletions

View File

@ -171,6 +171,7 @@ add_executable(breakhack
src/db
src/settings
src/actiontextbuilder
src/animation
)
# Sqlite has some warnings that I we don't need to see

View File

Before

Width:  |  Height:  |  Size: 297 B

After

Width:  |  Height:  |  Size: 297 B

117
src/animation.c Normal file
View File

@ -0,0 +1,117 @@
/*
* 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 "animation.h"
#include "timer.h"
#include "camera.h"
#include "sprite.h"
#include "util.h"
Animation *
animation_create(unsigned int clipCount)
{
Animation *animation = ec_malloc(sizeof(Animation)
+ clipCount * sizeof(AnimationClip));
animation->clipTimer = timer_create();
animation->clipCount = clipCount;
animation->currentClip = 0;
animation->loop = true;
animation->running = false;
animation->sprite = sprite_create();
return animation;
}
void
animation_load_texture(Animation *animation, const char *path, SDL_Renderer *renderer)
{
sprite_load_texture(animation->sprite, path, 0, renderer);
}
void
animation_update(Animation *animation)
{
if (!animation->running) {
return;
}
if (!timer_started(animation->clipTimer)) {
timer_start(animation->clipTimer);
}
if (timer_get_ticks(animation->clipTimer)
> animation->clips[animation->currentClip].renderTime)
{
animation->currentClip++;
if (animation->currentClip >= animation->clipCount) {
animation->currentClip = 0;
if (!animation->loop) {
animation_stop(animation);
return;
}
timer_start(animation->clipTimer);
}
}
animation->sprite->clip = (SDL_Rect) {
animation->clips[animation->currentClip].x,
animation->clips[animation->currentClip].y,
animation->clips[animation->currentClip].w,
animation->clips[animation->currentClip].h
};
}
void
animation_render(Animation *animation, Camera *camera)
{
if (!animation->running) {
return;
}
sprite_render(animation->sprite, camera);
}
void
animation_set_frames(Animation *animation, AnimationClip clips[])
{
for (size_t i = 0; i < animation->clipCount; i++) {
animation->clips[i] = clips[i];
}
}
void
animation_run(Animation *a)
{
a->running = true;
}
void
animation_stop(Animation *a)
{
a->running = false;
a->currentClip = 0;
timer_stop(a->clipTimer);
}
void
animation_destroy(Animation *animation)
{
timer_destroy(animation->clipTimer);
sprite_destroy(animation->sprite);
free(animation);
}

75
src/animation.h Normal file
View File

@ -0,0 +1,75 @@
/*
* 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 _ANIMATION_H
#define _ANIMATION_H
#include <SDL.h>
#include <stdbool.h>
typedef struct Timer Timer;
typedef struct Camera Camera;
typedef struct Sprite Sprite;
typedef struct AnimationClip
{
unsigned int x;
unsigned int y;
unsigned int w;
unsigned int h;
unsigned int renderTime;
} AnimationClip;
typedef struct Animation
{
Sprite *sprite;
Timer *clipTimer;
unsigned int currentClip;
bool loop;
unsigned int clipCount;
bool running;
AnimationClip clips[];
} Animation;
Animation*
animation_create(unsigned int clipCount);
void
animation_load_texture(Animation *, const char *path, SDL_Renderer*);
void
animation_set_frames(Animation*, AnimationClip clips[]);
void
animation_run(Animation*);
void
animation_update(Animation*);
void
animation_render(Animation*, Camera*);
void
animation_stop(Animation*);
void
animation_destroy(Animation*);
#endif // _ANIMATION_H

View File

@ -25,7 +25,7 @@
#include "timer.h"
#include "vector2d.h"
typedef struct {
typedef struct Camera {
Position pos;
Position basePos;
Vector2d velocity;

View File

@ -516,6 +516,8 @@ run_game(void)
map_render_top_layer(gMap, gCamera);
player_render_toplayer(gPlayer, gCamera);
if (gPlayer->class == MAGE || gPlayer->class == PALADIN)
roommatrix_render_mouse_square(gRoomMatrix, gCamera);

View File

@ -33,6 +33,7 @@
#include "texturecache.h"
#include "vector2d.h"
#include "actiontextbuilder.h"
#include "animation.h"
#define ENGINEER_STATS { 12, 12, 5, 7, 2, 2, 1 }
#define MAGE_STATS { 12, 12, 5, 7, 1, 2, 1 }
@ -133,6 +134,8 @@ has_collided(Player *player, RoomMatrix *matrix, Vector2d direction)
monster_hit(space->monster, hit);
animation_run(player->swordAnimation);
if (hit > 0) {
gui_log("You hit %s for %u damage",
space->monster->lclabel, hit);
@ -246,6 +249,27 @@ handle_next_move(UpdateData *data)
++step;
step = step % 4;
}
if (!vector2d_equals(nextDir, VECTOR2D_NODIR))
player->swordAnimation->sprite->pos = player->sprite->pos;
if (vector2d_equals(nextDir, VECTOR2D_UP)) {
player->swordAnimation->sprite->pos.y -= 32;
player->swordAnimation->sprite->angle = -90;
player->swordAnimation->sprite->flip = SDL_FLIP_NONE;
} else if (vector2d_equals(nextDir, VECTOR2D_DOWN)) {
player->swordAnimation->sprite->pos.y += 32;
player->swordAnimation->sprite->angle = 90;
player->swordAnimation->sprite->flip = SDL_FLIP_NONE;
} else if (vector2d_equals(nextDir, VECTOR2D_LEFT)) {
player->swordAnimation->sprite->pos.x -= 32;
player->swordAnimation->sprite->angle = 0;
player->swordAnimation->sprite->flip = SDL_FLIP_HORIZONTAL;
} else if (vector2d_equals(nextDir, VECTOR2D_RIGHT)) {
player->swordAnimation->sprite->pos.x += 32;
player->swordAnimation->sprite->angle = 0;
player->swordAnimation->sprite->flip = SDL_FLIP_NONE;
}
}
static void
@ -327,6 +351,24 @@ check_skill_trigger(UpdateData *data)
return true;
}
static void
build_sword_animation(Player *p, SDL_Renderer *renderer)
{
animation_load_texture(p->swordAnimation, "Extras/SwordSwing.png", renderer);
animation_set_frames(p->swordAnimation, (AnimationClip[]) {
{ 0, 0, 16, 16, 20 },
{ 16, 0, 16, 16, 20 },
{ 32, 0, 16, 16, 20 },
{ 48, 0, 16, 16, 20 },
{ 64, 0, 16, 16, 20 }
});
p->swordAnimation->loop = false;
p->swordAnimation->sprite->dim = GAME_DIMENSION;
p->swordAnimation->sprite->clip = (SDL_Rect) { 0, 0, 16, 16 };
p->swordAnimation->sprite->rotationPoint = (SDL_Point) { 16, 16 };
}
Player*
player_create(class_t class, SDL_Renderer *renderer)
{
@ -349,6 +391,9 @@ player_create(class_t class, SDL_Renderer *renderer)
player->state = ALIVE;
player->projectiles = linkedlist_create();
player->animationTimer = timer_create();
player->swordAnimation = animation_create(5);
build_sword_animation(player, renderer);
for (size_t i = 0; i < PLAYER_SKILL_COUNT; ++i) {
player->skills[i] = NULL;
@ -451,6 +496,12 @@ player_render(Player *player, Camera *cam)
}
}
void
player_render_toplayer(Player *player, Camera *camera)
{
animation_render(player->swordAnimation, camera);
}
void
player_reset_steps(Player *p)
{
@ -503,6 +554,8 @@ void player_update(UpdateData *data)
linkedlist_destroy(&player->projectiles);
player->projectiles = remaining;
animation_update(player->swordAnimation);
}
void
@ -511,6 +564,7 @@ player_destroy(Player *player)
if (player->sprite)
sprite_destroy(player->sprite);
animation_destroy(player->swordAnimation);
timer_destroy(player->animationTimer);
for (size_t i = 0; i < PLAYER_SKILL_COUNT; ++i) {

View File

@ -31,7 +31,8 @@
#define PLAYER_SKILL_COUNT 5
// Foward declare
struct UpdateData;
typedef struct UpdateData UpdateData;
typedef struct Animation Animation;
typedef enum PlayerClass { ENGINEER, MAGE, PALADIN, ROGUE, WARRIOR } class_t;
typedef enum PlayerState { ALIVE, DEAD, FALLING } state_t;
@ -64,6 +65,7 @@ typedef struct Player_t {
state_t state;
Skill *skills[PLAYER_SKILL_COUNT];
Timer *animationTimer;
Animation *swordAnimation;
} Player;
Player*
@ -90,6 +92,9 @@ player_update(struct UpdateData *);
void
player_render(Player*, Camera*);
void
player_render_toplayer(Player*, Camera*);
void
player_destroy(Player*);

View File

@ -26,7 +26,7 @@
#include "map_room_modifiers.h"
#include "input.h"
typedef struct Sprite_t Sprite;
typedef struct Sprite Sprite;
typedef struct Map_t Map;
typedef struct Monster_t Monster;
typedef struct Player_t Player;

View File

@ -51,7 +51,7 @@ sprite_create(void)
void
sprite_load_texture(Sprite *sprite,
char *path,
const char *path,
int index,
SDL_Renderer *renderer)
{
@ -68,7 +68,7 @@ sprite_load_texture(Sprite *sprite,
sprite->destroyTextures = true;
}
void sprite_load_text_texture(Sprite *sprite, char * path, int index, int size, int outline)
void sprite_load_text_texture(Sprite *sprite, const char * path, int index, int size, int outline)
{
if (index > 1)
fatal("in sprite_load_texture() index out of bounds");
@ -122,7 +122,7 @@ sprite_render(Sprite *s, Camera *cam)
cameraPos.x, cameraPos.y, s->dim.width, s->dim.height
};
if ((s->clip.w && s->clip.h) || s->angle != 0 || s->flip != SDL_FLIP_NONE) {
if (s->angle != 0 || s->flip != SDL_FLIP_NONE) {
texture_render_clip_ex(s->textures[s->texture_index],
&box,
&s->clip,

View File

@ -27,7 +27,7 @@
#include "roommatrix.h"
#include "timer.h"
typedef struct Sprite_t {
typedef struct Sprite {
Texture* textures[2];
SDL_Rect clip;
bool destroyTextures;
@ -46,9 +46,9 @@ typedef struct Sprite_t {
Sprite* sprite_create(void);
void sprite_load_texture(Sprite *, char *path, int index, SDL_Renderer *);
void sprite_load_texture(Sprite *, const char *path, int index, SDL_Renderer *);
void sprite_load_text_texture(Sprite *, char *path, int index, int size, int outline);
void sprite_load_text_texture(Sprite *, const char *path, int index, int size, int outline);
void sprite_set_texture(Sprite *, Texture *, int index);

View File

@ -21,7 +21,7 @@
#include <stdbool.h>
typedef struct {
typedef struct Timer {
unsigned int startTime;
} Timer;