- Home /
Displaying single sprite from spritesheet on GUI
I've got a sprite sheet of weapons and items that I've set to "multiple" sprite mode, so I have a bunch of "sub-sprites" from the main sheet. I've then created "icon" parameters for, say, a weapon, and dragged the corresponding sub-sprite from the sheet into the inspector slot - now the object has a reference to that sub-sprite.
I want to display this sprite on a GUI when it's selected (e.g. in an item shop screen), however when I try and use GUI.DrawTexture() on that object's sub-sprite, instead it draws the entire spritesheet it came from. I then tried using GUI.DrawTextureWithTexCoords(), but this made the sprite seemingly disappear, even though as far as I'm aware, the coordinates were correct. I also tried creating a prefab of the individual sprite and passing it to the UI to display, but this didn't work either (and seems a bit long-winded to do for every single one when I already have them separated as sub-sprites).
Is there a way to display the single sub-sprite from the main sheet on the GUI?
EDIT: I got DrawTextureWithTexCoords() to work (I forgot to set the last param to true meaning there was no alpha?), but even so, it was a complete pain to go through and find the coords of every single sprite in the main sheet, and displaying it was also annoying.
Ultimately I followed what @lunoland said, but instead of using a prefab with lots of child prefabs for each icon, I gave each item a Sprite attribute, then when the GUI needed to display that item, it just accessed its attached sprite attribute and updated the on-screen item prefab's sprite to be that. I don't know if this is the best way to do it, but it works for now and I'll play around with it some more.
Well, you need to do a little bit of work once and then you are set :)
If you sheet is 128x128 and your sprites/tiles are each 32x32, then you can automatically compute the number of sprites per row, and the number of rows (128/32 = 4). Now you write a simple function that takes the index of the sprite you want, for example the sixth sprite of the sheet, and since the function knows the values above it will then return the required coordinates for you to pass on to the DrawTexture function :)
As an additional step, you could make a small database of sorts, like a Dictionary, that lets you input an item name or ID and it gives you the sprite index (or you could even combine it with the custom functions above to get teh coordiantes directly).
Actually I did get DrawTextureWithTexCoords to work in the end, I didn't need to create any Dictionary, all I did was create an attribute for each item called "itemSprite", then when items are instantiated, I call upon an array of all the individual sprites (from the spritesheet), and give it a specific "itemSprite" attribute from there.
Then, when I want to display it on the GUI, I used code from this answer, because I can get the TexCoords of the sprite on the main sheet by calling .rect, then I adjusted the width and height params until they showed the sprite that I wanted.
I may not have explained it very well but basically using an array of individual sprites and then using code from that answer got DrawTextureWithTexCoords to work.
Answer by lunoland · Aug 05, 2016 at 10:52 AM
@Nephtis I would strongly recommend using the newer Canvas paradigm over OnGUI.
Create a single prefab for one of your icon sprites and get that set up and looking the way you want on the Canvas. Then just iterate over all your sprite icons, instantiating a new instance of the prefab and changing its sprite to the current sprite. You'll also want to parent each new object to the canvas and change the object's name to match the sprite or icon name.
I can't test this right now, but assuming you put your sprite in the folder Resources/Sprites, it would look something like:
public GameObject iconPrefab; // Assign these in the inspector
public Transform canvas;
void GenerateIcons() {
Sprite[] sprites = Resources.LoadAll<Sprite>("Sprites/YourSpriteName");
foreach (Sprite sprite in sprites) {
GameObject newIcon = Instantiate<GameObject>(iconPrefab);
newIcon.name = sprite.name;
newIcon.GetComponent<Image>().sprite = sprite;
newIcon.transform.SetParent(canvas, false);
}
}
Once you run the script and the new UI objects are created in the scene, you can select them and drag into your assets folder to create individual prefabs. This will make it super easy to adjust individual icons later on.
@lunoland Ok, so I've got a reference to the canvas and an icon prefab (which currently has a dummy icon as its sprite) in the UI code. I've done what your code says; when I run it, it creates 500 (the amount of sprites in the sheet) individual icon gameObjects (as children of the canvas) corresponding to each sprite. Am I correct in thinking you then want me to drag all of those into the assets folder, creating 500 icon prefabs?
500 is quite a lot. I would parent them all to an empty game object, name that "icons" or something, and then drag that to your assets folder. If you want to edit a single icon, you can easily just drag the prefab into the scene, find the icon in it's children, tweak the sprite or whatever as needed, then apply changes.
That seemed to crash Unity. I think I'm misunderstanding something here, so I'll run through what I'm doing:
Put your code into my UI script.
Gave the script public variables: GameObject iconPrefab (not sure what this is for but it's currently an empty GameObject with a spriterenderer), and Transform icons (used to be canvas but I'm now parenting the created gameobjects to icons, which is a child of the canvas).
Ran the script: this created 500 child gameobjects under the "icons" gameobject, each of which with a spriterenderer corresponding to sprites in the main sheet.
Tried to click and drag the "icons" gameobject into the prefabs folder, causing Unity to crash.
Is this correct? Let's say I had 10 icons ins$$anonymous$$d of 500, would the end goal be having gameobject prefabs for those icons? I assume I can then display them in some way that I couldn't before when using sub-sprites of a main sheet?
EDIT: I figured out why Unity was crashing, basically it was because I'd be trying to move the "icons" gameobject to the prefabs folder when the game was paused, and I guess Unity didn't like that. Instantiated the icons in the Start() function ins$$anonymous$$d, and now I've got the prefab you described.
Your answer
Follow this Question
Related Questions
Gui Box - Texture - Spritesheet 0 Answers
texCoords rect for GUI.DrawTextureWithTexCoords 3 Answers
strange results with GUI.DrawTexture() in the editor scene 1 Answer
Using Grayscale Textures For Transparency 1 Answer
ObjectField Sprite picker: The texCoords size is always one, on Single Sprite textures 0 Answers