Initial state of codebase refactor.

This commit is contained in:
Josh K 2018-07-17 23:30:35 -04:00
parent 6f6a429163
commit baf1203cfe
5 changed files with 183 additions and 176 deletions

View File

@ -1,4 +1,4 @@
#include "lmdave.h"
#include "game.h"
// global game state
game_state_t* gs = NULL;
@ -6,22 +6,28 @@ game_state_t* gs = NULL;
game_assets_t* g_assets = NULL;
// initialize a new game state
void init_game() {
gs->quit = 0;
gs->current_level = 0;
static void G_Init() {
gs = malloc( sizeof(game_state_t) );
memset( gs, 0, sizeof(game_state_t) );
// clean dave state
memset( &gs->ds, 0, sizeof(dave_state_t) );
// copy all levels loaded from exe by util
for ( int i = 0; i < NUM_EXE_LEVELS; ++i )
GetLevel( i, &gs->levels[i] );
// clean player state
memset( &gs->ps, 0, sizeof(player_state_t) );
}
// initialize game assets
void init_assets( SDL_Renderer* r ) {
static void G_InitAssets( SDL_Renderer* r ) {
// load resources from DAVE.EXE
Util_LoadTiles();
Util_LoadLevels();
g_assets = malloc( sizeof(game_assets_t) );
// copy all levels loaded from exe by util
for ( int i = 0; i < NUM_EXE_LEVELS; ++i )
Util_GetLevel( i, &gs->levels[i] );
// get loaded tile surface array from util lib
SDL_Surface** tileSfcs = GetTileSurfaces();
SDL_Surface** tileSfcs = Util_GetTileSurfaces();
// convert each surface from util's array to g_asset texture array
for ( int i = 0; i < NUM_EXE_TILES; ++i ) {
@ -31,40 +37,43 @@ void init_assets( SDL_Renderer* r ) {
SDL_SetColorKey( tileSfcs[i], 1, SDL_MapRGB( tileSfcs[i]->format, 0, 0, 0 ) );
g_assets->tile_tx[i] = SDL_CreateTextureFromSurface( r, tileSfcs[i] );
}
// tile surfaces should be converted as textures inside g_assets now
Util_FreeTileSurfaces();
}
// sets new beginning state based on current level
void start_level() {
void W_StartLevel() {
gs->view_x = 0;
gs->view_y = 0;
gs->scroll_x = 0;
gs->ds.jump_timer = 0;
gs->ds.on_ground = 0;
gs->ds.do_jump = 0;
gs->ps.jump_timer = 0;
gs->ps.on_ground = 0;
gs->ps.do_jump = 0;
// hardcoded player starts
switch ( gs->current_level ) {
case 0: case 4: case 5: case 7: case 9: gs->ds.tx = 2; gs->ds.ty = 8; break;
case 1: gs->ds.tx = 1; gs->ds.ty = 8; break;
case 2: gs->ds.tx = 2; gs->ds.ty = 5; break;
case 3: gs->ds.tx = 1; gs->ds.ty = 5; break;
case 6: gs->ds.tx = 1; gs->ds.ty = 2; break;
case 8: gs->ds.tx = 6; gs->ds.ty = 1; break;
case 0: case 4: case 5: case 7: case 9: gs->ps.tx = 2; gs->ps.ty = 8; break;
case 1: gs->ps.tx = 1; gs->ps.ty = 8; break;
case 2: gs->ps.tx = 2; gs->ps.ty = 5; break;
case 3: gs->ps.tx = 1; gs->ps.ty = 5; break;
case 6: gs->ps.tx = 1; gs->ps.ty = 2; break;
case 8: gs->ps.tx = 6; gs->ps.ty = 1; break;
default: break;
}
gs->ds.px = gs->ds.tx * TILE_SIZE;
gs->ds.py = gs->ds.ty * TILE_SIZE;
gs->ps.px = gs->ps.tx * TILE_SIZE;
gs->ps.py = gs->ps.ty * TILE_SIZE;
// reset items
gs->ds.gun = 0;
gs->ds.jetpack = 0;
gs->ds.trophy = 0;
gs->ds.check_door = 0;
gs->ps.gun = 0;
gs->ps.jetpack = 0;
gs->ps.trophy = 0;
gs->ps.check_door = 0;
}
// poll input
void check_input() {
static void G_CheckInput() {
SDL_Event ev;
while ( SDL_PollEvent( &ev ) ) {
@ -80,7 +89,7 @@ void check_input() {
// android back
if ( key == SDLK_AC_BACK ) { gs->quit = 1; }
// jump event
if ( key == SDLK_UP || key == SDLK_z ) { gs->ds.try_jump = 1; }
if ( key == SDLK_UP || key == SDLK_z ) { gs->ps.try_jump = 1; }
} break;
default: break;
@ -91,43 +100,47 @@ void check_input() {
const uint8_t* keys = SDL_GetKeyboardState( NULL );
// attempt dave movement by setting try_ flags
if ( keys[SDL_SCANCODE_RIGHT] ) gs->ds.try_right = 1;
if ( keys[SDL_SCANCODE_LEFT] ) gs->ds.try_left = 1;
//if ( keys[SDL_SCANCODE_UP] ) gs->ds.try_jump = 1;
if ( keys[SDL_SCANCODE_RIGHT] ) gs->ps.try_right = 1;
if ( keys[SDL_SCANCODE_LEFT] ) gs->ps.try_left = 1;
//if ( keys[SDL_SCANCODE_UP] ) gs->ps.try_jump = 1;
}
// clear all try input flags at end of frame
void clear_input() {
gs->ds.try_left = 0;
gs->ds.try_right = 0;
gs->ds.try_jump = 0;
gs->ds.try_fire = 0;
gs->ds.try_jetpack = 0;
gs->ds.try_up = 0;
gs->ds.try_down = 0;
static void G_ClearInput() {
gs->ps.try_left = 0;
gs->ps.try_right = 0;
gs->ps.try_jump = 0;
gs->ps.try_fire = 0;
gs->ps.try_jetpack = 0;
gs->ps.try_up = 0;
gs->ps.try_down = 0;
}
// remove item from world
void pickup_item( uint8_t tx, uint8_t ty ) {
// pickup functionality and remove from world
void P_PickupItem() {
uint8_t tx = gs->ps.check_pickup_x;
uint8_t ty = gs->ps.check_pickup_y;
if ( !tx || !ty ) return;
uint8_t til = gs->levels[gs->current_level].tiles[ty * 100 + tx];
// pickup functionality here
if ( til == 4 ) gs->ds.jetpack = 0xff;
if ( til == 4 ) gs->ps.jetpack = 0xff;
if ( til == 10 ) {
gs->ds.score += 1000;
gs->ds.trophy = 1;
gs->ps.score += 1000;
gs->ps.trophy = 1;
}
if ( til == 20 ) gs->ds.gun = 1;
if ( til == 20 ) gs->ps.gun = 1;
// remove
gs->levels[gs->current_level].tiles[ty * 100 + tx] = 0;
gs->ds.check_pickup_x = 0;
gs->ds.check_pickup_y = 0;
gs->ps.check_pickup_x = 0;
gs->ps.check_pickup_y = 0;
}
// returns 1 if passed pixel point is not within a solid tile
uint8_t is_clear( uint16_t px, uint16_t py ) {
uint8_t W_IsClear( uint16_t px, uint16_t py ) {
uint8_t tx, ty; // tile pos
uint8_t til; // tile index
@ -144,130 +157,131 @@ uint8_t is_clear( uint16_t px, uint16_t py ) {
// pickups
if ( til == 10 || til == 4 || til == 20 || (til >= 47 && til <= 52) ) {
gs->ds.check_pickup_x = tx;
gs->ds.check_pickup_y = ty;
gs->ps.check_pickup_x = tx;
gs->ps.check_pickup_y = ty;
}
// door
if ( til == 2 ) {
gs->ds.check_door = 1;
gs->ps.check_door = 1;
}
return 1;
}
// update collision point clear flags
void check_collision() {
void P_UpdateCollision() {
// 8 points of collision; relative to top left of tile 56 neutral frame (20x16)
// 0, 1 = top left, top right
gs->ds.col_point[0] = is_clear( gs->ds.px + 4, gs->ds.py - 0 );
gs->ds.col_point[1] = is_clear( gs->ds.px + 10, gs->ds.py - 0 );
gs->ps.col_point[0] = W_IsClear( gs->ps.px + 4, gs->ps.py - 0 );
gs->ps.col_point[1] = W_IsClear( gs->ps.px + 10, gs->ps.py - 0 );
// 2, 3 = right edge
gs->ds.col_point[2] = is_clear( gs->ds.px + 12, gs->ds.py + 2 );
gs->ds.col_point[3] = is_clear( gs->ds.px + 12, gs->ds.py + 14 );
gs->ps.col_point[2] = W_IsClear( gs->ps.px + 12, gs->ps.py + 2 );
gs->ps.col_point[3] = W_IsClear( gs->ps.px + 12, gs->ps.py + 14 );
// 4, 5 = bottom edge
gs->ds.col_point[4] = is_clear( gs->ds.px + 10, gs->ds.py + 16 );
gs->ds.col_point[5] = is_clear( gs->ds.px + 4, gs->ds.py + 16 );
gs->ps.col_point[4] = W_IsClear( gs->ps.px + 10, gs->ps.py + 16 );
gs->ps.col_point[5] = W_IsClear( gs->ps.px + 4, gs->ps.py + 16 );
// 6, 7 = left edge
gs->ds.col_point[6] = is_clear( gs->ds.px + 2, gs->ds.py + 14 );
gs->ds.col_point[7] = is_clear( gs->ds.px + 2, gs->ds.py + 2 );
gs->ps.col_point[6] = W_IsClear( gs->ps.px + 2, gs->ps.py + 14 );
gs->ps.col_point[7] = W_IsClear( gs->ps.px + 2, gs->ps.py + 2 );
// update on_ground flag if a bottom point (4,5) is not clear
gs->ds.on_ground = (!gs->ds.col_point[4] || !gs->ds.col_point[5]);
gs->ps.on_ground = (!gs->ps.col_point[4] || !gs->ps.col_point[5]);
}
// validate input whose try flags were set
void verify_input() {
void P_VerifyInput() {
// right; col points 2, 3
if ( gs->ds.try_right && gs->ds.col_point[2] && gs->ds.col_point[3] ) {
gs->ds.do_right = 1;
if ( gs->ps.try_right && gs->ps.col_point[2] && gs->ps.col_point[3] ) {
gs->ps.do_right = 1;
}
// left; col points 6, 7
if ( gs->ds.try_left && gs->ds.col_point[6] && gs->ds.col_point[7] ) {
gs->ds.do_left = 1;
if ( gs->ps.try_left && gs->ps.col_point[6] && gs->ps.col_point[7] ) {
gs->ps.do_left = 1;
}
// jump; on_ground and col points 0, 1
if ( gs->ds.try_jump && gs->ds.on_ground && !gs->ds.do_jump
&& (gs->ds.col_point[0] && gs->ds.col_point[1]) ) {
gs->ds.do_jump = 1;
if ( gs->ps.try_jump && gs->ps.on_ground && !gs->ps.do_jump
&& (gs->ps.col_point[0] && gs->ps.col_point[1]) ) {
gs->ps.do_jump = 1;
}
// reset jump timer if contact a ground while still "jumping"
if ( gs->ds.try_jump && gs->ds.on_ground && gs->ds.jump_timer )
gs->ds.jump_timer = 0;
if ( gs->ps.try_jump && gs->ps.on_ground && gs->ps.jump_timer )
gs->ps.jump_timer = 0;
}
// apply validated dave movement
void move_dave() {
// update dave's tile pos
// apply validated player movement
void P_Move() {
// update player's tile pos
// sample x towards the center
gs->ds.tx = (gs->ds.px + TILE_SIZE / 2) / TILE_SIZE;
gs->ds.ty = gs->ds.py / TILE_SIZE;
gs->ps.tx = (gs->ps.px + TILE_SIZE / 2) / TILE_SIZE;
gs->ps.ty = gs->ps.py / TILE_SIZE;
if ( gs->ds.do_right ) {
gs->ds.px += 2;
gs->ds.do_right = 0;
if ( gs->ps.do_right ) {
gs->ps.px += 2;
gs->ps.do_right = 0;
}
if ( gs->ds.do_left ) {
gs->ds.px -= 2;
gs->ds.do_left = 0;
if ( gs->ps.do_left ) {
gs->ps.px -= 2;
gs->ps.do_left = 0;
}
if ( gs->ds.do_jump ) {
if ( !gs->ds.jump_timer )
gs->ds.jump_timer = 25;
if ( gs->ps.do_jump ) {
if ( !gs->ps.jump_timer )
gs->ps.jump_timer = 25;
if ( gs->ds.col_point[0] && gs->ds.col_point[1] ) {
if ( gs->ds.jump_timer > 12 )
gs->ds.py -= 2;
if ( gs->ds.jump_timer >= 7 && gs->ds.jump_timer <= 12 )
gs->ds.py -= 1;
gs->ds.jump_timer--;
} else gs->ds.jump_timer = 0;
if ( gs->ps.col_point[0] && gs->ps.col_point[1] ) {
if ( gs->ps.jump_timer > 12 )
gs->ps.py -= 2;
if ( gs->ps.jump_timer >= 7 && gs->ps.jump_timer <= 12 )
gs->ps.py -= 1;
gs->ps.jump_timer--;
} else gs->ps.jump_timer = 0;
//gs->ds.jump_timer--;
//gs->ps.jump_timer--;
if ( !gs->ds.jump_timer )
gs->ds.do_jump = 0;
if ( !gs->ps.jump_timer )
gs->ps.do_jump = 0;
}
}
// apply gravity to dave
void apply_gravity() {
if ( !gs->ds.do_jump && !gs->ds.on_ground ) {
// apply gravity to player
void P_ApplyGravity() {
if ( !gs->ps.do_jump && !gs->ps.on_ground ) {
// check below sprite
if ( is_clear( gs->ds.px + 4, gs->ds.py + 17 ) && is_clear( gs->ds.px + 10, gs->ds.py + 17 ) )
gs->ds.py += 2;
if ( W_IsClear( gs->ps.px + 4, gs->ps.py + 17 ) && W_IsClear( gs->ps.px + 10, gs->ps.py + 17 ) )
gs->ps.py += 2;
else { // align to tile
uint8_t not_align = gs->ds.py % TILE_SIZE;
uint8_t not_align = gs->ps.py % TILE_SIZE;
if ( not_align ) {
gs->ds.py = not_align < (TILE_SIZE / 2) ?
gs->ds.py - not_align : gs->ds.py + TILE_SIZE - not_align;
gs->ps.py = not_align < (TILE_SIZE / 2) ?
gs->ps.py - not_align : gs->ps.py + TILE_SIZE - not_align;
}
}
}
}
void update_level() {
// level-wide state update
void W_Update() {
// check if at door and has trophy
if ( gs->ds.check_door ) {
if ( gs->ds.trophy ) {
if ( gs->ps.check_door ) {
if ( gs->ps.trophy ) {
if ( gs->current_level < 9 ) {
gs->current_level++;
start_level();
W_StartLevel();
} else {
// finshed level 10
gs->quit = 1;
}
} else { // no trophy
gs->ds.check_door = 0;
gs->ps.check_door = 0;
}
}
}
// update game view based on set scroll values
void scroll_screen() {
void W_ScrollView() {
// scroll view if dave is about to move off view
if ( gs->ds.tx - gs->view_x >= 18 )
if ( gs->ps.tx - gs->view_x >= 18 )
gs->scroll_x = 15;
if ( gs->ds.tx - gs->view_x < 2 )
if ( gs->ps.tx - gs->view_x < 2 )
gs->scroll_x = -15;
// do the scroll
@ -281,28 +295,28 @@ void scroll_screen() {
}
}
// update game logic
void update_game() {
// main update routine
static void G_Update() {
// update collision point flags
check_collision();
P_UpdateCollision();
// pickups
pickup_item( gs->ds.check_pickup_x, gs->ds.check_pickup_y );
P_PickupItem();
// verify input try flags
verify_input();
// apply dave movement
move_dave();
P_VerifyInput();
// apply player movement
P_Move();
// game view scrolling
scroll_screen();
// dave gravity
apply_gravity();
W_ScrollView();
// player gravity
P_ApplyGravity();
// update level-wide state
update_level();
W_Update();
// reset input flags
clear_input();
G_ClearInput();
}
// draw level at current view
void draw_world( SDL_Renderer* r ) {
void Draw_World( SDL_Renderer* r ) {
SDL_Rect dst;
// draw level view 20x10 tiles at 16x16px
for ( int j = 0; j < 10; ++j ) {
@ -316,33 +330,33 @@ void draw_world( SDL_Renderer* r ) {
}
}
// draw dave
void draw_dave( SDL_Renderer* r ) {
// draw player
void Draw_Player( SDL_Renderer* r ) {
SDL_Rect dst;
// relative to view
dst.x = gs->ds.px - gs->view_x * TILE_SIZE;
dst.y = gs->ds.py;
dst.x = gs->ps.px - gs->view_x * TILE_SIZE;
dst.y = gs->ps.py;
// tile 56 neutral; 20x16px
uint8_t til = 53;
dst.w = 20; dst.h = 16;
// render
// grounded debug
if ( gs->ds.on_ground ) {
if ( gs->ps.on_ground ) {
SDL_SetRenderDrawColor( r, 255, 0, 255, 255 );
SDL_RenderDrawRect( r, &dst );
}
SDL_RenderCopy( r, g_assets->tile_tx[til], NULL, &dst );
}
// draw to renderer
void render( SDL_Renderer* r ) {
// main drawing routine
static void G_Draw( SDL_Renderer* r ) {
// clear backbuffer
SDL_SetRenderDrawColor( r, 0, 40, 80, 0xff );
SDL_RenderClear( r );
draw_world( r );
draw_dave( r );
Draw_World( r );
Draw_Player( r );
// flip buffers
SDL_RenderPresent( r );
@ -352,13 +366,7 @@ void render( SDL_Renderer* r ) {
//const uint8_t R_SCALE = 3;
int main( int argc, char** argv ) {
// load resources from DAVE.EXE
LoadTiles();
LoadLevels();
gs = malloc( sizeof(game_state_t) );
init_game();
// initialize SDL
if ( SDL_Init( SDL_INIT_VIDEO ) )
SDL_Log( "SDL Init error: %s\n", SDL_GetError() );
@ -384,26 +392,25 @@ int main( int argc, char** argv ) {
// scaling hint
//SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "linear" );
g_assets = malloc( sizeof(game_assets_t) );
init_assets( renderer );
// tile surfaces should be converted as textures inside g_assets now
FreeTileSurfaces();
// initialize game state and assets
G_Init();
G_InitAssets( renderer );
// clear initial frame
SDL_SetRenderDrawColor( renderer, 0, 40, 80, 0xff );
SDL_RenderClear( renderer );
// set state for first level
start_level();
W_StartLevel();
// main loop
while ( gs->quit == 0 ) {
// fixed timestep
uint32_t st = SDL_GetTicks();
check_input();
update_game();
render( renderer );
G_CheckInput();
G_Update();
G_Draw( renderer );
uint32_t delay = FRAME_DELAY - (SDL_GetTicks() - st);
delay = delay > FRAME_DELAY ? 0 : delay;

View File

@ -41,7 +41,7 @@ typedef struct {
// collision point clear flags; 1 = clear
uint8_t col_point[8];
} dave_state_t;
} player_state_t;
// global game state
typedef struct {
@ -51,8 +51,8 @@ typedef struct {
uint8_t view_x, view_y;
int8_t scroll_x;
// dave player state
dave_state_t ds;
// player state
player_state_t ps;
level_t levels[NUM_EXE_LEVELS]; // copied from exe util's GetLevel
} game_state_t;

View File

@ -8,13 +8,13 @@
static level_t levels[NUM_EXE_LEVELS];
// copy a single level structure for external use
void GetLevel( unsigned n, level_t* lvl ) {
void Util_GetLevel( unsigned n, level_t* lvl ) {
if ( n > NUM_EXE_LEVELS - 1 ) n = 0;
memcpy( lvl, &levels[n], sizeof(level_t) );
}
// export all levels to seperate .dat file
void SaveLevels() {
void Util_SaveLevels() {
for ( int l = 0; l < NUM_EXE_LEVELS; ++l ) {
char fname[1024];
snprintf( fname, 1024, "./levels/level%02u.dat", l );
@ -38,7 +38,7 @@ void SaveLevels() {
}
// fill global level array with dat from exe
void LoadLevels() {
void Util_LoadLevels() {
const uint32_t lvl_dat_addr = 0x26e0a;
SDL_RWops* ddexe = SDL_RWFromFile( "res/DAVE.EXE", "rb" );
@ -72,7 +72,7 @@ void LoadLevels() {
}
// create a large world map image with all levels
void CreateWorldMap() {
void Util_CreateWorldMap() {
// create big empty surface for containing entire world map
SDL_Surface* map = SDL_CreateRGBSurface( 0, 1600, 1600, 32, 0, 0, 0, 0 );
// level, row, column
@ -84,7 +84,7 @@ void CreateWorldMap() {
dst.x = x * 16;
dst.y = l * 160 + y * 16;
dst.w = 16; dst.h = 16;
SDL_Surface** tile_sfc = GetTileSurfaces();
SDL_Surface** tile_sfc = Util_GetTileSurfaces();
SDL_BlitSurface( tile_sfc[til], NULL, map, &dst );
// hardcoded player and monster starts

View File

@ -9,7 +9,7 @@
static SDL_Surface* tile_sfc[NUM_EXE_TILES];
// export all tiles to bmp
void SaveTiles() {
void Util_SaveTiles() {
// Save out the all tile surfaces
for ( int curtil = 0; curtil < NUM_EXE_TILES; ++curtil ) {
SDL_Surface* sfc = tile_sfc[curtil];
@ -21,12 +21,12 @@ void SaveTiles() {
}
// return tile surface array for external use
SDL_Surface** GetTileSurfaces() {
SDL_Surface** Util_GetTileSurfaces() {
return tile_sfc;
}
// fill global tile array with tiles from exe
void LoadTiles() {
void Util_LoadTiles() {
const uint32_t vga_data_addr = 0x120f0;
const uint32_t vga_pal_addr = 0x26b0a;
// exe assumed uncompressed
@ -144,7 +144,7 @@ void LoadTiles() {
}
// free all loaded exe's tile surfaces
void FreeTileSurfaces() {
void Util_FreeTileSurfaces() {
for ( int i = 0; i < NUM_EXE_TILES; ++i ) {
SDL_FreeSurface( tile_sfc[i] );
}
@ -161,15 +161,15 @@ int main( int argc, char** argv ) {
}
SDL_RWclose( dscor );*/
LoadTiles();
SaveTiles();
Util_LoadTiles();
Util_SaveTiles();
// LEVELS
LoadLevels();
SaveLevels();
CreateWorldMap();
Util_LoadLevels();
Util_SaveLevels();
Util_CreateWorldMap();
FreeTileSurfaces();
Util_FreeTileSurfaces();
return 0;
}

View File

@ -9,10 +9,10 @@
#define NUM_EXE_LEVELS 10
// tiles
void LoadTiles();
SDL_Surface** GetTileSurfaces();
void SaveTiles();
void FreeTileSurfaces();
void Util_LoadTiles();
SDL_Surface** Util_GetTileSurfaces();
void Util_SaveTiles();
void Util_FreeTileSurfaces();
// level structure
// byte[256] path, two signed 8bit relative movement, 0xea 0xea for end
@ -26,9 +26,9 @@ typedef struct {
} level_t;
// levels
void LoadLevels();
void GetLevel( unsigned n, level_t* lvl );
void SaveLevels();
void CreateWorldMap();
void Util_LoadLevels();
void Util_GetLevel( unsigned n, level_t* lvl );
void Util_SaveLevels();
void Util_CreateWorldMap();
#endif