Moving objects in and out of memory?

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
klonoa
Posts: 76
Joined: Mon Nov 21, 2011 3:53 pm

Moving objects in and out of memory?

Post by klonoa »

Good day everyone.

After A year of school I thought I'd give programming for the nes another shot.
So far it's been going very good. Got some basic moving sprites and backgrounds.

I want to make a simple horizontal shooter but i'm kinda stuck on the following:

Say I spawn an enemy ship, I set some values using the .rs directive in nesasm to reserve some space in ram to hold it's height and width etc.
Now say that ship gets hit by a bullet and gets destroyed, how do I free up that memory that I have reserved for that ship?

It might be obvious that I'm coming from and object-oriented world and I'm basically missing my c++ new and delete statements.

I have the feeling i'm thinking all wrong, any advice for this noob?
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Re: Moving objects in and out of memory?

Post by thefox »

.rs is equivalent to making it a global (or static) variable in C++. So you cannot free it.

What's usually done is to allocate some fixed number of objects (say 20, or 32), each with a fixed number of state bytes (e.g., 8). There should be a byte in the state that indicates what the type of the object is (e.g., an "enemy ship", or a "bullet", or "unused"). Then, when you want to allocate a new object, you scan the object list for a free object and set it to the desired type. In your object handling code you scan through the list and call appropriate handlers (based on object type) for each item in the list. When you want to destroy the enemy ship (or whatever), you'd set the object type back to "unused".

You can speed this up by using a "free list", basically a linked list of free object slots. This means you don't have to scan through the whole list to find a free object, you can just pick one from the end of the linked list.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: Moving objects in and out of memory?

Post by unregistered »

Hi klono,

Um, I've never used nesasm but, from my experience with assembly language, variables (groups of bytes in RAM) can be declared before you assemble your game. After assembly, I don't believe it's possible to destroy a variable or create a new one. However, tokumaru told me how he uses temporary variables. To create a temporary variable:

Code: Select all

;your variable declaration section in zeropage goes here
;afterwards
LocalVariables4vblank
LocalVariables4scrollland
;etc.

;then in my vblank file (I'm using the asm6 assembler)
.enum LocalVariables4vblank
  tE .dsb 2
  t14 .dsb 2
.ende
Then tE can be used anywhere below that variable declaration section. Caution: Lets say your zeropage variables end with $0082. That would cause all of the LocalVariables4 labels to be initialized to #$0083. Therefore, tE would be assembled at locations $0083 and $0084 (because my temporary variables all have a size of 2 bytes... that's just me, feel free to use whatever size you want... it's your game. :)). The tempory (local) variables should only be used when you do not require the value at a later frame, or even for a short while because many, I guess, other local variables will be assigned seats at those same memory locations and so the value may vanish whenever a store to that memory location is processed. (The value wouldn't vanish if the store, sta stx or sty, assigned the exact same value to that memory location.) Hope this helps you. :)
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: Moving objects in and out of memory?

Post by unregistered »

thefox is way more advanced than me. :) But, tokumaru's local variables have helped me so much! :mrgreen: :D
adam_smasher
Posts: 271
Joined: Sun Mar 27, 2011 10:49 am
Location: Victoria, BC

Re: Moving objects in and out of memory?

Post by adam_smasher »

thefox's post is very good, listen to it.

if you'd like to deepen your understanding a little bit, one thing that might be worth thinking about is that there's nothing especially "magical" about new and delete in C++; they aren't that different from malloc() and free() in C, which are just ordinary library functions that run ordinary code. All they're doing (ignoring some details around modern operating systems and memory protection and stuff) is managing chunks of memory in an address space. It might be edifying to consider and research how and why they're implemented the way they are, and what are some of the pros and cons of them vs other memory management strategies.
User avatar
dougeff
Posts: 3079
Joined: Fri May 08, 2015 7:17 pm

Re: Moving objects in and out of memory?

Post by dougeff »

One thing. You can access objects faster in asm if you make each attribute a separate array. So, rather than an array of objects (with x,y,type,state,etc)...you have an array of x's, an array of y's, an array of types, etc.

You load the object number into the X register, and you can access it's attributes by using X as the index to each array. LDA x_array, X. Do something. LDA type_array, X.

BTW, I don't do this myself, but I've seen others do this.
nesdoug.com -- blog/tutorial on programming for the NES
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Re: Moving objects in and out of memory?

Post by Kasumi »

Basically you create an object "class". Say it has xPos, and yPos only for simplicity. In a higher level language you'd create an array of class objects. On NES it's better on the CPU to create an array of each element.
The higher level way:

Code: Select all

const int objectnum = 16;
struct object{
	int xPos;
	int yPos;
};
object objects[objectnum];
The NES way

Code: Select all

const int objectnum = 16;
int xPos[objectnum];
int yPos[objectnum];
Unlike a higher level thing, it's best to just have a fixed maximum number of objects. If you want a maximum of 16 objects with 16 elements, that's 256 bytes.

Code: Select all

objectnum = 16
xPos .rs objectnum
yPos .rs objectnum
To access their RAM, you have their object number in either X, or Y, and access their element using ,y or ,x addressing like so.

Code: Select all

inc yPos,x
lda objectstate,x
If you have a byte that says whether or not they're alive, on a really basic level you could have a type byte. If type is say... equal to zero, it means the object is dead. So destroying an object is as simple as storing zero to its type byte. (Maybe zeroing out the rest of its RAM as well.) Creating an object is as simple as looking for an object number that has a type byte equal to zero, and then changing the type byte of that object to the type of object you want to create. (And initializing its RAM to a state that type of object expects.)

Here's a long post I wrote on the subject with some more advanced methods: https://forums.nesdev.com/viewtopic.php ... ed#p152230
klonoa
Posts: 76
Joined: Mon Nov 21, 2011 3:53 pm

Re: Moving objects in and out of memory?

Post by klonoa »

Wow so many great tips in such little time!
Thanks everyone!
klonoa
Posts: 76
Joined: Mon Nov 21, 2011 3:53 pm

Re: Moving objects in and out of memory?

Post by klonoa »

adam_smasher wrote:thefox's post is very good, listen to it.

if you'd like to deepen your understanding a little bit, one thing that might be worth thinking about is that there's nothing especially "magical" about new and delete in C++; they aren't that different from malloc() and free() in C, which are just ordinary library functions that run ordinary code. All they're doing (ignoring some details around modern operating systems and memory protection and stuff) is managing chunks of memory in an address space. It might be edifying to consider and research how and why they're implemented the way they are, and what are some of the pros and cons of them vs other memory management strategies.
Do you have some resources you would recommend on the subject?
klonoa
Posts: 76
Joined: Mon Nov 21, 2011 3:53 pm

Re: Moving objects in and out of memory?

Post by klonoa »

thefox wrote:.rs is equivalent to making it a global (or static) variable in C++. So you cannot free it.

What's usually done is to allocate some fixed number of objects (say 20, or 32), each with a fixed number of state bytes (e.g., 8). There should be a byte in the state that indicates what the type of the object is (e.g., an "enemy ship", or a "bullet", or "unused"). Then, when you want to allocate a new object, you scan the object list for a free object and set it to the desired type. In your object handling code you scan through the list and call appropriate handlers (based on object type) for each item in the list. When you want to destroy the enemy ship (or whatever), you'd set the object type back to "unused".

You can speed this up by using a "free list", basically a linked list of free object slots. This means you don't have to scan through the whole list to find a free object, you can just pick one from the end of the linked list.
Funny how the fixed number of objects approach was in my head but it didn't 'feel' right to do it like that.
The free list idea is also a good tip!
User avatar
Sumez
Posts: 919
Joined: Thu Sep 15, 2016 6:29 am
Location: Denmark (PAL)

Re: Moving objects in and out of memory?

Post by Sumez »

Here's a shorter answer. You don't "free up memory", you just stop refering to it, and then when another object needs it, you initialize it with the values for that object.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Moving objects in and out of memory?

Post by rainwarrior »

There are some cases where you might want to reuse/reassign a static allocation, like if your game changes to a different mode.

If you know they're never going to be needed at the same time, you can still reassign the same memory statically. There's no encapsulation or type safety here, if you .rs a byte of memory, that's a byte you can use any way you want, and you can give the same byte many names/labels.

In NSEASM you can use .rsset to reset the .rs reservations to the address you want to overlap, and then create a new set of reservations on top. In CC65 you could do something similar with overlapping segments. Or you can just directly create an alias for an old reservation, if that's convenient ("new_name = old_name").

When doing this, though, you should probably have a clear plan of how you want to lay out memory. Know what's supposed to be "global" and survives the mode switch, and what isn't. Have a good idea of how much space each should take up, and maybe leave some extra room just in case you need it later. Though, this is something you might want to think about even if you're not trying to overlap stuff. If RAM is scarce it pays to manage your RAM budget. ;)
Post Reply