diff --git a/build/res/jumpd8.wav b/build/res/jumpd8.wav new file mode 100644 index 0000000..630b180 Binary files /dev/null and b/build/res/jumpd8.wav differ diff --git a/build/res/pickupd8.wav b/build/res/pickupd8.wav new file mode 100644 index 0000000..983e851 Binary files /dev/null and b/build/res/pickupd8.wav differ diff --git a/draw.c b/draw.c index 4d25e3e..66f7310 100644 --- a/draw.c +++ b/draw.c @@ -16,6 +16,7 @@ void Draw_World( SDL_Renderer* r ) { dst.x = i * TILE_SIZE; uint8_t til = gs->levels[gs->current_level].tiles[j * 100 + gs->view_x + i]; if ( til == 0 ) continue; + til = G_UpdateFrame( til, i ); SDL_RenderCopy( r, g_assets->tile_tx[til], NULL, &dst ); } } @@ -37,12 +38,13 @@ void Draw_Player( SDL_Renderer* r ) { // grounded walk tile else if ( gs->ps.on_ground ) { til = gs->ps.last_dir >= 0 ? 53 : 57; + til += (gs->ps.tick/4) % 3; } // jump tile else if ( gs->ps.do_jump || !gs->ps.on_ground ) til = gs->ps.last_dir >= 0 ? 67 : 68; // dead - if ( gs->ps.dead_timer ) til = 129; + if ( gs->ps.dead_timer ) til = 129 + (gs->tick/4) % 4; // render // 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_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 @@ -66,6 +72,11 @@ void Draw_Bullet( SDL_Renderer* r ) { // render 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.w = 24; dst.h = 20; til = m->dead_timer ? 129 : m->type; + til += (gs->tick / 3) % 4; 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; // tile 127 right, 128 left uint8_t til = gs->mbullet_dir > 0 ? 121 : 124; + til += (gs->tick / 3) % 3; dst.w = 20; dst.h = 3; // render 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 );*/ } } diff --git a/game.c b/game.c index 4d853c3..be88915 100644 --- a/game.c +++ b/game.c @@ -1,6 +1,7 @@ #include "game.h" #include "world.h" #include "draw.h" +#include "sound.h" // global game state game_state_t* gs = NULL; @@ -50,8 +51,8 @@ static void G_InitAssets( SDL_Renderer* r ) { Util_FreeTileSurfaces(); // sfx - //g_assets->sfx[0] = 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_JUMP] = S_LoadChunk( "res/jumpd8.wav" ); //Mix_LoadWAV_RW( rw, 1 ); + //g_assets->sfx[SFX_PICKUP] = S_LoadChunk( "res/pickupd8.wav" ); //Mix_LoadWAV_RW( rw, 1 ); } // poll input @@ -136,6 +137,17 @@ static void G_Update() { 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 static void G_Draw( SDL_Renderer* r ) { // clear backbuffer @@ -233,12 +245,12 @@ int main( int argc, char** argv ) { // destroy each tile texture for ( int i = 0; i < NUM_EXE_TILES; ++i ) SDL_DestroyTexture( g_assets->tile_tx[i] ); - free( g_assets ); - free( gs ); // 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_FreeMusic( g_assets->mus ); + free( g_assets ); + free( gs ); //Mix_CloseAudio(); // cleanup SDL diff --git a/game.h b/game.h index afe7391..bc56cf7 100644 --- a/game.h +++ b/game.h @@ -2,17 +2,18 @@ #define _LMDAVE_H #include -//#include // for dealing with resources in EXE #include "util/util.h" +#include "sound.h" #include "player.h" #include "monster.h" // global game state typedef struct { uint8_t quit; + uint16_t tick; uint8_t current_level; // view and scroll are per tile uint8_t view_x, view_y; @@ -35,7 +36,7 @@ typedef struct { // tiles as textures converted from util's tile surfaces SDL_Texture* tile_tx[NUM_EXE_TILES]; // sfx - //Mix_Chunk* sfx[2]; + Mix_Chunk* sfx[NUM_SFX]; // music //Mix_Music* mus; } game_assets_t; @@ -45,4 +46,9 @@ typedef struct { // fixed frame delay #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 + diff --git a/monster.c b/monster.c index 365bae8..7a2126e 100644 --- a/monster.c +++ b/monster.c @@ -35,13 +35,14 @@ void M_Fire() { for ( int i = 0; i < sizeof(gs->ms) / sizeof(gs->ms[0]); ++i ) { monster_state_t* m = &gs->ms[i]; // 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; if ( gs->mbullet_dir == 1 ) gs->mbullet_px = m->px + 18; if ( gs->mbullet_dir == -1 ) gs->mbullet_px = m->px - 10; gs->mbullet_py = m->py + 10; + m->fire_timer = 15; } } } diff --git a/monster.h b/monster.h index e477943..ce31d43 100644 --- a/monster.h +++ b/monster.h @@ -5,6 +5,7 @@ typedef struct { uint8_t type; // type and tile index uint8_t dead_timer; + uint8_t fire_timer; uint8_t path_index; // current point in path uint8_t tx, ty; // tile pos int16_t px, py; // pixel pos diff --git a/player.c b/player.c index 4530680..862e2be 100644 --- a/player.c +++ b/player.c @@ -65,7 +65,7 @@ void P_PickupItem() { gs->ps.check_pickup_x = 0; gs->ps.check_pickup_y = 0; // 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 @@ -174,25 +174,29 @@ void P_Move() { gs->ps.px += 2; gs->ps.last_dir = 1; gs->ps.do_right = 0; + gs->ps.tick++; } if ( gs->ps.do_left ) { gs->ps.px -= 2; gs->ps.last_dir = -1; gs->ps.do_left = 0; + gs->ps.tick++; } // up and down if ( gs->ps.do_up ) { gs->ps.py -= 2; gs->ps.do_up = 0; + gs->ps.tick++; } else if ( gs->ps.do_down ) { gs->ps.py += 2; gs->ps.do_down = 0; + gs->ps.tick++; // jump } else if ( gs->ps.do_jump ) { if ( !gs->ps.jump_timer ) { gs->ps.jump_timer = 25; //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] ) { diff --git a/player.h b/player.h index 6095972..bef4cb6 100644 --- a/player.h +++ b/player.h @@ -12,6 +12,7 @@ typedef struct { uint8_t on_ground; // last facing direction int8_t last_dir; + uint16_t tick; // input flags uint8_t try_right; diff --git a/sound.c b/sound.c new file mode 100644 index 0000000..cdbccdc --- /dev/null +++ b/sound.c @@ -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; +} + diff --git a/sound.h b/sound.h new file mode 100644 index 0000000..ed42c6e --- /dev/null +++ b/sound.h @@ -0,0 +1,18 @@ +#ifndef __SOUND_H +#define __SOUND_H + +#include +#include + +// 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 + diff --git a/world.c b/world.c index c4397d2..505e8bc 100644 --- a/world.c +++ b/world.c @@ -109,6 +109,8 @@ uint8_t W_IsVisible( int16_t px ) { // level-wide state update void W_Update() { + // update world tick + gs->tick++; // check if at door and has trophy if ( gs->ps.check_door ) { if ( gs->ps.trophy ) { @@ -137,6 +139,7 @@ void W_Update() { for ( int i = 0; i < sizeof(gs->ms) / sizeof(gs->ms[0]); ++i ) { monster_state_t* m = &gs->ms[i]; if ( m->type ) { + if ( m->fire_timer ) m->fire_timer--; if ( m->dead_timer ) { m->dead_timer--; if ( !m->dead_timer ) { m->type = 0; }