The building of Caveman - Part 5 - General code organization

posted in Caveman
Published September 29, 2014
Advertisement
The building of Caveman - Part 5 - General code organization


This is the general code organization used in Caveman:


void main:
----------------
initprog
runprog
endprog





initprog
------------------
init z3d game library - creates window, goes into 3d mode, creates fonts, inits audio, random number generator, timers, etc.
rockland animation - show company logo animation
load all assests - show loading screen. load: meshes, textures, models, animations, wavs, etc.
show title screen



runprog
-------------------
show main menu:
continue - load last saved game, rungame.
tutorial - init tutorial game, rungame.
new game - init new game, rungame.
load game - load saved game, rungame.
help - show help
tools - show modding tools menu
quit - quit caveman


endprog
-------------------------
unload all assets
shutdown d3d, audio, etc




Rungame is the main game loop, the real guts of the game. The game uses a fixed time step. The framerate is limited
to 15 FPS. Testing has shown this is the slowest a game can run and still be sufficiently responsive. The game has
accelerated time, so render is called one or fewer times per turn (update frame), depending on game speed. Caveman is
a hybrid game that combines FPS/RPG play with with the ability to interact with the environment, as seen in The SIMs.
The are hundreds of possible actions, from drinking water to making a stone knife. When the player is perfoming an
action, they can't move or fight, and must wait for the action to complete. Action specific handler code is called
each turn (update frame). When they are not performing an action, they can run around like in any normal FPS/RPG.

rungame
--------------------------while !quit { if ((turn_counter % turns_per_render)==0) drawscreen // render if (player_doing_action) do_action else process_input increment_game_clock run_simulation // update limit_framerate }
do_action
-----------------------------
runs the action handler code for the current action.
action handler code typically increments a counter, and after some limit is reached, performs a success check,
updates the simuation as needed, and ends the action. While performing an action, input is limited to
changing game speed and stopping the action.


An example action handler: drink water. this increases the bandmembers water by one every 10 turns until it hits
100, at which point it stops the action:

drink water
------------------------------------------------inc bandmember[a].action_counter[DRINK_WATER]if bandmember[a].action_counter[DRINK_WATER] < 10 returnbandmember[a].action_counter[DRINK_WATER]=0inc bandmember[a].waterif bandmember[a].water>=100 { bandmember[a].water=100 bandmember[a].current_action=DO_NOTHING }


process_input
------------------------------------
processes mouse and keyboard input. input controls can be remapped. raw inputs are mapped to input controls
such as IN_LEFT, or IN_ATTACK. process_input polls the input controls at 15 FPS, and always polls at least
once per render. movement inputs are translated into a move direction of forward, back, left, right, one of
the four diagonal directions, or none. code is then called to move the player in that direction, and play the
correct movement animation. About the only unusual thing about the code is the fact that movement must be
processed before jump, for movement velocties at takeoff to take effect while airborne. Caveman uses realistic
gravity and physics modeling for missiles and falling creatures (including jumping). So just like the real
world, once your feet leave the ground, you can't change your velocity. its all about your initial launch
velocities. Movement must be processed before jump to set those velocities.







run_simulation
-----------------------------------------
this is the main "update" routine. updates are done on an as needed basis. so things that get updated every
frame are updated in do_global_frame2, and things that only need to be updated once per second are updated
in do_global_second2, and so on for global minute, hour, day, and year.void run_simulation2() // the "model stuff" engine{do_global_frame2();if (frame==0) { do_global_second2(); if (second==0) { do_global_minute2(); if (minute==0) { do_global_hour2(); if (hour==0) { do_global_day2(); if (day==0) { do_global_year(); } } } } }}



do_global_frame2
-------------------------------------------------------------------------
this is the main update routine called every frame. it updates: bandmembers (PCs), missiles, animals (NPCs), rafts,
and clouds. Note that attacks are resolved one second after they are initiated, and a hit is only scored if the
weapon hits someone at that point in time. Also note that surprise is modeled in the form of "freezing" for a few
seconds before an entity can move or attack. move_rafts2 models raft movement (duh!) but also moves bandmembers,
NPCs, and dropped objects which are aboard the raft. So you can actually walk around and place object on a raft
while its in motion. model_falling2 handles the physics modeling for falling entities. update_clouds updates the
cloud particle system based on variables from the weather engine.
void do_global_frame2(){int a;BMupdate_all();model_missiles(); // model missile movementmove_animals(); // move animalsif (last_active_animal >= 0) // model animal attacks { for (a=0; a <= last_active_animal; a++) { if (!animal[a].active) continue; if (!animal[a].alive) continue; if (!animal[a].attacking) continue; animal[a].attack_counter++; if (animal[a].attack_counter>=30) { animal[a].attacking=0; animal[a].xr=0.0f; animal[a].attack_counter=0; continue; } if (animal[a].attack_counter==15) new_resolve_animal_attack(a); } }if (last_active_animal >= 0) // model animal suprise { for (a=0; a <= last_active_animal; a++) { if (!animal[a].active) continue; if (!animal[a].alive) continue; if (!animal[a].suprised) continue; animal[a].suprise_counter++; if (animal[a].suprise_counter>60) animal[a].suprised=0; } }move_rafts2();model_falling2();update_clouds();}
do_global_second, minute, day, and year are similar, modeling everything from animals entangled in nets or
bolas getting free, to background radiation (old age).


And that's the basic code structure of the game. pretty straight forward, a fixed time step game loop, with framerate
limiter. The only unusual things are: FPS/RPG mode or SIMs style do action mode, and the render based on
accelerated time.

Part 6:
https://www.gamedev.net/blog/1730/entry-2260310-the-building-of-caveman-part-6-data-structures/

Part 4:
https://www.gamedev.net/blog/1730/entry-2259583-the-building-of-caveman-part-4-the-z-game-library/
0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement