Advertisement
noradninja

Animated sprite sheet

Jul 4th, 2023
750
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 9.52 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4.  
  5. public class AnimateSpriteSheet : MonoBehaviour
  6. {
  7.     public string textureString = "_MainTex";
  8.     public int _columns = 2;                        // The number of columns of the texture
  9.     public int _rows = 2;                           // The number of rows of the texture
  10.     public Vector2 _scale = new Vector3(1f, 1f);    // Scale the texture. This must be a non-zero number. negative scale flips the image
  11.     public Vector2 _offset = Vector2.zero;          // You can use this if you do not want the texture centered. (These are very small numbers .001)
  12.     public Vector2 _buffer = Vector2.zero;          // You can use this to buffer frames to hide unwanted grid lines or artifacts
  13.     public float _framesPerSecond = 10f;            // Frames per second that you want to texture to play at
  14.     public bool _playOnce = false;                  // Enable this if you want the animation to only play one time
  15.     public bool _disableUponCompletion = false;     // Enable this if you want the texture to disable the renderer when it is finished playing
  16.     public bool _enableEvents = false;              // Enable this if you want to register an event that fires when the animation is finished playing
  17.     public bool _playOnEnable = true;               // The animation will play when the object is enabled
  18.     public bool _newMaterialInstance = false;       // Set this to true if you want to create a new material instance
  19.  
  20.     private int _index = 0;                         // Keeps track of the current frame
  21.     private Vector2 _textureSize = Vector2.zero;    // Keeps track of the texture scale
  22.     private Material _materialInstance = null;      // Material instance of the material we create (if needed)
  23.     private bool _hasMaterialInstance = false;      // A flag so we know if we have a material instance we need to clean up (better than a null check i think)
  24.     private bool _isPlaying = false;                // A flag to determine if the animation is currently playing
  25.  
  26.  
  27.     public delegate void VoidEvent();               // The Event delegate
  28.     private List<VoidEvent> _voidEventCallbackList; // A list of functions we need to call if events are enabled
  29.  
  30.     // Use this function to register your callback function with this script
  31.     public void RegisterCallback(VoidEvent cbFunction)
  32.     {
  33.         // If events are enabled, add the callback function to the event list
  34.         if (_enableEvents)
  35.             _voidEventCallbackList.Add(cbFunction);
  36.         else
  37.             Debug.LogWarning("AnimateTiledTexture: You are attempting to register a callback but the events of this object are not enabled!");
  38.     }
  39.  
  40.     // Use this function to unregister a callback function with this script
  41.     public void UnRegisterCallback(VoidEvent cbFunction)
  42.     {
  43.         // If events are enabled, unregister the callback function from the event list
  44.         if (_enableEvents)
  45.             _voidEventCallbackList.Remove(cbFunction);
  46.         else
  47.             Debug.LogWarning("AnimateTiledTexture: You are attempting to un-register a callback but the events of this object are not enabled!");
  48.     }
  49.  
  50.     public void Play()
  51.     {
  52.         // If the animation is playing, stop it
  53.         if (_isPlaying)
  54.         {
  55.             StopCoroutine("updateTiling");
  56.             _isPlaying = false;
  57.         }
  58.         // Make sure the renderer is enabled
  59.         GetComponent<Renderer>().enabled = true;
  60.  
  61.         //Because of the way textures calculate the y value, we need to start at the max y value
  62.         _index = _columns;
  63.  
  64.         // Start the update tiling coroutine
  65.         StartCoroutine(updateTiling());
  66.     }
  67.  
  68.     public void ChangeMaterial(Material newMaterial, bool newInstance = false)
  69.     {
  70.         if (newInstance)
  71.         {
  72.             // First check our material instance, if we already have a material instance
  73.             // and we want to create a new one, we need to clean up the old one
  74.             if (_hasMaterialInstance)
  75.                 Object.Destroy( GetComponent<Renderer>().sharedMaterial);
  76.  
  77.             // create the new material
  78.             _materialInstance = new Material(newMaterial);
  79.  
  80.             // Assign it to the renderer
  81.              GetComponent<Renderer>().sharedMaterial = _materialInstance;
  82.  
  83.             // Set the flag
  84.             _hasMaterialInstance = true;
  85.         }
  86.         else // if we dont have create a new instance, just assign the texture
  87.              GetComponent<Renderer>().sharedMaterial = newMaterial;        
  88.  
  89.         // We need to recalc the texture size (since different material = possible different texture)
  90.         CalcTextureSize();
  91.  
  92.         // Assign the new texture size
  93.          GetComponent<Renderer>().sharedMaterial.SetTextureScale(textureString, _textureSize);
  94.     }
  95.  
  96.     private void Awake()
  97.     {
  98.         // Allocate memory for the events, if needed
  99.         if (_enableEvents)
  100.             _voidEventCallbackList = new List<VoidEvent>();
  101.  
  102.         //Create the material instance, if needed. else, just use this function to recalc the texture size
  103.         ChangeMaterial( GetComponent<Renderer>().sharedMaterial, _newMaterialInstance);
  104.     }
  105.  
  106.     private void OnDestroy()
  107.     {
  108.         // If we wanted new material instances, we need to destroy the material
  109.         if (_hasMaterialInstance)
  110.         {
  111.             Object.Destroy( GetComponent<Renderer>().sharedMaterial);
  112.             _hasMaterialInstance = false;
  113.         }
  114.     }
  115.  
  116.     // Handles all event triggers to callback functions
  117.     private void HandleCallbacks(List<VoidEvent> cbList)
  118.     {
  119.         // For now simply loop through them all and call yet.
  120.         for (int i = 0; i < cbList.Count; ++i)
  121.             cbList[i]();
  122.     }
  123.  
  124.     private void OnEnable()
  125.     {
  126.  
  127.        CalcTextureSize();
  128.  
  129.         if (_playOnEnable)
  130.             Play();
  131.     }
  132.  
  133.     private void CalcTextureSize()
  134.     {
  135.         //set the tile size of the texture (in UV units), based on the rows and columns
  136.         _textureSize = new Vector2(1f / _columns, 1f / _rows);
  137.  
  138.         // Add in the scale
  139.         _textureSize.x = _textureSize.x / _scale.x;
  140.         _textureSize.y = _textureSize.y / _scale.y;
  141.  
  142.         // Buffer some of the image out (removes gridlines and stufF)
  143.         _textureSize -= _buffer;
  144.     }
  145.  
  146.     // The main update function of this script
  147.     private IEnumerator updateTiling()
  148.     {
  149.         _isPlaying = true;
  150.  
  151.         // This is the max number of frames
  152.         int checkAgainst = (_rows * _columns);
  153.  
  154.         while (true)
  155.         {
  156.             // If we are at the last frame, we need to either loop or break out of the loop
  157.             if (_index >= checkAgainst)
  158.             {
  159.                 _index = 0;  // Reset the index
  160.  
  161.                 // If we only want to play the texture one time
  162.                 if (_playOnce)
  163.                 {
  164.                     if (checkAgainst == _columns)
  165.                     {
  166.                         // We are done with the coroutine. Fire the event, if needed
  167.                         if(_enableEvents)
  168.                             HandleCallbacks(_voidEventCallbackList);
  169.  
  170.                         if (_disableUponCompletion)
  171.                             gameObject. GetComponent<Renderer>().enabled = false;
  172.  
  173.                         // turn off the isplaying flag
  174.                         _isPlaying = false;
  175.  
  176.                         // Break out of the loop, we are finished
  177.                         yield break;
  178.                     }
  179.                     else
  180.                         checkAgainst = _columns;    // We need to loop through one more row
  181.                 }
  182.  
  183.             }
  184.  
  185.             // Apply the offset in order to move to the next frame
  186.             ApplyOffset();
  187.  
  188.             //Increment the index
  189.             _index++;
  190.  
  191.             // Wait a time before we move to the next frame. Note, this gives unexpected results on mobile devices
  192.             yield return new WaitForSeconds(1f / _framesPerSecond);
  193.         }        
  194.     }
  195.  
  196.     private void ApplyOffset()
  197.     {
  198.         //split into x and y indexes. calculate the new offsets
  199.         Vector2 offset = new Vector2((float)_index / _columns - (_index / _columns), //x index
  200.                                       1 - ((_index / _columns) / (float)_rows));    //y index
  201.  
  202.         // Reset the y offset, if needed
  203.         if (offset.y == 1)
  204.             offset.y = 0.0f;
  205.  
  206.         // If we have scaled the texture, we need to reposition the texture to the center of the object
  207.         offset.x += ((1f / _columns) - _textureSize.x) / 2.0f;
  208.         offset.y += ((1f / _rows) - _textureSize.y) / 2.0f;
  209.  
  210.         // Add an additional offset if the user does not want the texture centered
  211.         offset.x += _offset.x;
  212.         offset.y += _offset.y;
  213.  
  214.         // Update the material
  215.          GetComponent<Renderer>().sharedMaterial.SetTextureOffset(textureString, offset);
  216.     }
  217.  
  218. //The following is an example of how to use the events:
  219.  
  220. void Start()
  221. {
  222.     if (_animatedTileTexture == null)
  223.     {
  224.         Debug.LogWarning("No animated tile texture script assigned!");
  225.     }
  226.     else
  227.         _animatedTileTexture.RegisterCallback(AnimationFinished);
  228.  
  229. }
  230.  
  231. // This function will get called by the AnimatedTiledTexture script when the animation is completed if the EnableEvents option is set to true
  232. void AnimationFinished()
  233. {
  234.         // The animation is finished
  235. }
  236.  
  237.  public AnimateSpriteSheet _animatedTileTexture;    // A reference to AnimatedTileTexture object
  238. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement