|
Post by Robin Harbron on Apr 20, 2007 23:15:52 GMT -5
I found the following posted recently over at our old SSOCC board. I replied pointing Leigh over to the new location here, but I figured I might as well give a shot at an answer. Hi, First time post! I've been doing some experiments with sprites in assembler (things going good so far!). One issue which has come to mind is to do with timing (I don't know if this then falls under the topic of interrupts because I haven't got that far yet). In a game, their could be a process for reading a joystick direction, so logic performed, and finally sprites output to their new location (and this looped over infinitely). What if though on each loop, the processing side of things could take varying amounts of time due to logic branching and what is performed? When things are running fast, visually you wouldn't notice a difference, but then slow it down, and the potential outcome is uneven animation frame display times for example. Is this a ligitimate issue that can be addressed or needs considering - or is it unavoidable? Thanks! Hi Leigh, and welcome. Hope you find your way over here to our new location Yes, this is a legitimate issue, and one that has at least a few common solutions. You're right about it being related to interrupts. Game programming typically requires you to think in terms of "ticks". Each tick you might do a number of things, such as read the joystick and/or keyboard, move the player based on that input, move some enemies based on some rules, check for collisions, and check for certain conditions to be met such as running out of health, or, eating that last dot in the maze and starting a new level. Any given task must be split up into little pieces, to be executed one tick at a time. If you want to move an enemy from left to right across the screen, you can't just use a simple loop to do that. Instead, you have to move the enemy, say, 2 pixels to the right, and then wait for next tick to move it again. The time it takes to execute each tick will vary depending on what needs to be processed that turn. If each tick ran one after another, the game would probably noticeably speed up and slow down, or at least not appear to be as smooth as it could be. Many platforms, such as the C-64, update their video 50 (PAL video standard) or 60 (NTSC) times per second. Many games "tick" at that same rate. The C-64's VIC-II chip can generate an interrupt when a specified raster line is about to be drawn, and this can be used to trigger each tick. A less sophisticated solution which may be better for beginners is to just poll the raster register at $D012 with a simple loop like this: lda #100; raster line 100 loop cmp $d012 bne loop
; do game processing code here, then jump back to top
Anyway, that's a start. I could go on an awful lot more, but there are plenty of other people with advice, and I'll wait until you show up
|
|
leigh
New Member
Posts: 2
|
Post by leigh on Apr 22, 2007 21:10:25 GMT -5
Hi Robin
Thanks for the reply! I will have a look at the couple of starting points you have given me and see where that leads. The program I currently have has a sprite animated and moving (similar to Contra) jumping on platforms on the screen and is working very well. will post back when I make some progress or hit another hurdle!
|
|
leigh
New Member
Posts: 2
|
Post by leigh on May 10, 2007 1:12:44 GMT -5
Hi Robin, I've done a bit of reading up on the topic and from what I can understand from what you have provided as a starting point is using a raster interrupt to regulate when my sprite movement code is called (by the example you gave, everytime the raster hits line 100, the code runs). If 1 iteration of my code is completed before the raster scan gets to 100, then (in theory), another iteration will take place as soon as the scan hits 100 the next time around. What about then if an iteration of code takes longer than a complete raster scan (say 2 times for example), and the next iteration can be completed within one scan - I assume this means I am back to the original problem? If so, does this mean I would have to determine the longest possible processing time for an iteration (based on complete raster scans), and somehow use this figure to regulate the call to run my code? From doing some extra reading wikholm.dyndns.org/~cswiki/doku.php?id=articles:introduction_to_stable_timingit sounds like this talks about some of the more complex solutions you suggested. Thanks for any more help! Leigh
|
|
|
Post by Robin Harbron on May 10, 2007 9:43:52 GMT -5
I've done a bit of reading up on the topic and from what I can understand from what you have provided as a starting point is using a raster interrupt to regulate when my sprite movement code is called (by the example you gave, everytime the raster hits line 100, the code runs). Yes, though the code I provided isn't interrupt code, it's just a busy loop waiting for a certain scan line to be reached. Interrupts allow the processor to be doing something else while "waiting" for e.g. scan line 100, but they're more complicated to set up, and have more "gotchas". I'll see if I can find a good example of that, but the busy loop method should be fine for starting out. Yes, exactly. Well, if the iteration always takes 2 screen refreshes, then there's really no problem, as the movement would still be steady. You'd just need to move the sprites twice as far per refresh. And the movement wouldn't appear as smooth. If it's a variable number of screen refreshes from one iteration to the next, that's when you'll have problems. Yes, you always need to plan around the worst case. But really, if all you're doing is moving some sprites around each refresh, you have loads of time. Many games manage to scroll the screen (one of the most processor intensive things that most C64 games have to do), move a bunch of sprites, handle collisions and some amount of AI/game logic, and play music and sound fx too, all at 50/60 hz. That's a related subject, but the main thrust of those articles is about being able to run code at cycle-precise times, which is of limited use in games (Mayhem in Monsterland's scrolling method being one notable exception). It's mostly used in demos, where special VIC tricks need cycle exact register changes. The busy-loop or IRQ method is totally sufficient for the sort of things you're trying.
|
|
TMR
Newbie
Posts: 38
|
Post by TMR on May 13, 2007 18:25:33 GMT -5
One point worth mentioning is that a bit of sprite handling should never get to the point where it needs more than a frame of CPU time. On average, a PAL machine can shift just under 2K of data in one frame if the code is fairly well optimised and assuming a few other odds and sods like music drivers are running; even a full-screen scroller with double buffering and colour scroll won't get past 1K per frame.
It's also wise to, if you're going to update sprites during the screen, to run one interrupt at raster position $00 that sets the sprites up from a table and a second routine at wherever in the frame to update the values in that table since changing sprite positions whilst the sprite is being drawn will make it "tear".
|
|
|
Post by richard on Nov 5, 2007 4:39:06 GMT -5
I am having trouble with my Sub Hunter game project. It is mainly to do with timing sprites that go over raster splits. Unfortunately I am not very good at raster timing (As you may have noticed). I am trying to get all the layers of the game background to scroll 100% without any flickering business going on (for example: raster jumping to the next bad line) when any - to all of the sprites go over the background. Please can you help me correct the IRQ code so that I can get timing 100% when sprites go over the raster splits? (Preferably the less technical way) Here is the code for where the IRQ is in operation: STAGE4_IRQ1: STA I1+1 LSR $D019 LDA #$42 ;The first main split in STA $D012 ;the game NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP ;TSX LDA #$00 ;Keep sprites turned off in this STA $D015 ;raster split. LDA #$18 ;Used for the top score and status STA $D016;bar. LDA #$0F STA $D021 LDA #$01 STA $D022 LDA #$09 STA $D023 LDA #<STAGE4_IRQ2 STA $FFFE LDA #>STAGE4_IRQ2 STA $FFFF I1 LDA #0 NMI RTI STAGE4_IRQ2 STA I2+1 LSR $D019 NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP LDA #$4A STA $D012 NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP LDA #$FF ;Turn on all sprites STA $D015 LDA #$10 ;This is more for the status STA $D016 LDA #$0F STA $D021 LDA #$09 STA $D022 LDA #$03 STA $D023 LDA #<STAGE4_IRQ3 STA $FFFE LDA #>STAGE4_IRQ3 STA $FFFF I2 LDA #0 RTI STAGE4_IRQ3 STA I3+1 LSR $D019 CLI
LDA #$6A STA $D012 NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP LDA TEMP1 ;First layer of the sea ;This is multicolor scroll 1 ORA #$10 STA $D016 LDA #$0E STA $D021 LDA #$01 STA $D022 LDA #$0E STA $D023 LDA #<STAGE4_IRQ4 STA $FFFE LDA #>STAGE4_IRQ4 STA $FFFF I3 LDA #0 RTI STAGE4_IRQ4 STA I4+1 LSR $D019 LDA #$82 STA $D012 LDA #$0E STA $D021 LDA #$0B STA $D023 LDA #$00 STA $D022 LDA TEMP2 ;Second scroll layer for the ORA #$10 ;sea background NOP NOP NOP NOP NOP NOP STA $D016 NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP LDA #<STAGE4_IRQ5 STA $FFFE LDA #>STAGE4_IRQ5 STA $FFFF I4 LDA #0 RTI STAGE4_IRQ5 STA I5+1 LSR $D019
LDA #$8A STA $D012 LDA #$0B STA $D021 LDA #$00 STA $D022 LDA #$0B STA $D023 LDA TEMP3 ;Third scroll layer for the sea ORA #$10 ;background NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP STA $D016 LDA #<STAGE4_IRQ6 STA $FFFE LDA #>STAGE4_IRQ6 STA $FFFF I5 LDA #0 RTI STAGE4_IRQ6 STA I6+1 LSR $D019 CLI
LDA #$98 STA $D012 LDA TEMP6 ;Background scroll (the grey NOP ;sea frame) NOP NOP NOP NOP NOP NOP NOP NOP NOP ORA #$10 STA $D016 LDA #$0B STA $D021 LDA #$00 STA $D022 LDA #$00 STA $D023 LDA #<STAGE4_IRQ7 STA $FFFE LDA #>STAGE4_IRQ7 STA $FFFF I6 LDA #0 RTI STAGE4_IRQ7 STA I7+1 LSR $D019 LDA #$AA STA $D012 NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP LDA TEMP6 ;The distant terrain ORA #$10 STA $D016 LDA STAGECOLOR1 STA $D021 LDA STAGECOLOR2 STA $D022 LDA STAGECOLOR3 STA $D023 LDA #<STAGE4_IRQ8 STA $FFFE LDA #>STAGE4_IRQ8 STA $FFFF I7 LDA #0 RTI STAGE4_IRQ8 STA I8+1 LSR $D019 LDA #$C2 STA $D012 LDA TEMP7 ;The top part of the ground BEQ *+2 ;surfaces scroll NOP NOP NOP NOP BIT $EA NOP NOP NOP NOP NOP NOP ORA #$10 STA $D016 LDA STAGECOLOR1 STA $D021 LDA STAGECOLOR2 STA $D022 LDA STAGECOLOR3 STA $D023 LDA #<STAGE4_IRQ9 STA $FFFE LDA #>STAGE4_IRQ9 STA $FFFF I8 LDA #0 RTI STAGE4_IRQ9 STA I9+1 LSR $D019 LDA #$E2 STA $D012 LDA TEMP8 ;The bottom surface scroll BEQ *+2 NOP NOP NOP NOP BIT $EA NOP NOP NOP NOP NOP NOP ORA #$10 STA $D016 LDA STAGECOLOR1 STA $D021 LDA STAGECOLOR2 STA $D022 LDA STAGECOLOR3 STA $D023 LDA #<STAGE4_IRQ10 STA $FFFE LDA #>STAGE4_IRQ10 STA $FFFF I9 LDA #0 RTI STAGE4_IRQ10 STA I10+1 LSR $D019
LDA #$F2 STA $D012 NOP NOP NOP NOP BIT $EA NOP NOP NOP NOP NOP NOP NOP LDA #$00 STA $D015 LDA #$18 ;Used for the bottom score STA $D016;status bar LDA #$0F STA $D021 LDA #$01 STA $D022 LDA #$09 STA $D023 LDA #<STAGE4_IRQ1 STA $FFFE LDA #>STAGE4_IRQ1 STA $FFFF LDA #$01 STA SYNC JSR $E003 ;Play Drax's in game music I10 LDA #0 RTI
|
|
|
Post by Robin Harbron on Nov 5, 2007 23:20:20 GMT -5
I am trying to get all the layers of the game background to scroll 100% without any flickering business going on (for example: raster jumping to the next bad line) when any - to all of the sprites go over the background. Please can you help me correct the IRQ code so that I can get timing 100% when sprites go over the raster splits? (Preferably the less technical way) To give really specific advice I think I'd just need to play with it, so I'd need a copy of your work disk + assembler, and instructions on how to get a build going. PM me to arrange that if you're interested. I know that you're not going to be able to time something like this out properly with just NOPs when you have sprites moving up and down. Each sprite displayed steals a couple cycles on the scan lines it's active, so code timed properly with no sprites will take too long once you're showing sprites there.
|
|
|
Post by richard on Nov 8, 2007 7:59:06 GMT -5
To give really specific advice I think I'd just need to play with it, so I'd need a copy of your work disk + assembler, and instructions on how to get a build going. PM me to arrange that if you're interested. Okay, thank you. Email sent. Yeuch I hope the timing problems can be fixed nicely. I'll need to find out more on timing raster lines that are using sprites Perhaps I should find some information in C=Hacking abut timing with sprites.
|
|