Games programming: Coding
Op deze pagina wat uitleg over het eigenlijke
programmeren van PinPin.
Het lastigste met spelletjes is de 'game loop': hoe zorg je er
voor dat het spel altijd op de juiste snelheid loopt, onafhankelijk van de
snelheid van de computer en het beeldscherm? Scherm refresh rates lopen van 50
Hz tot 85 Hz (en zelfs daarbuiten), toch moeten de figuurtjes even snel
bewegen, onafhankelijk van het systeem.
Dit bereik ik door de snelheid van de figuurtjes op een vaste
frequentie te berekenen, onafhankelijk van de beeldscherm frequentie. De main
loop van het programma ziet er (iets versimpeld) uit als hier beneden
weergegeven. De 'main loop' draait altijd op een snelheid
bepaald door de scherm-update, doordat de display-update-routine wacht op een
vertical refresh signaal van de beeldschermkaart (dit voorkomt een knipperend
beeld). Daarnaast is er een loop (de 'game loop') die zorgt
voor het bijwerken van de positie van de spelers etc, de timing hiervoor wordt
bepaald door een interrupt signaal dat altijd op bijvoorbeeld 50 Hz (20
miliseconden) loopt, onafhankelijk van de beeldscherm update frequentie (lees
verder...).
Dit gebeurt via een variabele genaamd fm_framer ,
welke welke 20 miliseconde via een interrupt wordt opgehoogd (zie verderop voor
de interrupt routine etc). Aan de hand van de stand van deze variabele wordt in
de main loop de 'game loop' 0, 1 of meerdere keren uitgevoerd, al naar gelang
wat nodig is.
Als de display frequentie boven de game loop frequentie ligt,
zal de game loop zo nu en dan worden overgeslagen om toch het goede tempo te
hebben. Bijvoorbeeld: 75 Hz display (D), 50 Hz game (G): de volgorde zal dan zijn
D D
G D G D D G D G D D G D G ....., verhouding van 3:2.
Mocht de display frequentie juist te traag zijn, dan zal de
game loop juist vaker worden uitgevoerd, zodat deze toch altijd gemiddeld 50
keer per seconde wordt uitgevoerd. Dit kan ook bijvoorbeeld gebeuren op een
trage computer, waarbij zoveel gerekend wordt dat de display update een aantal
beeldjes mist (er zijn al een aantal vertical sync's voorbij voor de volgende
aanroep van update_display( ) ). Beweging kan op een gegeven
moment dan wat schokkerig worden ( D
G G G G G G D G G G G G G D G G G .....), maar de bewegingssnelheid van de spelers
blijft gelijk!
void main_loop(void)
{
init_mytimers();
/* This is the 'main loop', repeated until SPACE or ESC is pressed */
while (!quit)
{
/* -- 'game loop': this loop is running at the game
rate,
not the display frame rate --- */
while(fm_framer>0)
{
keyhandler(0); /* function keys, Esc key etc */
fm_framer--; /* may be inc'd by interrupts! */
update_pinguin(); /* the players */
MapUpdateAnims(); /* other animations */
if(fish_on)
update_fish();
}
/* --------- end of game loop --------- */
/* The drawing of the various layers and characters
on the internal bitmap memory for later display */
update_background_layer();
if(fish_on) draw_fish();
draw_animals();
update_foreground_layer();
if(snow_on) let_it_snow();
display_score();
display_helptext();
/* copy the internal bitmap to the display via
DirectX,
this waits for a display vertical sync signal */
update_display();
}
}
Mocht de computer erg traag zijn (en het beeld erg knipperend),
dan kan je een aantal 'features' uitschakelen om zo rekentijd te besparen. Dit
zie je ook in de loop: de vissen en de sneeuw (die best nogal wat vragen van
het systeem) kunnen via de variabelen fish_on en
snow_on aan- en uit-geschakeld worden (bijvoorbeeld via een
configuratiemenu, of hier via bepaalde toetsen).
Een paar bijhorende routines rond de interrupts, met wat extra
'code' nodig voor Allegro, bijvoorbeeld om te zorgen dat de interrupt routines
in het cache geheugen blijven en niet uitgeswapt worden:
void
frame_timer()
/* increment frame_time */ {
fm_framer++;
/* set up at 50 Hz (20 ms) */ }
END_OF_FUNCTION(frame_timer);
void
init_mytimers()
/* set up game timers etc */ {
LOCK_VARIABLE(fm_framer); /* may not
be swapped out! */
LOCK_FUNCTION(frame_timer);
install_int_ex(frame_timer, MSEC_TO_TIMER(20));
fm_framer = 0;
}
Hopelijk geeft dit voldoende inzicht in de game timing.
|