Moving objects in and out of memory?
Moderator: Moderators
Moving objects in and out of memory?
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?
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?
Re: Moving objects in and out of memory?
.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.
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
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: Moving objects in and out of memory?
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:
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.
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
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: Moving objects in and out of memory?
thefox is way more advanced than me. But, tokumaru's local variables have helped me so much!
-
- Posts: 271
- Joined: Sun Mar 27, 2011 10:49 am
- Location: Victoria, BC
Re: Moving objects in and out of memory?
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.
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.
Re: Moving objects in and out of memory?
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.
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
Re: Moving objects in and out of memory?
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:
The NES way
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.
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.
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
The higher level way:
Code: Select all
const int objectnum = 16;
struct object{
int xPos;
int yPos;
};
object objects[objectnum];
Code: Select all
const int objectnum = 16;
int xPos[objectnum];
int yPos[objectnum];
Code: Select all
objectnum = 16
xPos .rs objectnum
yPos .rs objectnum
Code: Select all
inc yPos,x
lda objectstate,x
Here's a long post I wrote on the subject with some more advanced methods: https://forums.nesdev.com/viewtopic.php ... ed#p152230
Re: Moving objects in and out of memory?
Wow so many great tips in such little time!
Thanks everyone!
Thanks everyone!
Re: Moving objects in and out of memory?
Do you have some resources you would recommend on the subject?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.
Re: Moving objects in and out of memory?
Funny how the fixed number of objects approach was in my head but it didn't 'feel' right to do it like that.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.
The free list idea is also a good tip!
Re: Moving objects in and out of memory?
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.
- rainwarrior
- Posts: 8732
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: Moving objects in and out of memory?
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.
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.