2

I'm creating a multiplayer game, including different heros with different values (e.g. health, damage). I initially fetch these values from a database and store them into a struct.

-> I have little to no knowledge about structs 
-> and got told this is probably a performance loss / bad approach

Storing the values in the struct and creating a dictionary (int, my-struct) to obtain the values worked perfectly fine before.

I've come to the point where I want to store specific sprites for each hero inside this struct. I consider fetching these sprites through Resources.Load (which I guess is the most simple way)

public struct data
{
    public string Name;
    public int ID, hp, dmg, range, magazin;
    public float tbtwb, rltime;
    public Sprite heroSprite;   //Structs don't seem to like Unity's sprite type
}

public Dictionary<int, data>_HeroDict;

This is how I feed the struct and add an entry into the dictionary.

while (rdr.Read())
                    {
                        //Store it into the Dictionary
                        data itm = new data();

                        itm.Name = rdr["Name"].ToString();
                        itm.ID = int.Parse (rdr["ID"].ToString());
                        itm.hp = int.Parse (rdr["Hp"].ToString());
                        itm.dmg = int.Parse (rdr["Dmg"].ToString());
                        itm.magazin = int.Parse (rdr["Magazin"].ToString());
                        itm.range = int.Parse (rdr["Range"].ToString());
                        itm.tbtwb = float.Parse(rdr["Tbtwb"].ToString());
                        itm.rltime = float.Parse(rdr["Rltime"].ToString());

//What I thought of:
itm.heroSprite = Resources.Load ("Sprites/Sprite1", typeof(Sprite)) as Sprite;

                        _HeroDict.Add(itm.ID, itm);
                    }

My issue: I can't store sprites inside a struct and don't know about a workaround.

I've been told I could/should use a class instead of a struct, but I couldn't store a Sprite as well, not knowing why.

Can you point me into the right direction and give me an example approach?

Thanks in advance, Csharpest

Csharpest
  • 1,258
  • 14
  • 32
  • 1
    [`Resource.Load`](https://docs.unity3d.com/ScriptReference/Resources.Load.html) is used to load assets, not structs. For user types I'd suggest to use [serialization](http://stackoverflow.com/q/6115721/1997232), e.g. json. Then your object loading will be a single line, e.g. `var item = JsonConvert.DeserializeObject(rdr["DataAsJsonString"]);` – Sinatr Jan 25 '17 at 12:47
  • I will do some researches on that, thank you so far. Despite that, is there not a way I can just add a sprite to my dictionary? If I made my dictionary of type int, someClass ? I guess I will just create another class + dictionary, similiar to [SO - static sprite manager](https://stackoverflow.com/questions/24808866/how-to-store-a-sprite-in-a-global-variable-using-c-sharp-script-after-touch-even#24821306) – Csharpest Jan 25 '17 at 13:02
  • 1
    You can store a Sprite inside a struct, this is not the issue. Mostly the problem is that a Sprite would require serialization like mentioned in the comment. But you don't necessarily need to store the whole Sprite data, more likely just the texture and some information about it if needed. For the texture you can convert it to PNG which is just a byte [] and that can be saved easily. – Everts Jan 25 '17 at 13:27
  • 1
    You shouldn't have any problem of adding instance of `data` to `Dictionary` assuming key (that `int`) is unique, disregards how it's instantiated: as you do now or with deserialization. I am not quite sure what you are up to. If the sprite data serializable (as e.g. `byte[]` or `string`) then you shouldn't have problems when storing different `data` instances, as they all have their sprites properly saved/restored. If same sprite is used in more than one instance of `data`, then yes, sure, it make sens to save them separately and retrieve when you need them (e.g. property getter). – Sinatr Jan 25 '17 at 13:27
  • Thanks a lot, so serialization in this context would mean "convert Sprite to byte array"? What I'm up to: When changing your Hero in the game I want to set his hp, damage, sprite etc.. I'm doing this by referencing to the dictionary and taking the values where key = x. I did a workaround by creating a class that loads every characters sprite in an array on startup and make me receive it through a call on another dictionary. I'm not experienced enough to handle the (de)serialization for now I guess, but I'll try it out in the future. Although thanks for introducing me into this – Csharpest Jan 25 '17 at 14:16

1 Answers1

1

You can't store a sprite inside a struct or class. A sprite is a class internal to Unity. What you can store is a reference to a sprite, which is exactly what happens when you declare

Sprite sprite = whatever()

It is also important to know just how sprites are stored. A sprite is an asset. Assets are serialized into packages by Unity when your game is built. When you import a sprite, Unity does some magic and later gives it back to you just as it were when you imported it. This is why you can't store a sprite in your code/custom files/whatever. Even if you did find some way to do it, it would be highly inappropriate to do so, since Unity performs many optimizations you don't know of.

With this knowledge, what you can do to retrieve sprites (or any asset) from Unity's asset database is:

  1. Declare a public variable in one of your monobehaviour classes and assign references in the editor.
  2. Store your asset in a Resources folder and use Resources.Load to find and load it by name.

In your case, your best bet is to give each hero some sort of ID and use that as a name to load it from the resources.

I should also mention two more things: One, always use classes unless you absolutely know what you're doing. The way you worded your question indicates you don't, so use a class instead. More reading: Design guidelines from MSDN

Two, your code looks like you come from a C++ background and you're trying to somehow use your existing knowledge and old ways of doing things inside Unity. Don't. What you should really do is to create a prefab for each hero and load those from resources.

Arshia001
  • 1,854
  • 14
  • 19
  • Thanks a lot for your advice! But since it's a multiplayer game and I would have to re-instantiate the players prefab everytime a player swaps his Hero: I just change the SpriteRenderer and the mentioned values via script, still using one player prefab only. Do you think this approach is fine? And like I answered in a comment above: I created another Class containing a dictionary which gets it's content through Resources.LoadAll()... . It seems to work pretty well so far. – Csharpest Jan 26 '17 at 10:54
  • 1
    Separately loading a sprite from resources is fine. Also, to change heroes, my suggestion would be to either load them at runtime if it doesn't negatively impact performance (Hearthstone does this for every effect, sound, etc.) or just load them at startup and let them hang there. When you load an asset from resources, it remains loaded even without any active references so the next Load() call will cost nothing. – Arshia001 Jan 26 '17 at 19:46
  • Alright, then my way of doing it would be like you suggested, thank you! – Csharpest Feb 03 '17 at 10:19