Unity 2D销毁玩家对象并实例化带装备预制体后动画无限循环问题
问题分析与解决方案
问题根源
- 动画参数设置错误:
Update方法的else分支每帧都在设置PickST布尔值为true,如果该动画是循环状态,会导致无限重复播放。 - 触发逻辑持续执行:
OnTriggerStay2D会在碰撞体接触期间持续触发,反复将TorchSwordBool设为true,加剧动画循环问题。 - 销毁逻辑未触发:
DestroyPlayer方法未被调用,原玩家对象一直存在,持续执行拾取动画的设置逻辑。
修复步骤
1. 将拾取动画改为触发型(Trigger)
在Unity Animator面板中,把PickST参数的类型从Bool改为Trigger。Trigger只需触发一次,动画播放完成后自动停止,不会循环。
2. 替换触发检测方法
把OnTriggerStay2D改为OnTriggerEnter2D,确保只在首次接触火把剑时触发逻辑,避免重复执行:
void OnTriggerEnter2D(Collider2D coll) { if(coll.gameObject.tag == "TorchSword" && isGrounded && !TorchSwordBool) { TorchSwordBool = true; sprite.flipX = false; rb.constraints = RigidbodyConstraints2D.FreezePosition; transform.position = TorchSword.position; // 仅触发一次拾取动画 animationPlayer.SetBool("Walking", false); animationPlayer.SetTrigger("PickST"); DestroyTorchNSword(); } }
3. 简化Update中的动画逻辑
移除Update分支中重复设置PickST的代码,避免每帧执行无效操作:
else { animationPlayer.SetBool("Walking", false); }
4. 通过动画事件触发玩家销毁
打开拾取动画的Clip,在时间线末尾添加动画事件,绑定到脚本的DestroyPlayer方法。这样动画播放完成后,才会实例化新玩家并销毁旧玩家,避免逻辑冲突。
5. 检查新玩家预制体
确保CharacterSword预制体没有挂载相同的PlayerMovementNoSword脚本,或已将其TorchSwordBool初始值设为false,防止新玩家误触发拾取逻辑。
修改后的完整代码
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerMovementNoSword : MonoBehaviour { private float move; [SerializeField] private bool TorchSwordBool = false; [SerializeField] private Transform TorchSword; [SerializeField] private GameObject CharacterSword; [SerializeField] private float moveSpeed = 3f; [SerializeField]private bool jumping; [SerializeField] private float jumpSpeed = 4.8f; [SerializeField] private float ghostJump; [SerializeField] private bool isGrounded; public Transform feetPosition; [SerializeField] private Vector2 sizeCapsule; [SerializeField] private float angleCapsule = -90; public LayerMask whatIsGround; Rigidbody2D rb; SpriteRenderer sprite; Animator animationPlayer; void Start() { rb = GetComponent<Rigidbody2D>(); sprite = GetComponent<SpriteRenderer>(); animationPlayer = GetComponent<Animator>(); sizeCapsule = new Vector2 (0.302f, 0.01f); } void Update() { if(TorchSwordBool == false) { isGrounded = Physics2D.OverlapCapsule(feetPosition.position, sizeCapsule, CapsuleDirection2D.Horizontal, angleCapsule, whatIsGround); move = Input.GetAxis("Horizontal"); if (move !=0) { moveSpeed += 15f * Time.deltaTime; if (moveSpeed >= 3.0f) { moveSpeed = 3.0f; } } else { moveSpeed = 0; } if(Input.GetButtonDown("Jump") && ghostJump > 0) { jumping = true; } if(move < 0) { sprite.flipX = true; } else if(move > 0) { sprite.flipX = false; } if (isGrounded) { ghostJump = 0.05f; animationPlayer.SetBool("JumpingV", false); animationPlayer.SetBool("FallingV", false); animationPlayer.SetBool("JumpingH", false); if (rb.velocity.x != 0 && move != 0) { animationPlayer.SetBool("Walking", true); } else { animationPlayer.SetBool("Walking", false); } } else { ghostJump -= Time.deltaTime; if(ghostJump <= 0) { ghostJump = 0; } animationPlayer.SetBool("Walking", false); if (rb.velocity.x == 0) { if (rb.velocity.y > 0) { animationPlayer.SetBool("JumpingV", true); animationPlayer.SetBool("FallingV", false); animationPlayer.SetBool("JumpingH", false); } if (rb.velocity.y < 0) { animationPlayer.SetBool("JumpingV", false); animationPlayer.SetBool("FallingV", true); animationPlayer.SetBool("JumpingH", false); } } else { if (rb.velocity.y > 0) { animationPlayer.SetBool("JumpingV", false); animationPlayer.SetBool("FallingV", false); animationPlayer.SetBool("JumpingH", true); } if (rb.velocity.y < 0) { animationPlayer.SetBool("JumpingV", false); animationPlayer.SetBool("FallingV", true); animationPlayer.SetBool("JumpingH", false); } } } } else { animationPlayer.SetBool("Walking", false); } } void OnDrawGizmosSelected() { Gizmos.color = new Color(1, 0, 0, 0.5f); Gizmos.DrawCube(feetPosition.position, sizeCapsule); } void FixedUpdate() { if(TorchSwordBool == false) { rb.velocity = new Vector2(move * moveSpeed, rb.velocity.y); if(jumping) { rb.velocity = Vector2.up * jumpSpeed; jumping = false; } } } void OnTriggerEnter2D(Collider2D coll) { if(coll.gameObject.tag == "TorchSword" && isGrounded && !TorchSwordBool) { TorchSwordBool = true; sprite.flipX = false; rb.constraints = RigidbodyConstraints2D.FreezePosition; transform.position = TorchSword.position; animationPlayer.SetTrigger("PickST"); DestroyTorchNSword(); } } void DestroyTorchNSword() { Destroy(TorchSword.gameObject); } void DestroyPlayer() { Instantiate(CharacterSword, transform.position, Quaternion.identity); Destroy(gameObject); } }
内容的提问来源于stack exchange,提问作者Matthew Pina
相关产品推荐
相关产品推荐

