I have created a simple prefab called ScorePopup. It has a TextMeshPro
component. It also has an Animator
that moves the text up by 2 world units and fades out the color over 1 second. So in the animator, it has
ScorePopup: Text Mesh Pro.Font Color - goes from 1 to 0 over 1 second.
ScorePopup: Anchored Position
Anchored Position.x (stays at 0)
Anchored Position.y - goes from 0 to 2 over 1 second.
Now, imagine a game where an enemy is moving right to left. It gets hit with a bullet. I want to instantiate this ScorePopup in the position where the enemy was struck.
I tried instantiating it in my game script:
GameObject go = Instantiate(scorePopupPrefab, enemy.transform.position, Quaternion.identity);
go.GetComponent<TMP_Text>().text = score.ToString();
The problem is that the ScorePopup doesn't appear at the enemy's position - it appears at 0,0 in my scene, presumably because of the Anchored Position
values in the Animation.
So I tried instantiating the ScorePopup in my enemy script instead:
GameObject go = Instantiate(scorePopupPrefab, transform.position, Quaternion.identity, transform);
That correctly puts the scorePopup where the enemy is. However, the scorePopup moves to the left with the enemy. I want the score popup to appear at the striking position in scene/world space and do its animation there. It shouldn't move with the enemy.
What is the solution here? How can I instantiate a prefab in my scene at a designated position if the prefab has an internal position animation? This is for the very common scenario where you see a score float upward when a player earns points by striking or obtaining an object.
Edit: The text prefab does not have a canvas. It was created as an empty object and has a TMPRo - Text
component (and an Animator) added to it to display the text.
I also tried this:
public class ScorePopup : MonoBehaviour
{
private Animator animator;
void Awake()
{
animator = GetComponent<Animator>();
if (animator != null)
{
animator.enabled = false;
StartCoroutine(EnableAnimatorAfterDelay(0.1f));
}
}
IEnumerator EnableAnimatorAfterDelay(float delay)
{
yield return new WaitForSeconds(delay);
animator.enabled = true;
}
}
It appears briefly in the correct position, but then moves to 0,0 when the animation become enabled :(
You should simply have a root object that is not controlled by the animator -> can spawn wherever you want .. and then the animator only affects objects under this root object so they are animated relative to that root.
So your prefab should look like e.g.
PrefabRoot <-- this you place freely in the scene
|-- AnimatedText <-- this is animated relative to the PrefabRoot
Alternatively, of course for such a simple fade of moving the text and fade it out you could just not use the Animator
at all but rather handle the animation code wise so you have full control. I would use the Animator
only for more complex state machines and characters etc.