Doraku / DefaultEcs

Entity Component System framework aiming for syntax and usage simplicity with maximum performance for game development.
MIT No Attribution
658 stars 62 forks source link

Resource example, some questions #96

Closed PodeCaradox closed 4 years ago

PodeCaradox commented 4 years ago

Hey Doraku,

i have the problem with the serialization of the Texture2D, this Time i looked up your Documentation. But i don't exactly understand it. Here are my questions: 1.What is the ITextureLoader from the TextureResourceManager ?

  1. Why you need GraphicsDevice _device? In Monogame it should be the ContentManager with Load?

  2. How exactly does it work with shared Components? So for example i have the same Texture for more than on entity is it like this? entity.Set(new ManagedResource<string, Texture2D>("square.png")); entity1.SetSameAs(entity);

  3. From the Code of the TextureResourceManager, i assume that i also need to Set the SharedComponent so it will set it Correctly with the Get Method? My struct:

    public struct TextureShared
    {
        public Texture2D TextureSheet;
    }

    So i need first Set the TextureShared and than the ManagedResource?

Or do the TextureResourceManager look up for each struct with a type of Texture2D and Load them accordingly with the info? textureResourceManager.Manage(_world);

Maybe i missing some infos here, or i understand something wrong x) I hope you understand my questions and thanks for help.

Doraku commented 4 years ago

1.What is the ITextureLoader from the TextureResourceManager ?

  1. Why you need GraphicsDevice _device? In Monogame it should be the ContentManager with Load?

The code from the documentation comes from my own game. I used an ITextureLoader so it can have different implementation for different platform. It has changed a little from when I created this documentation but here is its current form:

    public sealed class TextureResourceManager : AResourceManager<string, Texture2D>
    {
        private readonly GraphicsDevice _device;
        private readonly IStreamLoader _loader;

        public TextureResourceManager(GraphicsDevice device, IStreamLoader loader)
        {
            _device = device;
            _loader = loader;
        }

        protected override Texture2D Load(string info)
        {
            using Stream stream = _loader.Load(info);

            return Texture2D.FromStream(_device, stream);
        }

        protected override void OnResourceLoaded(in Entity entity, string info, Texture2D resource)
        {
            entity.Get<DrawInfo>().Texture = resource;
        }
    }

// StreamLoader for Android
    public sealed class StreamLoader : IStreamLoader
    {
        private readonly AssetManager _assets;

        public StreamLoader(AssetManager assets)
        {
            _assets = assets;
        }

        public Stream Load(string name) => _assets.Open(name);
    }

// StreamLoader for Windows
    public sealed class StreamLoader : IStreamLoader
    {
        public Stream Load(string name) => File.OpenRead(name);
    }

So you see why I need the GraphicsDevice, I am not a fan of the ContentManager because you can't easily unload specifics resources and the goal of the AResourceManager is to handle loading/unloading of resources as needed by their ManagedResource<,>. If you want to use the ContentManager in tandem with a AResourceManager, have a look at this issue #91, hopefully you will find everything you need :)

  1. How exactly does it work with shared Components? So for example i have the same Texture for more than on entity is it like this? entity.Set(new ManagedResource<string, Texture2D>("square.png")); entity1.SetSameAs(entity);

yep, although you don't gain much by using a shared component, keep in mind that if you change the ManagedResource<string, Texture2D> on entity, it will only notify the change and thus do the AResourceManager.Load for entity, not entity1. Shared components are great when you want to share a value across multiple entities but it does not work well when you need to react to the change (as AResourceManager or WhenChanged rules for entity sets) since only the specific entity on which you make the change will notify its change, not all the other entities sharing the component. I hope this isn't too confusing ^^"

So i need first Set the TextureShared and than the ManagedResource?

If you use a TextureShared in AResourceManager.Load then yes you need to set it before setting the ManagedResource or calling AResourceManager.Manage. Continuing from the previous point, this is what you could do:

// the main entity
entity.Set<TextureShared>();
entity.Set(new ManagedResource<string, Texture2D>("square.png");

// no need to set the ManagedResource
entity1.SetSameAs<TextureShared>(entity);
entity2.SetSameAs<TextureShared>(entity);
entity3.SetSameAs<TextureShared>(entity);
...

textureManager.Manage(world);

This will only set the loaded texture once but since the component is shared on multiple entities, they will all have the same texture in the end. You could even use Texture2D directly without a struct wrapper.

Or do the TextureResourceManager look up for each struct with a type of Texture2D and Load them accordingly with the info?

The TextureResourceManager only react to change on ManagedResource<string, Texture2D> components. Once set on an entity and the parent world managed, it will use the string to load the texture (if the texture has already been loaded previously by an other entity, it uses the same instance, using the string as a key) and then call OnResourceLoaded with the entity and the texture for you to do as you please. Internally it counts the number of Managed Resource<string, Texture2D> with the same key/string so when they are all removed from entities, the texture is disposed (you can change this behavior by overriding AResourceManager.Unload).

I hope this fill the blank for you :)

PodeCaradox commented 4 years ago

Thanks for the fast answer, now i think iunderstand it correctly :)

jnoyola commented 4 years ago

I am not a fan of the ContentManager because you can't easily unload specifics resources and the goal of the AResourceManager is to handle loading/unloading of resources

Absolutely a valid point 😊 but... I added another note to #91 about how it's actually pretty easy to bypass ContentManager's cache and use it only as a reader, fully utilizing AResourceManager's cache and ability to unload.