https://youtu.be/-jkT4oFi1vk?si=izRR0C1xHx3-I23E 教程来源,油管AdamCYounis
一、c#状态机(游戏)
在看Unity入门教程,刚好看到这个,感觉挺好的,记录一下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class State : MonoBehaviour
{
public bool isComplete { get; protected set; }
protected float startTime;
public float time => Time.time - startTime;
public virtual void Enter() { }
public virtual void Do() { }
public virtual void FixDo() { }
public virtual void Exit() { }
}
注解1:public bool isComplete { get; protected set; }相当于
private bool _isComplete; // 私有字段存储实际值
public bool isComplete
{
get //公共的
{
return _isComplete;
}
protected set //受保护的
{
_isComplete = value;
}
}
简化版: 编译器自动创建私有字段
完整版: 手动创建私有字段和访问器
注解2:public float time => Time.time - startTime;相当于
public float time
{
get
{
return Time.time - startTime;
}
}
简化版: => 是表达式主体语法,用于只读计算属性
完整版: 传统的get访问器写法
注解3:virtual的功能
virtual关键字在C#中用于创建可被重写的方法,让子类能够提供自己的实现。
二、数值映射函数
public static float Map(float value , float min1,float max1,float min2,float max2,bool clamp = false)
{
float val = min2 + (max2 - min2) * ((value-min1) / (max1-min1));
return clamp ? Mathf.Clamp(val,Mathf.Min(min2,max2),Mathf.Max(min2,max2)):val;
}//有用的数值映射函数,比如从[0,10]映射到[0,100],3映射为30,还可以将摄氏度映射为华氏度等
注解:有用的数值映射函数,比如从[0,10]映射到[0,100],3映射为30,还可以将摄氏度映射为华氏度等,返回偏移值:
1、bool clamp = flase 是c#的语法,如果没有赋值就保留clamp = false的默认赋值
2、mathf.min以及mathf.max的作用主要是在反向映射的情况下不出错,但实际上映射出来是相反的,比如,[0,10]映射到[100,0],那么3会映射为70,这个暂时没什么用,后面可能会用到吧。
3、Mathf.Clamp(value, min, max) 的作用是限制数值范围:
- 如果
value < min,返回min - 如果
value > max,返回max - 如果
min ≤ value ≤ max,返回value
具体应用:在跳跃的时候刚好播放完整动画“Air”,(Speed = 0保证动画不会在停在一帧不动的时候乱跳)
void UpdateAirborne()
{
float time = Map(rigidbody2.velocity.y, -jumpForce, jumpForce, 0, 1, true);
animator.Play("Air",0,time);
animator.speed = 0;
if(isGrounded)
stateComplete = true;
}
注:animator.play(,,)中间那个0指的是animator的baseLayer层,index是0
三、角色控制代码供参考(最简单的版本),用于实现角色走路跳跃等,包括动画内容,不需要在animator界面中拉transition了:
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
public class PlayerScript : MonoBehaviour
{
public BoxCollider2D boxCollider2D;
public CapsuleCollider2D capsuleCollider2D;
public Animator animator;
private Rigidbody2D rigidbody2;
public float runSpeed = 5f;
public float horizontalSpeed = 0f;
//bool isFacingLeft = false;
public float jumpForce = 17f;
private bool isGrounded;
private bool stateComplete = true;
private LayerMask groundLayer;
enum PlayerState { Idle,Running,Airborne}
PlayerState state;
void Start()
{
rigidbody2 = GetComponent<Rigidbody2D>();
groundLayer = LayerMask.GetMask("Ground");
}
// Update is called once per frame
void Update()
{
FlipDetection2();
MoveWithInput();
if (stateComplete)
{
SelectState();
}
UpdateState();
}
private void FixedUpdate()
{
CheckGround();
}
void MoveWithInput()
{
horizontalSpeed = Input.GetAxisRaw("Horizontal") * runSpeed;
//animator.SetFloat("speed", Mathf.Abs(horizontalSpeed));
if (Mathf.Abs(Input.GetAxisRaw("Horizontal")) > 0)
{
rigidbody2.velocity = new Vector2(horizontalSpeed, rigidbody2.velocity.y);
}
//垂直速度
if (Input.GetButtonDown("Jump") && isGrounded)
{
rigidbody2.velocity = new Vector2(rigidbody2.velocity.x, jumpForce);
}
}
void CheckGround()
{
// Debug.Log(isGrounded);
int sumGround = Physics2D.OverlapAreaAll(boxCollider2D.bounds.min, boxCollider2D.bounds.max, groundLayer).Length;
if (sumGround > 0) {
isGrounded = true;
}
else
{
isGrounded = false;
}
}
void FlipDetection2()
{
if (horizontalSpeed != 0)
{
float direction = Mathf.Sign(horizontalSpeed);
//Mathf.Sign(float f); Returns a value of 1 when f is 0 or greater. Returns a value of -1 when f is negative.
transform.localScale = new Vector3( direction* Mathf.Abs(transform.localScale.x), transform.localScale.y, 1);
}
}
void UpdateState()
{
switch (state)
{
case PlayerState.Idle:
UpdateIdle();
break;
case PlayerState.Running:
UpdateRunning();
break;
case PlayerState.Airborne:
UpdateAirborne();
break;
}
}
void UpdateRunning()
{
float velX = rigidbody2.velocity.x;
animator.speed = Mathf.Abs(velX) / runSpeed;
if(!isGrounded|| Mathf.Abs(velX) <= 0.1)
stateComplete = true;
}
void UpdateIdle()
{
if(horizontalSpeed == 0 || !isGrounded)
stateComplete = true;
}
void UpdateAirborne()
{
float time = Map(rigidbody2.velocity.y, -jumpForce, jumpForce, 0, 1, true);
animator.Play("Air",0,time);
animator.speed = 0;
if(isGrounded)
stateComplete = true;
}
void SelectState()
{
stateComplete = false;
if (isGrounded)
{
if (horizontalSpeed == 0)
{
state = PlayerState.Idle;
StartIdle();
}
else
{
state = PlayerState.Running;
StartRunning();
}
}
else
{
state = PlayerState.Airborne;
StartAirborne();
}
}
void StartRunning()
{
animator.Play("Run");
}
void StartIdle()
{
animator.Play("Idle");
}
void StartAirborne()
{
animator.Play("Air");
}
public static float Map(float value , float min1,float max1,float min2,float max2,bool clamp = false)
{
float val = min2 + (max2 - min2) * ((value-min1) / (max1-min1));
return clamp ? Mathf.Clamp(val,Mathf.Min(min2,max2),Mathf.Max(min2,max2)):val;
}//有用的数值映射函数,比如从[0,10]映射到[0,100],3映射为30,还可以将摄氏度映射为华氏度等
}

5万+

被折叠的 条评论
为什么被折叠?



