Engine Optimization / Preventing Slowdown ?

SuperNatetendo

New member
Okay, so I'm at a loss here -

I'm trying to think of good ways to get more objects on screen with less slowdown. Specifically projectiles. I've simplified their Tile Collision to only a few points. But it doesn't gain me that much.

FrankenGraphics mentioned you could save time by only checking for collisions when at certain x or y coordinates, but I don't know ASM well enough to implement such a change.

Is there any other memory hogs that one could look into that could be removed/reworked for my single screen game?
 
Well tahat depends on the game. If your doing a adventure game top bottom. Remove the scrolling bit of that engine. What are you making ?
 
For the player side and monster side I may have an idea. it involves the ammo and charger code that dale uses I used it to prevent the player from shooting to much. for the monster you can setup delays in the action steps so that they can be timed to shoot every 10 seconds or 7 or however long, not sure the limit.
 

SuperNatetendo

New member
Gilbertmaxter said:
For the player side and monster side I may have an idea. it involves the ammo and charger code that dale uses I used it to prevent the player from shooting to much. for the monster you can setup delays in the action steps so that they can be timed to shoot every 10 seconds or 7 or however long, not sure the limit.

See, my problem is not that I'm having trouble limiting projectiles. It's that I DON'T want to limit them and instead want to modify the engine to be able to handle the increase in objects.
 

SuperNatetendo

New member
Gilbertmaxter said:
but there has to be a limit though I keep hearing that the nes has a object limit of 8 I thought.

It doesn't. Bubble Bobble for example was a game that had quite a few objects on screen. Very simple game, though. No, NESmaker's engine has a 10ish object limit, I know that.

It's really about how much you can tell the CPU to do.
 

FrankenGraphics

New member
You can keep hundreds of objects if you make them simple enough. It's mostly the matter of limited RAM resources. Dedicating more than a page (256 bytes) to all your game objects is probably not sensible.

Then, decide how many bytes you need to describe an object. NESmaker uses a whopping 37 bytes per objects, because uniformity is more important when designing an easy to use interface than efficiency. So at 6 objects, you're within a page. at 7 objects, you're using more than a page. This is not critical, i think, but at some point you'll start overflowing into other ram vars you need which will cause bugs that are sometimes hard to detect. So don't set max objects too high!

If you use aimed projectiles, a screen of 6-7 objects will slow down either way, so..

A more usual approach when designing a more specific-purpose action engine is keeping at least two tiers of object complexity (both how many bytes you need to describe it, and how much handling each object requires from frame to frame).
The platforming module has a sort of tacked-on special object case for projectiles, from what i can tell.
 

SuperNatetendo

New member
FrankenGraphics said:
You can keep hundreds of objects if you make them simple enough. It's mostly the matter of limited RAM resources. Dedicating more than a page (256 bytes) to all your game objects is probably not sensible.

Then, decide how many bytes you need to describe an object. NESmaker uses a whopping 37 bytes per objects, because uniformity is more important when designing an easy to use interface than efficiency. So at 6 objects, you're within a page. at 7 objects, you're using more than a page. This is not critical, i think, but at some point you'll start overflowing into other ram vars you need which will cause bugs that are sometimes hard to detect. So don't set max objects too high!

If you use aimed projectiles, a screen of 6-7 objects will slow down either way, so..

A more usual approach when designing a more specific-purpose action engine is keeping at least two tiers of object complexity (both how many bytes you need to describe it, and how much handling each object requires from frame to frame).
The platforming module has a sort of tacked-on special object case for projectiles, from what i can tell.

I'm dreading creating a separate class for projectiles, but it's seeming more and more that that's exactly what I have to do.

Today I was messing about in the Memory Map ASM to see if I could do what Kasumi had suggested to me in a previous thread.

Quote:

Kasumi said:
Your game seems to be using $0700-$0702 for something. Whatever it is, it probably isn't too difficult to move.

So in GameData/Object_RAM.asm are all the defines for object RAM. NameOfByte .dsb totalnumberofobjects. What you should do (and, indeed, what NES Maker should do) is change every ".dsb 10" to ".dsb TOTAL_MAX_OBJECTS". Then by changing TOTAL_MAX_OBJECTS from #$0A to something else (like say #$10, or #16), all of the defines will be updated at once. (But don't change it to #16 yet.)
Before:
Code:
TOTAL_MAX_OBJECTS = #$0a

Object_status .dsb 10
Object_type .dsb 10
Object_physics_byte .dsb 10
Object_x_hi .dsb 10
Object_x_lo .dsb 10
Object_y_hi .dsb 10
Object_y_lo .dsb 10
;etc
After:
Code:
TOTAL_MAX_OBJECTS = #$0a

Object_status .dsb TOTAL_MAX_OBJECTS
Object_type .dsb TOTAL_MAX_OBJECTS
Object_physics_byte .dsb TOTAL_MAX_OBJECTS
Object_x_hi .dsb TOTAL_MAX_OBJECTS
Object_x_lo .dsb TOTAL_MAX_OBJECTS
Object_y_hi .dsb TOTAL_MAX_OBJECTS
Object_y_lo .dsb TOTAL_MAX_OBJECTS
;etc
That will make zero difference in your ROM, so no need to test.

However, all the RAM you need isn't contiguous. Some of the RAM the objects will use is at $0400-$05FF and some of it will be moved to $0700-$07FF. If you changed TOTAL_MAX_OBJECTS to 16 before moving some of the RAM, it would use 16*37 bytes and go beyond $05FF.

There are 256 bytes from $0700 to $07FF. If you had 16 objects (which is the goal), you'd need 16 bytes for every DSB. So it follows that you can fit 16 object DSBs in $0700-$07FF, because 256/16=16.

So you need to move 16 of those defines (it doesn't matter which 16) to $0700. (16 defines, 16 bytes each is 256 bytes, which will fit perfectly in $0700-$07FF.) Which is (for now) as simple as adding .enum $0700 above Object_table_lo_lo:
Code:
.enum $0700
Object_table_lo_lo .dsb TOTAL_MAX_OBJECTS
Object_table_lo_hi .dsb TOTAL_MAX_OBJECTS
Object_table_hi_lo .dsb TOTAL_MAX_OBJECTS
Object_table_hi_hi .dsb TOTAL_MAX_OBJECTS
;etc
(But this will break your game, since it seems you're using $0700-$0702. Did you add something? Are you able to move what you're added anywhere else? Alternatively, start the enum at the next free byte you haven't used ($0703?) and move only 15 DSBs instead of 16.)
Now. TEST! This alone shouldn't break anything (except for the $0700-$0702 thing which you have to find some way to deal with). If it works, just change
Code:
TOTAL_MAX_OBJECTS = #$0a
to
Code:
TOTAL_MAX_OBJECTS = #16
And TEST! This should only cause problems if NES Maker is using 10 or $0A instead of TOTAL_MAX_OBJECTS somewhere other than these defines. Which... it shouldn't? But it might.

Edit: Oh, something else to be aware of. 16 objects at four sprites each is 64 sprites. I don't actually know what NES Maker does when you go over or hit it exactly, but that's another potential issue.

Unfortunately, I had no success with this method and it just messed up my game and had a bunch of lovely colorful glitches.

Essentially, I'm going to have to get really handy with ASM in order to make this happen. Or rather, if I'm going to make a competent version of my demo that has 2 player co-op. Hopefully I'll make some headway into it soon. For now, I have my rather odd optimization for gravity based objects which I'll post here.
 

SuperNatetendo

New member
Something that seems to make my game run faster and I'm not really even sure how -

Put at the top of the "CheckForVerticalEjection" macro:

Code:
MACRO CheckForVerticalEjection

	LDA Object_y_hi,x
	CLC
	ADC Object_bottom,x
	STA temp
	
	LDA Object_y_hi,x
	CLC
	ADC Object_top,x
	STA temp2
	
	LDA temp
	EOR temp2
	AND #$08
	BEQ +
	JMP doneEjecting
	+

Did a similar thing for HandleHoriztonalCollision:

Code:
MACRO CheckForHorizontalCollision
	
	LDA Object_x_hi,x
	CLC
	ADC Object_left,x
	AND #$04
	BEQ +
	JMP doneWithHorColCheck
	+

Honestly, the code is so ridiculous, because it was meant to be somewhat relevant to your suggestion, FrankenGraphics, but I don't think it does the "only check if position is on grid" thing. I think it's something quite opposite almost.

More proof I dunno wtf I'm doing.
 

FrankenGraphics

New member
I mean to review your code at some point, just pressed on time right now. Only writing to add that if you want to design a secondary object class, then there is ample room in the stack ($100).
For my project, i'm using this space to store 32 bytes of custom world state data (bitpacked - 1 shared bit per overworld/underworld screen pair). I could easily double that (and separate over- from underworld) if i needed to without risk of running into stack pointers. Seems perfect to me for a more action oriented game to use this space for a simpler object table.

Projectiles don't (and ideally for this platform shouldn't) need to be offscreen persistent. So xpos, ypos, and either one or two bytes for h / v speed respectively seems fine (depends on if you want to hook it up to the preexisting movement code or roll a separate case). maybe a properties byte, and maybe a timer. tile ID and acceleration/deceleration could be read from a small LUT derived or implied by the properties byte. It being a another class of object itself can imply things to the engine.
 
Top Bottom