Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How to start an animation every time a gui.button is clicked?

Discussion in 'Scripting' started by Exnihilon, May 3, 2014.

  1. Exnihilon

    Exnihilon

    Joined:
    Mar 2, 2014
    Posts:
    157
    Hello forum. I need some quidance on how to make a texture animation on a GameObject to run, every time a gui.button is pressed. Let me explain what I have done so far. I have the "Texture Swap Animator.js" script from WiKi, attached to a GameObject, which I call to run through another js script, that contains a GUI.Button.

    The Texture Swap Animator script is modified so, it only runs once, without looping. I want to make the script run from start everytime I hit the GUI.Button. How can this be done? Need your help to make it work as it should.

    Here is the codding of the "Texture Swap Animator.js":

    Code (csharp):
    1.  
    2. #pragma strict
    3.  
    4.     var frames : Texture2D[];
    5.     var framesPerSecond = 10.0;
    6.      
    7.     function Update ()
    8.  {
    9.         var index : int = Time.time * framesPerSecond;
    10.         if (index < frames.Length)
    11.         {
    12.             renderer.material.mainTexture = frames[index];
    13.         }
    14. }
    15.  
    Here is the coding of the script with the GUI.Button that is calling the above script to function:

    Code (csharp):
    1.  
    2.  
    3. #pragma strict
    4.     var native_width :  float = 480;
    5.     var native_height : float = 320;
    6.     var btnTexture1 : Texture;
    7.     var Cam1 : Camera;
    8.     var Cam1On : boolean = false;
    9.  
    10.     function Start()
    11.     {
    12.     Cam1.enabled = false;
    13.     }  
    14.    
    15.     function Update()
    16.     {
    17.     if (!Cam1On)
    18.     {
    19.     Cam1.enabled = false;
    20.     }
    21.     else
    22.     {
    23.        Cam1.enabled = true;
    24.     }
    25.     }
    26.  
    27. function OnGUI ()
    28.     {
    29.         //set up scaling
    30.         var rx : float = Screen.width / native_width;
    31.         var ry : float = Screen.height / native_height;
    32.      
    33.         GUI.matrix = Matrix4x4.TRS (Vector3(0, 0, 0), Quaternion.identity, Vector3 (rx, ry, 1));
    34.      
    35.         //now create your GUI normally, as if you were in your native resolution
    36.         //The GUI.matrix will scale everything automatically.
    37.  
    38.  if (!btnTexture1)
    39.                {
    40.             Debug.LogError("Please assign a texture on the inspector");
    41.             return;
    42.             }
    43.            
    44.             if(GUI.Button(Rect(230, 120, 40, 25), btnTexture1))    
    45.                 {
    46.                 Cam1On = !Cam1On;
    47.                 }
    48.  
    49.  
    I need to mention that the GameObject with the attached "Texture Swap Animator.js" script is visible only when the "Cam1On=true", by clicking that GUI.Button.

    Could someone be kind enough to point me to the right direction on how to implement this functionality to my Unity project?

    Thank you all in advance for your time reading this post. Waiting for your answers.
     
  2. QuinnWinters

    QuinnWinters

    Joined:
    Dec 31, 2013
    Posts:
    490
    It looks to me like what you're wanting to do could be done with a public boolean variable on the main script. In the following I put the main script on a gameobject named MyGameobject and I named the main script TestCam. The texture script is on a separate object. The bulk of the texture script doesn't run unless the gui button created in the main script is pressed and the runMe variable gets temporarily set to true.

    Code (csharp):
    1. #pragma strict
    2.  
    3. var frames : Texture2D[];
    4. var framesPerSecond = 10.0;
    5. var MyGameobject : GameObject;
    6. private var runMe = false;
    7.  
    8. function Update () {
    9.  
    10.     runMe = MyGameobject.GetComponent(TestCam).runMe;
    11.  
    12.     if (runMe) {
    13.    
    14.         MyGameobject.GetComponent(TestCam).runMe = false;
    15.    
    16.         var index : int = Time.time * framesPerSecond;
    17.        
    18.         if (index < frames.Length) {
    19.             renderer.material.mainTexture = frames[index];
    20.         }
    21.    
    22.     }
    23.  
    24. }
    Code (csharp):
    1. #pragma strict
    2. var native_width :  float = 480;
    3. var native_height : float = 320;
    4. var btnTexture1 : Texture;
    5. var Cam1 : Camera;
    6. var Cam1On : boolean = false;
    7. public var runMe = false;
    8.  
    9. function Start() {
    10.  
    11.     Cam1.enabled = false;
    12.  
    13. }  
    14.  
    15. function Update() {
    16.  
    17.     if (!Cam1On) {
    18.         Cam1.enabled = false;
    19.     }
    20.    
    21.     else {
    22.        Cam1.enabled = true;
    23.     }
    24.  
    25. }
    26.  
    27. function OnGUI () {
    28.  
    29.     //set up scaling
    30.     var rx : float = Screen.width / native_width;
    31.     var ry : float = Screen.height / native_height;
    32.  
    33.     GUI.matrix = Matrix4x4.TRS (Vector3(0, 0, 0), Quaternion.identity, Vector3 (rx, ry, 1));
    34.  
    35.     //now create your GUI normally, as if you were in your native resolution
    36.     //The GUI.matrix will scale everything automatically.
    37.  
    38.     if (!btnTexture1) {
    39.         Debug.LogError("Please assign a texture on the inspector");
    40.         return;
    41.     }
    42.        
    43.     if(GUI.Button(Rect(230, 120, 40, 25), btnTexture1)) {
    44.         Cam1On = !Cam1On;
    45.         runMe = true;
    46.     }
    47.  
    48. }
     
  3. Exnihilon

    Exnihilon

    Joined:
    Mar 2, 2014
    Posts:
    157
    Thanks @QuinnWinters for your time, modifing the code I've posted. I' ll give it a try and I' ll report back about the outcome.
     
  4. Exnihilon

    Exnihilon

    Joined:
    Mar 2, 2014
    Posts:
    157
    Well @QuinnWinters, I have tried to run the code you posted, but I think I don't quite following.

    In my scene there is a gameobject named "Cam1" with a boolean "Cam1On" that if set to true, the camera is enabled and sees the other gameobject named "Animator" that the "TextureSwapAnimator" script is attached to.

    I understand that, there should be a public variable, you named it "runMe = false" at the "TextureSwapAnimator" script, which should be changed to "true", through the main script with the GUI.button, that you named it "TestCam", by accessing it as a component, right?

    So for now we have 2 gameobjects, the one in my scene named "Animator", that is the "TextureSwapAnimator" script attached, and the other gameobject, named "Cam1". Should there be another gameobject to function properly? I'm quite puzzled.
     
  5. Exnihilon

    Exnihilon

    Joined:
    Mar 2, 2014
    Posts:
    157
    Finally after some trial and error attempts, managed to make the code run, as expected, following @QuinnWinters suggested code snippet.

    But there is a catch. Although the "TextureSwapAnimator" script is running on gui.button click, it is only run for one time that button is pressed.

    What modifications should be done to the code, to make it run from start, every time the user clicks that gui.button?

    Sould a counter be attached to the script, and if so, how this can be coded?

    Anyone having a suggestion, please respont to a noob's request. Thank you all.
     
  6. Exnihilon

    Exnihilon

    Joined:
    Mar 2, 2014
    Posts:
    157
    Well it seems that I was mistaken by the behaviour of @QuinnWinter's suggested code snippet. Although the logic of variable acting as a trigger to make the texture animation started, is valid, the implementation does not functions as it should.

    Let me explain. The variable "runMe" that is set at start as "false" should be declares "true", on the click of the gui.button, and only by this action of the user. Well the script at Unity play, does not behaves like that, instead either the variable "runMe" cannot be chanced, or either the player starts with the variable declared as "true", even without the user interaction!

    Any clues why this is happening? Maybe there is an alternative approch to start the texure animation only on a gui.button click and every time this click taken place.

    So if anyone of you have an idea, please respont to a new comer in Unity and programming. Thank you all in advance for your answers.
     
  7. QuinnWinters

    QuinnWinters

    Joined:
    Dec 31, 2013
    Posts:
    490
    My apologies, I took it that you wanted the texture animation code to run only once. It's easily fixed to make it run until the gui button is clicked again.

    Remove the following line from the texture animation script:
    Code (csharp):
    1. MyGameobject.GetComponent(TestCam).runMe = false;
    And in the main script in the gui button click section replace runMe = true; with:
    Code (csharp):
    1. runMe = !runMe
     
  8. Exnihilon

    Exnihilon

    Joined:
    Mar 2, 2014
    Posts:
    157
    Hi again @QuinnWinters and thanks for your time to review the code snippet. If you read through my post (06:44 pm), the script does not functions as it should be. I have ommited the lines you suggested, and now and before that, the textures advance without user interaction on button click, as if the variable "runMe" is not be taken into account by the compiler.

    Any thougths or a work arround on this issue?
     
  9. QuinnWinters

    QuinnWinters

    Joined:
    Dec 31, 2013
    Posts:
    490
    I don't see a reason why the runMe variable should get set to true without user interaction, but you will need to alter the code to change the texture so that it no longer animates when runMe gets set back to false. As the code currently is the texture gets told to start animating but is not told to stop when runMe goes back to false. Adding an else after the if in the texture script and setting the texture back to its normal mode without the frames array should accomplish this.
     
  10. Exnihilon

    Exnihilon

    Joined:
    Mar 2, 2014
    Posts:
    157
    Sorry for being that noob, to ask again but how should the texture script be modified to its normal state, without the frames array?
    I don't quite following you @QuinnWinters. The frames should be there to animate, don't they?
     
  11. Exnihilon

    Exnihilon

    Joined:
    Mar 2, 2014
    Posts:
    157
    I tried to modified as you suggested @QuinnWinters, so the texture scripts is now as following:

    Code (csharp):
    1.  
    2. #pragma strict
    3.  
    4.     var frames : Texture2D[];
    5.     var framesPerSecond = 10.0;
    6.     var myGameobject : GameObject;
    7.     private var runMe = false;
    8.      
    9.     function Update ()
    10.     {
    11.      
    12.         runMe = myGameobject.GetComponent(CameraTrigger).runMe;
    13.      
    14.         if (runMe)
    15.         {
    16.        
    17.             //myGameobject.GetComponent(CameraTrigger).runMe = false;
    18.        
    19.             var index : int = Time.time * framesPerSecond;
    20.            
    21.             if (index < frames.Length)
    22.             {
    23.                 renderer.material.mainTexture = frames[index];
    24.                  Debug.Log (Time.time + ", " + framesPerSecond + ", " + frames.Length + ", " + index);
    25.             }
    26.             else
    27.             {
    28.             index = index % frames.Length;
    29.             renderer.material.mainTexture = frames[index];
    30.             }
    31.         }
    32.      
    33. }    
    34.  
    35.  
    But I can get the funtionality I want. The texture on users click has already started, as I can see the 2nd to 3rd frame of the animation, as the camera is on. Furthermore, on the last frame it loops from start.

    This is not good. It should only start on the gui.button clicked, and everytime the user clicks this button, should start from the beginning. What are we measing here?
     
  12. QuinnWinters

    QuinnWinters

    Joined:
    Dec 31, 2013
    Posts:
    490
    After the if statement in the texture script put the following to stop the texture from animating.

    Code (csharp):
    1. else {
    2.  
    3.     renderer.material.mainTexture = renderer.material.mainTexture;
    4.  
    5. }
     
  13. Exnihilon

    Exnihilon

    Joined:
    Mar 2, 2014
    Posts:
    157
    Well, @QuinnWinters, I have added the "else statement" as you suggested and I get no compilation errors but I get this message in console:

    "(63,63): Warning BCW0020: WARNING: Assignment made to same expression. Did you mean to assign to something else? (BCW0020) (Assembly-UnityScript-firstpass)"

    The code now should be function as it should, right? Well It does not, cause on gui.button click, still I miss the first 2 frames of the animation, as the camera switches on (Cam1On = !Cam1On).

    Also the texture script advances to the end and stop, which is good to do so.

    If I click again the gui.button I see the last frame of the texture script. It does not rewind so to start from frame 1.

    Below is a screenshot to show what is the functionality so far:

    $testCamFrames.jpg



    Why this is happening as, I have reseted the frames as you suggested? Is there something else to think off, to make this script work o.k.?

    Meaning, startting the camera to see from the 1st frame of animation, and on everytime the button is clicked to start from the very first frame.
     
    Last edited: May 5, 2014
  14. QuinnWinters

    QuinnWinters

    Joined:
    Dec 31, 2013
    Posts:
    490
    My apologies, I'm not sure what I was thinking with that last reply, that does indeed give a warning. Up until now I've just been looking at the code and not trying to run it, but now that I've tried to run it I can't get the texture to actually animate. I tinkered with it for a bit with no luck, so I went an alternate route to achieve the same goal. Instead of using the texture animation script you were using I used a different one. After some tweaking I made it reset to frame 1 when the gui button stops it, and start from frame 1 when the gui button starts it again. Perhaps this will work for you.

    Code (csharp):
    1. #pragma strict
    2.  
    3. var MyGameobject : GameObject;
    4. private var runMe = false;
    5. var uvAnimationTileX = 10; //Here you can place the number of columns of your texture sheet.  I used a texture with 10 columns.
    6. var uvAnimationTileY = 1; //Here you can place the number of rows of your texture sheet.
    7. var framesPerSecond = 2.0;
    8. var myStart : float;
    9.  
    10. function Update () {
    11.  
    12.     runMe = MyGameobject.GetComponent(TestCam).runMe;
    13.  
    14.     if (runMe) {
    15.    
    16.         if (myStart == 0) {  //If myStart is 0
    17.             myStart = Time.time;  //Set the time to be the current time
    18.         }
    19.    
    20.         //Calculate index
    21.         var index : int = (Time.time-myStart) * framesPerSecond;
    22.         //Repeat when exhausting all frames
    23.         index = index % (uvAnimationTileX * uvAnimationTileY);
    24.      
    25.         //Size of every tile
    26.         var size = Vector2 (1.0 / uvAnimationTileX, 1.0 / uvAnimationTileY);
    27.      
    28.         //Split into horizontal and vertical index
    29.         var uIndex = index % uvAnimationTileX;
    30.         var vIndex = index / uvAnimationTileX;
    31.      
    32.         //Build offset
    33.         //V coordinate is the bottom of the image in opengl so we need to invert.
    34.         var offset = Vector2 (uIndex * size.x, 1.0 - size.y - vIndex * size.y);
    35.      
    36.         renderer.material.SetTextureOffset ("_MainTex", offset);
    37.         renderer.material.SetTextureScale ("_MainTex", size);
    38.    
    39.     }
    40.    
    41.     else {
    42.    
    43.         renderer.material.SetTextureOffset ("_MainTex", Vector2(0,0));  //Reset the texture to frame 1
    44.         myStart = 0;  //Set the time to 0 so it can start over when the button is pressed again
    45.    
    46.     }
    47.  
    48. }
     
  15. Exnihilon

    Exnihilon

    Joined:
    Mar 2, 2014
    Posts:
    157
    Hello @QuinnWinters. Nice to have you back on this thread.

    Well this code you posted, certainly looks much better than the other script. I have tried it, by placing a strip of 10 frames. The script runs every time user clicks the gui.button, plays from start to finish, and runs again from start (looping), so this function is o.k., as expected.

    Well, it is not as much important to have a run ones script for what I want to achieve in my app, but for learning purposes only, how should I stop the looping? I have tried to commented out, lines 23 and 44, but the script keeps looping. I have tried anything else I can thing off, but no good.

    Please respond, so we can close this thread successfully. Thank you for your time and effort.
     
  16. QuinnWinters

    QuinnWinters

    Joined:
    Dec 31, 2013
    Posts:
    490
    You can add in another boolean to check if it's played all the frames in the animation, and if it has have it stop playing the animation on the last frame. I cleaned up the code and fully commented it so you can understand exactly what's going on in each line.

    Code (csharp):
    1. #pragma strict
    2.  
    3. var myGameObject : GameObject;                                                      //The gameobject with the TestCam script on it.  Drag and drop the object into this slot in the inspector
    4. var uvAnimationTileX = 10;                                                          //The number of columns of your sheet.  I used a texture with 10 columns
    5. var uvAnimationTileY = 1;                                                           //The number of rows of your sheet
    6. var framesPerSecond = 2.0;                                                          //Frames of animation to run each second
    7. private var myStart : float;                                                        //For temporarily holding the time
    8. private var runMe = false;                                                          //Should the texture animate or not
    9. private var totalFrames : float;                                                    //How many frames the animation has
    10. private var animationDone = false;                                                  //Has the animation finished played
    11.  
    12. function Update () {
    13.  
    14.     runMe = myGameObject.GetComponent(TestCam).runMe;                               //Get the runMe variable from the TestCam script
    15.    
    16.     if (runMe) {                                                                    //If runMe is true
    17.    
    18.         if (myStart == 0) {                                                         //If myStart is 0
    19.             myStart = Time.time;                                                    //Set the time to be the current time
    20.             animationDone = false;                                                  //The animation has not finished playing
    21.             totalFrames = uvAnimationTileX * uvAnimationTileY - 1;                  //Get the total number of frames in the animation (and subtract one to keep the animation from going back to frame 1 when it finishes)
    22.         }
    23.        
    24.         if (!animationDone) {                                                       //If the animation is not finished playing
    25.        
    26.             var index : int = (Time.time - myStart) * framesPerSecond;              //Calculate index.  Index is the current time minus the time the animation started times the frames per second
    27.             index = index % (uvAnimationTileX * uvAnimationTileY);                  //Multiply the number of columns by the number of rows, divide them by index and set index to equal the fraction that's left over
    28.            
    29.             var size = Vector2 (1.0 / uvAnimationTileX, 1.0 / uvAnimationTileY);    //Size of every tile.  Because there are 10 columns and 1 row this equals out to 0.1, 1 (size.x and size.y)
    30.            
    31.             //Split into horizontal and vertical index
    32.             var uIndex = index % uvAnimationTileX;                                  //Horizontal index, aka the U of UV, is the remaining fraction of the number of columns divided by index
    33.             var vIndex = index / uvAnimationTileX;                                  //Vertical index, aka the V of UV, is the number of columns divided by index
    34.            
    35.             var offset = Vector2 (uIndex * size.x, 1.0 - size.y - vIndex * size.y); //Build offset.  V coordinate is the bottom of the image in opengl so we need to invert
    36.            
    37.             renderer.material.SetTextureOffset ("_MainTex", offset);                //Change the texture offset
    38.             renderer.material.SetTextureScale ("_MainTex", size);                   //Change the texture size (tiling)
    39.            
    40.             if (Time.time - myStart >= totalFrames / framesPerSecond) {             //If the elapsed time is greater than or equal to the amount of time it takes the animation to play
    41.                 animationDone = true;                                               //The animation has finished playing
    42.             }
    43.        
    44.         }
    45.    
    46.     }
    47.    
    48.     else {                                                                          //If runMe is false
    49.    
    50.         renderer.material.SetTextureOffset ("_MainTex", Vector2(0,0));              //Set the texture offset back to U = 0, V = 0
    51.         myStart = 0;                                                                //Reset the time to 0
    52.    
    53.     }
    54.  
    55. }
     
  17. Exnihilon

    Exnihilon

    Joined:
    Mar 2, 2014
    Posts:
    157
    Hello @QuinnWinters. I'd like to thank you for your time and effort to post the code snippet for animation on texture, with a start/stop functionality.
    The code works o.k. and the comments, were useful to a new comer in Unity3d like me, to learn from.

    You are certainly a skillful coder. Would it be to much, if I may ask you, to take a look at the following posts of mine, regarding some problems that I have with some coding?

    A Compilation error when calling a C# from a Unityscript (js) in Unity3d:
    http://forum.unity3d.com/threads/24...yscript-(js)-in-Unity3d?p=1613611#post1613611

    Texture on a GUI.Button disappears when scene is reloaded:
    http://forum.unity3d.com/threads/24...-when-scene-is-reloaded?p=1616987#post1616987

    Your opinions and suggestions will be more than welcome.