[Header("Stunned info")]
public float stunDuration;
public Vector2 stunDirction;
protected bool canBeStunned;
[SerializeField] protected GameObject counterImage;
public virtual void OpenCounterAttackWindow()
{
canBeStunned = true;
counterImage.SetActive(true);
}
public virtual void CloseCounterAttackWindow()
{
canBeStunned = false;
counterImage.SetActive(false);
}
public virtual bool CanBeStunned()
{
if(canBeStunned)
{
CloseCounterAttackWindow();
return true;
}
return false;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : Entity
{
[SerializeField] protected LayerMask whatIsPlayer;
[Header("Stunned info")]
public float stunDuration;
public Vector2 stunDirction;
protected bool canBeStunned;
[SerializeField] protected GameObject counterImage;
[Header("Move info")]
public float moveSpeed;
public float idleTime;
public float battleTime;
[Header("Attack info")]
public float attackDistance;
public float attackCooldown;
[HideInInspector] public float lastTimeAttacked;
public EnemyStateMachine stateMachine { get; private set; }//定义敌人状态机类
//唤醒控制器
protected override void Awake()
{
base.Awake();
stateMachine = new EnemyStateMachine();
}
protected override void Update()
{
base.Update();
stateMachine.currentState.Update();
}
#region 是否反击
public virtual void OpenCounterAttackWindow()
{
canBeStunned = true;
counterImage.SetActive(true);
}
//此函数通过animator调用
public virtual void CloseCounterAttackWindow()
{
canBeStunned = false;
counterImage.SetActive(false);
}
//此函数通过animator调用
public virtual bool CanBeStunned()
{
if(canBeStunned)
{
CloseCounterAttackWindow();
return true;
}
return false;
}
//表示是否能被攻击的函数,
#endregion
public virtual void AnimationFinishTrigger() => stateMachine.currentState.AnimationFinishTrigger();
public virtual RaycastHit2D IsPlayerDetected() => Physics2D.Raycast(wallCheck.position, Vector2.right * facingDir, 10, whatIsPlayer);
protected override void OnDrawGizmos()
{
base.OnDrawGizmos();
Gizmos.color = Color.yellow;
Gizmos.DrawLine(transform.position, new Vector3(transform.position.x + attackDistance * facingDir, transform.position.y));
}
}
public override bool CanBeStunned()
{
if(base.CanBeStunned())
{
stateMachine.ChangeState(stunnedState);
return true;
}
return false;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy_Skeleton : Enemy
{
#region State
public SkeletonIdleState idleState { get; private set; }
public SkeletonMoveState moveState { get; private set; }
public SkeletonBattleState battleState { get; private set; }
public SkeletonAttackState attackState { get; private set; }
public SkeletonStunnedState stunnedState { get; private set; }
#endregion
protected override void Awake()
{
base.Awake();
idleState = new SkeletonIdleState(stateMachine, this, "Idle", this);
moveState = new SkeletonMoveState(stateMachine, this, "Move", this);
battleState = new SkeletonBattleState(stateMachine, this, "Move", this);
attackState = new SkeletonAttackState(stateMachine, this, "Attack", this);
stunnedState = new SkeletonStunnedState(stateMachine, this, "Stunned", this);
}
protected override void Start()
{
base.Start();
stateMachine.Initialize(idleState);
}
protected override void Update()
{
base.Update();
}
public override bool CanBeStunned()
{
if(base.CanBeStunned())
{
stateMachine.ChangeState(stunnedState);
return true;
}
return false;
}
}
private void OpenCounterAttackWindow() => enemy.OpenCounterAttackWindow();
private void CloseCounterAttackWindow() => enemy.CloseCounterAttackWindow();
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy_SkeletonAnimationTriggers : MonoBehaviour
{
private Enemy_Skeleton enemy => GetComponentInParent();
private void AnimationTrigger()
{
enemy.AnimationFinishTrigger();
}
private void AttackTrigger()
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(enemy.attackCheck.position, enemy.attackCheckRadius);
foreach (var hit in colliders)
{
if (hit.GetComponent() != null)
{
hit.GetComponent().Damage();
}
}
}
private void OpenCounterAttackWindow() => enemy.OpenCounterAttackWindow();
private void CloseCounterAttackWindow() => enemy.CloseCounterAttackWindow();
}
[Header("Attack details")]
public Vector2 [] attackMovement;
public float counterAttackDuration = .2f;
public PlayerCounterAttackState counterAttack { get; private set; }
counterAttack = new PlayerCounterAttackState(this, stateMachine, "CounterAttack");
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
public class Player : Entity
{
[Header("Attack details")]
public Vector2 [] attackMovement;
public float counterAttackDuration = .2f;
public bool isBusy { get; private set; }
[Header("Move Info")]
[SerializeField] public float moveSpeed = 12;
[SerializeField] public float jumpForce = 12;
[Header("Dash Info")]
[SerializeField] private float dashColdown;
[SerializeField] private float dashUsageTimer;
[SerializeField] public float dashSpeed;
[SerializeField] public float dashDuration;
[SerializeField] public float dashDir { get; private set; }
#region States
public PlayerStateMachine stateMachine { get; private set; }
public PlayerIdleState idleState { get; private set; }
public PlayerMoveState moveState { get; private set; }
public PlayerJumpState jumpState { get; private set; }
public PlayerAirState airState { get; private set; }
public PlayerDashState dashState { get; private set; }
public PlayerWallSlideState wallSlide { get; private set; }
public PlayerWallJumpState wallJump { get; private set; }
public PlayerPrimaryAttackState primaryAttack { get; private set; }
public PlayerCounterAttackState counterAttack { get; private set; }
#endregion
protected override void Awake()
{
base.Awake();
stateMachine = new PlayerStateMachine();
idleState = new PlayerIdleState(this,stateMachine,"Idle");
moveState = new PlayerMoveState(this, stateMachine, "Move");
jumpState = new PlayerJumpState(this, stateMachine, "Jump");
airState = new PlayerAirState(this, stateMachine, "Jump");
dashState = new PlayerDashState(this, stateMachine, "Dash");
wallSlide = new PlayerWallSlideState(this, stateMachine, "WallSlide");
wallJump = new PlayerWallJumpState(this, stateMachine, "WallJump");
primaryAttack = new PlayerPrimaryAttackState(this, stateMachine, "Attack");
counterAttack = new PlayerCounterAttackState(this, stateMachine, "CounterAttack");
//this 就是 player
}
protected override void Start()
{
base.Start();
stateMachine.Initialize(idleState);
}
public float timer;
public float cooldown = 5;
protected override void Update()//在mano种update会自动刷新但其他没有mano的不会故需要在这个updata中调用函数以实现
//stateMachine中的update
{
base.Update();
CheckForDashInput();
stateMachine.currentState.Update();
timer -= Time.deltaTime;
if (timer < 0 && Input.GetKeyDown(KeyCode.R))
{
timer = cooldown;
}
}
public IEnumerator BusyFor(float _seconds)
{
isBusy = true;
yield return new WaitForSeconds(_seconds);
isBusy = false;
}
public void AnimationTrigger() => stateMachine.currentState.AnimationFinishTrigger();
private void CheckForDashInput()
{
if (IsWallDetected())
return;
dashUsageTimer -= Time.deltaTime;
if (Input.GetKeyDown(KeyCode.LeftShift)&& dashUsageTimer<0)
{
dashUsageTimer = dashColdown;
dashDir = Input.GetAxisRaw("Horizontal");
if(dashDir == 0)
{
dashDir = facingDir;
}
}
}
}
public override void Update()
{
base.Update();
if (Input.GetKey(KeyCode.Q))//摁Q进行反击
stateMachine.ChangeState(player.counterAttack);
if (Input.GetKeyDown(KeyCode.Mouse0))
stateMachine.ChangeState(player.primaryAttack);
if(!player.IsGroundDetected())
stateMachine.ChangeState(player.airState);
if (Input.GetKeyDown(KeyCode.Space) && player.IsGroundDetected())
stateMachine.ChangeState(player.jumpState);
}
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
public class PlayerGroundState : PlayerState
{
public PlayerGroundState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName) : base(_player, _stateMachine, _animBoolName)
{
}
public override void Enter()
{
base.Enter();
}
public override void Exit()
{
base.Exit();
}
public override void Update()
{
base.Update();
if (Input.GetKey(KeyCode.Q))
stateMachine.ChangeState(player.counterAttack);
if (Input.GetKeyDown(KeyCode.Mouse0))
stateMachine.ChangeState(player.primaryAttack);
if(!player.IsGroundDetected())
stateMachine.ChangeState(player.airState);
if (Input.GetKeyDown(KeyCode.Space) && player.IsGroundDetected())
stateMachine.ChangeState(player.jumpState);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCounterAttackState : PlayerState
{
//此脚本通过PlayerGroundState调用,及当按下Q时,进入本脚本
public PlayerCounterAttackState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName) : base(_player, _stateMachine, _animBoolName)
{
}
public override void Enter()
{
base.Enter();
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);
//将距离内的所以碰撞器打包进自己建立的碰撞器包中,通过调用Physics2D中的OverlapCircleAll函数来实现该目的
foreach (var hit in colliders)
{
if (hit.GetComponent() != null)
{
if(hit.GetComponent().CanBeStunned())//当Enemy中的CanBeStunned()的返回值为True时,将SuccessfulCounterAttack设为true,及调用成功反击动画
{
stateTimer = 10;
player.anim.SetBool("SuccessfulCounterAttack", true);
}
}
if (stateTimer < 0 || triggerCalled)
{
stateMachine.ChangeState(player.idleState);
}
//通过或||来调用改回默认状态,当triggerCalled为true时,及动画已经完成。
//设置triggerCalled为true,也是是通过animator控制的
//当stateTimer为0返回默认状态,是因为当反击并没有成功时,时不会调用SuccessfulCounterAttack动画的,也就没法用triggerCalled为true来返回默认状态
}
}
}