Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
  • Help Room /
avatar image
0
Question by agScreen · Mar 28, 2017 at 07:29 PM · animationitweenprefab-instancerecursion

Prefab Instantiation Issue or Perhaps iTween?

HI all,

Short time reader, first time poster here. Great resources. Unity and the Unity community continue to impress. Now, on to the madness...

I've run into an issue with a proof of concept (which in fairness, is still just a learning process) for a classic memory card matching game. I've stripped away everything that's not relevant into an isolated scene in the hopes that the problem would become more evident, but the only two conclusions I've come to I'm not sure how to resolve.

The isolated concept:

Four cards are in a grid, the top two match one another and the bottom two match one another.

Game play sequence of events:

Clicking the first card reveals it's face and remains visible until a second card is revealed

Clicking the second card reveals its face then performs a check to see if they were a match.

If match, they remain visible, else they hide themselves.

The problem is with the animations. If you click subsequent cards at certain speeds they get "interrupted" and throw off the correct state. My first thought was that I'm using iTween for animation and that I'm possibly not handling those tweens properly, but the more I experiment with it, the less I feel that's the case; though the way I'm recursively calling iTweens to create a "sequence" may also be my issue. Maybe @pixelplacement will have a thought. Also, if I'm instantiating new prefabs into my grid how can calling the animation method in one instance cause issues in another? So confused as to where I've lost track here. I'll list the scripts in code here, but I'm also going to add a link to a webGL version and the assets of the game below in case nothing stands out in the code and someone feels like really digging in.

Any advice, comments, criticism, etc. are appreciated!

WebGL: http://thisguy.forgot.his.name/isolation/

Assets zipped: http://thisguy.forgot.his.name/isolation/Assets.zip

Scripts:

 // Game.cs
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.UI;
 using UnityEngine.SceneManagement;
 public class Game: MonoBehaviour {
     private Button restart;
     public List<GameObject> Target { get; set; }
     public List<int> Match { get; set; }
     void Awake() {
         restart = GameObject.Find ("Restart").GetComponent<Button> ();
         restart.onClick.AddListener (Restart);
         ResetMatches ();
     }
     private void Restart() {
         SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
     }
     private void ResetMatches() {
         Target = new List<GameObject> ();
         Match = new List<int> ();
     }
     public void CheckMatch() {
         if (!IsMatch ()) {
             Target [0].GetComponent<Card> ().FlipCard ();
             Target [1].GetComponent<Card> ().FlipCard ();
         }
         ResetMatches ();
     }
     private bool IsMatch() {
         return Match [0] == Match [1] && Target[0] != Target[1];
     }
 }
 // Grid.cs
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.UI;
 public class Grid: MonoBehaviour {
     public GameObject cardPrefab;
     private Transform grid;
     void Awake () {
         grid = gameObject.transform;
     }
     void Start() {
         Generate ();
     }
     private void CreateCard (int i, int matchId, string text) {
         GameObject prefab;
         prefab = (GameObject)Instantiate (cardPrefab);
         prefab.transform.SetParent (grid);
         prefab.GetComponent<RectTransform> ().localScale = Vector3.one;
         prefab.name = "card-" + i.ToString ();
         prefab.GetComponent<Card> ().MatchId = matchId;
         prefab.GetComponentInChildren<Text> ().text = text;
     }
     private void Generate () {
         CreateCard (0, 0, "a");
         CreateCard (1, 0, "A");
         CreateCard (2, 1, "b");
         CreateCard (3, 1, "B");
     }
 }
 // AnimationSequence.cs
 using System;
 using UnityEngine;
 public struct AnimationSequence {
     public AnimationSequence (string onUpdateHandler, Vector3 origin, Vector3 destination, float duration, string easeType, float delay) {
         OnUpdateHandler = onUpdateHandler;
         Origin = origin;
         Destination = destination;
         Duration = duration;
         EaseType = easeType;
         Delay = delay;
     }
     public string OnUpdateHandler { get; set; }
     public Vector3 Origin { get; set; }
     public Vector3 Destination { get; set; }
     public float Duration { get; set; }
     public string EaseType { get; set; }
     public float Delay { get; set; }
 }
 // Card.cs
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.UI;
 public class Card: MonoBehaviour {
     private Game game;
     private Button button;
     private Transform front;
     private Transform back;
     private Dictionary<string, AnimationSequence[]> animationSequences;
     private float sequenceDuration = 1f;
     private float pairShownDuration = 0.75f;
     private string currentSequence = "";
     private string lastSequence = "";
     private int currentSequenceIndex = -1;
     private bool IsFlipped { get; set; }
     public int MatchId { get; set; }
     void Awake () {
         game = GameObject.FindObjectOfType<Game> ();
         front = gameObject.transform.FindChild ("Front");
         back = gameObject.transform.FindChild ("Back");
         button = GetComponent<Button> ();
         button.onClick.AddListener (OnClick);
         iTween.Init (gameObject);
         CreateSequences ();
     }
     public void FlipCard (bool reveal = false) {
         string sequence = (reveal) ? "reveal" : "hide";
         HandleSequence (sequence);
     }
     private void OnClick () {
         // disallow clicks on flipped cards
         if (!IsFlipped) {
             IsFlipped = true;
             FlipCard (true);
             game.Match.Add (MatchId);
             game.Target.Add (gameObject);
         }
     }
     private void CreateSequences () {
         animationSequences = new Dictionary<string, AnimationSequence[]> ();
         // reveal
         AnimationSequence[] reveal = new AnimationSequence[2];
         reveal [0] = new AnimationSequence ("HandleBack", Vector3.zero, new Vector3 (0, -90, 0), sequenceDuration / reveal.Length, "easeInBack", 0f);
         reveal [1] = new AnimationSequence ("HandleFront", new Vector3 (0, 90, 0), Vector3.zero, sequenceDuration / reveal.Length, "easeOutBack", 0f);
         // hide 
         AnimationSequence[] hide = new AnimationSequence[2];
         hide [0] = new AnimationSequence ("HandleFront", Vector3.zero, new Vector3 (0, 90, 0), sequenceDuration / hide.Length, "easeInBack", pairShownDuration);
         hide [1] = new AnimationSequence ("HandleBack", new Vector3 (0, -90, 0), Vector3.zero, sequenceDuration / hide.Length, "easeOutBack", 0f);
         animationSequences.Add ("reveal", reveal);
         animationSequences.Add ("hide", hide);
     }
     private void HandleSequence (string sequence) {
         currentSequence = sequence;
         RunSequence ();
     }
     private void RunSequence () {
         // if the current sequence was cleared below (at end of sequence)
         // check last sequence for "complete" events and return
         if (currentSequence == "") {
             if (lastSequence == "reveal" && game.Match.Count > 1) {
                 game.CheckMatch ();
             }
             if (lastSequence == "hide") {
                 IsFlipped = false;
             }
             lastSequence = "";
             return;
         }
         currentSequenceIndex++;
         string onUpdateHandler = animationSequences [currentSequence] [currentSequenceIndex].OnUpdateHandler;
         Vector3 origin = animationSequences [currentSequence] [currentSequenceIndex].Origin;
         Vector3 destination = animationSequences [currentSequence] [currentSequenceIndex].Destination;
         float duration = animationSequences [currentSequence] [currentSequenceIndex].Duration;
         string easeType = animationSequences [currentSequence] [currentSequenceIndex].EaseType;
         float delay = animationSequences [currentSequence] [currentSequenceIndex].Delay;
         Hashtable hashParams = iTween.Hash ("from", origin, "to", destination, "time", duration, "onupdate", onUpdateHandler, "onupdatetarget", gameObject, "easetype", easeType, "oncomplete", "RunSequence", "delay", delay);
         iTween.ValueTo (gameObject, hashParams);
         // the sequence is at end of its tweens, clear sequence
         // for the next recursive call of this method
         if (currentSequenceIndex == animationSequences [currentSequence].Length - 1) {
             lastSequence = currentSequence;
             currentSequence = "";
             currentSequenceIndex = -1;
         }
     }
     private void HandleBack(Vector3 rotation) {
         back.localEulerAngles = rotation;
     }
     private void HandleFront(Vector3 rotation) {
         front.localEulerAngles = rotation;
     }
 }


Comment
Add comment
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by agScreen · Mar 29, 2017 at 11:25 AM

I was able to deduce my issue and wanted to share in case others run into a similar issue. Or perhaps someone will find it useful that just runs across this trying to find out how to flip some cards.

I guess my issue was in regard to "instantiation". What I did to resolve was to abstract the "sequencer" aspects out of my card and into its own "sequencer" game object with it's on script component. Initially, I was instantiating the new game object and then subsequently trying to find it when i needed to reference it next. THAT was a huge red flag. Anytime the script did a GameObject.Find() for that game object it would lock up Unity entirely and I had to force quit. Eventually, it became apparent (at least this is my best understanding) that I needed to leave the current objects in tact and create new ones that wouldn't interrupt the current values.

There may still be some concerns, but I feel good about what I've got now. With a little more abstraction in the Sequencer script I may be able to turn it into a "timeline" script for building tweens. I wonder what @pixelplacement would think of this? If anyone has any suggestions of better methodologies, comments, questions, etc. feel free. Again, I'll place the scripts here, but I'll also updated the WebGL demo (and I'll leave it up indefinitely) and a new link for the "fixed" assets.

WebGL Demo: http://thisguy.forgot.his.name/isolation/

Assets Fixed: http://thisguy.forgot.his.name/isolation/AssetsFixed.zip

Scripts:

 // Game.cs
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.UI;
 using UnityEngine.SceneManagement;
 public class Game: MonoBehaviour {
     private Button restart;
     public List<GameObject> Target { get; set; }
     public List<int> Match { get; set; }
 ​    public int CardsFlipped { get; set; }
     void Awake() {
         restart = GameObject.Find ("Restart").GetComponent<Button> ();
         restart.onClick.AddListener (Restart);
         ResetMatches ();
     }
     private void Restart() {
         SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
     }
     private void ResetMatches() {
         Target = new List<GameObject> ();
         Match = new List<int> ();
     }
     public void CheckMatch() {
         if (!IsMatch ()) {
             Target [0].GetComponent<Card> ().FlipCard ();
             Target [1].GetComponent<Card> ().FlipCard ();
         }
         ResetMatches ();
     }
     private bool IsMatch() {
         return Match [0] == Match [1] && Target[0] != Target[1];
     }
 }
 // Grid.cs
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.UI;
 public class Grid: MonoBehaviour {
     public GameObject cardPrefab;
     private Transform grid;
     void Awake () {
         grid = gameObject.transform;
     }
     void Start() {
         Generate ();
     }
     private void CreateCard (int i, int matchId, string text) {
         GameObject prefab;
         prefab = (GameObject)Instantiate (cardPrefab);
         prefab.transform.SetParent (grid);
         prefab.GetComponent<RectTransform> ().localScale = Vector3.one;
         prefab.name = "card-" + i.ToString ();
         prefab.GetComponent<Card> ().MatchId = matchId;
         prefab.GetComponentInChildren<Text> ().text = text;
     }
     private void Generate () {
         CreateCard (0, 0, "a");
         CreateCard (1, 0, "A");
         CreateCard (2, 1, "b");
         CreateCard (3, 1, "B");
     }
 }
 // AnimationSequence.cs
 using System;
 using UnityEngine;
 public struct AnimationSequence {
     public AnimationSequence (string onUpdateHandler, Vector3 origin, Vector3 destination, float duration, string easeType, float delay) {
         OnUpdateHandler = onUpdateHandler;
         Origin = origin;
         Destination = destination;
         Duration = duration;
         EaseType = easeType;
         Delay = delay;
     }
     public string OnUpdateHandler { get; set; }
     public Vector3 Origin { get; set; }
     public Vector3 Destination { get; set; }
     public float Duration { get; set; }
     public string EaseType { get; set; }
     public float Delay { get; set; }
 }
 // Card.cs
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.UI;
 public class Card: MonoBehaviour {
     private Game game;
     private Button button;
     private Transform front;
     private Transform back;
     public bool IsFlipped { get; set; }
     public int MatchId { get; set; }
     void Awake () {
         game = GameObject.FindObjectOfType<Game> ();
         front = gameObject.transform.FindChild ("Front");
         back = gameObject.transform.FindChild ("Back");
         button = GetComponent<Button> ();
         button.onClick.AddListener (OnClick);
         iTween.Init (gameObject);
     }
     private GameObject GetSequencer(string sequence) {
         Transform[] transforms = new Transform[2];
         transforms [0] = back;
         transforms [1] = front;
         GameObject sequencer = new GameObject ("sequencer-" + gameObject.name);
         sequencer.AddComponent<Sequencer> ();
         sequencer.GetComponent<Sequencer> ().Init (gameObject, transforms, sequence);
         return sequencer;
     }
     public void FlipCard (bool reveal = false) {
         string sequence = (reveal) ? "reveal" : "hide";
         GameObject sequencer = GetSequencer (sequence);
         sequencer.GetComponent<Sequencer> ().Play ();
     }
     private void OnClick () {
         // disallow clicks on flipped cards
         if (!IsFlipped && game.CardsFlipped < 2) {
             ​game.CardsFlipped++;
             IsFlipped = true;
             FlipCard (true);
             game.Match.Add (MatchId);
             game.Target.Add (gameObject);
         }
     }
 }
 // Sequencer.cs
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 public class Sequencer: MonoBehaviour {
     private Game game;
     private GameObject Target { get; set; }
     private Transform[] Transforms { get; set; }
     private string SequenceName { get; set; }
     private AnimationSequence[] sequence;
     private float sequenceDuration = 1f;
     private float pairShownDuration = 0.75f;
     private string lastSequence;
     private int currentSequenceIndex = -1;
     public void Init (GameObject target, Transform[] transforms, string sequenceName) {
         game = GameObject.FindObjectOfType<Game> ();
         Target = target;
         Transforms = transforms;
         SequenceName = sequenceName;
         CreateSequence ();
     }
     public void Play() {
         HandleSequence ();
     }
     private void CreateSequence () {
         int sequenceLength = 2;
         sequence = new AnimationSequence[sequenceLength];
         switch (SequenceName) {
             case "reveal":
                 sequence [0] = new AnimationSequence ("HandleBack", Vector3.zero, new Vector3 (0, -90, 0), sequenceDuration / sequenceLength, "easeInBack", 0f);
                 sequence [1] = new AnimationSequence ("HandleFront", new Vector3 (0, 90, 0), Vector3.zero, sequenceDuration / sequenceLength, "easeOutBack", 0f);
             break;
             case "hide":
                 sequence [0] = new AnimationSequence ("HandleFront", Vector3.zero, new Vector3 (0, 90, 0), sequenceDuration / sequenceLength, "easeInBack", pairShownDuration);
                 sequence [1] = new AnimationSequence ("HandleBack", new Vector3 (0, -90, 0), Vector3.zero, sequenceDuration / sequenceLength, "easeOutBack", 0f);
             break;
         }
     }
     private void SequenceComplete(string sequenceName) {
         if (sequenceName == "reveal" && game.Match.Count > 1) {
             game.CheckMatch ();
         }
         if (sequenceName == "hide") {
             Target.GetComponent<Card> ().IsFlipped = false;
             ​game.CardsFlipped--;
         }
         lastSequence = "";
         // destroy the sequencer game object; initially tried keeping it and then finding the relevant
         // sequencer in the card after first creating one, but I think THAT is the issue I had before;
         // completely new instances of sequencers are needed to not corrupt previous values
         Destroy (gameObject);
     }
     private void HandleSequence () {
         // if the current sequence was cleared below (at end of sequence)
         // check last sequence for "complete" events and return
         if (SequenceName == "") {
             SequenceComplete (lastSequence);
             return;
         }
         currentSequenceIndex++;
         string onUpdateHandler = sequence [currentSequenceIndex].OnUpdateHandler;
         Vector3 origin = sequence [currentSequenceIndex].Origin;
         Vector3 destination = sequence [currentSequenceIndex].Destination;
         float duration = sequence [currentSequenceIndex].Duration;
         string easeType = sequence [currentSequenceIndex].EaseType;
         float delay = sequence [currentSequenceIndex].Delay;
         Hashtable hashParams = iTween.Hash ("from", origin, "to", destination, "time", duration, "onupdate", onUpdateHandler, "onupdatetarget", gameObject, "easetype", easeType, "oncomplete", "HandleSequence", "oncompletetarget", gameObject, "delay", delay);
         iTween.ValueTo (Target.gameObject, hashParams);
         // the sequence is at end of its tweens, clear sequence
         // for the next recursive call of this method
         if (currentSequenceIndex == sequence.Length - 1) {
             lastSequence = SequenceName;
             SequenceName = "";
             currentSequenceIndex = -1;
         }
     }
     private void HandleBack(Vector3 rotation) {
         Transforms[0].localEulerAngles = rotation;
     }
     private void HandleFront(Vector3 rotation) {
         Transforms[1].localEulerAngles = rotation;
     }
 }


Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

181 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Screen flickers when iTween function gets executed. 0 Answers

Should I make completely new animation and animator for every new lift I will create? 1 Answer

iTween Switching Paths 0 Answers

itween 3rd character humanoid issue 0 Answers

Itween roatation is not working properly on low configuration pc with 2gb ram 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges