Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考
此代码仅为较上一P有所改变的代码
【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili
Enemy.cs
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
public class Enemy : Entity
{
[SerializeField] protected LayerMask whatIsPlayer;
[Header("Stun Info")]
public float stunnedDuration;//stunned持续时间
public Vector2 stunnedDirection;//stunned改变后的速度
protected bool canBeStunned;//判断是否可以被反击
[SerializeField] protected GameObject counterImage;//一个代表着是否可以被反击的信号
[Header("Move Info")]
public float moveSpeed;
public float idleTime;
public float battleTime;//多久能从battle状态中退出来
[Header("Attack Info")]
public float attackDistance;
public float attackCooldown;//攻击冷却
[HideInInspector] public float lastTimeAttacked;//最后一次攻击的时间
#region 类
public EnemyStateMachine stateMachine;
#endregion
protected override void Awake()
{
base.Awake();
stateMachine = new EnemyStateMachine();
}
protected override void Start()
{
base.Start();
}
protected override void Update()
{
base.Update();
stateMachine.currentState.Update();
//Debug.Log(IsPlayerDetected().collider.gameObject.name + "I see");//这串代码会报错,可能使版本的物体,因为在没有找到Player的时候物体是空的,NULL,你想让他在控制台上显示就报错了
}
public virtual void OpenCounterAttackWindow()//打开可以反击的信号的函数
{
canBeStunned = true;
counterImage.SetActive(true);
}
public virtual void CloseCounterAttackWindow()//关闭可以反击的信号的函数
{
canBeStunned = false;
counterImage.SetActive(false);
}
//protected virtual bool CanBeStunned()//没搞懂
//{
// if(canBeStunned)
// {
// CloseCounterAttackWindow();
// return true;
// }
// return false;
//}
public virtual void AnimationFinishTrigger() => stateMachine.currentState.AnimationFinishTrigger();//动画完成时调用的函数,与Player相同
public virtual RaycastHit2D IsPlayerDetected() => Physics2D.Raycast(wallCheck.position, Vector2.right * facingDir, 7, whatIsPlayer);//用于从射线投射获取信息的结构。
//该函数的返回值可以变,可以只返回bool,也可以是碰到的结构
protected override void OnDrawGizmos()
{
base.OnDrawGizmos();
Gizmos.color = Color.yellow;//把线改成黄色
Gizmos.DrawLine(transform.position, new Vector3(transform.position.x + attackDistance * facingDir, transform.position.y));//用来判别是否进入attackState的线
}
}
Enemy_Skeleton.cs
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEditorInternal;
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(this, stateMachine, "Idle", this);
moveState = new SkeletonMoveState(this,stateMachine, "Move", this);
battleState = new SkeletonBattleState(this, stateMachine, "Move", this);
attackState = new SkeletonAttackState(this, stateMachine, "Attack", this);
stunnedState = new SkeletonStunnedState(this, stateMachine, "Stunned", this);
}
protected override void Start()
{
base.Start();
stateMachine.Initialize(idleState);
}
protected override void Update()
{
base.Update();
if(Input.GetKeyDown(KeyCode.U))
{
stateMachine.ChangeState(stunnedState);//暂时用U来控制进入stunned
}
}
//protected override bool CanBeStunned()
//{
// if(base.CanBeStunned())
// {
// stateMachine.ChangeState(stunnedState);
// return true;
// }
// return false;
//}
}
Enemy_SkeletonAnimationTrigger.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy_SkeletonAnimationTriggers : MonoBehaviour
{
private Enemy_Skeleton enemy => GetComponentInParent<Enemy_Skeleton>();//拿到enemy实体
private void AnimationTrigger()
{
enemy.AnimationFinishTrigger();//调用实体上的函数,使triggerCalled为true;
}
private void AttackTrigger()
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(enemy.attackCheck.position, enemy.attackCheckRadius);//创建一个碰撞器组,保存所有圈所碰到的碰撞器
//https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Physics2D.OverlapCircleAll.html
foreach (var hit in colliders)//https://blog.csdn.net/m0_52358030/article/details/121722077
{
if (hit.GetComponent<Player>() != null)
{
hit.GetComponent<Player>().Damage();
}
}
}
private void OpenCounterWindow() => enemy.OpenCounterAttackWindow();
private void CloseCounter() => enemy.CloseCounterAttackWindow();
}