Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考
此代码仅为较上一P有所改变的代码
【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili
Player.cs
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;public class Player : MonoBehaviour
{[Header("Move Info")]public float moveSpeed;//定义速度,与xInput相乘控制速度的大小public float jumpForce;[Header("Dash Info")][SerializeField] private float dashCooldown;private float dashUsageTimer;//为dash设置冷却时间,在一定时间内不能连续使用public float dashSpeed;//冲刺速度public float dashDuration;//持续时间public float dashDir { get; private set; }[Header("Collision Info")][SerializeField] private Transform groundCheck;//transform类,代表的时物体的位置,后面会来定位子组件的位置 [SerializeField] private float groundCheckDistance;[SerializeField] private Transform wallCheck;//transform类,代表的时物体的位置,后面会来定位子组件的位置 [SerializeField] private float wallCheckDistance;[SerializeField] private LayerMask whatIsGround;//LayerMask类,与Raycast配合,https://docs.unity3d.com/cn/current/ScriptReference/Physics.Raycast.htmlpublic int facingDir { get; private set; } = 1;private bool facingRight = true;//判断是否朝右#region 定义Unity组件public Animator anim { get; private set; }//这样才能配合着拿到自己身上的animator的控制权public Rigidbody2D rb { get; private set; }//配合拿到身上的Rigidbody2D组件控制权#endregion#region 定义Statespublic 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 PlayerPrimaryAttack primaryAttack { get; private set; }#endregionprivate void 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, "Jump");//wallJump也是Jump动画primaryAttack = new PlayerPrimaryAttack(this, stateMachine, "Attack");//this 就是 Player这个类本身}//Awake初始化所以State,为所有State传入各自独有的参数,及animBool,以判断是否调用此动画(与animatoin配合完成)private void Start(){anim = GetComponentInChildren<Animator>();//拿到自己身上的animator的控制权rb = GetComponent<Rigidbody2D>();stateMachine.Initialize(idleState);}private void Update()//在mano中update会自动刷新但其他没有mano的不会故,需要在这个updata中调用其他脚本中的函数stateMachine.currentState.update以实现 //stateMachine中的update{stateMachine.currentState.Update();//反复调用CurrentState的Update函数CheckForDashInput();}public void AnimationTrigger() => stateMachine.currentState.AnimationFinishTrigger();//从当前状态拿到AnimationTrigger进行调用的函数public void CheckForDashInput(){dashUsageTimer -= Time.deltaTime;//给dash上冷却时间if (IsWallDetected()){return;}//修复在wallslide可以dash的BUGif (Input.GetKeyDown(KeyCode.LeftShift) && dashUsageTimer < 0){dashUsageTimer = dashCooldown;dashDir = Input.GetAxisRaw("Horizontal");//设置一个值,可以将dash的方向改为你想要的方向而不是你的朝向if (dashDir == 0){dashDir = facingDir;//只有当玩家没有控制方向时才使用默认朝向}stateMachine.ChangeState(dashState);}}//将Dash切换设置成一个函数,使其在所以情况下都能使用public void SetVelocity(float _xVelocity, float _yVelocity){rb.velocity = new Vector2(_xVelocity, _yVelocity);//将rb的velocity属性设置为对应的想要的二维向量。因为2D游戏的速度就是二维向量FlipController(_xVelocity);//在其他设置速度的时候调用翻转控制器}//控制速度的函数,此函数在其他State中可能会使用,但仅能通过player.SeVelocity调用public bool IsGroundDetected(){return Physics2D.Raycast(groundCheck.position, Vector2.down, groundCheckDistance, whatIsGround);}//通过RayCast检测是否挨着地面,https://docs.unity3d.com/cn/current/ScriptReference/Physics.Raycast.html//xxxxxxxx() => xxxxxxxx == xxxxxxxxxx() return xxxxxxxxx;public bool IsWallDetected(){return Physics2D.Raycast(wallCheck.position, Vector2.right * facingDir, wallCheckDistance, whatIsGround);}//通过RayCast检测是否挨着地面,https://docs.unity3d.com/cn/current/ScriptReference/Physics.Raycast.html//xxxxxxxx() => xxxxxxxx == xxxxxxxxxx() return xxxxxxxxx;private void OnDrawGizmos(){Gizmos.DrawLine(groundCheck.position, new Vector3(groundCheck.position.x, groundCheck.position.y - groundCheckDistance));//绘制一条从 from(前面的) 开始到 to(后面的) 的线。Gizmos.DrawLine(wallCheck.position, new Vector3(wallCheck.position.x + wallCheckDistance, wallCheck.position.y));//绘制一条从 from(前面的) 开始到 to(后面的) 的线。}//画线函数public void Flip(){facingDir = facingDir * -1;facingRight = !facingRight;transform.Rotate(0, 180, 0);//旋转函数,transform不需要额外定义,因为他是自带的}//翻转函数public void FlipController(float _x)//目前设置x,目的时能在空中时也能转身{if (_x > 0 && !facingRight)//当速度大于0且没有朝右时,翻转{Flip();}else if (_x < 0 && facingRight){Flip();}}
}
PlayerState.cs
using System.Collections;
using System.Collections.Generic;
using System.Security.Authentication.ExtendedProtection;
using UnityEngine;
//被继承的总类,后面的所以state都需要继承它
//实际上Player并没有进入过这个状态,没有调用此脚本,所有的调用均属于此脚本的子脚本
public class PlayerState
{protected PlayerStateMachine stateMachine;//创建PlayerStateMachine类,以承接来自Player.cs传过来的东西protected Player player;//创建Player类,以承接来自Player.cs传过来的东西protected float stateTimer;protected bool triggerCalled;//动画是否完成控制值#region Unity组件protected Rigidbody2D rb;//纯简化,将player.rb --> rb#endregionprivate string animBoolName;//控制此时的anim的BOOL值protected float xInput;//设置一个可以保存当前是否在按移动键的变量protected float yInput;public PlayerState(Player _player,PlayerStateMachine _stateMachine,string _animBoolName){this.player = _player;this.stateMachine = _stateMachine; this.animBoolName = _animBoolName;}//构造函数,用于传递信息public virtual void Enter(){player.anim.SetBool(animBoolName, true);//通过animator自带的函数,将animator里的Bool值改变为想要的值rb = player.rb;//纯简化,将player.rb --> rbtriggerCalled = false;//默认为false表示没有完成动画}public virtual void Update(){stateTimer -= Time.deltaTime;//https://docs.unity3d.com/cn/current/ScriptReference/Time-deltaTime.html//从上一帧到当前帧的间隔(以秒为单位)(只读)。这个表达式就是表示每一帧都不断的减少时间player.anim.SetFloat("yVelocity", rb.velocity.y);//通过animator自带的函数,将animator里的Float值改变为想要的值,改变yVelocity以控制Jump与Fall动画的切换xInput = Input.GetAxisRaw("Horizontal");//对于键盘和游戏杆输入,该值将处于 -1...1 的范围内。 由于未对输入进行平滑处理,键盘输入将始终为 -1、0 或 1。 如果您想自己完成键盘输入的所有平滑处理,这非常有用。yInput = Input.GetAxisRaw("Vertical");}public virtual void Exit(){player.anim.SetBool(animBoolName, false);//通过animator自带的函数,将animator里的Bool值改变为想要的值}public virtual void AnimationFinishTrigger(){triggerCalled = true;}//动画控制函数,当动画完成时将控制器设置为true表达其动画已经完成了
}
PlayerGroundState.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//GroundState用于保证只有在Idle和Move这两个地面状态下才能调用某些函数,并且稍微减少一点代码量
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.GetKeyDown(KeyCode.Mouse0))//p38 2.从ground进入攻击状态{stateMachine.ChangeState(player.primaryAttack);}if(player.IsGroundDetected()==false){stateMachine.ChangeState(player.airState);}// 写这个是为了防止在空中直接切换为moveState了。if (Input.GetKeyDown(KeyCode.Space) && player.IsGroundDetected()){stateMachine.ChangeState(player.jumpState);}//空格切换为跳跃状态}}
PlayerPrimaryAttack.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PlayerPrimaryAttack : PlayerState
{//p38 2.从ground进入public PlayerPrimaryAttack(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(triggerCalled){stateMachine.ChangeState(player.idleState);}}
}
PlayerAnimationTrigger.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class playerAnimationTriggers : MonoBehaviour
{private Player player => GetComponentInParent<Player>();//获得夫组件上的实际存在的Player组件private void AnimationTrigger(){player.AnimationTrigger();}
}