Player animations
|
@ -8,6 +8,7 @@ include(GenerateG3A)
|
|||
include(Fxconv)
|
||||
|
||||
find_package(Gint 2.3 REQUIRED)
|
||||
find_package(LibImg 2.2 REQUIRED)
|
||||
|
||||
add_custom_target(filepaths
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
|
@ -55,7 +56,6 @@ set(SOURCES
|
|||
|
||||
set(ASSETS
|
||||
assets/graphics/tileset.png
|
||||
assets/graphics/player.png
|
||||
assets/graphics/burst.png
|
||||
assets/graphics/coin-particle.png
|
||||
assets/graphics/switch-particle.png
|
||||
|
@ -63,6 +63,10 @@ set(ASSETS
|
|||
assets/graphics/exit-active-particle.png
|
||||
assets/graphics/exit-unlock-particle.png
|
||||
assets/graphics/font.png
|
||||
assets/graphics/player/blink.png
|
||||
assets/graphics/player/idle.png
|
||||
assets/graphics/player/jump.png
|
||||
assets/graphics/player/walk.png
|
||||
)
|
||||
|
||||
set(FLAGS
|
||||
|
@ -77,6 +81,7 @@ add_executable(${PROJECT_NAME} ${SOURCES} ${ASSETS})
|
|||
add_dependencies(${PROJECT_NAME} filepaths)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE ${FLAGS})
|
||||
target_link_libraries(${PROJECT_NAME} Gint::Gint)
|
||||
target_link_libraries(${PROJECT_NAME} LibImg::LibImg)
|
||||
|
||||
generate_g3a(TARGET ${PROJECT_NAME}
|
||||
OUTPUT "${PROJECT_NAME}.g3a"
|
||||
|
|
Before Width: | Height: | Size: 804 B After Width: | Height: | Size: 715 B |
|
@ -1,27 +1,27 @@
|
|||
# gint bopti_image_t
|
||||
tileset.png:
|
||||
type: bopti-image
|
||||
name: bimg_tileset
|
||||
player.png:
|
||||
type: bopti-image
|
||||
name: bimg_player
|
||||
burst.png:
|
||||
type: bopti-image
|
||||
name: bimg_burst
|
||||
|
||||
# libimg img_t
|
||||
coin-particle.png:
|
||||
type: bopti-image
|
||||
name: bimg_coin_particle
|
||||
type: libimg-image
|
||||
name: img_coin_particle
|
||||
switch-particle.png:
|
||||
type: bopti-image
|
||||
name: bimg_switch_particle
|
||||
type: libimg-image
|
||||
name: img_switch_particle
|
||||
switch-activated-particle.png:
|
||||
type: bopti-image
|
||||
name: bimg_switch_activated_particle
|
||||
type: libimg-image
|
||||
name: img_switch_activated_particle
|
||||
exit-active-particle.png:
|
||||
type: bopti-image
|
||||
name: bimg_exit_active_particle
|
||||
type: libimg-image
|
||||
name: img_exit_active_particle
|
||||
exit-unlock-particle.png:
|
||||
type: bopti-image
|
||||
name: bimg_exit_unlock_particle
|
||||
type: libimg-image
|
||||
name: img_exit_unlock_particle
|
||||
|
||||
# Fonts
|
||||
font.png:
|
||||
|
|
Before Width: | Height: | Size: 541 B |
After Width: | Height: | Size: 151 B |
|
@ -0,0 +1,12 @@
|
|||
idle.png:
|
||||
type: libimg-image
|
||||
name: img_player_idle
|
||||
walk.png:
|
||||
type: libimg-image
|
||||
name: img_player_walk
|
||||
blink.png:
|
||||
type: libimg-image
|
||||
name: img_player_blink
|
||||
jump.png:
|
||||
type: libimg-image
|
||||
name: img_player_jump
|
After Width: | Height: | Size: 499 B |
After Width: | Height: | Size: 163 B |
After Width: | Height: | Size: 221 B |
|
@ -2,4 +2,11 @@
|
|||
/* Copyright (C) 2021 KikooDX */
|
||||
#pragma once
|
||||
|
||||
enum GameState { TitleScreen, MainMenu, LevelSelection, Playing, GamePause, PackDone };
|
||||
enum GameState {
|
||||
TitleScreen,
|
||||
MainMenu,
|
||||
LevelSelection,
|
||||
Playing,
|
||||
GamePause,
|
||||
PackDone
|
||||
};
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
/* Copyright (C) 2021 KikooDX */
|
||||
#pragma once
|
||||
|
||||
#include <gint/display.h>
|
||||
#include <libimg.h>
|
||||
|
||||
#define MAX_PARTICLES 64
|
||||
|
||||
struct Particle {
|
||||
bopti_image_t *texture;
|
||||
img_t *texture;
|
||||
int x;
|
||||
int y;
|
||||
int frame_width;
|
||||
|
@ -17,10 +17,15 @@ struct Particle {
|
|||
int life_ini;
|
||||
int life;
|
||||
int looping;
|
||||
int flip_h;
|
||||
};
|
||||
|
||||
void particles_init(void);
|
||||
void particles_update(void);
|
||||
void particle_update(struct Particle *particle);
|
||||
void particles_draw(void);
|
||||
void particle_create(bopti_image_t *texture, int x, int y, int frame_width,
|
||||
int frame_duration, int particles);
|
||||
void particle_draw(struct Particle particle);
|
||||
void particle_create(img_t *texture, int x, int y, int frame_width,
|
||||
int frame_duration, int looping, int flip_h);
|
||||
struct Particle particle_init(img_t *texture, int x, int y, int frame_width,
|
||||
int frame_duration, int looping, int flip_h);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "input.h"
|
||||
#include "level.h"
|
||||
#include "particles.h"
|
||||
|
||||
#define PLAYER_WIDTH 10
|
||||
#define PLAYER_HEIGHT 10
|
||||
|
@ -23,6 +24,12 @@ struct Player {
|
|||
int jump_grace;
|
||||
int jumps_left;
|
||||
enum AirState air_state;
|
||||
/* animations */
|
||||
struct Particle anim;
|
||||
struct Particle blink_anim;
|
||||
struct Particle idle_anim;
|
||||
struct Particle jump_anim;
|
||||
struct Particle walk_anim;
|
||||
};
|
||||
|
||||
/* used for collisions */
|
||||
|
|
|
@ -19,7 +19,7 @@ int mainmenu_update(struct MainMenu *mainmenu, struct Input input)
|
|||
}
|
||||
/* increase selected pack id */
|
||||
if (input.keystates[K_DOWN] == KS_PRESS ||
|
||||
input.keystates[K_RIGHT] == KS_PRESS) {
|
||||
input.keystates[K_RIGHT] == KS_PRESS) {
|
||||
if (mainmenu->cursor < MENU_ENTRIES - 1)
|
||||
mainmenu->cursor += 1;
|
||||
else
|
||||
|
|
|
@ -6,24 +6,34 @@
|
|||
|
||||
extern struct Particle particles[MAX_PARTICLES];
|
||||
|
||||
void particle_create(bopti_image_t *texture, int x, int y, int frame_width,
|
||||
int frame_duration, int looping)
|
||||
void particle_create(img_t *texture, int x, int y, int frame_width,
|
||||
int frame_duration, int looping, int flip_h)
|
||||
{
|
||||
/* find unused slot */
|
||||
int i = MAX_PARTICLES;
|
||||
while (i-- > 0)
|
||||
if (!particles[i].life)
|
||||
break;
|
||||
struct Particle *particle = &particles[i];
|
||||
|
||||
particle->texture = texture;
|
||||
particle->x = x;
|
||||
particle->y = y;
|
||||
particle->frame_width = frame_width;
|
||||
particle->frame_height = texture->height;
|
||||
particle->frame_duration = frame_duration;
|
||||
particle->frame = 0;
|
||||
particle->life_ini = frame_duration * texture->width / frame_width;
|
||||
particle->life = particle->life_ini;
|
||||
particle->looping = looping;
|
||||
particles[i] = particle_init(texture, x, y, frame_width, frame_duration,
|
||||
looping, flip_h);
|
||||
}
|
||||
|
||||
struct Particle particle_init(img_t *texture, int x, int y, int frame_width,
|
||||
int frame_duration, int looping, int flip_h)
|
||||
{
|
||||
struct Particle particle;
|
||||
|
||||
particle.texture = texture;
|
||||
particle.x = x;
|
||||
particle.y = y;
|
||||
particle.frame_width = frame_width;
|
||||
particle.frame_height = texture->height;
|
||||
particle.frame_duration = frame_duration;
|
||||
particle.frame = 0;
|
||||
particle.life_ini = frame_duration * texture->width / frame_width;
|
||||
particle.life = particle.life_ini;
|
||||
particle.looping = looping;
|
||||
particle.flip_h = flip_h;
|
||||
|
||||
return particle;
|
||||
}
|
||||
|
|
|
@ -2,12 +2,10 @@
|
|||
/* Copyright (C) 2021 KikooDX */
|
||||
|
||||
#include "particles.h"
|
||||
#include <gint/display.h>
|
||||
#include <libimg.h>
|
||||
|
||||
extern struct Particle particles[MAX_PARTICLES];
|
||||
|
||||
static void particle_draw(struct Particle particle);
|
||||
|
||||
void particles_draw(void)
|
||||
{
|
||||
int i = MAX_PARTICLES;
|
||||
|
@ -15,12 +13,36 @@ void particles_draw(void)
|
|||
particle_draw(particles[i]);
|
||||
}
|
||||
|
||||
static void particle_draw(struct Particle particle)
|
||||
void particle_draw(struct Particle particle)
|
||||
{
|
||||
if (!particle.life)
|
||||
return;
|
||||
|
||||
dsubimage(particle.x, particle.y, particle.texture,
|
||||
particle.frame * particle.frame_width, 0,
|
||||
particle.frame_width, particle.frame_height, DIMAGE_NOCLIP);
|
||||
/* create image to apply transformations on */
|
||||
/* alloc */
|
||||
const img_t transformed_img =
|
||||
img_create(particle.frame_width, particle.frame_height);
|
||||
/* check */
|
||||
if (img_null(transformed_img))
|
||||
return;
|
||||
|
||||
/* fill image with transparent */
|
||||
img_fill(transformed_img, IMG_ALPHA);
|
||||
|
||||
/* get frame subimage */
|
||||
const img_t frame_simg =
|
||||
img_sub(*particle.texture, particle.frame * particle.frame_width, 0,
|
||||
particle.frame_width, particle.frame_height);
|
||||
|
||||
/* apply transformations if needed */
|
||||
if (particle.flip_h)
|
||||
img_hflip(frame_simg, transformed_img);
|
||||
else
|
||||
img_render(frame_simg, transformed_img);
|
||||
|
||||
/* render image */
|
||||
img_render_vram(transformed_img, particle.x, particle.y);
|
||||
|
||||
/* free */
|
||||
img_destroy(transformed_img);
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
extern struct Particle particles[MAX_PARTICLES];
|
||||
|
||||
static void particle_update(struct Particle *particle);
|
||||
|
||||
void particles_update(void)
|
||||
{
|
||||
int i = MAX_PARTICLES;
|
||||
|
@ -14,7 +12,7 @@ void particles_update(void)
|
|||
particle_update(&particles[i]);
|
||||
}
|
||||
|
||||
static void particle_update(struct Particle *particle)
|
||||
void particle_update(struct Particle *particle)
|
||||
{
|
||||
if (!particle->life)
|
||||
return;
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
extern struct Level level;
|
||||
|
||||
extern bopti_image_t bimg_coin_particle;
|
||||
extern bopti_image_t bimg_switch_particle;
|
||||
extern bopti_image_t bimg_switch_activated_particle;
|
||||
extern bopti_image_t bimg_exit_active_particle;
|
||||
extern bopti_image_t bimg_exit_unlock_particle;
|
||||
extern img_t img_coin_particle;
|
||||
extern img_t img_switch_particle;
|
||||
extern img_t img_switch_activated_particle;
|
||||
extern img_t img_exit_active_particle;
|
||||
extern img_t img_exit_unlock_particle;
|
||||
|
||||
static Tile collide_single(int x, int y);
|
||||
static int collide_sub_single(int x, int y, Tile sub, Tile rep);
|
||||
|
@ -88,16 +88,16 @@ static int collide_sub_single(int x, int y, Tile sub, Tile rep)
|
|||
/* spawn animations */
|
||||
switch (sub) {
|
||||
case TILE_GOLD:
|
||||
particle_create(&bimg_coin_particle, px, py, TILE_WIDTH,
|
||||
2, 0);
|
||||
particle_create(&img_coin_particle, px, py, TILE_WIDTH,
|
||||
2, 0, 0);
|
||||
break;
|
||||
case TILE_SWITCH:
|
||||
/* still image */
|
||||
particle_create(&bimg_switch_activated_particle, px, py,
|
||||
TILE_WIDTH, 1, 1);
|
||||
particle_create(&img_switch_activated_particle, px, py,
|
||||
TILE_WIDTH, 1, 1, 0);
|
||||
/* activation animation */
|
||||
particle_create(&bimg_switch_particle, px, py,
|
||||
TILE_WIDTH, 8, 0);
|
||||
particle_create(&img_switch_particle, px, py,
|
||||
TILE_WIDTH, 8, 0, 0);
|
||||
/* exit unlock animation */
|
||||
{
|
||||
int ty = level.height;
|
||||
|
@ -115,10 +115,10 @@ static int collide_sub_single(int x, int y, Tile sub, Tile rep)
|
|||
found:
|
||||
tx *= TILE_WIDTH;
|
||||
ty *= TILE_HEIGHT;
|
||||
particle_create(&bimg_exit_active_particle, tx,
|
||||
ty, TILE_WIDTH, 2, 1);
|
||||
particle_create(&bimg_exit_unlock_particle, tx,
|
||||
ty, TILE_WIDTH, 4, 0);
|
||||
particle_create(&img_exit_active_particle, tx,
|
||||
ty, TILE_WIDTH, 2, 1, 0);
|
||||
particle_create(&img_exit_unlock_particle, tx,
|
||||
ty, TILE_WIDTH, 4, 0, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -4,20 +4,30 @@
|
|||
#include "conf.h"
|
||||
#include "filepaths.h"
|
||||
#include "level.h"
|
||||
#include "particles.h"
|
||||
#include "player.h"
|
||||
#include "zxcolors.h"
|
||||
#include <gint/display.h>
|
||||
|
||||
extern struct Level level;
|
||||
|
||||
extern bopti_image_t bimg_player;
|
||||
extern bopti_image_t bimg_burst;
|
||||
|
||||
void player_draw(struct Player player)
|
||||
{
|
||||
dimage(player.x, player.y, &bimg_player);
|
||||
/* set animation position */
|
||||
struct Particle anim = player.anim;
|
||||
anim.x = player.x;
|
||||
anim.y = player.y;
|
||||
anim.x -= (anim.frame_width - PLAYER_WIDTH) / 2;
|
||||
anim.y -= (anim.texture->height - PLAYER_HEIGHT) / 2;
|
||||
/* draw animation */
|
||||
particle_draw(anim);
|
||||
|
||||
/* draw burst */
|
||||
if (player.air_state == AirRising && player.jumps_left < AIR_JUMPS)
|
||||
dimage(player.x, player.y + PLAYER_HEIGHT, &bimg_burst);
|
||||
|
||||
/* print level name
|
||||
* this shouldn't be in player code */
|
||||
dprint_opt(DWIDTH - 4, DHEIGHT, ZX_WHITE, C_NONE, DTEXT_RIGHT,
|
||||
|
|
|
@ -3,11 +3,18 @@
|
|||
|
||||
#include "conf.h"
|
||||
#include "level.h"
|
||||
#include "particles.h"
|
||||
#include "player.h"
|
||||
#include "tiles.h"
|
||||
#include <libimg.h>
|
||||
|
||||
extern struct Level level;
|
||||
|
||||
extern img_t img_player_blink;
|
||||
extern img_t img_player_idle;
|
||||
extern img_t img_player_jump;
|
||||
extern img_t img_player_walk;
|
||||
|
||||
struct Player player_init(void)
|
||||
{
|
||||
int x = 0;
|
||||
|
@ -23,6 +30,13 @@ struct Player player_init(void)
|
|||
.air_state = AirNeutral,
|
||||
};
|
||||
|
||||
/* initialize animations */
|
||||
player.blink_anim = particle_init(&img_player_blink, 0, 0, 10, 4, 0, 0);
|
||||
player.idle_anim = particle_init(&img_player_idle, 0, 0, 10, 1, 1, 1);
|
||||
player.jump_anim = particle_init(&img_player_jump, 0, 0, 8, 6, 0, 0);
|
||||
player.walk_anim = particle_init(&img_player_walk, 0, 0, 12, 6, 1, 0);
|
||||
player.anim = player.idle_anim;
|
||||
|
||||
/* find spawn position in level */
|
||||
x = level.width;
|
||||
while (x-- > 0) {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "conf.h"
|
||||
#include "input.h"
|
||||
#include "level.h"
|
||||
#include "particles.h"
|
||||
#include "player.h"
|
||||
#include "tiles.h"
|
||||
#include <gint/keyboard.h>
|
||||
|
@ -12,12 +13,16 @@ static void player_move(struct Player *player, int x, int y);
|
|||
|
||||
extern struct Level level;
|
||||
|
||||
/* return -1 on pause, return 1 if exit reached, 2 on death/reset and 0 otherwise */
|
||||
/* return -1 on pause, return 1 if exit reached, 2 on death/reset and 0
|
||||
* otherwise */
|
||||
int player_update(struct Player *player, struct Input input)
|
||||
{
|
||||
Tile collisions[COLLIDE_POINTS];
|
||||
const int on_ground = player_collide_solid(player->x, player->y + 1);
|
||||
|
||||
int jumped = 0;
|
||||
const int previous_flip_h = player->anim.flip_h;
|
||||
|
||||
/* process input */
|
||||
const int k_left = input.keystates[K_LEFT] != KS_UP;
|
||||
const int k_right = input.keystates[K_RIGHT] != KS_UP;
|
||||
|
@ -80,6 +85,7 @@ int player_update(struct Player *player, struct Input input)
|
|||
/* jump (youhou) */
|
||||
if (k_jump && player->jump_buffer &&
|
||||
(player->jump_grace || player->jumps_left)) {
|
||||
jumped = 1;
|
||||
/* ground jump */
|
||||
if (player->jump_grace) {
|
||||
player->jump_grace = 0;
|
||||
|
@ -128,6 +134,25 @@ int player_update(struct Player *player, struct Input input)
|
|||
MARGIN_LETAL, 1)) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* update animation */
|
||||
if (jumped)
|
||||
player->anim = player->jump_anim;
|
||||
|
||||
particle_update(&player->anim);
|
||||
|
||||
if (player->anim.life == 0) {
|
||||
if (dir_x != 0)
|
||||
player->anim = player->walk_anim;
|
||||
else
|
||||
player->anim = player->idle_anim;
|
||||
}
|
||||
|
||||
/* horizontal flip */
|
||||
player->anim.flip_h = previous_flip_h;
|
||||
if (dir_x)
|
||||
player->anim.flip_h = dir_x == -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|