创建一个C# script
编辑
默认是virtual studio打开,官方社区版免费
教程代码 8个方位水平移动
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float turnSpeed = 20f;//角速度为20
Vector3 m_Movement;//声明Vector3对象,它代表一个三维的向量,用记录玩家期望的朝向
Quaternion m_Rotation = Quaternion.identity;//声明一个四元数对象m_Rotation,并初始化为一个代表无旋转的值,用于记录旋转
Animator m_Animator;//声明一个Animator对象,为Animator组件所用
Rigidbody m_Rigidbody;//声明一个Rigidbody对象,为Rigidbody组件所用
// Start is called before the first frame update
void Start()
{
m_Animator = GetComponent<Animator>();//关联Animator组件,<>括号内是类型参数用于查询Animator组件
m_Rigidbody = GetComponent<Rigidbody>();//关联Animator组件
}
// 每帧调用一次
void FixedUpdate()
{
/*获得水平轴和垂直轴的矢量值*/
float horizontal = Input.GetAxis("Horizontal");//获得水平轴的值 AD
float vertical = Input.GetAxis("Vertical");//获得垂直轴的值 WS
/*合成目标向量*/
m_Movement.Set(horizontal, 0f, 0f);//设置移动向量的值,该向量由三个坐标轴的值构成,竖直值轴的值应该为0,0f代表该数为浮点数类型,因为John不会向上或向下移动
m_Movement.Normalize();//规范化该向量,使其在任何方向的大小一致
/*是否移动的bool值*/
bool hasHorizontalInput = !Mathf.Approximately(horizontal, 0f);//如果水平轴的值近似为0则该值为false
bool hasVerticalInput = !Mathf.Approximately(vertical, 0f);//如果垂直轴的值近似为0则该值为false
bool isWalking = hasHorizontalInput || hasVerticalInput;//是否行走,很明显这里是或的关系,true行走,false空闲
m_Animator.SetBool("IsWalking",isWalking);//这里将isWalking的布尔值传入先前的IsWalking参数
/*获得旋转所需的四元数值*/
Vector3 desiredForward = Vector3.RotateTowards(transform.forward, m_Movement, turnSpeed * Time.deltaTime, 0f);//得到朝向
//@1 transform.forward 是个访问Transform组件的捷径,获得当前的朝向
//@2 目标朝向
//@3 每帧的变化角度 d_angle = turnSpeed * time.deltaTime,time.deltaTime是每帧之间的间隔时间
//@4
m_Rotation = Quaternion.LookRotation(desiredForward);//得到的旋转
}
// 将之前所得到的m_Movement和m_Rotation应用于root motion
void OnAnimatorMove()
{
/*实现移动*/
m_Rigidbody.MovePosition(m_Rigidbody.position + m_Movement * m_Animator.deltaPosition.magnitude);
/*实现转向*/
m_Rigidbody.MoveRotation(m_Rotation);
}
}
//ps:类名要和文件名一致,否则无法运行,public修饰的变量将会在Inspector窗口显示
个人练习 实现任意方向的水平运动
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*改良版,将胶囊碰撞组件替换成了Character controller组件,解决了碰撞后乱动的问题,顺便试试中文编码*/
public class CharacterControl : MonoBehaviour
{
private struct State //存储状态信息的结构体
{
public bool hasLeftInput;
public bool hasRightInput;
public bool hasForwardInput;
public bool hasBackwardInput;
public bool isCircling;
public bool isGoStright;
public bool isTurning;
public bool isRetreat;
public bool isWalking;
public bool isIdel;
};
private bool retreatEnable; //是否允许快速转身
private bool isMoving;
private float angle;
private float 移动速度;
private Vector3 moveDirection;
private Quaternion m_Rotation;
private CharacterController m_Controller;
private Animator m_Animator;
private Rigidbody m_Rigidbody;
/*set control key*/
public KeyCode 左转键 = KeyCode.LeftArrow;
public KeyCode 右转键 = KeyCode.RightArrow;
public KeyCode 前进键 = KeyCode.UpArrow;
public KeyCode 快速回头键 = KeyCode.DownArrow;
public float 最大移动速度 = 0.025f; //移动速度
public float 最大角速度 = 20f; //模型的旋转速度
public float 静止角速度 = 4f; //每帧最多转4度
public float 运动角速度 = 4f; //每帧最多转4度
public float 加速度 = 0.001f; //每帧
public string walkControl = string.Copy("Iswalk");
// Start is called before the first frame update
void Start()
{
m_Controller = GetComponent<CharacterController>();
m_Animator = GetComponent<Animator>();
m_Rigidbody = GetComponent<Rigidbody>();
initData();
}
// Update is called once per frame
void FixedUpdate()
{
State state = StateCheck();//检查按键获得状态
m_Animator.SetBool("walkControl", state.isWalking); //播放移动动画
moveDirection = MoveByThis(state);//获得移动方向
m_Rotation = Quaternion.LookRotation(Vector3.RotateTowards(transform.forward, moveDirection, 最大角速度 * Time.deltaTime, 0f));//获得下一帧的旋转量
}
void OnAnimatorMove()
{
m_Controller.Move((isMoving? 1f:0f)*moveDirection);//移动
m_Rigidbody.MoveRotation(m_Rotation);//旋转
}
State StateCheck()//检查按键获得状态
{
State state = new State();
state.hasLeftInput = Input.GetKey(左转键);
state.hasRightInput = Input.GetKey(右转键);
state.hasForwardInput = Input.GetKey(前进键);
state.hasBackwardInput = Input.GetKey(快速回头键);
bool hasVerticalInput = state.hasForwardInput || state.hasBackwardInput && state.hasBackwardInput != state.hasForwardInput;//异或
bool hasHorizontalInput = state.hasLeftInput || state.hasRightInput && state.hasRightInput != state.hasLeftInput;
state.isCircling = !hasVerticalInput && hasHorizontalInput;//是否处于原地转圈状态
state.isGoStright = state.hasForwardInput && !hasHorizontalInput;//是否处于直行状态
state.isTurning = state.hasForwardInput && hasVerticalInput;//是否处于转向行走状态
state.isRetreat = state.hasBackwardInput && !hasHorizontalInput;//是否回头
state.isWalking = state.hasForwardInput || hasHorizontalInput;//是否播放行走动画
state.isIdel = !hasVerticalInput && !hasHorizontalInput;
isMoving = state.isGoStright || state.isTurning;
return state;
}
Vector3 MoveByThis(State state)//获得移动方向
{
Vector3 Direction = Vector3.zero;
if (Mathf.Approximately(angle % 360f, 0f))//watch dog 防止溢出
{
angle = 0f;
}
if( 移动速度 < 最大移动速度 && state.hasForwardInput)
{
移动速度 += 加速度;
}//更新速度
if (state.isCircling)
{
if (state.hasRightInput)
{
angle += 静止角速度;
}
else if (state.hasLeftInput)
{
angle -= 静止角速度;
}
移动速度 = 最大移动速度;
retreatEnable = true;//置为允许快速转身
Direction.Set(移动速度 * Mathf.Sin(angle * Mathf.PI / 180), 0f, 移动速度 * Mathf.Cos(angle * Mathf.PI / 180));
return Direction;
}
else if (state.isRetreat)//快速转身,只有在retreatEnable为true的情况下才能快速转身
{
if (retreatEnable)
{
angle += 180f;
retreatEnable = false;//快速转身置为不允许,防止按住不放,反复转身
移动速度 = 最大移动速度;
}
Direction.Set(移动速度 * Mathf.Sin(angle * Mathf.PI / 180), 0f, 移动速度 * Mathf.Cos(angle * Mathf.PI / 180));
return Direction;
}
else if (state.isTurning)//移动中转向,两帧4度
{
if (state.hasRightInput)
{
angle += 运动角速度;
}
else if (state.hasLeftInput)
{
angle -= 运动角速度;
}
Direction.Set(移动速度 * Mathf.Sin(angle * Mathf.PI / 180), 0f, 移动速度 * Mathf.Cos(angle * Mathf.PI / 180));
return Direction;
}
else//仅仅按住W或什么都没按的时候
{
if(state.isIdel)
{
移动速度 = 0f;
}
retreatEnable = true;
return moveDirection;
}
}
void initData()//初始化一些变量
{
angle = 0f;
retreatEnable = true;
移动速度 = 0f;
m_Rotation = Quaternion.identity;
moveDirection = Vector3.zero;
}
}
API
启用脚本
单击Hierarchy窗口中的JohnLemon,Inspector窗口open prefab,选中Asset/Scripts中的脚本拖到Inspector窗口的最下边
保存运行就可以使用WASD控制John一移动了。
总结
游戏角色行为是玩家输入行为的映射应该要一一对应,每一种同类行为动作之间关系应该是互斥的,比如向左走的同时就不可能向右走。