左键:连续的系列普通攻击 右键:蓄力的特殊攻击
inputSystem的绑定:(均是普通的点按操作)
inputActions.GamePlay.LAttack.started += StartLAttack;
inputActions.GamePlay.RAttack.started += StartFocusAttack;
inputActions.GamePlay.RAttack.canceled += StopFocusAttack;
普通攻击函数:
要点: 1:攻击状态,翻滚状态,格挡状态下均不能进行攻击。
2:ApplyAttackInput:表示能否输入攻击信号,配合动画Behaviour实现。在一段攻击动画开始进行若干时间(根据不同动画自定义)后才能继续攻击,实现平滑的连续攻击。(可停顿)
3:非攻击状态下 默认ApplyAttackInput为true。
private void StartLAttack(InputAction.CallbackContext obj)
{
if (!playerAnimationInf.IsAttack)
ApplyAttackInput = true;
if (!ApplyAttackInput || playerAnimationInf.IsRoll||playerAnimationInf.IsGuard) return;
ApplyAttackInput = false;
//判定是否能够对于处于虚弱状态的敌人进行处决
EnemyController weakEnemy = SelectWeakEnemy();
if (weakEnemy!= null)
{
//执行实际的处决
Vector3 toDirection = new Vector3(weakEnemy.transform.position.x - transform.position.x, transform.forward.y, weakEnemy.transform.position.z - transform.position.z);
StartCoroutine(RotateForwardWithSpeed(toDirection, 5));
weakEnemy.IsExecuted = true;
GlobalEvent.CallEnemyExitWeakState(weakEnemy);
anim.SetTrigger(Execution);
}
else
{
//正常进行普通攻击
if (curLockedEnemy != null)
{
Vector3 toDirection = new Vector3(curLockedEnemy.transform.position.x - transform.position.x, transform.forward.y, curLockedEnemy.transform.position.z - transform.position.z);
StartCoroutine(RotateForwardWithSpeed(toDirection, 5));
}
anim.SetTrigger(LAttack);
}
}
配合攻击动画使用的一些AnimationBehaviour:
1:ResetAttackTrigger(重置攻击Trigger,防止抽搐式地攻击)
分为两个脚本,一个在动画Enter时重置,一个在动画End时重置 LAttack信号。
2:ActiveAttackInput(恢复攻击信号)
在Enter时将ApplyAttackInput设置为false,调用计时器在给定的时间(允许下一次攻击的最小时间间隔)后将ApplyAttackInput重置为true
配合攻击动画使用的一些AnimationEvent:
1:攻击和翻滚时的人物的移动修正
利用协程解决,在动画人物将要移动时开启协程(可以设置速度值),在人物移动停止时终止协程。(再开启移动协程的同时取消上一次的移动修正协程)
//攻击时的移动修正
private Coroutine currentMoveAttackCoroutine;
//翻滚时的移动修正
private Coroutine currentMoveRollCoroutine;
public void StartAttackMove(float speed)
{
if (currentMoveAttackCoroutine != null) StopCoroutine(currentMoveAttackCoroutine);
if (IsRoll) return;
currentMoveAttackCoroutine = StartCoroutine(MoveForward(speed));
}
public void StopAttackMove()
{
StopCoroutine(currentMoveAttackCoroutine);
}
public void StartRollMove(float speed)
{
if (currentMoveAttackCoroutine != null) StopCoroutine(currentMoveAttackCoroutine);
if (currentMoveRollCoroutine != null) StopCoroutine(currentMoveRollCoroutine);
currentMoveRollCoroutine = StartCoroutine(MoveForward(speed));
}
public void StopRollMove()
{
StopCoroutine(currentMoveRollCoroutine);
}
private IEnumerator MoveForward(float speed)
{
while (true)
{
if (!physicalCheck.haveBarrierInMoveDirectino(transform.position + transform.up * 0.5f, transform.forward, transform.forward.normalized.magnitude * speed * 2.5f * Time.deltaTime))
playerController.characterController.Move(transform.forward.normalized * speed * Time.deltaTime);
yield return null;
}
}
2:人物攻击的判定和音效处理
(1)为人物的武器加上Trigger碰撞体,在动画中使用录制功能设定在攻击的几处关键帧中启用武器的碰撞体,在碰撞体的OnTriggerEnter事件中可以处理角色的受伤等。
[RequireComponent(typeof(Collider))]
public class AttackDefinition : MonoBehaviour
{
public float attackBaseDamage;
public float energyAmount; //如果对方是敌人 或者 对方正在普通格挡 会造成对方的体力消耗
public CharacterStats attacker;
public DamageType damageType;
public float DamageAmount => attackBaseDamage + damageType switch
{
DamageType.Physical => attacker.CurPhysicalDamage,
DamageType.Magical => attacker.CurMagicDamage,
DamageType.True => 0,
_ => 0
};
private void OnTriggerEnter(Collider other)
{
other.GetComponent<CharacterStats>()?.TakeDamage(this);
//碰撞体挂载在子物体上的特殊情况
if (other.GetComponentInParent<MetalonController>() || other.GetComponentInParent<GolemController>())
other.GetComponentInParent<CharacterStats>()?.TakeDamage(this);
}
}
(2)在攻击的关键帧中添加播放音效的事件即可。
蓄力攻击函数:
//开始蓄力攻击
private void StartFocusAttack(InputAction.CallbackContext obj)
{
if (playerAnimationInf.IsAttack) return;
if (playerAnimationInf.IsRoll||playerAnimationInf.IsGuard) return;
ApplyAttackInput = false;
if (curLockedEnemy != null)
{
Vector3 toDirection = new Vector3(curLockedEnemy.transform.position.x - transform.position.x, transform.forward.y, curLockedEnemy.transform.position.z - transform.position.z);
StartCoroutine(RotateForwardWithSpeed(toDirection, 5));
}
anim.SetBool(RAttackHold, true);
}
private void StopFocusAttack(InputAction.CallbackContext obj)
{
anim.SetBool(RAttackHold, false);
}
判断是否正在攻击:(实现有些动作禁止在攻击时做出)
利用动画中的Tag,分别设置 “Normal Attack” 和 “Focus Attack” 的标签。(包括蓄力的准备和停止工作等)
利用Animator获取当前战斗层级下的状态的标签信息。
public bool IsLeftAttack
{
get => anim.GetCurrentAnimatorStateInfo(animatorCombatLayer).IsTag("Normal Attack");
}
public bool IsFocusAttack
{
get => anim.GetCurrentAnimatorStateInfo(animatorCombatLayer).IsTag("Focus Attack");
}
public bool IsAttack
{
get => IsLeftAttack || IsFocusAttack;
}