Unity 3D:动画的过渡
Unity 3D: Transition of Animation
我是 Unity3D 的新手,我正在研究以下教程:
https://www.youtube.com/watch?v=gXpi1czz5NA
一切正常。
我想添加一个功能,如果骷髅用他的剑击中什么东西,他会像受到伤害一样真正回来。一种让他的剑与物体碰撞的穷人的方式。
但我发现它不能正常工作。我似乎可以选择使 'hit' 进入无限循环,或者完全忽略命中。这是我的代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class chase : MonoBehaviour {
public Transform player;
static Animator anim;
// Use this for initialization
void Start () {
anim = GetComponent<Animator> ();
}
// Update is called once per frame
void Update () {
//Debug.Log (anim.ToString ());
//Debug.Log ("Start Update");
Vector3 direction = player.position - this.transform.position;
//Debug.Log ("Distance: " + direction.magnitude.ToString ());
float angle = Vector3.Angle (direction, this.transform.forward);
//Debug.Log ("Angle: " + angle.ToString ());
//Debug.Log(anim.GetCurrentAnimatorStateInfo(0).IsName("Damage"));
// Get top animation currently running
AnimatorStateInfo stateInfo = anim.GetCurrentAnimatorStateInfo(0);
if (Vector3.Distance (player.position, this.transform.position) < 10 && angle < 120 && !stateInfo.IsName ("Attack") && !anim.GetBool("Hit")) {
direction.y = 0;
this.transform.rotation = Quaternion.Slerp (this.transform.rotation, Quaternion.LookRotation (direction), 0.1f);
anim.SetBool ("isIdle", false);
if (direction.magnitude > 2) {
this.transform.Translate (0, 0, 0.03f);
anim.SetBool ("isWalking", true);
anim.SetBool ("isAttacking", false);
anim.SetBool ("Hit", false);
} else {
anim.SetBool ("isAttacking", true);
anim.SetBool ("isWalking", false);
anim.SetBool ("Hit", false);
}
}
else{
anim.SetBool ("isIdle", true);
anim.SetBool ("isWalking", false);
anim.SetBool ("isAttacking", false);
anim.SetBool ("Hit", false);
}
}
}
这里是剑碰撞脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SwordCollision : MonoBehaviour {
private Animator anim;
// We just collided with an object
private void OnTriggerEnter(Collider collider) {
int layer = collider.gameObject.layer;
anim = this.GetComponentInParent<Animator> ();
//Debug.Log (anim.ToString ());
if (layer != LayerMask.NameToLayer ("Floor") && layer != LayerMask.NameToLayer ("Monster")) {
Debug.Log ("Sword Hit something:" + collider.name.ToString());
Debug.Log (LayerMask.LayerToName(layer));
anim.SetBool ("isIdle", false);
anim.SetBool ("isWalking", false);
anim.SetBool ("isAttacking", false);
anim.SetBool ("Hit", true); // kicks off damage state
}
}
}
我将攻击和伤害动画的过渡设置为 "has exit time",以便它们可以一直播放。其他转换没有这个,所以它们可以在 'hit' 发生时立即中断。
问题似乎是在剑碰撞脚本注册命中并将 "Hit" 布尔值设置为 "true"(以启动损坏动画)后追逐脚本立即取消它,所以命中永远不会发生。 (即 anim.SetBool("Hit",假);)
但是,如果我注释掉那一行,那么伤害动画就会发生,但显然它会卡在一个循环中,因为现在我没有什么可以关闭它的。
这让我惊慌失措,因为攻击动画的设置几乎完全相同。但我认为一个正确工作的原因是因为布尔值 "isAttacking" 在追逐脚本中不断设置为 'true' 直到动画真正开始。因为损坏动画是从不同的脚本开始的,所以在允许追逐脚本更改 "hit".[=13 的布尔值之前,我似乎没有一种简单的方法来确保动画开始=]
有什么办法吗?像延迟或保证动画改变状态的东西。或者在更改布尔值之前检查 'damage' 动画何时完成的方法?
这是我最终想出的解决方案。在我看来有点hacky。我仍然觉得我没有以最好的方式做到这一点。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class chase : MonoBehaviour {
public Transform player;
static Animator anim;
// Use this for initialization
void Start () {
anim = GetComponent<Animator> ();
}
// Update is called once per frame
void Update () {
//Debug.Log (anim.ToString ());
//Debug.Log ("Start Update");
Vector3 direction = player.position - this.transform.position;
//Debug.Log ("Distance: " + direction.magnitude.ToString ());
float angle = Vector3.Angle (direction, this.transform.forward);
//Debug.Log ("Angle: " + angle.ToString ());
//Debug.Log(anim.GetCurrentAnimatorStateInfo(0).IsName("Damage"));
// Get top animation currently running
AnimatorStateInfo stateInfo = anim.GetCurrentAnimatorStateInfo(0);
if (anim.GetBool("Hit") && !stateInfo.IsName ("Damage")) {
print ("keep going");
anim.SetBool ("isIdle", false);
anim.SetBool ("isWalking", false);
anim.SetBool ("isAttacking", false);
anim.SetBool ("Hit", true);
}
else if (Vector3.Distance (player.position, this.transform.position) < 10 && angle < 120 && !stateInfo.IsName ("Attack") && !stateInfo.IsName ("Damage")) {
direction.y = 0;
this.transform.rotation = Quaternion.Slerp (this.transform.rotation, Quaternion.LookRotation (direction), 0.1f);
anim.SetBool ("isIdle", false);
if (direction.magnitude > 2) {
print ("Following");
//this.transform.Translate (0, 0, 0.03f);
anim.SetBool ("isWalking", true);
anim.SetBool ("isAttacking", false);
anim.SetBool ("Hit", false);
} else {
print ("Attacking");
anim.SetBool ("isAttacking", true);
anim.SetBool ("isWalking", false);
anim.SetBool ("Hit", false);
}
}
else {
print("Back to Idle");
anim.SetBool ("isIdle", true);
anim.SetBool ("isWalking", false);
anim.SetBool ("isAttacking", false);
anim.SetBool ("Hit", false);
}
}
}
我是 Unity3D 的新手,我正在研究以下教程:
https://www.youtube.com/watch?v=gXpi1czz5NA
一切正常。
我想添加一个功能,如果骷髅用他的剑击中什么东西,他会像受到伤害一样真正回来。一种让他的剑与物体碰撞的穷人的方式。
但我发现它不能正常工作。我似乎可以选择使 'hit' 进入无限循环,或者完全忽略命中。这是我的代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class chase : MonoBehaviour {
public Transform player;
static Animator anim;
// Use this for initialization
void Start () {
anim = GetComponent<Animator> ();
}
// Update is called once per frame
void Update () {
//Debug.Log (anim.ToString ());
//Debug.Log ("Start Update");
Vector3 direction = player.position - this.transform.position;
//Debug.Log ("Distance: " + direction.magnitude.ToString ());
float angle = Vector3.Angle (direction, this.transform.forward);
//Debug.Log ("Angle: " + angle.ToString ());
//Debug.Log(anim.GetCurrentAnimatorStateInfo(0).IsName("Damage"));
// Get top animation currently running
AnimatorStateInfo stateInfo = anim.GetCurrentAnimatorStateInfo(0);
if (Vector3.Distance (player.position, this.transform.position) < 10 && angle < 120 && !stateInfo.IsName ("Attack") && !anim.GetBool("Hit")) {
direction.y = 0;
this.transform.rotation = Quaternion.Slerp (this.transform.rotation, Quaternion.LookRotation (direction), 0.1f);
anim.SetBool ("isIdle", false);
if (direction.magnitude > 2) {
this.transform.Translate (0, 0, 0.03f);
anim.SetBool ("isWalking", true);
anim.SetBool ("isAttacking", false);
anim.SetBool ("Hit", false);
} else {
anim.SetBool ("isAttacking", true);
anim.SetBool ("isWalking", false);
anim.SetBool ("Hit", false);
}
}
else{
anim.SetBool ("isIdle", true);
anim.SetBool ("isWalking", false);
anim.SetBool ("isAttacking", false);
anim.SetBool ("Hit", false);
}
}
}
这里是剑碰撞脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SwordCollision : MonoBehaviour {
private Animator anim;
// We just collided with an object
private void OnTriggerEnter(Collider collider) {
int layer = collider.gameObject.layer;
anim = this.GetComponentInParent<Animator> ();
//Debug.Log (anim.ToString ());
if (layer != LayerMask.NameToLayer ("Floor") && layer != LayerMask.NameToLayer ("Monster")) {
Debug.Log ("Sword Hit something:" + collider.name.ToString());
Debug.Log (LayerMask.LayerToName(layer));
anim.SetBool ("isIdle", false);
anim.SetBool ("isWalking", false);
anim.SetBool ("isAttacking", false);
anim.SetBool ("Hit", true); // kicks off damage state
}
}
}
我将攻击和伤害动画的过渡设置为 "has exit time",以便它们可以一直播放。其他转换没有这个,所以它们可以在 'hit' 发生时立即中断。
问题似乎是在剑碰撞脚本注册命中并将 "Hit" 布尔值设置为 "true"(以启动损坏动画)后追逐脚本立即取消它,所以命中永远不会发生。 (即 anim.SetBool("Hit",假);)
但是,如果我注释掉那一行,那么伤害动画就会发生,但显然它会卡在一个循环中,因为现在我没有什么可以关闭它的。
这让我惊慌失措,因为攻击动画的设置几乎完全相同。但我认为一个正确工作的原因是因为布尔值 "isAttacking" 在追逐脚本中不断设置为 'true' 直到动画真正开始。因为损坏动画是从不同的脚本开始的,所以在允许追逐脚本更改 "hit".[=13 的布尔值之前,我似乎没有一种简单的方法来确保动画开始=]
有什么办法吗?像延迟或保证动画改变状态的东西。或者在更改布尔值之前检查 'damage' 动画何时完成的方法?
这是我最终想出的解决方案。在我看来有点hacky。我仍然觉得我没有以最好的方式做到这一点。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class chase : MonoBehaviour {
public Transform player;
static Animator anim;
// Use this for initialization
void Start () {
anim = GetComponent<Animator> ();
}
// Update is called once per frame
void Update () {
//Debug.Log (anim.ToString ());
//Debug.Log ("Start Update");
Vector3 direction = player.position - this.transform.position;
//Debug.Log ("Distance: " + direction.magnitude.ToString ());
float angle = Vector3.Angle (direction, this.transform.forward);
//Debug.Log ("Angle: " + angle.ToString ());
//Debug.Log(anim.GetCurrentAnimatorStateInfo(0).IsName("Damage"));
// Get top animation currently running
AnimatorStateInfo stateInfo = anim.GetCurrentAnimatorStateInfo(0);
if (anim.GetBool("Hit") && !stateInfo.IsName ("Damage")) {
print ("keep going");
anim.SetBool ("isIdle", false);
anim.SetBool ("isWalking", false);
anim.SetBool ("isAttacking", false);
anim.SetBool ("Hit", true);
}
else if (Vector3.Distance (player.position, this.transform.position) < 10 && angle < 120 && !stateInfo.IsName ("Attack") && !stateInfo.IsName ("Damage")) {
direction.y = 0;
this.transform.rotation = Quaternion.Slerp (this.transform.rotation, Quaternion.LookRotation (direction), 0.1f);
anim.SetBool ("isIdle", false);
if (direction.magnitude > 2) {
print ("Following");
//this.transform.Translate (0, 0, 0.03f);
anim.SetBool ("isWalking", true);
anim.SetBool ("isAttacking", false);
anim.SetBool ("Hit", false);
} else {
print ("Attacking");
anim.SetBool ("isAttacking", true);
anim.SetBool ("isWalking", false);
anim.SetBool ("Hit", false);
}
}
else {
print("Back to Idle");
anim.SetBool ("isIdle", true);
anim.SetBool ("isWalking", false);
anim.SetBool ("isAttacking", false);
anim.SetBool ("Hit", false);
}
}
}