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

Way to manage spawning points

Way to manage spawning points
by on (#237699)
My current project has been on hold for longer than I would love to (busy, sickness, the usual thing) and now that most of the things around the game has been done (title, intro etc), I need to focus on the actual game engine, something that is still foreign to me and I'm not sure how to apoarch most of the missing blocks yet. Working with an old code base that may not be appropriate for the current goal is not helping either ^^;;;

One thing I want to work on first since it will affect entities is spawning points on the map. My editor code is too old and don't remember most of it so I won't add that option so I need to find an easy way to define them manually. One idea I had is since my map contain metatile columns and the engine requires to process data once a new column must be loaded, I could have a table the size of the currently shown columns (16) and based on the location of that column, a entity could be spawned around that. This means unless a new column is added, you don't need to refresh the possible spawning list and only active entities (spawners) would be active until the list is updated again.

I still don't know how to code it yet, but this is my mental image of it at the moment and I'm not sure if it could be a good starting poinf or not. This way, I could have a LUT for every column in the map that points to a spawner or not and it should be quite easy to make the data by hand too. The main problem is more to develop it and see if the idea works well since my time is limited and have to split my coding in micro-session, which really kill the mood to put the effort on it since the scope is larger than "fix that 1 pixel off sprite" or something like that :lol:

So, I'm looking if my idea seems interesting and to look how people approach this problem. Since it's nesdev, we may have talked about it in a derailed thread so I will start searching the forum and see what I can find here and there :lol:
Re: Way to manage spawning points
by on (#237709)
This is how I do it, and it seems to work very well for me (by the way, when I say 'object' below, I'm referring to my own programming construct, not an obejct in the NES sense of a single 8*8 sprite tile, just to be clear.):

My level data is stored in metatile columns like yours is. My game only scrolls horizontally, so that made sense to me. when my loading seam reaches a new column, it checks at that same index into what I call the 'object map'. only one object can spawn per column, so that is a limitation, but if you wanted to change that it probably wouldn't be too hard. (I also have my level map and object map divided into rooms and zones so data can be compressed and repeated, but that's probably outside the scope of this discussion.)

Every object has a 'type'. the type is just the index into the object arrays in ROM. Type 0 is null, so if the seam is on an index in the column map with a 0, it spawns nothing. otherwise, the number in the object map is the type to spawn on that column. the spawning routine stores that number in the object type array in RAM. then it uses that to index into all the other tables in ROM to populate the rest of the data in the RAM object arrays. The object map also contains a byte to indicate what Y position to spawn the object at (since the X position is already determined by the column).

One more thing: Every object also has what I call an 'objectID'. it's a single byte that's made up of part of the room number and part of the column number. If an object with a certain ID is already loaded into RAM, it doesn't spawn another object with the same ID. this is to prevent the same object from spawning over and over if the seam is sitting on the same tile column. when most objects despawn (such as enemies being killed, etc.) their type is changed to 0 (null) but their ID is left in place. That way, you don't get the same enemy spawning over and over if you kill it while the seam is on its spawn point. it's possible for many objects in the game to share the same ID, but since they'd have to be at least 16 rooms apart, by the time you scrolled that far another object would have overwritten that slot and ID.
Re: Way to manage spawning points
by on (#237715)
I personally don't like to hardcode object information in the map data... I have a separate list for objects, sorted by their X coordinate, and two pointers to that list, marking the left and right edges of the "active zone". As the camera moves, these pointers are adjusted to include or exclude objects in/from the active zone.

When an object enters the active zone, its "alive" bit is checked (all objects in the level have 1 bit of RAM to indicate whether they're alive or dead), and if it's alive, the bit is set to "dead" (to prevent the object from being activated multiple times), and the object is activated. When an object's spawn point leaves the active zone, it will detect that and decide whether to deactivate itself, which is normally only done if its current coordinates are also outside of the active zone, to prevent those weird cases when an object barely goes out of screen and the player chases it but finds nothing. The deactivation rules vary per object though, since this task is initiated by their own AI routines.

When an object deactivates itself, it can restore its global "alive" bit, if it wants to be activated again in the future, or leave it cleared, if it's supposed to stay dead forever.
Re: Way to manage spawning points
by on (#237716)
@gravelstudios

It's only scroll horizontally in my case too so it seems my idea was something very common. Most of what you said is what I had in mind so I may try to implement it soon.

@tokumaru

The data is not hardcoded in the map itself but more of a list independent that is used to know which data to "activate" based on the current metatile column shown. The advantage of it is the size of the list will be as big as the count of metatile column and the refresh of the current active list is only done when a new column is loaded. As for their coordinate, they are relative to the spawn point, which means the metatile column. So it is similar to your solution except the granularity is on the metatile column while in your case it's more a the list and their x coordinate will decide the the group to be shown. I guess in your case there is less waste since you won't have empty slots.
Re: Way to manage spawning points
by on (#237718)
My object map is completely separate from my level data map. this was originally because I had already designed my scrolling engine and it did not account for object data to be intermingled in with the level data, so I had to write it as a separate entity. After I wrote it though, I realized the benefit of this is that I can mix-and-match rooms of level data with rooms of object data to create more variety. So I can recycle a room in level data, but use a different object layout to make it feel like a different room. Or I can use the same object layout in multiple different rooms. This helps to mitigate some of the wasted space where every column without an object spawning has a 0 in the object map.

Also, moving platforms are handled a little differently. They are objects and do have types and IDs, but they also have their own tables that indicate their speed, direction, etc. when a moving platform is spawned, it does a linear search through those tables for the correct data using its zone, room, and X-coordinate to find the rest of its properties. I felt this linear search was a little wasteful in terms of cycles, but it's only one frame while the platform spawns, so I didn't think it was too bad.
Re: Way to manage spawning points
by on (#237719)
Different object types, such as moving platforms, like you mentioned, may need different properties, and I handle that by giving each object in the object definition table a "parameter" byte. If 8 bits are enough to represent an object's type's attributes, great, if not, those 8 bits are used to index a table that contains the actual properties.
Re: Way to manage spawning points
by on (#237732)
@tokumaru

Regarding your list, how do you manage it? In the example explained above, the list is refreshed only when a new metatile column is added and it will take 16 entities based on that (or a more clever way is possible later but let's keep it simple) but in your list, I'm not sure how it work. My guess would be something like, on every frame it need to check which items are still in the viewport from the selected list and it will start to check based on the 2 pointers (start/tail), if the pointers needs to be moved to access different objects from the list since they are ordered by the X coordinate.

Maybe my explanation is not that clear (I'm bad at explaining things ^^;;) but it is something like that?
Re: Way to manage spawning points
by on (#237739)
Basically, the pointers point to the next "candidates" for spawning on either end of the active area - these are objects that aren't yet in the active area, but will eventually be if the camera moves towards them.

So, every few pixels scrolled (the exact amount can be whatever you want, depending on how often you want to spawn/despawn objects), you calculate where the boundaries of the active area are (these are a constant number of pixels behind and ahead of the camera), check whether the candidate in the direction of the movement entered the active area, in which case it needs to be spawned. Then you check the next object, and the next, and keep spawning every object that entered the active area, then stop at the first one that's outside of the active area, and that becomes the first candidate for the next time.

Similarly, on the other end, keep testing which objects left the active area, and move the pointer accordingly. Those tests are done using the spawning coordinates of the objects though, not their current coordinates, so you can't immediately despawn them if they're not static objects. My solution is to despawn objects when only when the following 2 conditions are met:

1- the object's spawn coordinates are outside of the active area (each active object is responsible for keeping track of this status);

2- the object is off-screen (this is signaled by the meta-sprite drawing routine, which knows when objects are off-screen if no sprites are output;

Vertical scrolling complicates things a bit, because you can't simply look at the next spawn candidates anymore. When vertical scrolling happens, I search all objects between the 2 pointers looking for the ones that are in range vertically.
Re: Way to manage spawning points
by on (#237743)
tokumaru wrote:
Different object types, such as moving platforms, like you mentioned, may need different properties, and I handle that by giving each object in the object definition table a "parameter" byte. If 8 bits are enough to represent an object's type's attributes, great, if not, those 8 bits are used to index a table that contains the actual properties.

For the record, in Super Mario World, certain types of object use the X spawn point, rather than using another byte of data, to further differentiate the object, likely to save memory/hacking the sprite data format after it's done. Some examples on the top of my head: P-switches, Lakitu, Yoshi eggs, key/star/wing/p-balloon blocks.
Re: Way to manage spawning points
by on (#237745)
@tokumaru

I see. It gives me some idea on how to make it so I guess the best thing is to start experiment and see how it goes ;) Some of my concern with pointers is since you can move horizontally in both direction, you have to update based on the direction so I'm not sure how much processing it will take (early optimization syndrome :lol:). The other thing is, in my current project, some object, even though they are in the active window, may react in different ways:

- only become active when very close to it
- is actually active from x1~x2 and respawn non-stop until you are outside that window

I think is instead of overthinking, I should just try to make something simple, see how it goes and refactor on top of it ^^;;