This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Object update order

Object update order
by on (#171607)
The order in which game objects are updated can affect the way objects interact with each other. Ideally, each object's A.I. will run only once per frame, so we can assume that objects that can affect others (mainly their position, but other attributes too) should be updated first. Moving platforms, for example: if the player is standing on a moving platform and the platform is updated first, all the player's A.I. has to do is apply the same displacement that was applied to the platform, before running its regular physics code.

But what about objects that can affect each other, such as enemies and the player, that can hurt each other? Depending on who's updated first, there may be a 1-frame delay before a collision between them is handled. This is not such a big problem, the only side effect is that sometimes we see the objects overlapping for a frame and sometimes we don't, and that's hardly noticeable.

There are more complicated cases, such as blocks that can be pushed by the player but can also carry the player. When the player is pushing the block, the player's A.I. should run first, so the block can copy its displacement. When the player is riding the block, however, it's the player that has to copy the block's displacement.

In my engine, I have a number of object groups that I update in order, so I can handle the block issue by moving the block between different groups depending on its state, this is fast and not such a big deal.

I do wonder how other programmers handle these issues, though. Do you visit objects more than once? Do you update objects out of order when necessary? What are other possible solutions to handle object interactions?

Note that some of the problems I presented above exist only because I'm trying to program objects in a way that only the object itself can alter its state. Objects can consult the state of other objects, but they can't change anything. That's a way to keep each object's code centralized, but I'm not sure that's the most accurate model of the real world, though... When an object pushes another, it does in fact modify that object's position, regardless of what it's doing.
Re: Object update order
by on (#171610)
Now isn't this a familiar conversation!

I spend a lot of time wondering about this myself, but I have pretty limited experience with applying this to actual NES games. I've been theorizing about an object handling routine that visits each object more than once, but uses different logic each time. This is largely based on conversations in the thread I linked, what with the 'inbox' variables that Kasumi talked about. But until I apply it I'd just be talking out of my ass, so I'll hang back and see who has interesting ideas here.
Re: Object update order
by on (#171615)
Interesting to see that discussion made you think about the issue a bit more as well.

I figured you guys would know best when it comes to objects modifying one anothers' positions. I haven't done this yet, but I thought about it some more since we talked about it. I would think you would need to treat these more like BG collisions than object collisions, meaning to check them right after object movement and before executing any other logic.

If they are two solid objects which eject one another, but also cause damage upon collision, then I'd think one of the objects would need to be accepted as a valid position. The simplest example would be to say that only player positions get corrected by objects. Any non-player objects, like enemies, and moving platformers, are only subject to BG collisions.

I think you'd first need to move these "infallible" objects, without performing object collisions. Then, during your player logic, apply movement, check object collisions, set flags for the damage you'll need to process, eject from object collisions, then check BG collision and eject from those second.

I'm a little unclear about whether or not this causes the possibility of two objects overlapping at the end due to 1. colliding with one another, ejecting player into wall 2. ejecting from wall back over enemy. If so, then that seems to me the logical route versus overlapping the wall. I would think though, that if you separate object collisions into X and Y axis, like BG collisions, then it may solve that issue.

This however, doesn't cover enemies riding platforms. So I think platforms would need a different object type. That would be an optimization also, since the platforms won't need a lot of the logic enemies will. They may not even need BG collisions, depending on how you program them.

Now the box you can ride and pick up creates an interesting paradox. One on hand, it's an infallible platform, and on the other hand, it's modified by player position. If it's carried by the player, it needs to share the player's velocity in any given frame. If it's one you can throw, then it needs to check against enemies and cause collisions with them, so in that case, the enemy becomes the infallible object.

I'd think I'd probably try having the box become a different type of object when it's lifted. So, that would create four object types, and I think they could be handled in this order:

1. "Infallible" Platforms - objects which players and enemies can stand on, not subject to movement from any collisions, probably not subject to BG collisions
2. Enemy Objects - check against platforms and BG
3. Player Objects - check against platforms, enemies, and BG, set values for moveable objects
4. Moveable Objects - check against platformers, enemies, and BG

I would think the reasoning behind only allowing an object to modify itself is so any movements are corrected by collision, as well as the objects' state being corrected. With this model, I don't think you'd have a problem with that. The moveable objects (things being carried) would need to be set, not to the velocity variable of the player carrying it, but rather the actual number of pixels it moved that frame. So it seems it must come after the player. It can still make all of these movements inside of its loop though.

I see a couple possible issues though. One is a matter of how you want to carry objects. If they are carried in front of the player, the carried object won't test against backgrounds until it's too late. If you're carrying the box above your head, this model would work well for game rules where in the box above your head falls behind the character when they go under a ceiling which is too low. If a method of stopping player movement entirely is preferred, then there would be issues. Modifying the player's hitbox size to the size of the carried object would create problems. Specifically, the carried object would then cause the player to take damage when contacting an enemy. You may prefer it to be immune to damage or maybe even hurt the enemy.

Ultimately, thinking about this topic more thoroughly has brought me to believe it's more complex than one may think at first glance, and is most likely largely dependent on game rules. Perhaps someone with more experience would have a more concrete answer, but I hope my thoughts on the matter may at least encourage brainstorming on the matter.

One thought that I have on the general topic of update orders and collisions is that it's most efficient to check collisions from your longest object list. If I'm checking collisions from 1 player vs. 32 bullets, I have to have a loop to run through all 32 bullets, and a way of verifying which bullets are active. These steps are already covered in the logic loop for the bullets themselves, so collision checking from 1 bullet to 1 player (or 2 players) becomes a simple unrolled routine that executes for any bullet that survives to the end of its own movement loop. I'm not sure though, if that can be juggled inside of the platform/carry object paradox you proposed, however.
Re: Object update order
by on (#171641)
I have some experience in this area, both on the NES, and in other forms of programming.

I tend to keep each "type" of object, split into standard groupings:
1 = The Player
2 = Objects (Blocks, Platforms)
3 = Monsters
4 = Particles/Effects

The first use of this organization, is that I can more easily sort them when updating the OAM, so particles will flicker first, before monsters, then objects, and eventually the player, in the worst-case scenario. It's all a juggling act.

The second use of this, allows me to use bit-flags during object-processing, for dynamic object interaction. The player moving an object in the map, or standing on a moving enemy/platform, for example.

For the record-- I check object/background collision before updating object logic, because with some clever optimizations, it's considerably faster than processing things the other way around.
Re: Object update order
by on (#171647)
tokumaru wrote:
I do wonder how other programmers handle these issues, though. Do you visit objects more than once? Do you update objects out of order when necessary? What are other possible solutions to handle object interactions?

Don't forget the option of an object directly affecting another. (EDIT: oh right you don't do that >_> but it's the common approach in older games) E.g. in the moving platform example, chances are when the platform moves it will apply its displacement on the player as well (rather than waiting for the player object to do it). Yeah there's the issue of going through walls, but if your physics engine checks for collisions always (even when your momentum is 0) it may just self-correct itself the next frame when it notices a collision against a wall and pushes you out. Or you could just add the displacement by invoking the physics engine itself, that is (if you have enough CPU time to spare for it, and if movement is in just one axis then it may be simplified).

Of course if you go the data-oriented programming way then you don't let objects modify neither others nor themselves like that, the physics code is a separate step from object behavior =P (there's still the worry about when a collision response causes yet more collisions to be handled)
Re: Object update order
by on (#171648)
tokumaru wrote:
In my engine, I have a number of object groups that I update in order, so I can handle the block issue by moving the block between different groups depending on its state, this is fast and not such a big deal.

Just out of curiosity, are you using linked lists for your object groups?
Re: Object update order
by on (#171650)
thefox wrote:
Just out of curiosity, are you using linked lists for your object groups?

Yes. I have functions for adding and removing objects to/from each group:

Code:
   ;add the object to a group of objects
   lda Object::FirstObjects+Group
   sta Object::InstancesNext, x
   stx Object::FirstObjects+Group
   rts

Code:
   ;remove the object from a group of objects
   lda Object::InstancesNext, x
   ldy Object::Previous
   bmi :+
   sta Object::InstancesNext, y
   rts
:   sta Object::FirstObjects+Group
   rts

The index of the object is specified in the X register. Object::Previous is a "global" variable that contains the index of the object that was processed before the current one (it's set to $ff before the first object of each group is updated).
Re: Object update order
by on (#171653)
Guilty wrote:
Now isn't this a familiar conversation!

Indeed... I actually thought of posting this in that thread back then, but for some reason I didn't.

Quote:
This is largely based on conversations in the thread I linked, what with the 'inbox' variables that Kasumi talked about.

I really like the "message" approach. I have been thinking of ways to make it work for the various types of interactions objects need. The biggest problem I see is what I described above, that there might be a 1 frame delay before an object gets a message if I don't run its logic twice.

darryl.revok wrote:
I would think you would need to treat these more like BG collisions than object collisions, meaning to check them right after object movement and before executing any other logic.

This is my conclusion as well, which is why I decided to update solid objects that can't be pushed first, so that they act almost like background elements, and all other objects can collide with them.

Quote:
If they are two solid objects which eject one another, but also cause damage upon collision, then I'd think one of the objects would need to be accepted as a valid position. The simplest example would be to say that only player positions get corrected by objects. Any non-player objects, like enemies, and moving platformers, are only subject to BG collisions.

I know this is the case in the Sonic games. I can understand why programmers would do it like this, an with careful enemy placement this doesn't become so apparent to players, but I can't stop thinking how nice it'd be if enemies could react to dynamic barriers, moving platforms and such...

Quote:
I'd think I'd probably try having the box become a different type of object when it's lifted.

This is a good idea, better than handling the change using states and changing the update order.

Quote:
1. "Infallible" Platforms - objects which players and enemies can stand on, not subject to movement from any collisions, probably not subject to BG collisions
2. Enemy Objects - check against platforms and BG
3. Player Objects - check against platforms, enemies, and BG, set values for moveable objects
4. Moveable Objects - check against platformers, enemies, and BG

This is exactly how I was planning to use the 4 object groups I currently support (I can change the number of groups by simply changing a constant, though, if necessary).

Quote:
I would think the reasoning behind only allowing an object to modify itself is so any movements are corrected by collision, as well as the objects' state being corrected.

To me the reasoning is actually to encapsulate all the code that deals with each object, so that I can modify details about the object during development without having to go hunting for fragments of code that deal with it that might be hidden in other objects.

Quote:
With this model, I don't think you'd have a problem with that. The moveable objects (things being carried) would need to be set, not to the velocity variable of the player carrying it, but rather the actual number of pixels it moved that frame.

Yes, and this displacement is conveniently available in each object's "speed" variables. Unless the object was stopped by an obstacle, a case that would need special handling.

Quote:
Ultimately, thinking about this topic more thoroughly has brought me to believe it's more complex than one may think at first glance, and is most likely largely dependent on game rules.

True. I guess that most of the time games end up largely simplifying the model, at least back in the 8 and 16-bit days.

Quote:
One thought that I have on the general topic of update orders and collisions is that it's most efficient to check collisions from your longest object list. If I'm checking collisions from 1 player vs. 32 bullets, I have to have a loop to run through all 32 bullets, and a way of verifying which bullets are active. These steps are already covered in the logic loop for the bullets themselves, so collision checking from 1 bullet to 1 player (or 2 players) becomes a simple unrolled routine that executes for any bullet that survives to the end of its own movement loop.

Yes... I'm still thinking it having enemies collide with the player, instead of the other way around, isn't the best option.

Alp wrote:
I tend to keep each "type" of object, split into standard groupings:
1 = The Player
2 = Objects (Blocks, Platforms)
3 = Monsters
4 = Particles/Effects

How do moving platforms work with this scheme? If the player is updated before the platforms, couldn't he end up falling when a platform moves instead of following it?

Sik wrote:
in the moving platform example, chances are when the platform moves it will apply its displacement on the player as well (rather than waiting for the player object to do it).

Having objects directly modify the positions of other objects does seem like the simplest approaches in some cases, and may even be a more accurate modeling of the real world, but since a platform can carry many objects, but an object can only ride one platform, in this case it's simpler to have each object reference the one it's standing on than the other way around.
Re: Object update order
by on (#171655)
tokumaru wrote:
Having objects directly modify the positions of other objects does seem like the simplest approaches in some cases, and may even be a more accurate modeling of the real world, but since a platform can carry many objects, but an object can only ride one platform, in this case it's simpler to have each object reference the one it's standing on than the other way around.

Fair enough, but this logic can still get you out in other situations that don't seem as obvious.

Mind you, the approach of handling all physics as a separate step from object logic would probably work with your limitation of objects not modifying other objects. In fact, it may even make physics "just work" even for object combinations you didn't think on.
Re: Object update order
by on (#171663)
I'm considering allowing objects to modify another object's positions, but nothing else. Positions and bounding boxes are, as far as I can predict, universal, so this should be fairly safe to do. There might be a 1 frame delay between the object being pushed and it reacting to being pushed, but that would probably go unnoticed. Objects popping or jittering is what draws attention.
Re: Object update order
by on (#171693)
tokumaru wrote:
I'm considering allowing objects to modify another object's positions, but nothing else.

Would you modify the object's position or its velocity? If you could modify its velocity, then its movement would still be encapsulated.
Quote:
There might be a 1 frame delay between the object being pushed and it reacting to being pushed, but that would probably go unnoticed.

I was thinking about an issue with the model I described, is that an enemy will be hit by a thrown box at the end of a frame, after its been buffered. It will get the message of its collision on the next frame, and will have already acted on the player for the frame in which it was hit. My guess is that would be insignificant. Everything would still be functioning on the same frame.

I think the specific game rules make a difference. Like, can you push a box that an enemy can stand on? That would throw a wrench in the model I described. I'm kind of thinking of the item being picked up becoming a weapon.

A deliberate wait before pushing a box in a game is pretty standard for a couple reasons. It makes sense, due to inertia of the box, and helps differentiate the intentions of the player's controller input. Can the logic be worked in a way so that handling the case of a player moving a platform object is okay to "wrap" around to the next frame?

(Also, will enemies also be modifying objects? That would introduce a lot more considerations)

So just kind of brainstorming off the top of my head, I think at the end of the frame, if the player has pushed against a moveable box for 16 frames or so, send a message to move box. The next frame, box moves, and sends a message to move player. Move the player either way so the box doesn't move for an extra frame. Check controller to see if player is still pushing against the box. Control will be sent around for another loop of box movement if player is still pressing same direction.

Having the box first is pretty important actually, because you could push it into a wall. In that case, box needs to be the first one to stop movement, so it will need to check BG collisions.
Re: Object update order
by on (#171706)
darryl.revok wrote:
Would you modify the object's position or its velocity? If you could modify its velocity, then its movement would still be encapsulated.

Directly moving an object is a way to make an object that's pushed after it has already been processed not to be displayed in the wrong place. Changing the velocity after it's been processed will do nothing until the next frame, so it doesn't really fix the problem.

Quote:
My guess is that would be insignificant. Everything would still be functioning on the same frame.

Exactly. 1 frame at 60Hz is too fast for anyone to notice in a lot of cases. Positions are more troublesome because they can cause popping and jittering, which are very noticeable.

Quote:
Like, can you push a box that an enemy can stand on? That would throw a wrench in the model I described. I'm kind of thinking of the item being picked up becoming a weapon.

I think most 8 and 16-bit games have levels designed to avoid these situations, because simple engines simply can't handle that stuff.

Quote:
So just kind of brainstorming off the top of my head, I think at the end of the frame, if the player has pushed against a moveable box for 16 frames or so, send a message to move box. The next frame, box moves, and sends a message to move player. Move the player either way so the box doesn't move for an extra frame. Check controller to see if player is still pushing against the box. Control will be sent around for another loop of box movement if player is still pressing same direction.

So the game basically alternates between the player pushing the box and the box pulling the player? Seems a bit strange, but it's a way to keep the box as a single object and still working as a platform for other objects.
Re: Object update order
by on (#171708)
tokumaru wrote:
Directly moving an object is a way to make an object that's pushed after it has already been processed not to be displayed in the wrong place. Changing the velocity after it's been processed will do nothing until the next frame, so it doesn't really fix the problem.
Does your engine update the sprite buffer during the object loop?

In my previous game engine I was doing the full OAM buffer as its own routine. It was just the first way that I thought to do it. More recently I put the buffering inside of the object loops. This makes a lot of sense for things like bullets which don't have metasprite routines. However, I'm thinking about switching it back, at least for non-bullet objects, so I can handle sprite counts higher than 64 more easily.

Even if you can update the sprite buffer for the object later, moving it again sounds sticky. Other objects could possibly depend on its position. You could push a box overtop of an enemy. It wouldn't react to that until the next frame, but then the box could move again. So there would be one frame worth of overlap between a pushed box and an object it's pushing in turn.

I see a different problem with the model though. Platforms don't check against anything, so a pushed box can't stop on account of another object. That's okay if you can continue to push the other object, but what if you can't? What if it's too heavy, or you push it into a wall?

I guess an obvious solution would be to check platforms against the positions of objects last state before moving. It sounds like this model is becoming costly in processing to include so many features.

I do think though that moving an object at the end of the frame that other (already processed) objects depend on for position, is a potentially bad idea.
Re: Object update order
by on (#171735)
darryl.revok wrote:
Does your engine update the sprite buffer during the object loop?

I tried many things... First I used to process objects in random order and I updated the sprite buffer at that time. Then, when I realized I'd need to have control over the order in which objects are updated, I tried to come up with a type of sprite cycling that would still work if the objects were updated in order, and failing that I ultimately decided to split the update and drawing procedures completely, so I'm using 2 loops now.

Quote:
Even if you can update the sprite buffer for the object later, moving it again sounds sticky. Other objects could possibly depend on its position.

Hum... Say that a box has just finished its update step, and is supposedly resting at its final position. Then an enemy moves towards the box, detects the collision and ejects itself. Finally, the player pushes the block from the other side. If we allow the box to be moved, it would overlap the enemy. To catch something like this we'd have to update the box again, have it collide with objects again, so that it could push the enemy as well. Then we'd have to update the enemy again, and so on... Yeah, I guess that allowing objects to move other objects isn't a good idea at all. It solves nothing, because we still have to make the object validate the new position.

I have thought of another way to process objects, but haven't thought of all the implications yet:

1- Handle any messages the object may have received LAST frame;
2- Put the object in the drawing queue, using the current position and metasprite;
3- Handle any messages the object may have received THIS frame;
4- Process physics and collisions, send messages as necessary;

This would cause the previous state of the objects to be displayed on the screen (i.e. there'd be a 1-frame input lag), but all messages would be processed before the object was displayed, ensuring that the displayed state is always stable. Not that I have any RAM left for a drawing queue, though!
Re: Object update order
by on (#171749)
I am reminded of a devblog/LP which addresses moving platforms and stacked objects in this post, kinda.
Re: Object update order
by on (#171798)
I'm not sure I understand how you guys are setting up your objects. Currently I just have $0400 dedicated to object data, and each object begins with a byte declaring its type, then four bytes for its coordinates, then four bytes for velocities, then whatever additional stuff the object may need. Objects are ticked in the order they appear in RAM. I've never given any thought to it outside of that though... what is this linked list deal? Is that less RAM intensive or something? What's the implementation there...?
Re: Object update order
by on (#171801)
Guilty wrote:
Currently I just have $0400 dedicated to object data, and each object begins with a byte declaring its type, then four bytes for its coordinates, then four bytes for velocities, then whatever additional stuff the object may need. Objects are ticked in the order they appear in RAM.

This approach probably works for simpler games, but there are some things that simply can't be done with this setup.

I currently have 24 object slots, each containing 32 bytes of attributes:

- type (1 byte);
- next object (1 byte); (next empty slot or next object in the same group)
- logic routine index (1 byte);
- X coordinate (3 bytes);
- Y coordinate (3 bytes);
- X speed (2 bytes);
- Y speed (2 bytes);
- angular speed (2 bytes);
- angle (1 byte);
- slope threshold (1 bytes); (used when walking off ledges)
- link to related object (1 byte);
- bounding box index (1 byte);
- pattern offset (1 byte); (mainly for double buffering patterns)
- sprite attributes (1 byte);
- animation script pointer (2 bytes);
- animation counter (1 byte);
- extended state index (1 byte); (memory position that's preserved after the object is unloaded)
- index in the list of level objects (2 bytes); (to manipulate dead/alive state)
- compact spawn coordinates (2 bytes); (to control object destruction)
- general purpose (3 bytes);

A lot of objects don't need all this information, and they're free to use the memory for other things if necessary.

Quote:
what is this linked list deal? Is that less RAM intensive or something? What's the implementation there...?

A linked list is a means of grouping things without having to reorder them. A variable indicates the first element in a list, and each element links to the next element. An invalid link (e.g. $ff) indicates the end of the list.

I, for example, have a list of free slots, so I can just grab the first one when I need to instantiate a new object, instead of having to go looking for a free slot. I also use linked lists to create different groups of objects, to control the order in which they're updated. Objects in group 0 go first, then those in group 1, and so on. When an object is instantiated, it inserts itself in the appropriate group. Another use for object groups is reducing the number of collision checks without having to check for object types. In a shooting game, for example, you could have a group only for bullets, so that collisions against them can be optimized.

EDIT: Another thing I consider important when dealing with object RAM is to use a structure of arrays instead of an array of structures, since the 6502 works better with the former. If I stored object attributes linearly, and I had more than 256 bytes worth of object RAM, I'd have to use a pointer and I'd need to load Y with the offset of each attribute I wanted to access before doing it. Things are not nearly as bad if everything is linear but fits in 256 bytes or less, because then you can use code like lda ObjectRAM+OBJECT_TYPE, x, where X contains the offset to the object and OBJECT_TYPE is a constant containing the offset to that specific attribute. I still prefer to use a structure of arrays though, so I can do lda ObjectType, x, where X is simply the slot index, meaning I don't need to shift bits when dealing with slot indices and slots are not restricted to sizes that are powers of 2. For example, if I need a new attribute to implement a new feature I can simply find 24 (or how many active objects the engine supports) bytes anywhere and create an array there.
Re: Object update order
by on (#171806)
I'll now ask a series of questions to see what kinds of things I need to consider when differing from your technique.
tokumaru wrote:
- logic routine index (1 byte);

Is this really needed? I simply call upon a specific logic routine that depends on the object, and if the object has more than one state then it can select that state's logic from there. RTS tricks.
Quote:
- X coordinate (3 bytes);
- Y coordinate (3 bytes);

24-bit coordinates? Are your play fields larger than 16 screens wide/tall or do you just need a lot of sub-pixel precision?
Quote:
- slope threshold (1 bytes); (used when walking off ledges)

I don't know what kind of game you're making, but wouldn't may objects not require this byte at all? I mean, particle effects and such. Or is this just the format for the 'actor' group of objects?
Quote:
- pattern offset (1 byte); (mainly for double buffering patterns)

As in, offset in the pattern table? That way this object can load its own tiles into CHR ram whenever it needs? That's a pretty cool trick if so, but I worry about vBlank time needed for all those ppu updates. And I also don't understand 'double buffering patterns'? Something something Battletoads.
Quote:
- sprite attributes (1 byte);

I feel like the sprite attributes could just be determined by an object's current state. Or do you store it here during object logic and return to it for a second pass to draw it?
Quote:
- animation script pointer (2 bytes);

This could be an index to a table as well, right? Save more RAM?
Quote:
- extended state index (1 byte); (memory position that's preserved after the object is unloaded)

This is really interesting to me and I don't understand the concept.
Quote:
- index in the list of level objects (2 bytes); (to manipulate dead/alive state)

This is so that the object doesn't get loaded again when you leave the playing field and come back, right? Cool idea.
Quote:
- compact spawn coordinates (2 bytes); (to control object destruction)

This is to keep objects from straying too far away from their 'home' location, yeah?

Quote:
Another thing I consider important when dealing with object RAM is to use a structure of arrays instead of an array of structures, since the 6502 works better with the former.

I believe I understand this, but my terminology may be fuzzy. The method I described would be considered a structure of arrays, yes? Even though different objects may take up different array lengths of RAM?
Thanks for the patience, I don't know of any other place to learn about these kinds of concepts.
Re: Object update order
by on (#171811)
You'll probably want to add variables to your objects as they're needed. Nothing wrong with doing what works now and putting another variable when you have a routine to use it.

Guilty wrote:
tokumaru wrote:
- logic routine index (1 byte);

Is this really needed? I simply call upon a specific logic routine that depends on the object, and if the object has more than one state then it can select that state's logic from there. RTS tricks.

These things seem trivial at first, but pulling up this info from your object data every frame can get costly on top of a complex game. If you have the RAM, sometimes its worth the cycle savings to preserve some things.

Quote:
Quote:
- sprite attributes (1 byte);

I feel like the sprite attributes could just be determined by an object's current state. Or do you store it here during object logic and return to it for a second pass to draw it?

I'm a little confused by this one. Does this negate the possibility of using flipped sprites inside of a metasprite, or multiple palettes in one metasprite? Mine is set so that if my objects are facing left, the horizontal flip bit is EORed, so a sprite which is reversed when right will un-reverse when facing left.
I suppose you'd get some ROM savings for not needing that per tile, if you don't need the functionality of it. Metasprite definitions can sure add up. I find myself needing to reverse on a per-tile basis a bit though.

Quote:
Quote:
- animation script pointer (2 bytes);

This could be an index to a table as well, right? Save more RAM?

If it was, this would be a pain to derive each frame. If you have one state per one animation, then sure, it's not too hard, but it's often a bit inefficient to program things that way. It all depends on the game. Complex metaspriting gets pretty heavy on the cycles. If you have to go through a lot of logic to get your animation pointer, just save it.
Re: Object update order
by on (#171818)
darryl.revok wrote:
If it was, this would be a pain to derive each frame. If you have one state per one animation, then sure, it's not too hard, but it's often a bit inefficient to program things that way. It all depends on the game. Complex metaspriting gets pretty heavy on the cycles. If you have to go through a lot of logic to get your animation pointer, just save it.

Er, 'pain to derive' in terms of cpu cycles? Because right now I've got a series of predefined metasprites, a series of predefined animations (which contain indexes to those metasprites) and indexed lists of both. Each object that needs animation calls on a subroutine that finds the current metasprite using a given animation index and animation time, and that data is fed into the metasprite drawing routine. I haven't exactly timed out the duration of the routine or anything but I don't think that's too much to ask of the NES? After all, graphics typically take up the bulk of the cpu tick anyways...? Stop me if I'm wrong of course.
Re: Object update order
by on (#171820)
I wouldn't think that the bulk of your CPU time should be spent on graphics. If you run a very complex metasprite engine, that's going to significantly cut into the number of objects you can have on screen, the complexity of your game logic and interactions. If your metasprite engine is robust enough to reject individual tiles instead of just full objects, meaning that an object half off-screen doesn't wrap around to the other side, then that's more overhead gone. Do you want your metasprite engine to handle colors/h/v flip per tile? If so, that's a bit more. It's all about what's most important to you. Time it out and see how long it takes to find your pointers if you want, but you really won't know for sure until you build the rest of your game engine. You may change the way your objects work 5 times before you're done. Doing a lot of indirect indexed addressing on a list of objects adds up. What's more important, the cycles or the bytes? Have you got to a point that either of them matter? If not, then I'd say continue with what's most comfortable to program and maintain, because I'm sure you'll have to make changes before you're done in one way or another.
Re: Object update order
by on (#171822)
Guilty wrote:
tokumaru wrote:
- logic routine index (1 byte);

Is this really needed? I simply call upon a specific logic routine that depends on the object, and if the object has more than one state then it can select that state's logic from there. RTS tricks.

The purpose of this variable is precisely to make this selection. I prefer to directly look up an address than check a bunch of state variables before deciding what to do.

Quote:
Quote:
- X coordinate (3 bytes);
- Y coordinate (3 bytes);

24-bit coordinates? Are your play fields larger than 16 screens wide/tall or do you just need a lot of sub-pixel precision?

I plan on having "Sonic 3"-sized levels, so I support up to 128 screens wide/tall. I'll probably not go that far, but I do want vast areas to run and jump through, instead of room-basef levels.

Quote:
Quote:
- slope threshold (1 bytes); (used when walking off ledges)

I don't know what kind of game you're making, but wouldn't may objects not require this byte at all? I mean, particle effects and such. Or is this just the format for the 'actor' group of objects?

This is used for handling peaks. When the leading point of an object starts to descend, its Y position is locked to the top of the peak until either the left or right points go past the highest point of the peak. The point that does becomes the primary collision point. This variable indicates where the highest point is. Objects that walk along the ground need this, but the format is the same for every object. Objects that don't need this can use the byte for other things, or not touch it at all.

Quote:
Quote:
- pattern offset (1 byte); (mainly for double buffering patterns)

As in, offset in the pattern table? That way this object can load its own tiles into CHR ram whenever it needs? That's a pretty cool trick if so, but I worry about vBlank time needed for all those ppu updates. And I also don't understand 'double buffering patterns'? Something something Battletoads.

Double buffering means displaying a copy of the graphics while you update a hidden copy, that gets displayed when it's complete. Only the player does this, but being able to relocate tiles allows me to combine enemies differently across different levels, for example.

Quote:
Quote:
- sprite attributes (1 byte);

I feel like the sprite attributes could just be determined by an object's current state. Or do you store it here during object logic and return to it for a second pass to draw it?

Since I have to store things like direction, map plane, and such, I might as well do it in the same format the OAM expects and save time. This byte is EORed with each attribute byte that comes from the metasprite definitions. I also use the bits the NES doesn't for other sprite related stuff, like whether sprites should be written to OAM bottom to top or top to bottom.

Quote:
Quote:
- animation script pointer (2 bytes);

This could be an index to a table as well, right? Save more RAM?

If this was an index to a table of animations, if need a second byte to specify the frame, so I might as well just point to the frame within the animation directly, and not bother calculating the address every frame.

Quote:
Quote:
- extended state index (1 byte); (memory position that's preserved after the object is unloaded)

This is really interesting to me and I don't understand the concept.

Each object gets 1 bit of state by default, enough to specify a permanent dead/alive state, but some objects need more than that. These objects use this byte to indicate which byte(s) in a separate table it uses for its extended permanent state.

Quote:
Quote:
- index in the list of level objects (2 bytes); (to manipulate dead/alive state)

This is so that the object doesn't get loaded again when you leave the playing field and come back, right? Cool idea.

Yes. Also to keep them dead for good when they actually die.

Quote:
Quote:
- compact spawn coordinates (2 bytes); (to control object destruction)

This is to keep objects from straying too far away from their 'home' location, yeah?

Could be, but the main purpose is to not unload objects while their spawn point of still in range. This could cause them to mysteriously vanish, until the player moved enough to get the spawn point out of range and back in. To avoid this, I only unload objects of both their spawn coordinates and current coordinates are out of range.

Quote:
Quote:
Another thing I consider important when dealing with object RAM is to use a structure of arrays instead of an array of structures, since the 6502 works better with the former.

I believe I understand this, but my terminology may be fuzzy. The method I described would be considered a structure of arrays, yes? Even though different objects may take up different array lengths of RAM?

To me yours sounds like an array of structures... Do you have all bytes for the first object, then all bytes for the second object, and so on? If so, that's an array of structures. Structures of arrays may not look as neat when you look at the memory map, but they're nearly always faster to manipulate with the 6502.
Re: Object update order
by on (#171855)
tokumaru wrote:
darryl.revok wrote:
Would you modify the object's position or its velocity? If you could modify its velocity, then its movement would still be encapsulated.

Directly moving an object is a way to make an object that's pushed after it has already been processed not to be displayed in the wrong place. Changing the velocity after it's been processed will do nothing until the next frame, so it doesn't really fix the problem.



The way I did it, I had the moving platform perform the initial collision with players and enemies, and give a signal that they're on that object. Then it's up to the player or enemie's tile collision routine to follow the moving platform around, and do the rest of the collision.
Re: Object update order
by on (#171864)
Sounds good, but... When objects are touching, their bounding boxes usually don't overlap, they just... touch. This means that when an object is riding a platform, there's no collision to detect. Unless you cheat by allowing 1 pixel overlaps or something.
Re: Object update order
by on (#172218)
tokumaru wrote:
How do moving platforms work with this scheme? If the player is updated before the platforms, couldn't he end up falling when a platform moves instead of following it?

Based on the player's relative position to a platform object, a collision check is performed, setting a bit-flag if positive-- resulting in the platform "dragging" the player object, when updating.

It has no effect on the player's overall state, so they can still walk around while being transported.
Re: Object update order
by on (#172248)
tokumaru wrote:
Sounds good, but... When objects are touching, their bounding boxes usually don't overlap, they just... touch. This means that when an object is riding a platform, there's no collision to detect. Unless you cheat by allowing 1 pixel overlaps or something.


It only does horizontal collision when on platforms. When a character jumps it manually disconnects it from a platform.
Re: Object update order
by on (#177553)
Bringing this thread back from the dead.
@tokumaru, I'm working on object implementation again and I'm really curious how your objects are referencing their variables. Currently the only way I can imagine your system working is if you arrange each 'column' in ram to be an object (say, $4001, $4011, $4021, ...) and then the objects would read their variables through a read such as $4000,x where X is the slot to which they've been assigned. But then you would be limited to 16 objects, unless you had each group assigned to different pages of RAM. How does a given object check its own variables if it could be in any slot?
Re: Object update order
by on (#177554)
$4000 is the APU. Did you mean $0400?

Yes, you can put different property stripes in different pages of RAM. So if you have 16 objects, each with 20 bytes of properties, you can put 16 properties in one page and 4 properties in the next.

An object references its properties by having its move subroutine take X (the index into the property arrays) as an argument.
Re: Object update order
by on (#177557)
Code:
spriteramstart = $0300
objectnum = 20

OBJaddrhigh = spriteramstart+objectnum*0
OBJaddrlow = spriteramstart+objectnum*1

OBJxhigh = spriteramstart+objectnum*2
OBJxlow = spriteramstart+objectnum*3
OBJyhigh = spriteramstart+objectnum*4
OBJylow = spriteramstart+objectnum*5

OBJwidth = spriteramstart+objectnum*6
OBJheight = spriteramstart+objectnum*7


OBJtype = spriteramstart+objectnum*8
OBJrequests = spriteramstart+objectnum*9

OBJdestroynum = spriteramstart+objectnum*10

OBJextra00 = spriteramstart+objectnum*11
OBJextra01 = spriteramstart+objectnum*12
OBJextra02 = spriteramstart+objectnum*13
OBJextra03 = spriteramstart+objectnum*14
OBJextra04 = spriteramstart+objectnum*15
OBJextra05 = spriteramstart+objectnum*16
OBJextra06 = spriteramstart+objectnum*17
OBJextra07 = spriteramstart+objectnum*18
OBJextra08 = spriteramstart+objectnum*19

OBJxvel = spriteramstart+objectnum*20
OBJxvelsub = spriteramstart+objectnum*21
;etc

You're not limited to 16 objects. You can change at any time by changing object num. And variables are indeed accessed with OBJaddrhigh,x (or whatever piece of RAM they want) where X is their object number.

Edit: I suppose it's true you'd be limited to 16 if you didn't want page crossing, but I don't think it's too big a concern. In the worst case, you can arrange the RAM so that variables that will suffer the page cross penalty are ones that aren't accessed frequently.
Re: Object update order
by on (#177559)
Kasumi wrote:
I suppose it's true you'd be limited to 16 if you didn't want page crossing, but I don't think it's too big a concern. In the worst case, you can arrange the RAM so that variables that will suffer the page cross penalty are ones that aren't accessed frequently.

You could just add a few bytes of padding where needed to get to the end of a page (if not aligned already). Also, if your assembler has a .res keyword or equivalent (or .align) it's convenient for that sort of thing:
Code:
OBJa = spriteramstart+objectnum*3
OBJb = spriteramstart+objectnum*4
OBJc = spriteramstart+padding+objectnum*5

; vs

OBJa: .res objectnum
OBJb: .res objectnum
.align 256 ; pads to next page
OBJc: .res objectnum
Re: Object update order
by on (#177561)
Kasumi wrote:
You're not limited to 16 objects. You can change at any time by changing object num. And variables are indeed accessed with OBJaddrhigh,x (or whatever piece of RAM they want) where X is their object number.

Edit: I suppose it's true you'd be limited to 16 if you didn't want page crossing, but I don't think it's too big a concern. In the worst case, you can arrange the RAM so that variables that will suffer the page cross penalty are ones that aren't accessed frequently.

Okay that took a really long time to wrap my head around, but I think I'm seeing that. You're talking about arranging all the variables sequentially, with all 'OBJxhigh' listed, then all 'OBJxlow', etc. I don't understand where OBJaddrlow comes in to play though.

Also, in general I see a lot of interplay between the words 'sprite' and 'object'. I've been using the term 'spriteRAM' (in my mind at least) to describe the OAMDMA page. That's obviously not what you're meaning with 'spriteramstart' though, and I'm just gonna take that at face value....

tepples wrote:
$4000 is the APU. Did you mean $0400?


Er... Yeah... That's embarrassing. That's me taking numbers off the top of my head on my phone here.
Re: Object update order
by on (#177562)
Sprite, object, actor can all refer to the same things. Really, I probably should call it objectramstart since I call my stuff objects these days. But I didn't when I started. :D

I call the hardware sprite RAM mirror OAM. But none of that particularly matters so long as whatever you're calling whatever makes sense to you.

Basically I go through the list of objects like this:

Code:
ldx #objectnum-1
spritestart:   
   
   

spriteend:
   dex
   bpl spritestart

So code between spriteend and spritestart can load OBJRAM,x and get the byte associated with that object. And you've already correctly seen that the memory is basically
Code:
OBJaddrhigh =  spriteramstart+0
OBJaddrhigh0 = spriteramstart+0
OBJaddrhigh1 = spriteramstart+1
OBJaddrhigh2 = spriteramstart+2
;etc

which is how it all works.
Code:
lda OBJaddrhigh0
;is equivalent to
ldx #0
lda OBJaddrhigh,x

lda OBJaddrhigh1
;is equivalent to
ldx #1
lda OBJaddrhigh,x

The loop above initializes X to the right slot before the object itself is run. I typically don't change it throughout. If X is changed, remember to change it back or really bad things can happen when the object returns to the loop.

As far as OBJaddrlow/OBJaddrhigh... it's just something I do, but the actual variables/number of variables you use for this method (which I think is basically tokumaru's method) is agnostic to how you access/lay them out.

Anyway it's an address for an indirect jmp, more or less. in between spritestart and spriteend, I have something like:

Code:
lda OBJaddrlow,x
sta tempptrlow
lda OBJaddrhigh,x
sta tempptrhigh

jmp (tempptrlow)


To create an object (after finding a free slot) which tokumaru describes in this post, I run code like this:

Code:
lda #<playerobject.main
sta OBJaddrlow,x
lda #>playerobject.main
sta OBJaddrhigh,x
;Replace playerobject.main with the label for the code of whatever object you want to make


The object itself at its simplest looks like this
Code:
playerobject.main:;This is reached because of the indirect jmp
;Code here can access the object slot's RAM immediately with
;something like lda OBJxvel,x
;But this object only returns so the look can continue
jmp spriteend;This returns to the loop so the next object/the rest of the program can run

There are other ways to do it, but that is what I personally use OBJaddrlow and OBJaddrhigh for.
Re: Object update order
by on (#177591)
Here's how I do it:

Code:
Object::SLOT_COUNT = $18 ;number of object slots

Code:
Object::InstancesType: .res Object::SLOT_COUNT ;type of the object occupying the slot
Object::InstancesNext: .res Object::SLOT_COUNT ;link to the next slot in the same list
Object::InstancesLogicState: .res Object::SLOT_COUNT ;index of the logic routine the object is currently using
Object::InstancesXFraction: .res Object::SLOT_COUNT ;fractional part of the object's horizontal coordinate
Object::InstancesXLow: .res Object::SLOT_COUNT ;low byte of the object's horizontal coordinate
Object::InstancesXHigh: .res Object::SLOT_COUNT ;high byte of the object's horizontal coordinate
Object::InstancesYFraction: .res Object::SLOT_COUNT ;fractional part of the object's vertical coordinate
Object::InstancesYLow: .res Object::SLOT_COUNT ;low byte of the object's vertical coordinate
Object::InstancesYHigh: .res Object::SLOT_COUNT ;high byte of the object's vertical coordinate
Object::InstancesSpeedXFraction: .res Object::SLOT_COUNT ;fractional part of the object's horizontal speed
Object::InstancesSpeedX: .res Object::SLOT_COUNT ;integer part of the object's horizontal speed
Object::InstancesSpeedYFraction: .res Object::SLOT_COUNT ;fractional part of the object's vertical speed
Object::InstancesSpeedY: .res Object::SLOT_COUNT ;integer part of the object's vertical speed
Object::InstancesAngle: .res Object::SLOT_COUNT ;angle of the object
Object::InstancesSpeedFraction: .res Object::SLOT_COUNT ;fractional part of the object's angular speed
Object::InstancesSpeed: .res Object::SLOT_COUNT ;integer part of the object's angular speed
Object::InstancesBoundingBox: .res Object::SLOT_COUNT ;index of the object's bounding box
Object::InstancesCollisionResponse: .res Object::SLOT_COUNT ;indicates how the object presents itself to the world
Object::InstancesPatternsOffset: .res Object::SLOT_COUNT ;base index for the object's patterns
Object::InstancesAttributes: .res Object::SLOT_COUNT ;various flags that control sprite attributes
Object::InstancesAnimationScriptLow: .res Object::SLOT_COUNT ;low byte of the pointer to the current animation script
Object::InstancesAnimationScriptHigh: .res Object::SLOT_COUNT ;high byte of the pointer to the current animation script
Object::InstancesAnimationCounter: .res Object::SLOT_COUNT ;number of frames to wait before advancing to the next animation frame
Object::InstancesExtendedState: .res Object::SLOT_COUNT ;index of a byte in the table of extended states
Object::InstancesIndexLow: .res Object::SLOT_COUNT ;low byte of the object's index in the list it was loaded from
Object::InstancesIndexHigh: .res Object::SLOT_COUNT ;high byte of the object's index in the list it was loaded from
Object::InstancesSpawnBlockX: .res Object::SLOT_COUNT ;horizontal coordinate of the 128x128-pixel block the object originates from
Object::InstancesSpawnBlockY: .res Object::SLOT_COUNT ;vertical coordinate of the 128x128-pixel block the object originates from
Object::InstancesSlopeThreshold: .res Object::SLOT_COUNT ;position of the highest point of the ledge on which the object is standing
Object::InstancesLink: .res Object::SLOT_COUNT ;link to an active object related to this one
Object::InstancesCustom0: .res Object::SLOT_COUNT ;memory for active objects
Object::InstancesCustom1: .res Object::SLOT_COUNT ;memory for active objects

Of course this adds up to a lot more than 256 bytes (24 slots * 32 bytes = 768 bytes), so I actually split these definitions across different pages to avoid page crossing when accessing these properties. Not that the occasional page crossing would've been a big deal, but since I could avoid it for free, I decided to do it.

Guilty wrote:
How does a given object check its own variables if it could be in any slot?

When processing the objects, a loop manipulates X (in my case, the slot order is defined by linked lists) before calling each object's update routine, so when the object is called, X is already pointing to the slot of where its instance is loaded. This value is also stored in a variable, so object routines can temporarily use X for other purposes if they need to, and later they can reload the slot index from the variable.