Tile animations for world and entities. Implemented a fire timer for monsters to limit their fire rate. Preliminary sound support.

This commit is contained in:
slipyx 2018-08-10 23:19:28 -04:00
parent 985338f814
commit 954a4b8b51
12 changed files with 93 additions and 11 deletions

BIN
build/res/jumpd8.wav Normal file

Binary file not shown.

BIN
build/res/pickupd8.wav Normal file

Binary file not shown.

20
draw.c
View File

@ -16,6 +16,7 @@ void Draw_World( SDL_Renderer* r ) {
dst.x = i * TILE_SIZE; dst.x = i * TILE_SIZE;
uint8_t til = gs->levels[gs->current_level].tiles[j * 100 + gs->view_x + i]; uint8_t til = gs->levels[gs->current_level].tiles[j * 100 + gs->view_x + i];
if ( til == 0 ) continue; if ( til == 0 ) continue;
til = G_UpdateFrame( til, i );
SDL_RenderCopy( r, g_assets->tile_tx[til], NULL, &dst ); SDL_RenderCopy( r, g_assets->tile_tx[til], NULL, &dst );
} }
} }
@ -37,12 +38,13 @@ void Draw_Player( SDL_Renderer* r ) {
// grounded walk tile // grounded walk tile
else if ( gs->ps.on_ground ) { else if ( gs->ps.on_ground ) {
til = gs->ps.last_dir >= 0 ? 53 : 57; til = gs->ps.last_dir >= 0 ? 53 : 57;
til += (gs->ps.tick/4) % 3;
} }
// jump tile // jump tile
else if ( gs->ps.do_jump || !gs->ps.on_ground ) else if ( gs->ps.do_jump || !gs->ps.on_ground )
til = gs->ps.last_dir >= 0 ? 67 : 68; til = gs->ps.last_dir >= 0 ? 67 : 68;
// dead // dead
if ( gs->ps.dead_timer ) til = 129; if ( gs->ps.dead_timer ) til = 129 + (gs->tick/4) % 4;
// render // render
// grounded debug // grounded debug
@ -51,6 +53,10 @@ void Draw_Player( SDL_Renderer* r ) {
SDL_RenderDrawLine( r, dst.x, dst.y+dst.h, dst.x+dst.w, dst.y+dst.h ); SDL_RenderDrawLine( r, dst.x, dst.y+dst.h, dst.x+dst.w, dst.y+dst.h );
} }
SDL_RenderCopy( r, g_assets->tile_tx[til], NULL, &dst ); SDL_RenderCopy( r, g_assets->tile_tx[til], NULL, &dst );
/*dst.w = TILE_SIZE; dst.h = TILE_SIZE;
dst.x = (gs->ps.tx - gs->view_x) * TILE_SIZE;
dst.y = gs->ps.ty * TILE_SIZE + TILE_SIZE;
SDL_RenderDrawRect( r, &dst );*/
} }
// draw player bullet // draw player bullet
@ -66,6 +72,11 @@ void Draw_Bullet( SDL_Renderer* r ) {
// render // render
SDL_RenderCopy( r, g_assets->tile_tx[til], NULL, &dst ); SDL_RenderCopy( r, g_assets->tile_tx[til], NULL, &dst );
/*SDL_SetRenderDrawColor( r, 255, 0, 255, 255 );
dst.w = TILE_SIZE; dst.h = TILE_SIZE;
dst.x = ((gs->ps.bullet_px / TILE_SIZE) - gs->view_x) * TILE_SIZE;
dst.y = (gs->ps.bullet_py / TILE_SIZE) * TILE_SIZE + TILE_SIZE;
SDL_RenderDrawRect( r, &dst );*/
} }
} }
@ -81,6 +92,7 @@ void Draw_Monsters( SDL_Renderer* r ) {
dst.y = TILE_SIZE + m->py;// - 10; dst.y = TILE_SIZE + m->py;// - 10;
dst.w = 24; dst.h = 20; dst.w = 24; dst.h = 20;
til = m->dead_timer ? 129 : m->type; til = m->dead_timer ? 129 : m->type;
til += (gs->tick / 3) % 4;
SDL_RenderCopy( r, g_assets->tile_tx[til], NULL, &dst ); SDL_RenderCopy( r, g_assets->tile_tx[til], NULL, &dst );
} }
} }
@ -94,10 +106,16 @@ void Draw_MonsterBullet( SDL_Renderer* r ) {
dst.y = TILE_SIZE + gs->mbullet_py; dst.y = TILE_SIZE + gs->mbullet_py;
// tile 127 right, 128 left // tile 127 right, 128 left
uint8_t til = gs->mbullet_dir > 0 ? 121 : 124; uint8_t til = gs->mbullet_dir > 0 ? 121 : 124;
til += (gs->tick / 3) % 3;
dst.w = 20; dst.h = 3; dst.w = 20; dst.h = 3;
// render // render
SDL_RenderCopy( r, g_assets->tile_tx[til], NULL, &dst ); SDL_RenderCopy( r, g_assets->tile_tx[til], NULL, &dst );
/*SDL_SetRenderDrawColor( r, 255, 0, 255, 255 );
dst.w = TILE_SIZE; dst.h = TILE_SIZE;
dst.x = ((gs->mbullet_px / TILE_SIZE) - gs->view_x) * TILE_SIZE;
dst.y = (gs->mbullet_py / TILE_SIZE) * TILE_SIZE + TILE_SIZE;
SDL_RenderDrawRect( r, &dst );*/
} }
} }

22
game.c
View File

@ -1,6 +1,7 @@
#include "game.h" #include "game.h"
#include "world.h" #include "world.h"
#include "draw.h" #include "draw.h"
#include "sound.h"
// global game state // global game state
game_state_t* gs = NULL; game_state_t* gs = NULL;
@ -50,8 +51,8 @@ static void G_InitAssets( SDL_Renderer* r ) {
Util_FreeTileSurfaces(); Util_FreeTileSurfaces();
// sfx // sfx
//g_assets->sfx[0] = S_LoadChunk( "res/jumpd8.wav" ); //Mix_LoadWAV_RW( rw, 1 ); //g_assets->sfx[SFX_JUMP] = S_LoadChunk( "res/jumpd8.wav" ); //Mix_LoadWAV_RW( rw, 1 );
//g_assets->sfx[1] = S_LoadChunk( "res/pickupd8.wav" ); //Mix_LoadWAV_RW( rw, 1 ); //g_assets->sfx[SFX_PICKUP] = S_LoadChunk( "res/pickupd8.wav" ); //Mix_LoadWAV_RW( rw, 1 );
} }
// poll input // poll input
@ -136,6 +137,17 @@ static void G_Update() {
G_ClearInput(); G_ClearInput();
} }
// update tile animation
uint8_t G_UpdateFrame( uint8_t til, uint8_t salt ) {
uint8_t mod;
switch ( til ) {
case 6: case 25: case 129: mod = 4; break;
case 10: case 36: mod = 5; break;
default: mod = 1; break;
}
return til + (gs->tick/5+salt) % mod;
}
// main drawing routine // main drawing routine
static void G_Draw( SDL_Renderer* r ) { static void G_Draw( SDL_Renderer* r ) {
// clear backbuffer // clear backbuffer
@ -233,12 +245,12 @@ int main( int argc, char** argv ) {
// destroy each tile texture // destroy each tile texture
for ( int i = 0; i < NUM_EXE_TILES; ++i ) for ( int i = 0; i < NUM_EXE_TILES; ++i )
SDL_DestroyTexture( g_assets->tile_tx[i] ); SDL_DestroyTexture( g_assets->tile_tx[i] );
free( g_assets );
free( gs );
// free audio // free audio
//for ( int i = 0; i < sizeof(g_assets->sfx) / sizeof(g_assets->sfx[0]) ) //for ( int i = 0; i < NUM_SFX; ++i )
//Mix_FreeChunk( g_assets->sfx[i] ); //Mix_FreeChunk( g_assets->sfx[i] );
//Mix_FreeMusic( g_assets->mus ); //Mix_FreeMusic( g_assets->mus );
free( g_assets );
free( gs );
//Mix_CloseAudio(); //Mix_CloseAudio();
// cleanup SDL // cleanup SDL

10
game.h
View File

@ -2,17 +2,18 @@
#define _LMDAVE_H #define _LMDAVE_H
#include <SDL.h> #include <SDL.h>
//#include <SDL/SDL_mixer.h>
// for dealing with resources in EXE // for dealing with resources in EXE
#include "util/util.h" #include "util/util.h"
#include "sound.h"
#include "player.h" #include "player.h"
#include "monster.h" #include "monster.h"
// global game state // global game state
typedef struct { typedef struct {
uint8_t quit; uint8_t quit;
uint16_t tick;
uint8_t current_level; uint8_t current_level;
// view and scroll are per tile // view and scroll are per tile
uint8_t view_x, view_y; uint8_t view_x, view_y;
@ -35,7 +36,7 @@ typedef struct {
// tiles as textures converted from util's tile surfaces // tiles as textures converted from util's tile surfaces
SDL_Texture* tile_tx[NUM_EXE_TILES]; SDL_Texture* tile_tx[NUM_EXE_TILES];
// sfx // sfx
//Mix_Chunk* sfx[2]; Mix_Chunk* sfx[NUM_SFX];
// music // music
//Mix_Music* mus; //Mix_Music* mus;
} game_assets_t; } game_assets_t;
@ -45,4 +46,9 @@ typedef struct {
// fixed frame delay // fixed frame delay
#define FRAME_DELAY 33 #define FRAME_DELAY 33
// common functions
// update a tile index based on game tick for animation
uint8_t G_UpdateFrame( uint8_t til, uint8_t salt );
#endif #endif

View File

@ -35,13 +35,14 @@ void M_Fire() {
for ( int i = 0; i < sizeof(gs->ms) / sizeof(gs->ms[0]); ++i ) { for ( int i = 0; i < sizeof(gs->ms) / sizeof(gs->ms[0]); ++i ) {
monster_state_t* m = &gs->ms[i]; monster_state_t* m = &gs->ms[i];
// assumed size of 24x20 // assumed size of 24x20
if ( m->type && !m->dead_timer && W_IsVisible( m->px ) && W_IsClear( m->px+12, m->py+10, 0 ) ) { if ( m->type && !m->dead_timer && W_IsVisible( m->px ) && W_IsClear( m->px+12, m->py+10, 0 ) && !m->fire_timer ) {
gs->mbullet_dir = gs->ps.px < m->px ? -1 : 1; gs->mbullet_dir = gs->ps.px < m->px ? -1 : 1;
if ( gs->mbullet_dir == 1 ) if ( gs->mbullet_dir == 1 )
gs->mbullet_px = m->px + 18; gs->mbullet_px = m->px + 18;
if ( gs->mbullet_dir == -1 ) if ( gs->mbullet_dir == -1 )
gs->mbullet_px = m->px - 10; gs->mbullet_px = m->px - 10;
gs->mbullet_py = m->py + 10; gs->mbullet_py = m->py + 10;
m->fire_timer = 15;
} }
} }
} }

View File

@ -5,6 +5,7 @@
typedef struct { typedef struct {
uint8_t type; // type and tile index uint8_t type; // type and tile index
uint8_t dead_timer; uint8_t dead_timer;
uint8_t fire_timer;
uint8_t path_index; // current point in path uint8_t path_index; // current point in path
uint8_t tx, ty; // tile pos uint8_t tx, ty; // tile pos
int16_t px, py; // pixel pos int16_t px, py; // pixel pos

View File

@ -65,7 +65,7 @@ void P_PickupItem() {
gs->ps.check_pickup_x = 0; gs->ps.check_pickup_x = 0;
gs->ps.check_pickup_y = 0; gs->ps.check_pickup_y = 0;
// sfx // sfx
//Mix_PlayChannel( S_CHAN_PICKUP, g_assets->sfx[1], 0 ); //Mix_PlayChannel( S_CHAN_PICKUP, g_assets->sfx[SFX_PICKUP], 0 );
} }
// update collision point clear flags // update collision point clear flags
@ -174,25 +174,29 @@ void P_Move() {
gs->ps.px += 2; gs->ps.px += 2;
gs->ps.last_dir = 1; gs->ps.last_dir = 1;
gs->ps.do_right = 0; gs->ps.do_right = 0;
gs->ps.tick++;
} }
if ( gs->ps.do_left ) { if ( gs->ps.do_left ) {
gs->ps.px -= 2; gs->ps.px -= 2;
gs->ps.last_dir = -1; gs->ps.last_dir = -1;
gs->ps.do_left = 0; gs->ps.do_left = 0;
gs->ps.tick++;
} }
// up and down // up and down
if ( gs->ps.do_up ) { if ( gs->ps.do_up ) {
gs->ps.py -= 2; gs->ps.py -= 2;
gs->ps.do_up = 0; gs->ps.do_up = 0;
gs->ps.tick++;
} else if ( gs->ps.do_down ) { } else if ( gs->ps.do_down ) {
gs->ps.py += 2; gs->ps.py += 2;
gs->ps.do_down = 0; gs->ps.do_down = 0;
gs->ps.tick++;
// jump // jump
} else if ( gs->ps.do_jump ) { } else if ( gs->ps.do_jump ) {
if ( !gs->ps.jump_timer ) { if ( !gs->ps.jump_timer ) {
gs->ps.jump_timer = 25; gs->ps.jump_timer = 25;
//gs->ps.last_dir = 0; //gs->ps.last_dir = 0;
//Mix_PlayChannel( S_CHAN_JUMP, g_assets->sfx[0], 0 ); //Mix_PlayChannel( S_CHAN_JUMP, g_assets->sfx[SFX_JUMP], 0 );
} }
if ( gs->ps.col_point[0] && gs->ps.col_point[1] ) { if ( gs->ps.col_point[0] && gs->ps.col_point[1] ) {

View File

@ -12,6 +12,7 @@ typedef struct {
uint8_t on_ground; uint8_t on_ground;
// last facing direction // last facing direction
int8_t last_dir; int8_t last_dir;
uint16_t tick;
// input flags // input flags
uint8_t try_right; uint8_t try_right;

18
sound.c Normal file
View File

@ -0,0 +1,18 @@
#include "sound.h"
// custom chunk loader for emscripten support
Mix_Chunk* S_LoadChunk( const char* f ) {
SDL_RWops* rw = SDL_RWFromFile( f, "rb" );
int sz = SDL_RWsize( rw );
uint8_t* rwdat = malloc( sz );
SDL_RWread( rw, rwdat, 1, sz );
SDL_RWclose( rw );
rw = SDL_RWFromConstMem( rwdat, sz );
Mix_Chunk* chunk = Mix_LoadWAV_RW( rw, 1 );
SDL_RWclose( rw );
free( rwdat );
if ( chunk == NULL ) { printf( "Failed to load chunk %s!\n", f ); return NULL; }
return chunk;
}

18
sound.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef __SOUND_H
#define __SOUND_H
#include <SDL.h>
#include <SDL/SDL_mixer.h>
// sfx names
typedef enum {
SFX_JUMP,
SFX_PICKUP,
NUM_SFX
} SFX_NAME;
// custom chunk loader for emscripten support
Mix_Chunk* S_LoadChunk( const char* f );
#endif

View File

@ -109,6 +109,8 @@ uint8_t W_IsVisible( int16_t px ) {
// level-wide state update // level-wide state update
void W_Update() { void W_Update() {
// update world tick
gs->tick++;
// check if at door and has trophy // check if at door and has trophy
if ( gs->ps.check_door ) { if ( gs->ps.check_door ) {
if ( gs->ps.trophy ) { if ( gs->ps.trophy ) {
@ -137,6 +139,7 @@ void W_Update() {
for ( int i = 0; i < sizeof(gs->ms) / sizeof(gs->ms[0]); ++i ) { for ( int i = 0; i < sizeof(gs->ms) / sizeof(gs->ms[0]); ++i ) {
monster_state_t* m = &gs->ms[i]; monster_state_t* m = &gs->ms[i];
if ( m->type ) { if ( m->type ) {
if ( m->fire_timer ) m->fire_timer--;
if ( m->dead_timer ) { if ( m->dead_timer ) {
m->dead_timer--; m->dead_timer--;
if ( !m->dead_timer ) { m->type = 0; } if ( !m->dead_timer ) { m->type = 0; }