Page 20 of 109

Posted: Thu Sep 01, 2011 7:03 pm
by Jarhmander
unregistered (a few pages back) wrote:Thank you all for the honest and helpfull advice. Scrolling will be ok for me to attempt, I think, because there are two big thick books that remind me of programming with Torque, a 3D game engine. It was a hard and immensly difficult task, but God was there with me and he helped me figure it out. :D We made an A and I got credit for an internship for that class! :) My mom helped me remember the last part of that. I think I can do this scrolling... my sister helped me to find this Nerdy Nights scrolling article. And it has made some sense so far... I've made it to the drawing new columns part. Will read this again after supper.
unregistered wrote:I'm sorry for saying some of the code that you spent valuable time typing out for me was a waste. My sister helped me understand my mistake but I asked her too late. Ok. Thank you for your response tokumaru. Have a good night. :)
You've got a quite interesting family!

Posted: Fri Sep 02, 2011 10:12 am
by unregistered
3gengames wrote:Well, start making parts of the entire system. Stuff like background collision
Thank you 3gengames. :) :D Found this thread; it was my starting place to learn about background collision.

http://nesdev.com/bbs/viewtopic.php?t=7 ... +collision
tokumaru wrote:I'm not gonna lie to you, this will be hard to get right. This is the part where your little NES program stops being a playground and starts becoming a game. At this point, everything you program needs to be more robust and integrated, everything must be a "system", rather than just random blocks of code with immediate results on the screen. This is serious business.
This sounds like fun. :) The posts you mentioned/linked are so great! Thank you tokumaru! :D
~J-@D!~ wrote:You've got a quite interesting family!
Thank you! :D I love them all so very much!

Posted: Mon Sep 05, 2011 8:24 am
by unregistered
tokumaru wrote:Considering that there are usually several objects that need collision tests against the background, the time taken to do this will easily be more than 20 scanlines, so that fact that this HAS to be done outside of VBlank is not even up for discussion.
Ok, so collision should be done outside of VBlank. Does this mean collision code should go in to the empty loop that "; Transfers control to the VBLANK routines"?

Posted: Mon Sep 05, 2011 9:54 am
by tokumaru
unregistered wrote:Does this mean collision code should go in to the empty loop that "; Transfers control to the VBLANK routines"?
Not necessarily. If you currently have your whole engine running in the NMI (which I assume you do, since you have an empty loop), just be sure to run the collision code after the VRAM updates (i.e. sprite DMA, name table updates, setting the scroll, etc.).

The NMI fires as soon as VBlank starts. Since VBlank is quite short, you can't waste time doing tasks that could be performed outside of VBlank, so you should rush to the video updates and get them done as soon as possible. THEN you do the other stuff, such as music, collision and all other game logic.

It does feel kinda "backwards", but since you are doing it all inside the NMI then there's no other way.

Posted: Mon Sep 05, 2011 9:58 am
by 3gengames
It's not so backwards if you think of it as preprocessing and thinking of it like you're doing next frame's work now.

Posted: Mon Sep 05, 2011 12:10 pm
by tokumaru
That's why I said "kinda" backwards. What's more confusing to a newbie, IMO, is that the first time the NMI runs there are no updates to do, because the frame logic hasn't run yet. To work around that you have to implement a "FrameReady" or "FirstFrame" flag, to skip the first session of VRAM updates.

Posted: Mon Sep 05, 2011 12:21 pm
by 3gengames
I just preprocess the first frame of my game myself, turn on the screen/nmi when it hits and is ready, and then hits the groun running, no variables needed. See, unregistered, there's many ways to go about everything. Youcan do different tests on mini programs and find what works best for you and the mini programs will really help you get a better understanding each one. :)

Posted: Mon Sep 05, 2011 12:42 pm
by tepples
tokumaru wrote:the first time the NMI runs there are no updates to do, because the frame logic hasn't run yet. To work around that you have to implement a "FrameReady" or "FirstFrame" flag, to skip the first session of VRAM updates.
You have to do that anyway in an NMI-driven game engine in case your game logic runs over 27 kcycles.

Posted: Wed Sep 07, 2011 2:30 pm
by unregistered
tokumaru wrote:
unregistered wrote:Does this mean collision code should go in to the empty loop that "; Transfers control to the VBLANK routines"?
Not necessarily. If you currently have your whole engine running in the NMI (which I assume you do, since you have an empty loop)
What normally would go into the empty loop? Are there any downsides to having a whole engine running in the NMI?

Posted: Wed Sep 07, 2011 3:27 pm
by tokumaru
unregistered wrote:What normally would go into the empty loop?
There are 3 main ways to set up NES programs:

1. Game logic in the main loop, video and audio updates in the NMI:
The whole game logic (i.e. movement, collisions, etc.) is in the main loop, and once it finishes the program waits for the NMI to fire. When it fires, it performs all the necessary video and audio updates, and then control is returned to the main loop, where the next frame will be processed.

2. Game logic and video and audio updates in the main loop, the NMI only sets a flag:
The whole game logic is in the main loop, and once it finishes the program waits for VBlank. The NMI will simply set a flag to indicate that VBlank has started and then return, at which point the main loop will proceed to perform video and audio updates and loop back to process the next frame.

3. Video and audio updates and game logic in the NMI, the main loop is empty:
Video and audio updates based on the previous frame are performed first, and then the game logic of the following frame is calculated. Absolutely nothing is done in the main loop. This is considered the most newbie-friendly method because the programmer doesn't have to worry about 2 "threads" running in parallel, and the NMI automatically firing 60 (or 50, if it's a PAL NES) times per second is a very convenient way to time the program without any effort (i.e. no need to wait for VBlank).
Are there any downsides to having a whole engine running in the NMI?
Yes, if you have raster effects timed from the start of the frame (such as a status bar). Methods 2 an 3 suck for handling cases when the game logic takes too long (i.e. longer than a frame) to complete and you have such effects. Unpleasant visual glitches and music slowdown are the side effects of this (the program can even crash if sprite 0 hits are involved). Method 1 is the best to avoid these problems.

Simple games will hardly use too much CPU time unless they are very badly programmed, but complex games with scrolling, large number of active enemies, and so on, will certainly have a few sections with slowdown, and this is an issue for them.

Posted: Wed Sep 07, 2011 5:57 pm
by unregistered
tokumaru wrote:
unregistered wrote:What normally would go into the empty loop?
There are 3 main ways to set up NES programs:

1. Game logic in the main loop, video and audio updates in the NMI:
The whole game logic (i.e. movement, collisions, etc.) is in the main loop, and once it finishes the program waits for the NMI to fire. When it fires, it performs all the necessary video and audio updates, and then control is returned to the main loop, where the next frame will be processed.

2. Game logic and video and audio updates in the main loop, the NMI only sets a flag:
The whole game logic is in the main loop, and once it finishes the program waits for VBlank. The NMI will simply set a flag to indicate that VBlank has started and then return, at which point the main loop will proceed to perform video and audio updates and loop back to process the next frame.

3. Video and audio updates and game logic in the NMI, the main loop is empty:
Video and audio updates based on the previous frame are performed first, and then the game logic of the following frame is calculated. Absolutely nothing is done in the main loop. This is considered the most newbie-friendly method because the programmer doesn't have to worry about 2 "threads" running in parallel, and the NMI automatically firing 60 (or 50, if it's a PAL NES) times per second is a very convenient way to time the program without any effort (i.e. no need to wait for VBlank).
Are there any downsides to having a whole engine running in the NMI?
Yes, if you have raster effects timed from the start of the frame (such as a status bar). Methods 2 an 3 suck for handling cases when the game logic takes too long (i.e. longer than a frame) to complete and you have such effects. Unpleasant visual glitches and music slowdown are the side effects of this (the program can even crash if sprite 0 hits are involved). Method 1 is the best to avoid these problems.

Simple games will hardly use too much CPU time unless they are very badly programmed, but complex games with scrolling, large number of active enemies, and so on, will certainly have a few sections with slowdown, and this is an issue for them.
tokumaru, wow, you could write an NES book! :D Thank you so much for all of this info! I'm going to try Method 1. :) Does Method 1 have an empty loop in it where it waits for NMI?

Posted: Wed Sep 07, 2011 7:26 pm
by tokumaru
unregistered wrote:tokumaru, wow, you could write an NES book!
Nah, I get things wrong more often than I'd like! =)
Does Method 1 have an empty loop in it where it waits for NMI?
It often uses a flag to indicate that the frame calculations are done and the data necessary for VRAM updates is ready. The main loop will look something like this:

Code: Select all

	;initialize the flag to "false"
	lda #$00
	sta FrameReady

MainLoop:

	;DO THE GAME LOGIC HERE

	;indicate that the frame calculations are done
	dec FrameReady

WaitForUpdates:

	;wait for the flag to change
	bit FrameReady
	bmi WaitForUpdates

	jmp MainLoop
And the NMI will be similar to this:

Code: Select all

NMI:
	;skip the video updates if the frame calculations aren't over yet
	bit FrameReady
	bpl SkipUpdates

	;PERFORM VIDEO UPDATES HERE

	;modify the flag
	inc FrameReady

SkipUpdates:

	;PERFORM TASKS THAT MUST BE PERFORMED EVEN
	;WHEN THE FRAME IS NOT READY, SUCH AS UPDATING
	;THE MUSIC OR DRAWING A STATUS BAR

	;return from the NMI
	rti
I'm using "FrameReady" as a boolean variable here ($00 = false, $ff = true), but you can implement this logic differently if you want.

Posted: Thu Sep 08, 2011 12:41 pm
by tepples
tokumaru wrote:
unregistered wrote:tokumaru, wow, you could write an NES book!
Nah, I get things wrong more often than I'd like! =)
Don't worry: if you make the book on Wikibooks, other people will have a chance to fix what you get wrong.

Posted: Thu Sep 08, 2011 4:07 pm
by unregistered
tokumaru wrote:
unregistered wrote:tokumaru, wow, you could write an NES book!
Nah, I get things wrong more often than I'd like! =)
Ah, ok. :)
tokumaru wrote:And the NMI will be similar to this:

Code: Select all

NMI:
	;skip the video updates if the frame calculations aren't over yet
	bit FrameReady
	bpl SkipUpdates

	;PERFORM VIDEO UPDATES HERE

	;modify the flag
	inc FrameReady

SkipUpdates:

	;PERFORM TASKS THAT MUST BE PERFORMED EVEN
	;WHEN THE FRAME IS NOT READY, SUCH AS UPDATING
	;THE MUSIC OR DRAWING A STATUS BAR

	;return from the NMI
	rti
I'm keeping jsr react_to_input in the video updates because the video may be changed by the controller. Is that right? : )

Thanks for the awesome example code tokumaru! :D

Posted: Thu Sep 08, 2011 6:05 pm
by tokumaru
unregistered wrote:I'm keeping jsr react_to_input in the video updates because the video may be changed by the controller. Is that right? : )
I think it makes more sense to put it at the start of the main loop. After all, the way your game reacts to input is part of the game logic. In a way, EVERYTHING in the game affects the video, and that's why you run all the game logic first, to prepare everything for the video updates that will follow.