Unity类银河战士恶魔城学习总结(P178 Archer s arrow 弓箭手的箭)
【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili
教程源地址:https://www.udemy.com/course/2d-rpg-alexdev/
本章节制作了一个弓箭手的箭
Arrow_Controller.cs
1.OnTriggerEnter2D方法
- 功能:检测箭矢与其他对象的碰撞。
- 逻辑:
- 如果碰撞对象的层级与
targetLayerName
匹配:- 获取碰撞对象的
CharacterStats
组件并调用TakeDamage(damage)
方法,造成伤害。 - 调用
StuckInto(collision)
方法,使箭矢嵌入碰撞对象。
- 获取碰撞对象的
- 如果碰撞对象的层级为"Ground":
- 直接调用
StuckInto(collision)
方法,使箭矢嵌入地面。
- 直接调用
- 如果碰撞对象的层级与
2.StuckInto方法
- 功能:处理箭矢嵌入目标后的状态变化。
- 步骤:
- 停止粒子系统:停止箭矢子对象中的
ParticleSystem
,例如拖尾效果。 - 禁用碰撞体:禁用箭矢的
Collider2D
,防止进一步的碰撞检测。 - 停止移动:将
canMove
设为false
,阻止在Update
中继续移动。 - 设置刚体为运动学:将
rb.isKinematic
设为true
,使箭矢不再受物理引擎影响。 - 冻结所有刚体约束:通过
rb.constraints = RigidbodyConstraints2D.FreezeAll
冻结箭矢的所有移动和旋转,确保其在嵌入后不再移动。 - 设置父对象:将箭矢的
transform
设置为碰撞对象的子对象,使其随碰撞对象一起移动。 - 销毁箭矢:在5到7秒后销毁箭矢对象,使用
Random.Range(5,7)
生成销毁延迟时间。
- 停止粒子系统:停止箭矢子对象中的
3.FlipArrow()方法
功能:翻转箭矢的方向,使其朝相反方向移动,并更改目标层级。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//2024.12.11
public class Arrow_Controller : MonoBehaviour
{
[SerializeField] private int damage;//箭矢造成的伤害值
[SerializeField] private string targetLayerName = "Player";//箭矢的目标层
[SerializeField] private float xVelocity;
[SerializeField] private Rigidbody2D rb;
[SerializeField] private bool canMove;
[SerializeField] private bool flipped;
private void Update()
{
if(canMove)
rb.velocity = new Vector2(xVelocity, rb.velocity.y);
}
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.gameObject.layer == LayerMask.NameToLayer(targetLayerName))
{
collision.GetComponent<CharacterStats>().TakeDamage(damage);
StuckInto(collision);
}
else if (collision.gameObject.layer == LayerMask.NameToLayer("Ground"))
{
StuckInto(collision);
}
}
private void StuckInto(Collider2D collision)//射中目标
{
GetComponentInChildren<ParticleSystem>().Stop();//停止粒子系统
GetComponent<Collider2D>().enabled = false;
canMove = false;
rb.isKinematic = true;//刚体为运动
rb.constraints = RigidbodyConstraints2D.FreezeAll;
transform.parent = collision.transform;//箭矢的父物体为碰撞物体
Destroy(gameObject, Random.Range(5,7));
}
public void FlipArrow()
{
if (flipped)
return;
xVelocity = xVelocity * -1;
flipped = true;
transform.Rotate(0,180,0);
targetLayerName = "Enemy";
}
}
PlayerCounterAttackState.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCounterAttackState : PlayerState
{
private bool canCreateClone;
public PlayerCounterAttackState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName) : base(_player, _stateMachine, _animBoolName)
{
}
public override void Enter()
{
base.Enter();
canCreateClone = true;
stateTimer = player.counterAttackDuration;
player.anim.SetBool("SuccessfulCounterAttack", false);
}
public override void Exit()
{
base.Exit();
}
public override void Update()
{
base.Update();
player.SetZeroVelocity();
Collider2D[] colliders = Physics2D.OverlapCircleAll(player.attackCheck.position, player.attackCheckRadius);
foreach (var hit in colliders)
{
if(hit.GetComponent<Arrow_Controller>()!= null)
{
hit.GetComponent<Arrow_Controller>().FlipArrow();
SuccesfulCounterAttack();
}
if (hit.GetComponent<Enemy>() != null)
{
if (hit.GetComponent<Enemy>().CanBeStunned())
{
SuccesfulCounterAttack();
player.skill.parry.UseSkill();
if (canCreateClone)
{
canCreateClone = false;
player.skill.parry.MakeMirageOnParry(hit.transform);
}
}
}
}
if (stateTimer < 0 || triggerCalled)
stateMachine.ChangeState(player.idleState);
}
private void SuccesfulCounterAttack()
{
stateTimer = 10;//大于1的数,保证不会进入idle状态
player.anim.SetBool("SuccessfulCounterAttack", true);
}
}