Object Resource Acquisition

Started by
16 comments, last by Satharis 6 years, 6 months ago

For a sprite based 2D RPG style game, how should assets such as textures, animations, music and sound effects be distributed to and accessed by game objects?

Assuming you have a resource manager dedicated to loading and containing the resources, should this manager be passed indiscriminately to wherever there is a need for a resource(s)?

Should the resource manager segregate various textures and animations from sprite sheets as they are loaded and hold segregated sets (maps/lists) of these textures and animations based on a pre-determined need by different game objects so that they can be quickly set up? By this I mean, where you are certain object A needs only a set of X animations and Y sound effects throughout the lifetime of the program.

If all textures, animations, music and sound effects should not be segregated as they are loaded and should instead each be stored in one big container of their respective type for all objects to freely choose from, how should the objects retrieve the resources they need efficiently and with minimal lines of code? Any object could hold any combination of textures, animations or sound effects held by the resource manager. I believe it would be easy with this approach to have very many lines of code dedicated to retrieving all the resources an object will need, for every object.

Finally, should objects hold resources at all? At this point I don't see why objects shouldn't hold their own graphical resources since the objects contain the data such as position, width and height that the resources would need in order to be rendered correctly. However, I'm not so sure about resources such as sound effects, since these types of resources don't need any information from the object in order to play. Should they be held and controlled elsewhere, by dedicated music and sound effect playing systems?

 

 

Advertisement
12 hours ago, Seer said:

Assuming you have a resource manager dedicated to loading and containing the resources, should this manager be passed indiscriminately to wherever there is a need for a resource(s)?

No, do not pass them around indiscriminately.  First off, few systems should need to know about them.  Game objects themselves have no need to know about it.

Game objects rarely render themselves.  Game objects usually have a handle to their models, textures, or animations, and they can request the various graphics systems do something different, but usually it is extremely inefficient for the game objects themselves to be involved with the rendering or the resource details.

But that doesn't directly answer your question...

Among the best models is to only pass the data to systems on a "need to know" basis.  It takes some discipline both in design and implementation, but it can be done.  Again, since the game objects themselves don't do the drawing, they should generally have no need to know the details of how they are rendered.  They might need to switch to different models or textures, such as a "damaged" or "inactive" version, but that should generally be handled as a message to the other subsystems and not through direct manipulation.

Unfortunately in many games there is less discipline, people make sloppy decisions, and time is more critical than implementation quality.  When you must make this sad choice, the typical model is a "well known instance".  The typical implementation is a global structure that contains pointers to the active instances of some key libraries, such as logging, audio, rendering, and a few others. The instances themselves are only modified at well-defined times, such as only being modified during game initialization or only being modified when the entire game is outside the simulation loop.

13 hours ago, Seer said:

Should the resource manager segregate various textures and animations from sprite sheets as they are loaded and hold segregated sets (maps/lists) of these textures and animations based on a pre-determined need by different game objects so that they can be quickly set up? By this I mean, where you are certain object A needs only a set of X animations and Y sound effects throughout the lifetime of the program.

Things that are not the same should not be treated the same.  Things that are the same should be treated the same.  A texture is not a model.  A sprite-sheet is not a regular texture. Animations and sounds are not the same as the others on the list. 

As for loading the things being needed, it is moderately common to have a prefetching system, depending on the game.  Elements can have data that says "I need this at startup", and other data that says "I need this eventually".  The first needs to get loaded up front, but the rest can wait until the main game is running.

The exact details of such a system depend on the game and its needs. For example, in a major game (not a hobby project that doesn't have the manpower) all the expected audio can be pulled from the animation events that use them, and the build tools extract the list of audio that can be triggered. Since audio is something that needs to be instantly responsive it is generally best to load it from disk in advance.  A smarter system can pull them up after the main load, continuing a background load as the level becomes playable.

13 hours ago, Seer said:

Any object could hold any combination of textures, animations or sound effects held by the resource manager.

Generally no.  The individual game object does not hold any of those.

A subsystem that controls rendering controls the textures and models, both as sub-subsystems, and they do it in a way that best fits how they will be used, with different size buffers and resource caches, and different rules for resource proxies as needed, generally storing the resources directly on the video card, all focusing on how to render quickly. A subsystem that controls animations is quite separate, with completely different access patterns, different buffering system, different resource caches, different proxy services, designed around quickly processing the animations for the rapid series of matrix multiplies and transfer to the cards that must take place.  Sound effects are similarly handled differently, kept in different areas of memory for fast audio playback.

An individual game object may hold a handle or proxy given to them by the subsystem, but the game object themselves typically don't own those resources at all.

13 hours ago, Seer said:

At this point I don't see why objects shouldn't hold their own graphical resources since the objects contain the data such as position, width and height that the resources would need in order to be rendered correctly. However, I'm not so sure about resources such as sound effects, since these types of resources don't need any information from the object in order to play.

Mostly covered above.

The rendering system can be built to handle rendering. It can sort objects based on how they must be rendered.  Commonly this means based on material orders, shaders, transparency/translucency, and other factors.  The rendering system can also use the information to render multiple instances of the data with a single call. Such systems can build and maintain a collection of rendering order keys using bitmasks which are trivially sorted to greatly improve rendering speed. 

If each game object itself owned this then drawing would require much more processing, visiting every game object to discover all those properties, and re-sorting instead of keeping cached sort keys. 

Audio is problematic when it must be mixed or processed.  If you're mixing together a bunch of positional audio information, it is horribly inefficient to query each object every frame to find out if the audio has changed, to mix only the audio through the single simulation step, and so on.  Audio processing is handled radically different from graphics, and different from the simulation. Say you've got some 44.1KHz audio, some 192KHz audio, and you want to play them together.  But if you're mixing them per graphics frame, you're mixing together perhaps 7056 samples and 30720 samples, and things get difficult. Similar issues happen if you try to mix them by simulation step since often simulation happens at irregular times, often many rapid simulation steps to catch up, followed by a delay waiting for rendering or other processing.  It's even worse when something causes graphics frames.

Instead an audio processing system can handle all the work in a separate processing thread, often in its own CPU core quietly humming away. The system can operate as best fits the audio hardware, keeping the audio buffers fed completely independently of what game objects and rendering systems are doing.  The audio system can listen for events that impact audio and handle them when makes best sense for that subsystem, such as when the next round of audio buffer updates take place.

 

However, for a small hobby game, you're unlikely to have the manpower to do most of that stuff. You'll get better performance with such systems, but they take time and effort to develop.  If you're using an established game engine or good middleware tools they'll handle it for you, and that's highly recommended if your goal is to complete an actual game.

Thanks frob.

To see if I understand you correctly:

  • Game objects should not hold references to resources
  • Game objects should never come in contact with the resource manager
  • Systems such as a Renderer can interact with the resource manager to retrieve the resources they need, probably at startup
  • Game objects should send messages to the appropriate systems so that operations such as drawing a texture or animation or playing a sound are performed by those systems

Is that right?

When sending messages to a system, would it be appropriate for the game object sending the message to do so via a held reference to the system? For example:


public class Player
{
	private Renderer renderer;

	public class Player(Renderer renderer)
	{
		this.render = renderer;
	}

	public void update()
	{
		// If I want to draw something
		renderer.render(Animation.NPC1_WALK_DOWN, position.x, position.y);
	}

	// render() method begone!
}

Here the call to render() would add an animation to a Map of Animations based on the Enum in the first parameter. When all the game objects have finished updating, the Renderer would then render all the things objects this frame have told it to render. Once it's done, it would clear the Map and await further instructions in the next frame. And so on.

This is just a rough idea based on my current understanding of what you recommend. Does it have merit or am I thinking about this incorrectly? I know that adding to and then clearing from a Collection of things every frame could become expensive depending on the number of draw calls but it's all I can think of that would probably work at the moment. If it's definitely not suitable, what else would you recommend doing instead?

9 minutes ago, Seer said:

To see if I understand you correctly:

  • Game objects should not hold references to resources
  • Game objects should never come in contact with the resource manager
  • Systems such as a Renderer can interact with the resource manager to retrieve the resources they need, probably at startup
  • Game objects should send messages to the appropriate systems so that operations such as drawing a texture or animation or playing a sound are performed by those systems

Is that right?

Fairly close.

For the first one, game objects generally should not hold resources directly. Holding a reference to a resource is generally fine, but there must be rules in place to ensure the reference (handle, pointer, proxy, whatever) is valid. 

Game objects should rarely directly hit a resource manager. They can do it indirectly, send messages, request handles to items.

14 minutes ago, Seer said:

public void update() { renderer.render(Animation.NPC1_WALK_DOWN, position.x, position.y); }

Usually not, no.  It certainly isn't something you would want to call every frame like that.  In most games rendering and simulation processing are decoupled, there can be multiple updates for each render.

If you're looking to animate something, you would tell your animation system to animate it. The animation system and rendering system work together.

So you might (completely depending on your game engine) request a handle to an animation, request a handle to the model, and then use the animation system to play the animation on the model. The game object certainly should not be instructing the renderer to render. You might enable or disable rendering occasionally, you might reposition something, but usually the systems should operate completely independently. 

 

On 25.9.2017 at 4:25 AM, frob said:

not a hobby project that doesn't have the manpower

Depends on time and motivation of the hobbyist ;)

 

Maybe I could go into some more detail from experience with fiddling arround with rendering/audio and also professional penetrating the render system. Gameobjects themselfs are mostly instances of certain combination of mesh/texture with or without any animation attached to them depending how the engine handles them. Unity heavily uses components to stack meshes, materials (not single textures), audio and animation together and I think Unreal uses some kind object composition to do something similar so the loading process tells asset manager to create certain instance where scene objects are loaded immediatly and prefabs are loaded dynamically when referenced. They are some kind of serialized to the scene data/prefab data and back assembled from there by the resource manager that keeps track of references. I use similar to Unreal a resource handle in my solution that is background reference counted and swapped out when caching for other resources when not used any more and/or the entire scene is unloaded. I have some kind of resource management that is similar to memory management keeping track of objects (where objects here mean Mesh, Texture, Animation-Data instances) and interact with the graphics units storage (and also fences, locks and other stuff that may be out of scope for now). "GameObjects" (I dislike this term) are then attached those resource handles for rendering. Game code might trigger some resource loading especially when on-demand changing some linked instances (changing textures, materials, meshes) and immediatly gets an empty handle back that is ready to use when loading thread (a Task inside the task system) finishes in the background and for so long contains none(default) or old data (that might be these eye breaking purple texture often seen in a game :D ).

I keep this resource handle option open for procedural generation of meshes like maps or some toy implementation for dynamic vegetation often used in prototypes.

Sound system is a completely different approach (as already mentioned). Soundbuffers are used to be filled immeadetly up with chunks of data when reaching out of where you otherwise would get nasty audio artifacts. Usually those sound buffers are implemented as single data streams that are mixed by the software into one or more concourent ring buffer(s) shifting the read pointer arround (what is the reason for crashing games to playback the last bits of audio any and any again when audio thread is not shutting down). This is because audio calculations for your scene might be an as well complicated task as rendering is. Audio sources might be static or position based so those ones must to be valued down depending on the distance to your recipients position, any object between them and a couple of things more where audio also could be clipped as for example meshes can be clipped by frustum when there are a bunch of louder audio sources so that the quite once dont need to be mixed up.

Resources might also be implementation dependent managed by the audio system or resource manager where calling an audio file for playing is just messaging into the audio system. This will then enqueue/dequeue data for playback depending on the audio source or mark buffers as suspended for the command of pausing sound or whole mixed buffers just when switching into pause menu all in-game audio stops from playback except some feedback sounds and music.

I personally like the idea to trigger audio from animation FSMs so this will prevent extra work for the gameplay programmer

On 9/26/2017 at 9:08 PM, frob said:

Holding a reference to a resource is generally fine, but there must be rules in place to ensure the reference (handle, pointer, proxy, whatever) is valid. 

Then is something like this actually okay:


public class Player
{
    private Map<AnimationName, Animation> playerAnimations;
    private Map<SoundName, Sound> playerSounds;
    
    public void update()
    {
        // Control resources
    }
}

If that is fine then why not, for a simple game, allow the objects to render themselves? They have all the information they need to do so in this case and so long as the rendering takes place after all the updates I do not see why there should be a problem.

 

On 9/26/2017 at 9:08 PM, frob said:

Game objects should rarely directly hit a resource manager.

Does passing resources from a resource manager when constructing the object count?

 

If objects can hold their own resources (as references like in Java) and receive them from the resource manager at construction, what would be a good way for them to get just what they need from the manager without it costing many lines of code (assuming the manager has not pre-emptively tailored different sets of resources to specific objects, which I'm beginning to think is a silly thing to do)?

 

On 9/26/2017 at 9:08 PM, frob said:

 In most games rendering and simulation processing are decoupled, there can be multiple updates for each render.

That won't be the case for me, not right now anyway. Maybe when I have more experience and I see a need. Right now everything that needs to render renders after everything has updated, in the same frame every frame.

 

On 9/26/2017 at 9:08 PM, frob said:

The game object certainly should not be instructing the renderer to render.

That call 


renderer.render(Animation.NPC1_WALK_DOWN, position.x, position.y);

was just an example of the Player sending a message to the Renderer to add the Animation described by the passed Enum to its Map of Animations to render in its own time, which would be after everything has updated that frame. It's not saying to the Renderer, "render this now while the updates are happening". I could have called it something better, like addToRenderMapToRenderLater(). Well maybe not better, but more explicit anyway :)

If that is still not a good idea, then how should objects send messages to the various systems to tell them to do something?

 

May I please have some feedback?

If this were in For Beginners the replies would be a little different.  In those tiny little games you do anything you can to make the game work.  In the bigger gameplay parts of the site, we make the assumption that the game is going for more substance.

 

For the topics of objects rendering themselves ...

When I see the words that "an object should render itself", my impression is that the individual game object knows about its own texture, model, and shaders, will position the various rendering matrices to whatever is needed, switch textures, switch shaders, set the appropriate shader parameters, then render the model.  In your 2D game that model will likely be a textured quad, but it still incurs the costs.

Since you're talking about a 2D based rendering, each object drawing itself ignores depth ordering and again ignores the passes required for effects like transparency / translucence / bloom /etc.  If you draw them in arbitrary order then depth is going to be a serious issue as 2D objects have a critical need for proper ordering to appear correctly.

If you were talking about 3D rendering it has issues with those same effects and also with situations like reflection and shadow processing, and with performance as shaders and textures will probably seldom (if ever) reused.

In either of those cases, those commands will quickly saturate the bus to the card, and those particular commands are slow to run.  You could probably get away with that if you've got a handful of game items and no complex graphics or features like transparency / translucence / bloom / etc. 

In game engines there is a rendering system that controls all the items to be rendered, sorts them based on visual properties like transparency, shaders, textures, models, depth, and so on, then renders them in an order that has minimal draw calls and minimal data transfers to/from the card.  

Do you mean something different with that?

 

The questions regarding resource management, that primarily boils down to the issues of object lifetimes and of efficient creation time.  In games (and in all software, really) managing the lifetime of objects is very important.

Objects need to be created, used, and destroyed in reliable patterns.  When those patterns are violated the resources are leaked, and eventually the program will crash. The larger the resource and the more constrained the system the faster that will happen.  A dedicated system for each type of resource can ensure that each object can be managed through its entire lifetime. 

On the parallel task of creation time, a simple example is the time to create a model object.  In naive code creating a game model will require finding the file, opening it, reading and parsing the model contents, opening one or more texture files, reading them, parsing the images, and so on. These operations are all slow. Opening something on disk might happen to be fast, but it could also take multiple seconds to open, multiple seconds to read, etc.  Rather than waiting for potentially enormous times, the typical pattern is to respond near-instantly with a proxy object which has enough information to be usable, but which has the contents pending.  It works in conjunction with the resource controller to load it in to the correct hardware as it is eventually loaded, and to call back when it is ready.

Again, in the smallest games you don't need that kind of thing.  For your hobby project, certainly you can go parse all the files one at a time as they are loaded, and if loading the game takes a minute or so that is still faster than the major AAA games loading hundreds of thousands of resources.

 

The message you are sending can work fine for a very small game, but will not scale well. Instead of notifying a single system about an event, the typical pattern is a broadcast where you notify all interested listeners about the event. Typically there are very few things registered to respond, so the array of calls may hit zero, one, or some other small number of active listeners, but the purpose is that it extends to any number of interested game systems.

At what point is a game no longer considered small enough to be able to implement simplified patterns, such as objects referencing resources? Would games with the scope of GBA era titles such as Pokemon Emerald, Golden Sun or Dragonball Z: The Legacy of Goku 2 be considered sufficiently small enough in this regard? It is only up to the scope of games such as these that I am interested in making for now. I have no interest in making 3D games. I care about how best to handle sprite sheets, textures extracted from sprite sheets, animations made using those textures, sound effects, background music and fonts. That's basically it.

I have a few questions related to these:

  1. Should a given sprite sheet containing sets of animations, such as character animations, have an accompanying data file specifying values such as X position, Y position, width, height, X offset from origin and Y offset from origin for every frame in the sheet, so that you can properly extract the frames with necessary data when loading the sprite sheet?
  2. Should sprite sheets be loaded individually? I ask because I have heard of something called an atlas which packs sets of individual sprite sheets into one big sprite sheet and supposedly it is what you should use.
  3. To be absolutely clear, if a resource manager is what loads and initially holds the various resources, should it only hold resources in separate containers of that type of resource? For example, all textures would go in a container holding only textures, all animations would go in a container holding only animations, and so on for every type of resource. Then, when a system needs the resources its domain governs, it just takes a flat container of those resources from the resource manager and works from there.

 

With resource loading, generally what I do is load all resources at the start of the program so that they are all available and ready to be used. Only once everything has loaded does the program continue. For the scope of the kind of game I am interested in making, is this an acceptable approach? If so, at what scope, if any, does it become unacceptable or problematic?

 

Would you recommend the observer pattern for sending messages from objects to systems? If so, would you recommend implementing it with a kind of one for all approach where every observing system acts on the same function call, such as notify(Event, Object), differing in how they respond based only on the Event Enum which is passed? This way, each systems notify() definition would be comprised of a switch over the Events which are relevant to it. Object would be passed so that any type of data that needs to be sent can be wrapped in an Object and sent that way. Object could be replaced by Data, passing derived Data types instead I think.

If not that then would you recommend using a set of disparate Listener interfaces instead, where the type of Listener can be different with more pertinent, sculpted function names and signatures for the relevant system. I have not used this type of observer pattern before as I have never been able to get my head around it being so used to doing it the way I described above, so if this is how you would recommend implementing the observer pattern would you mind explaining how?

 

On the issue of ordering objects for rendering, I can see how a dedicated Renderer system would be good because it can take care of rendering the objects in a certain order as specified by whatever value or values are meaningful to you. For example, in 2D games where sprites don't take up an entire tile for themselves and are able to stand behind one another, you would probably want to order the objects by their Y position value so that those who are "above" are rendered before those who are "below" and appear behind those below them should they enter the same space.

Even in this case however, the Renderer, once finished ordering the objects, can still simply render them by doing something like:


for(GameObject gameObject : gameObjects)
{
	gameObject.render(...);
}

In this case the Renderer has properly ordered all the objects and all it then does is tell them to render themselves. Is that still not a good solution?

@frob knows what he is talking about, I would listen to his experience.  You seem obsessed with game objects rendering themselves, but even in small games this is highly inefficient and a poor design, which can lead to bad behaviors as a programmer which are difficult to change later.  You become limited very quickly with what you can do with objects rendering themselves honestly (from past experience here too which required a complete rewrite of the game and it's underlying rendering tech...).  If each object renders itself you loose the ability to batch render, which is something very good for efficiency which is always good.  Otherwise you're wasting GPU/CPU power/cycles for zero benefit other then your perceived one which doesn't actually exist.

Even simple games can benefit from stateless rendering systems, see these couple articles and the ones they reference also:

http://realtimecollisiondetection.net/blog/?p=86

This is a 3 part series, the links are at the bottom of this article:

https://blog.molecular-matters.com/2014/11/06/stateless-layered-multi-threaded-rendering-part-1/

5 hours ago, Seer said:

Should sprite sheets be loaded individually? I ask because I have heard of something called an atlas which packs sets of individual sprite sheets into one big sprite sheet and supposedly it is what you should use.

A texture atlas and a sprite sheet are check alike honestly.  They both tightly pack other images/textures and you need to know where they are from data files.  I honestly create the largest texture I can (on the GPU) that is a bit bigger then I need to load all my textures/images/sprites do I have zero requirements to change my working texture.  Only the shader needs to change then.

 

5 hours ago, Seer said:

Would you recommend the observer pattern for sending messages from objects to systems?

This is what I use, templated for the data being sent to keep type safety.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

This topic is closed to new replies.

Advertisement