Unity 按键输入封装&实现第一人称移动&相机移动

实现在Unity中重新封装按键输入

1.创建脚本Input.cs

//自定义轴
public class fps_InputAxis
{
public KeyCode positive;
public KeyCode negative;
}
//自定义按键集合
public Dictionary<string, KeyCode> buttons = new Dictionary<string, KeyCode>();
//自定义轴集合
public Dictionary<string, fps_InputAxis> axis = new Dictionary<string, fps_InputAxis>();
//Unity轴集合
public List<string> unityAxis = new List<string>();

1.1 初始化方法

void Start(){
SetupDefaults();
}
private void SetupDefaults(string type = ""){
//初始化按键
if (type == "" || type == "button"){
if (buttons.Count == 0){
AddButton("File", KeyCode.Mouse0); //开火
AddButton("Reload", KeyCode.R); //装弹
AddButton("Jump", KeyCode.Space); //跳跃
AddButton("Crouch", KeyCode.C); //蹲伏
AddButton("Sprint", KeyCode.LeftShift); //冲刺
}
}
//初始化自定义轴
if (type == "" || type == "Axis"){
if (axis.Count == 0){
AddAxis("Horizontal", KeyCode.W, KeyCode.S);
AddAxis("Vertical", KeyCode.A, KeyCode.D);
}
}
//初始化unity轴
if (type == "" || type == "UnityAxis"){
if (unityAxis.Count == 0){
AddUnityAxis("Mouse X");
AddUnityAxis("Mouse Y");
AddUnityAxis("Horizontal");
AddUnityAxis("Vertical");
}
}
}

1.2 添加按键、轴方法

//添加按键
private void AddButton(string n, KeyCode k){
if (buttons.ContainsKey(n))
buttons[n] = k;
else
buttons.Add(n, k);
}
//添加自定会轴
private void AddAxis(string n, KeyCode pk, KeyCode nk){
if (axis.ContainsKey(n))
axis[n] = new fps_InputAxis() {positive = pk, negative = nk};
else
axis.Add(n, new fps_InputAxis() {positive = pk, negative = nk});
}
//添加unity轴
private void AddUnityAxis(string n) {
if (!unityAxis.Contains(n))
unityAxis.Add(n);
}

1.3 获取按键

//外界获取按键的值—按下
public bool GetButton(string button) {
if (buttons.ContainsKey(button)){
return Input.GetKey(buttons[button]);
}
return false;
}
//返回按键是否按下状态
public bool GetButtonDown(string button) {
if (buttons.ContainsKey(button)) {
return Input.GetKeyDown(buttons[button]);
}
return false;
}
//获取轴(-1~1)float 类型
public float GetAxis(string axis) {
if(this.unityAxis.Contains(axis)){
return Input.GetAxis(axis);
}else
return 0;
}
//获取轴,返回一个值,只有-1,0,1这三个值
public float GetAxisRaw(string axis) {
if(this.axis.ContainsKey(axis)) {
float val = 0;
if(Input.GetKey(this.axis[axis].positive)) {
return 1;
}
if(Input.GetKey(this.axis[axis].negative)) {
return -1;
}
return val;
}else if(unityAxis.Contains(axis)){
return Input.GetAxisRaw(axis);
}
else{
return 0;
}
}

2. 增加参数控制'FPS_PlayerParameter.cs'

[RequireComponent(typeof(CharacterController))]//添加特性
public class FPS_PlayerParameter : MonoBehaviour
{
[HideInInspector] //隐藏属性
public Vector2 inputSmootLook;//鼠标输入
[HideInInspector] //隐藏属性
public Vector2 inputMoveVerctor;//按键输入
[HideInInspector] //隐藏属性
public bool inputCtouch;//是否蹲伏
[HideInInspector] //隐藏属性
public bool inputJump;//是否跳跃
[HideInInspector] //隐藏属性
public bool inputSprint;//是否冲刺
[HideInInspector] //隐藏属性
public bool inputFire;//是否开火
[HideInInspector] //隐藏属性
public bool inputReload;//是否装弹
}

3. 按键输入

3.1 取消光标显示

public bool LookCursor
{
//如果是锁定状态就返回true 否则就返回false
get { return Cursor.lockState == CursorLockMode.Locked ? true : false; }
set
{
//光标不可见
Cursor.visible = value;
Cursor.lockState = value ? CursorLockMode.Locked : CursorLockMode.None;
}
}

3.2 输入和输入参数 的引用 实例化

private FPS_PlayerParameter parameter;
private FPS_Input input;
private void Start()
{
//开启取消光标
LookCursor = true;
parameter = this.GetComponent<FPS_PlayerParameter>();
input = GameObject.FindGameObjectWithTag(Tags.gameController).GetComponent<FPS_Input>();
}

3.3 赋值

private void Update()
{
InitialInput();
}
private void InitialInput(){
parameter.inputMoveVerctor = new Vector2(input.GetAxis("Horizontal"),input.GetAxis("Vertical"));
parameter.inputSmootLook = new Vector2(input.GetAxisRaw("Mouse X"), input.GetAxisRaw("Mouse Y"));
parameter.inputCtouch = input.GetButton("Crouch");
parameter.inputJump = input.GetButton("Jump");
parameter.inputSprint = input.GetButton("Sprint");
parameter.inputFire = input.GetButton("Fire");
parameter.inputReload = input.GetButtonDown("Reload");
}

4.第一人称相机旋转实现

4.1 设置默认参数

public Vector2 mouseLockSensitivity = new Vector2(5, 5);//灵敏度
public Vector2 rotaionXLimit = new Vector2(87, -87);//X轴转动范围
public Vector2 rotaionYLimit = new Vector2(-360,360);//Y轴转动范围
public Vector3 positionOffset = new Vector3(0, 2, 0.2f);//摄像机位置
private Vector2 currentMouseLook = Vector2.zero;//当前的输入状态
private float x_Angle = 0;//X轴默认位置
private float y_Angle = 0;//Y轴默认位置
private FPS_PlayerParameter parameter;//鼠标输入
private Transform m_transform;

4.2 实例化

void Start(){
parameter = GameObject.FindGameObjectWithTag(Tags.player).GetComponent<FPS_PlayerParameter>();
m_transform = transform;
m_transform.localPosition = positionOffset;
}

4.3 计算相机旋转角度

void Update() {
UpdateInput();
}
void UpdateInput() {
if (parameter.inputSmootLook == Vector2.zero)
return;
GetMouseLook();
y_Angle += currentMouseLook.x;
x_Angle += currentMouseLook.y;
//y_Angle值范围判定
y_Angle = y_Angle < -360 ? y_Angle += 360 : y_Angle;
y_Angle = y_Angle > 360 ? y_Angle -= 360 : y_Angle;
y_Angle = Mathf.Clamp(y_Angle, rotaionYLimit.x, rotaionYLimit.y);
//x_Angle值范围判定
x_Angle = x_Angle < -360 ? x_Angle += 360 : x_Angle;
x_Angle = x_Angle > 360 ? x_Angle -= 360 : x_Angle;
x_Angle = Mathf.Clamp(x_Angle, -rotaionXLimit.x, -rotaionXLimit.y);
}
private void GetMouseLook() {
currentMouseLook.x = parameter.inputSmootLook.x;
currentMouseLook.y = parameter.inputSmootLook.y;
//添加灵敏度
currentMouseLook.x *= mouseLockSensitivity.x;
currentMouseLook.y *= mouseLockSensitivity.y;
currentMouseLook.y *= -1;
}

4.4 移动相机旋转角度

void LateUpdate() {
Quaternion xQuaternion = Quaternion.AngleAxis(y_Angle, Vector3.up);
Quaternion yQuaternion = Quaternion.AngleAxis(0, Vector3.left);
m_transform.parent.rotation = xQuaternion * yQuaternion;
yQuaternion = Quaternion.AngleAxis(-x_Angle, Vector3.left);
m_transform.rotation = xQuaternion * yQuaternion;
}

5.第一人称移动实现

5.1 玩家移动状态定义

public enum PlayerState {//玩家状态
None,//默认
Idle,//站立
Walk,//行走
Crouch,//蹲伏
Run,//跑
}

5.2 移动变量定义

private PlayerState state = PlayerState.None;//玩家状态
public PlayerState State {
get {
if (runing)
state = PlayerState.Run;
else if (walking)
state = PlayerState.Walk;
else if (creouching)
state = PlayerState.Crouch;
else
state = PlayerState.Idle;
return state;
}
public float sprintSpeed = 10.0f;// 冲刺状态速度
public float sprintJumpSpeed = 8.0f;//冲刺状态下跳跃速度
public float normaltSpeed = 6.0f;//行走状态速度
public float normalJumpSpeed = 7.0f;//行走状态下跳跃速度
public float crouchSpeed = 2.0f;//蹲伏状态速度
public float crouchJumpSpeed = 5.0f;//蹲伏状态下跳跃速度
public float crouchDeletHeight = 0.5f;//蹲伏状态下下降的高度
public float cameraMoveSpeed = 8.0f;// 蹲伏时相机速度
public float gravity = 20.0f;//重力
public AudioClip JumpAudio;//跳跃音效
private float speed;//玩家当前速度
private float jumpSpeed;//玩家当前跳跃速度
private Transform mainTransform;
private float standardCamHeight;//正常状态相机高度
private float crouchingCamHeight;//蹲伏状态相机高度
private bool grounded = false;//玩家是否在地面
private bool walking = false;//玩家是否在行走
private bool creouching = false;//玩家是否在蹲伏
private bool stopCreouching = false;//玩家是否停止蹲伏
private bool runing = false;//玩家是否在跑
private Vector3 normalControllerCenter = Vector3.zero;
private float normalControllerHeight = 0.0f;
private float rimer = 0;
private CharacterController controller;
private AudioSource audioSource;
private FPS_PlayerParameter parameter;
private Vector3 moveDirection = Vector3.zero;

5.3 初始化

private void Start() {
crouching = false;
walking = false;
runing = false;
speed = normaltSpeed;
jumpSpeed = normalJumpSpeed;
mainCamera = GameObject.FindGameObjectWithTag(Tags.mainCamera).transform;
standardCamHeight = mainCamera.localPosition.y;
crouchingCamHeight = standardCamHeight - crouchDeletHeight;
audioSource = GetComponent<AudioSource>();
controller = GetComponent<CharacterController>();
parameter = GetComponent<FPS_PlayerParameter>();
normalControllerCenter = controller.center;
normalControllerHeight = controller.height;
}

5.4 移动方法

//移动
private void UpdateMove() {
if (grounded) {
moveDirection = new Vector3(parameter.inputMoveVerctor.x, 0, parameter.inputMoveVerctor.y);
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
if (parameter.inputJump) {
moveDirection.y = jumpSpeed;
AudioSource.PlayClipAtPoint(JumpAudio,transform.position);
CurrentSpeed();
}
}
moveDirection.y -= gravity * Time.deltaTime;
CollisionFlags flags = controller.Move(moveDirection * Time.deltaTime);
grounded = (flags&CollisionFlags.CollidedBelow)!=0;
if (Mathf.Abs(moveDirection.x)>0&&grounded||Mathf.Abs(moveDirection.z)>0&&grounded) {
if (parameter.inputSprint) {
walking = false;
runing = true;
crouching = false;
}else if (parameter.inputCtouch) {
crouching = true;
walking = false;
runing = false;
}
else {
walking = true;
runing = false;
crouching = false;
}
}
else {
if (walking)
walking = false;
if (runing)
runing = false;
if (parameter.inputCtouch)
crouching = true;
else
crouching = false;
}
if (crouching) {
controller.height = normalControllerHeight - crouchDeletHeight;
controller.center = normalControllerCenter - new Vector3(0, crouchDeletHeight /2 ,0 );
}
else {
controller.height = normalControllerHeight;
controller.center = normalControllerCenter;
}
UpdateCrouch();
CurrentSpeed();
}

5.5 根据当前状态修改移动速度

//修改当前速度
private void CurrentSpeed() {
switch (State) {
case PlayerState.Idle:
speed = normaltSpeed;
jumpSpeed = normalJumpSpeed;
break;
case PlayerState.Walk:
speed = normaltSpeed;
jumpSpeed = normalJumpSpeed;
break;
case PlayerState.Crouch:
speed = crouchSpeed;
jumpSpeed = crouchJumpSpeed;
break;
case PlayerState.Run:
speed = sprintSpeed;
jumpSpeed = sprintJumpSpeed;
break;
}
}

5.6 移动时声音播放

//移动声音播放
private void AudioManagement() {
if (State == PlayerState.Walk) {
audioSource.pitch = 1.0f;
if (!audioSource.isPlaying) {
audioSource.Play();
}
}else if (State == PlayerState.Run) {
audioSource.pitch = 1.3f;
if (!audioSource.isPlaying) {
audioSource.Play();
}
}else {
audioSource.Stop();
}
}

5.7 根据蹲伏状态修改视角高度

//更新蹲伏是视角高度
private void UpdateCrouch() {
if (crouching) {
if (mainCamera.localPosition.y>crouchingCamHeight) {
if (mainCamera.localPosition.y- (crouchDeletHeight * Time.deltaTime * cameraMoveSpeed) <crouchingCamHeight) {
mainCamera.localPosition = new Vector3(mainCamera.localPosition.x, crouchingCamHeight, mainCamera.localPosition.z);
}else {
mainCamera.localPosition -= new Vector3(0, crouchDeletHeight * Time.deltaTime, 0);
}
}else {
mainCamera.localPosition = new Vector3(mainCamera.localPosition.x, crouchingCamHeight, mainCamera.localPosition.z);
}
} else {
if (mainCamera.localPosition.y<standardCamHeight) {
if (mainCamera.localPosition.y+ (crouchDeletHeight * Time.deltaTime * cameraMoveSpeed) >standardCamHeight) {
mainCamera.localPosition = new Vector3(mainCamera.localPosition.x, standardCamHeight, mainCamera.localPosition.z);
}else {
mainCamera.localPosition += new Vector3(0, crouchDeletHeight * Time.deltaTime * cameraMoveSpeed, 0);
}
}else {
mainCamera.localPosition = new Vector3(mainCamera.localPosition.x, standardCamHeight, mainCamera.localPosition.z);
}
}
posted @   星空探险家  阅读(48)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示