Advice for timing

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
casprog
Posts: 70
Joined: Fri Oct 28, 2016 12:37 pm

Advice for timing

Post by casprog »

I have some sprites I'm trying to control the speed of, or how often they move.

What I have done is place a counter in my NMI,

Code: Select all

; increase frame counter
LDA frameCounter
CLC
ADC #$01
STA frameCounter
In my game logic, which is separate from my NMI code, I check if frameCounter is greater than 30 (or roughly half a second) and I move my sprites if that condition is true. I then reset the frame counter back to zero.

Is this a common approach to timing? I figure the NMI will fire roughly 60 times a second so I can piggyback off that?

In Allegro and SDL I would get the current time and compare if the elapsed time between the last movement was greater than some timing variable.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Advice for timing

Post by tepples »

Yes, that's one way of indicating to the main thread that an NMI has occurred.

But there's a shortcut for the addition:

Code: Select all

inc frameCounter
If your NMI handler is fairly simple, this also saves you from having to push and pull A so as not to disrupt the main thread's use of A. Many of my games so far have used just this sort of trivial NMI handler. You can see it in, for example, my NROM project template:

Code: Select all

.proc nmi_handler
  inc nmis
  rti
.endproc
If you have more than one thing animating at once, you'll need to let frameCounter free-run without resetting it, and then treat frameCounter as you would retrace_count in Allegro: saving the value at the start of an interval and comparing it at the end of an interval.
User avatar
Memblers
Site Admin
Posts: 3902
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: Advice for timing

Post by Memblers »

You'll want to look at fixed-point addition, aka sub-pixel precision. It's explained pretty well in this thread:
https://forums.nesdev.com/viewtopic.php?f=10&t=12125

I don't know how often a timer-based approach is used for movement, but I can say that I've used it before in my earlier programs and it was ugly and inflexible. Using sub-pixel positioning (with 16 bits for movement rates and positions, where only the upper 8 bits are full pixels) is much cleaner.
JRoatch
Formerly 43110
Posts: 394
Joined: Wed Feb 05, 2014 7:01 am
Location: us-east
Contact:

Re: Advice for timing

Post by JRoatch »

like tepples said, I think it's best to not reset the NMI counter variable in main code.

2 ways to implement a half second timer is to have a variable that decrements towards 0 each frame in your main code, or to add 30 with the NMI counter into a different variable and compare that every frame.

Code: Select all

; setup 
lda #30
sta timer_1

; for every frame in your main loop
dec timer_1
bne timer_1_not_triggered
  ; do action
timer_1_not_triggered:
This second method is different in that even if the main loop lags, the timer will still fire in at least 30 frames, but it has the disadvantage of having half the range due to using bmi to account for the frameCounter overshooting from lag.

Code: Select all

; setup
clc
lda frameCounter
adc #30
sta timer_2

; for every frame in your main loop
lda frameCounter
cmp timer_2
bmi timer_2_not_triggered
  ; do action
timer_2_not_triggered:
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Advice for timing

Post by tepples »

Memblers wrote:I don't know how often a timer-based approach is used for movement
Thwaite and RHDE use a 6-frame timer for tiny sprites that need to move only once every tenth of a second or less often. The units in both games move once every 0.2 seconds. Machine guns in several games use a frame count to tell how often to fire. Counting frames between moves is also commonly used for cursor movement and in falling block games for sideways piece movement, both of which behave similarly to keyboard autorepeat.

But for things that change continuously, such as the position of a character in a platformer, I agree that fixed-point arithmetic is the best choice.
User avatar
rainwarrior
Posts: 8062
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Advice for timing

Post by rainwarrior »

If the numbers involved are powers of two, like 2, 4, 8, 16, etc. as an alternative to storing individual states you can just apply bitwise operations to the free-running frameCounter variable you have.

For example, if you have 4 frames of animation, and want to switch every 8 frames:

Code: Select all

lda frameCounter
lsr
lsr
lsr ; A = frameCounter / 8
and #3 ; A = A % 4
; A is now either 0,1,2,3 and will change every 8 frames.
I don't do this for most of my objects, because I usually want different timings besides ones that line up with 4/8/16 etc. but I still find it's a useful alternative in some cases.
casprog wrote:Is this a common approach to timing? I figure the NMI will fire roughly 60 times a second so I can piggyback off that?

In Allegro and SDL I would get the current time and compare if the elapsed time between the last movement was greater than some timing variable.
It is a very common approach to count frames in some way, and base your animation timings off of that, yes.

This is often applicable to modern games, too, if they have a fixed framerate design (e.g. fighting games almost always do this). Choosing a fixed vs. variable framerate makes a big impact on a game's design, but with NES normally a fixed framerate approach is presumed.
Post Reply