实现在Unity中重新封装按键输入
| |
| 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>(); |
| |
| 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); |
| } |
| } |
| |
| 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}); |
| } |
| |
| 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; |
| } |
| |
| public float GetAxis(string axis) { |
| if(this.unityAxis.Contains(axis)){ |
| return Input.GetAxis(axis); |
| }else |
| return 0; |
| } |
| |
| 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); |
| } |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了