Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to change sprite image from script?

Discussion in '2D' started by amjadyahya, Nov 20, 2013.

  1. amjadyahya

    amjadyahya

    Joined:
    Nov 16, 2013
    Posts:
    11
    How can I change the sprite image from script? In the editor I have setup a texture with multiple frames (fruits_0, fruits_1 .. etc.) then I have assigned (fruits_0) to a game object named fruit. Now I want to be able to change fruit's image to display frame (fruits_1) instead of (fruits_0), how to do that in script?

    Thanks.
     
    sivavarun07 and blox5000 like this.
  2. unitylover

    unitylover

    Joined:
    Jul 6, 2013
    Posts:
    346
    Create a reference variable for each sprite you want to use in code. You can then assig these references to the sprite property of the sprite renderer of your game object.
     
    romanzpolski, hopetolive and blox5000 like this.
  3. Jtec

    Jtec

    Joined:
    Dec 13, 2012
    Posts:
    6
  4. amjadyahya

    amjadyahya

    Joined:
    Nov 16, 2013
    Posts:
    11
    @unitylover: thanks, but bear with me for a moment, why can't I just assign it directly, why do I need a reference? when I want to change the position, I just assign a new x,y,z coordinates to the object:
    transform.position = new Vector3(0f, 0f, 0f);

    I mean why can't I use this: SpriteRenderer.Sprite=new Sprite(fruits_1);
     
  5. loki70x7

    loki70x7

    Joined:
    Apr 19, 2010
    Posts:
    54
    If you are not using a reference how is the code going to know where the image you want to use as the sprite is?

    You would have to load the image first with Resources.Load. Something like:
    Code (csharp):
    1. Sprite myFruit = Resources.Load("fruits_1", typeof(Sprite)) as Sprite;
     
  6. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Don't put sprites in Resources; they can't be auto-atlased if you do that. Just use public references.

    Code (csharp):
    1. var spriteImage : Sprite;
    2.  
    3. function Start () {
    4.     GetComponent(SpriteRenderer).sprite = spriteImage;
    5. }
    --Eric
     
    _protagonist, twobob and edencakir like this.
  7. amjadyahya

    amjadyahya

    Joined:
    Nov 16, 2013
    Posts:
    11
    Thanks everybody, the solution I'm seeking is posted here.
     
  8. stepnoy

    stepnoy

    Joined:
    Nov 30, 2013
    Posts:
    2
    Is there any other way to do that? I have about 40 sprites in tileset, and I need to assign a sprite to rendered basing on random seed in script parameters. Is there a way to do that using only name/index of sprite in particular sprite sheet?
     
    Last edited: Dec 1, 2013
  9. Checkmark

    Checkmark

    Joined:
    Dec 2, 2013
    Posts:
    3
    I have been looking all over to find exactly this piece of information. Hopefully someone will come around and provide an answer. I have to think that there is a way to reference an individual sprite from a texture of type sprite-multiple
     
  10. Checkmark

    Checkmark

    Joined:
    Dec 2, 2013
    Posts:
    3
    For lack of having a method to directly access individual sprites created by Unity, I found the following workaround to get the job done. This requires that the individual sprites in the texture are in a grid. Basically, instead of having Unity build the individual sprite frames, you build them yourself.

    Add the sprite texture to your project as normal, with Type: "Sprite" and Sprite Mode "Single" (will not work if set to Multiple). I also have the Pixels to Units set to 1, which is consistent with the way I have my project setup. I then have the following class to build and allow access to the individual sprite frames:


    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class MapDisplay : BaseBehavior
    6. {
    7.  
    8.     public Texture2D TilesTexture;
    9.  
    10.     List<Sprite> _tileFrames;
    11.  
    12.     private float TILE_UNIT_WIDTH = 48f;
    13.     private float TILE_UNIT_HEIGHT = 48f;
    14.  
    15.     private int NUM_FRAMES_X = 8;
    16.     private int NUM_FRAMES_Y = 5;
    17.  
    18.     // Use this for initialization
    19.     void Awake () {
    20.         SetupSpriteFrames();
    21.     }
    22.    
    23.     // Update is called once per frame
    24.     void Update () {
    25.    
    26.     }
    27.  
    28.     public Sprite GetSpriteFrame(int tx, int ty)
    29.     {
    30.         return (tx >= 0  tx < NUM_FRAMES_X  ty >= 0  ty < NUM_FRAMES_Y) ? _tileFrames[ty * NUM_FRAMES_X + tx] : _tileFrames[0];
    31.     }
    32.  
    33.     private void SetupSpriteFrames()
    34.     {
    35.         _tileFrames = new List<Sprite>();
    36.        
    37.         Vector2 pv = new Vector2(0f, 0f);
    38.  
    39.         for (int j = 0; j < NUM_FRAMES_Y; j++)
    40.         {
    41.             for (int i = 0; i < NUM_FRAMES_X; i++)
    42.             {
    43.                 Rect loc = new Rect(i * TILE_UNIT_WIDTH, (NUM_FRAMES_Y - (j+1)) * TILE_UNIT_HEIGHT, TILE_UNIT_WIDTH, TILE_UNIT_HEIGHT);
    44.                 Sprite s = Sprite.Create(TilesTexture, loc, pv, 1f);
    45.                
    46.                 _tileFrames.Add(s);
    47.             }
    48.         }
    49.     }
    50.  
    51.  
    52.  
    53. }
    54.  
    Note: BaseBehavior, in addition to being mis-spelled, is just a wrapper around MonoBehaviour, and my tile size in pixels is 48x48.
    Once you attach this script to a GameObject, drag the texture you imported into the TilesTexture property and you should be good to go.

    Here is an example of how the class is then used, where the individual frame is identified by its x and y coordinates within the texture image starting at the top left:


    Code (csharp):
    1. public void SetTileGraphic(MapTerrain mt, MapDisplay parentMap)
    2.     {
    3.         // get reference to sprite renderer
    4.         SpriteRenderer sr = this.transform.FindChild("MapTileSprite").gameObject.GetComponent<SpriteRenderer>();
    5.  
    6.         switch (mt.TerrainType)
    7.         {
    8.             case MapTerrain.TERRAIN_FOREST:
    9.                 sr.sprite = parentMap.GetSpriteFrame(1, 0);
    10.                 break;
    11.             case MapTerrain.TERRAIN_HILLS:
    12.                 sr.sprite = parentMap.GetSpriteFrame(2, 0);
    13.                 break;
    14.             case MapTerrain.TERRAIN_WATER:
    15.                 sr.sprite = parentMap.GetSpriteFrame(3, 0);
    16.                 break;
    17.             case MapTerrain.TERRAIN_PLAINS::
    18.                 sr.sprite = parentMap.GetSpriteFrame(0, 0);
    19.                 break;
    20.         }
    21.     }

    Still hoping there is a way to reference Sprites created in the editor via code, either which I do not know about, or in a future release.
     
    kervenBN and KillMobil like this.
  11. musiko

    musiko

    Joined:
    Mar 5, 2013
    Posts:
    4
    @Checkmark Without using sprite sheet, the draw call count is increased significantly, right?
     
  12. Checkmark

    Checkmark

    Joined:
    Dec 2, 2013
    Posts:
    3
    @musiko I think you have it right. Building sprite frames like this is likely going to cost you, but I have not dug into the rendering code.

    This is one of the reasons I ended up purchasing 2DToolkit, which has worked out very well and is providing the solution I needed. I hope that the Unity team adds a way to access individual sprite frames in a Multi-Sprite texture in a future release.
     
    mhmtemnacr likes this.
  13. billy000

    billy000

    Joined:
    Feb 13, 2014
    Posts:
    1
    What image format do you use as the sprite image? gif, png, jpeg or tiff?
     
  14. iniestar24

    iniestar24

    Joined:
    Feb 26, 2014
    Posts:
    2
    Hello there,

    I got your script working but I can't do it with other sprite, just the one that I got my script in. How can I define which Sprite I want to change?
     
  15. SiegfriedCroes

    SiegfriedCroes

    Joined:
    Oct 19, 2013
    Posts:
    569
    I made a little script to make this really easy:

    To use it you just do:

    Javascript
    Code (csharp):
    1.  
    2. var sprites : SpriteCollection;
    3.  
    4. function Start()
    5. {
    6.     sprites = new SpriteCollection("Spritesheet"); // Spritesheet = path + name of sprite in Resources folder
    7.  
    8.     GetComponent("SpriteRenderer").sprite = sprites.GetSprite("Sprite1"); //name of specific sprite in spritesheet
    9. }
    10.  
    C#
    Code (csharp):
    1.  
    2. SpriteCollection sprites;
    3.  
    4. function Start()
    5. {
    6.     sprites = new SpriteCollection("Spritesheet");
    7.  
    8.     GetComponent<SpriteRenderer>().sprite = sprites.GetSprite("Sprite1");
    9. }
    10.  
     

    Attached Files:

    Last edited: Mar 26, 2014
    malialis and Tatanan like this.
  16. iniestar24

    iniestar24

    Joined:
    Feb 26, 2014
    Posts:
    2
    Cheers dude, thanks for the help :D

    But that wasn't what I wanted. I have the script running on my character so when it collides whit some objects the background image changes. My problem it's instead of changing the background I'm changing the character because I put the script in the character. My problem it's how can I swap the new sprite with the background instead of the character?
     
    Last edited: Mar 27, 2014
  17. SiegfriedCroes

    SiegfriedCroes

    Joined:
    Oct 19, 2013
    Posts:
    569
    Then instead of doing:

    Code (csharp):
    1. GetComponent("SpriteRenderer").sprite = sprites.GetSprite("Sprite1");
    You should do:

    Code (csharp):
    1. GameObject.Find("nameOfBackgroundGameObject").GetComponent("SpriteRenderer").sprite = sprites.GetSprite("Sprite1");
     
  18. DarkSlash

    DarkSlash

    Joined:
    Sep 30, 2011
    Posts:
    127
    I need also to change the image in runtime, I have this code:

    Code (csharp):
    1.     GameObject background;
    2.     background = new GameObject("background");
    3.     background.AddComponent("SpriteRenderer");
    4.     background.GetComponent<SpriteRenderer>().sprite = Resources.Load<Sprite>("background");
    But then how I change the size of background?
     
  19. LaurensiusTony

    LaurensiusTony

    Joined:
    May 22, 2013
    Posts:
    78
    well i using this to change my sprite in runtime
    Code (CSharp):
    1.  
    2.     public Sprite[] sprites;
    3.     private SpriteRenderer spriteRenderer;
    4.  
    5.     public int index = 0;
    6.  
    7.     // Use this for initialization
    8.     void Start () {
    9.         spriteRenderer = renderer as SpriteRenderer;
    10.     }
    11.  
    12.     // Update is called once per frame
    13.     void Update () {
    14.         spriteRenderer.sprite = sprites[index];
    15.     }
    so that is the basic and you just need to tweak the index number to showing the sprite you want
    and if you want to achieve spriteanimation like looping all your sprite to showing animation then just
    tweak it into this

    Code (CSharp):
    1.  
    2.     public Sprite[] sprites;
    3.     public float framesPerSecond;
    4.     private SpriteRenderer spriteRenderer;
    5.  
    6.     // Use this for initialization
    7.     void Start () {
    8.         spriteRenderer = renderer as SpriteRenderer;
    9.     }
    10.  
    11.     // Update is called once per frame
    12.     void Update () {
    13.         int index = (int)(Time.timeSinceLevelLoad * framesPerSecond);
    14.         index = index % sprites.Length;
    15.         spriteRenderer.sprite = sprites[index];
    16.     }
     
    Johnmschneider likes this.
  20. Photoshop1

    Photoshop1

    Joined:
    May 26, 2015
    Posts:
    2
  21. U_Ku_Shu

    U_Ku_Shu

    Joined:
    Dec 9, 2014
    Posts:
    5
    Resources.Load are searching in the directory "Assets/Resources"
    That's why you need to do

    _sprites = Resources.LoadAll<Sprite>(spritesPath);

    or

    _sprites = Resources.Load<Sprite>(spritesPath);

    with spritesPath as relative path.
    If you need to load all from folder "Assets/Resources/Sprites", you need to write only "Sprites".
     
  22. wasicool7

    wasicool7

    Joined:
    Jul 28, 2016
    Posts:
    25
    Hi, sorry about this but could you help me with something, you see I want to know if there was a way of scaling my images and locking it to a size of it's anchor points so that when I click on maximize on play the images can be stretched out. Thank you. :)
     
  23. Ziplock9000

    Ziplock9000

    Joined:
    Jan 26, 2016
    Posts:
    360
    So what's the right way to do this when you might have many images you want to load from and you don't want to lose auto-atlased sprites?
     
  24. eltrexx

    eltrexx

    Joined:
    Feb 1, 2018
    Posts:
    11
    +1 Ressources.Load seems what we need, but if auto-atlas is needed then how do to this ? Coz I won't assign them all through editor...
     
  25. KingKong320

    KingKong320

    Joined:
    Mar 2, 2018
    Posts:
    21
    Can anyone tell me where that image goes when i download it and assign it to gameobject,and quit the game ,is it deleted from all the memory of device?
     
    romatomas likes this.
  26. treecki

    treecki

    Joined:
    Feb 6, 2017
    Posts:
    29
    I may be missing something, but couldn't you make a scriptable object that contains all the sprite information but stays in resources? So you'd have a scriptable object with maybe a list or dictionary and you have an editor script to grab the assets and refresh the sprites in the Scriptable Object with the Asset/Sprites folder. This can be a dictionary with the name of the sprites as the key. So when you want to load from Resources you can do so from the Scriptable Object, but your sprites are still being auto-atlased.
     
  27. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,314
    It's not clear who you are responding to. Note that this thread is from 2013. The last post was over 3 years ago.
     
  28. treecki

    treecki

    Joined:
    Feb 6, 2017
    Posts:
    29
    I was responding to the general thread and the strategy for keeping track of sprites and loading them without losing auto-atlasing by having them in resources. I wanted to see if there were any downsides to my current strategy and/or if resources.load(sprite path) was better for some reason.