Game loop
Just working on my first ever Spectrum game, and am struggling to work out what the game-loop should look like.
I've got interrupts enabled (mode 2) - although I'm not doing anything in the interrupt routine at the moment.
From what I understand, interrupts occur when the TV beam hits the end of the bottom line, so I thought a basic game-loop could be this (pseudo code):
loop: halt ; wait for interrupt to occur
clear_sprites
update_stuff
draw_sprites
jr loop
Does this look right? I've decided to XOR my sprites onto the screen, so the first problem I've hit is the very first 'clear_sprites' routine actually draws them on the screen, and then the draw_sprites routine clears them off (unless they've moved a bit).
I could set a flag to say if first time in the loop don't clear them - but thats already getting a bit messy, and I wondered if there was a simpler / nicer approach.
I did think about padding the sprites with blanks around all edges, then I wouldn't actually need a clear_sprites step, but that seemed like a bit of a faff too.
When I was thinking about the halt instruction I then thought it might be better to do something like this:
loop: update_stuff
halt
clear_sprites (from old position)
draw_sprites (at new position)
jr loop
Which seems to give me a bit more time in the vblank, but adds the additional step of remembering everythings old position.
The game itself is going to be a space invaders clone (so a few sprites on screen, though not all necessarily moving every frame).
Any help / ideas are welcome.
I've got interrupts enabled (mode 2) - although I'm not doing anything in the interrupt routine at the moment.
From what I understand, interrupts occur when the TV beam hits the end of the bottom line, so I thought a basic game-loop could be this (pseudo code):
loop: halt ; wait for interrupt to occur
clear_sprites
update_stuff
draw_sprites
jr loop
Does this look right? I've decided to XOR my sprites onto the screen, so the first problem I've hit is the very first 'clear_sprites' routine actually draws them on the screen, and then the draw_sprites routine clears them off (unless they've moved a bit).
I could set a flag to say if first time in the loop don't clear them - but thats already getting a bit messy, and I wondered if there was a simpler / nicer approach.
I did think about padding the sprites with blanks around all edges, then I wouldn't actually need a clear_sprites step, but that seemed like a bit of a faff too.
When I was thinking about the halt instruction I then thought it might be better to do something like this:
loop: update_stuff
halt
clear_sprites (from old position)
draw_sprites (at new position)
jr loop
Which seems to give me a bit more time in the vblank, but adds the additional step of remembering everythings old position.
The game itself is going to be a space invaders clone (so a few sprites on screen, though not all necessarily moving every frame).
Any help / ideas are welcome.
Post edited by feynman on
Comments
It's when it hits the end of the bottom border (thus restarts at the top of the upper border).
loop:
draw_sprites
halt ; wait for interrupt to occur
clear_sprites
update_stuff
jr loop
You will have to print the sprite once before (or in the moment) you initialise your routine. Later, each time you move your sprite, you XOR it in the old address (to clear it) and the XOR it in the new address to print it.
As you are going to use a XOR routine, I'd go for this approach (so you don't have to worry for the screen refresh if you don't mind a little tearing):
I use a XOR routine that gets both the old coordinates of the sprite and the new ones, so it does the clear/print thing line by line of the sprite instead of clearing the whole sprite and then printing it again in the new position. So when the electron gets you, it only affect one line of the sprite. If you use a similar aproach, you can do this:
Print sprite
Loop:
Get movement
Update Sprite (Clear/Print)
Update stuff
GOTO Loop
Small change to my main loop, but obvious when I see it written down. (I'll go with Einar's approach, at least to begin with).
What's a common use of the interrupt routine? I've got interrupts enabled mainly so I can use the Halt in the main loop. Should I be thinking of putting stuff in there? (and if so - what? sound?) (or is that question too general to answer...)
frame interrupt occurs 1/50th of second. Count up 50 of them and you have a second, etc.
Sound might not be a good thing to put in interrupt routines because they usually need more than 50hz per second, but I know some games do have them. AY-music routine could also work.
Also, remember that anything inside an interrupt routine will be executed just after your halt instruction in your main loop, i.e. immediately before your sprite routines. This might be a good or a bad thing.
If you have no idea you could always put a counter inside the routine and increment it. You can then refer to it later in your main game code. But you could also add a counter just after the halt in your main loop instead.
Games List 2016 - Games List 2015 - Games List 2014
Still struggling with sound actually (48K so beeper only). Anybody know any good guides to using the speaker for producing sound effects, etc?
It all depends how much time each operation takes. You don't want to get caught in the screen while you cleared a sprite but didn't redraw it at new position - it would make sprite disappear. Usually when coder doesn't have control on such events sprites appear and disappear randomly which is called flicker and looks badly of course.
You may organize your job so to start drawing when raster reaches a BOTTOM border, not top one. It will give you more time to do drawing.
Then there are other techniques as buffers but as you wrote, you draw directly to screen. It's perfectly okay as long as it works ;)
Personally I do:
Loop
- ClearSprites
- DrawSprites
- Do Stuff
Jp Loop
with HALT somewhere in between of these operations :)
Still struggling to see how I can play a sound effect using the 48K beeper that spans across several frames of action.
e.g. Player fires - I want a sound effect that lasts (say) half a second. I don't want to stop the game for half a second, so I need to split my sound out over this time. Do I just play a small bit of sound each frame? Wont this sound odd?
It really depends on how you are drawing to the screen.
One thing I think you are maybe not considering is how the TV display is drawn. After the ULA interrupts there are about 14k z80 cycles until the first pixel of the top left corner is drawn by the TV raster. The raster proceeds left to right, top to bottom until the entire display file is traversed by the TV raster.
Why is this important? Because if you are busy erasing things while the TV raster crosses the area being erased, you will see flicker (sprites gone, then later reappearing). If the raster crosses the mid section of a sprite that is not erased, you may see it torn (the top half at an earlier position compared to the bottom half). I think flicker is probably a worse effect.
If you want to erase and then redraw, you want to position your halt to give you the best chance to finish these operations before the raster catches up with you. There are a lot of different ways to do this. One that has source code in the public right now is antoniovillena's FASE sprite engine (which, btw, you could use instead of writing one from scratch).
If you want to just XOR sprites on screen, it may be acceptable to totally ignore this issue because XOR suffers much less from flicker unless the sprites move far between updates.
Other draw algorithms never suffer from flicker because they never erase anything. Instead they draw completed graphics to a buffer and then copy the finished result to screen. sp1 (my sig) is an example that draws completed graphics to screen one character square at a time.
Playing beeper sounds takes all the cpu's time because you need to control the tone periods precisely by counting the exact time the z80 takes between toggling the speaker state. In other words, if you are playing a beeper tune across a few frames, you are not moving sprites on the screen :). You can try to play a segment of a tone every 1/50s in the interrupt (remember that 14k cycle delay to the first pixel? well some draw strategies might want to wait 14k cycles before doing anything so you can fill that time with tasks like sound generation that take a known amount of time) but a lot of people may think that sounds too harsh for music (as opposed to sound effects) but you could try anyway. JetSetWilly is an example.
Sound effects are brief and sporadic -- they can almost always fit into the "play a bit every 1/50s" model that work on interrupt.
Alternatively you can use the AY to play music. That doesn't require much of the z80's attention.
That's what you do. Design your sound effects to sound ok.
Write games in C using Z88DK and SP1
The basic principle is changing the state of bit 4 of port #FE in a loop. The type of sound you get is defined by how much time has passed between each of the state changes.
So e.g. for a pure tone of a specific frequency you insert a fixed delay of some kind between the OUTs. If you use two different (but still fixed) delay durations, it is a constant frequency tone as well which however is going to sound more 'thin'; this is what it looks like.
For noise, the delays should be random. Noise frequency is inversely proportional to the average delay duration.
For multichannel sound, several methods exist, e.g.
1) Using several tone channels with low duty cycle values so that they don't interfere with each other and actually sound like distinct channels ('pulse width modulation').
2) Creating a 'middle signal state' of sorts - w/e it's called - by flipping the bit state really fast, and then adding/subtracting tonal pulses to that.
It's sort of all building upon these really.
In my (brief) experience, when I've been mucking about with short beeper-type sound FX, I've found it's best to keep the sounds quite short for commonly heard sounds that play "in their entirety" in a frame (e.g. a footstep or a shot).
Half a second sounds like quite a long time for a sound to play in its entirety.
If it's going something like "peeeoooowwwnnn....!" "peeeooooownnnn..!"* then I'd personally split it over multiple frames, to keep the action going.
(*apologies for the use of technical jargon)
And you can find more threads about beeper here on wos, its quite popular topic in development forum.
I didn't realise the forum defaulted to only showing posts from the last month (doh! thought it was a bit odd there were only 3 pages :confused:)
In your main loop you replace the halt by
Do sound until interrupt sets flag
The advantage here is you don't waste time by doing nothing. Cobra does it same way.