Criei um prefab simples chamado ScorePopup. Ele tem um TextMeshPro
componente. Ele também tem um Animator
que move o texto para cima em 2 unidades do mundo e desbota a cor em 1 segundo. Então, no animador, ele tem
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.
Agora, imagine um jogo em que um inimigo está se movendo da direita para a esquerda. Ele é atingido por uma bala. Quero instanciar este ScorePopup na posição em que o inimigo foi atingido.
Tentei instanciá-lo no meu script de jogo:
GameObject go = Instantiate(scorePopupPrefab, enemy.transform.position, Quaternion.identity);
go.GetComponent<TMP_Text>().text = score.ToString();
O problema é que o ScorePopup não aparece na posição do inimigo - ele aparece em 0,0 na minha cena, provavelmente por causa dos Anchored Position
valores na animação.
Então tentei instanciar o ScorePopup no meu script inimigo:
GameObject go = Instantiate(scorePopupPrefab, transform.position, Quaternion.identity, transform);
Isso coloca corretamente o scorePopup onde o inimigo está. No entanto, o scorePopup se move para a esquerda com o inimigo. Quero que o score popup apareça na posição de ataque no espaço de cena/mundo e faça sua animação lá. Ele não deve se mover com o inimigo.
Qual é a solução aqui? Como posso instanciar um prefab na minha cena em uma posição designada se o prefab tem uma animação de posição interna? Isso é para o cenário muito comum em que você vê uma pontuação flutuar para cima quando um jogador ganha pontos ao atacar ou obter um objeto.
Editar: O prefab de texto não tem uma tela. Ele foi criado como um objeto vazio e tem um TMPRo - Text
componente (e um Animator) adicionado a ele para exibir o texto.
Eu também tentei isso:
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;
}
}
Ele aparece brevemente na posição correta, mas depois muda para 0,0 quando a animação é ativada :(
Você deve simplesmente ter um objeto raiz que não seja controlado pelo animador -> pode aparecer onde você quiser... e então o animador afeta apenas os objetos sob esse objeto raiz para que eles sejam animados em relação a essa raiz.
Então seu pré-fabricado deve se parecer com, por exemplo
Alternativamente, é claro que para um fade tão simples de mover o texto e fazê-lo desaparecer, você pode simplesmente não usar o
Animator
em tudo, mas sim manipular o código de animação de forma inteligente para ter controle total. Eu usaria oAnimator
apenas para máquinas de estado e personagens mais complexos, etc.É sempre difícil combinar bem a posição da tela da IU e a posição do mundo. Tentar e depurar é necessário.
Descobri duas soluções para sua situação.
Calcular a posição exata:
Canvas Render Mode
,Canvas Scaler
pode afetar o cálculo da posição. você pode usarcamera.WorldToScreenPoint(enemy.transform.position)
. Para notar, ele usa a posição do eixo left_down, então se o ponto de pivô da IU for central, talvez você deva menos a metade de screen.height e width. E defina a posição calculada para a posição local do texto ou posição ancorada.Maneira simples, mas hackeada: você encontrou a posição (0,0) com o inimigo alvo como pai funciona bem. Então você pode usar isso. No seu GameScript,
O 4º valor ou
Instantiate
é se deve definir um pai específico. Então a ideia é instanciar o prefab como filho do inimigo alvo e definir o pai comonull
para que a UI não pertença à posição do inimigo.