Unity第一人称恐怖游戏Player Controller快跑功能失效求助
Unity第一人称恐怖游戏快跑功能失效排查与修复
问题描述
正在开发一款基于Unity+C#的3D第一人称恐怖游戏,使用Character Controller组件实现玩家移动,功能需求如下:
- W/A/S/D:前后左右移动
- Left Control:切换站立/爬行状态
- Left Shift:按住W时,若冷却计时器≤0则触发快跑;满足计时器≥冷却值、松开W或再次按Left Shift时停止快跑(站立/爬行均可触发)
- Space:跳跃
当前其他功能正常,仅快跑(Fast()函数)失效,按下Left Shift无法触发快跑。原脚本如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Character_Movement_V2 : MonoBehaviour { CharacterController characterController; //test public float showSpeed; public float gravity = -9.81f; public float gravityMultiplier = 3f; public float verticalVelocity; public float movspeed = 1f; public float isFastSpeed = 1f; public float CrawlSpeed = 1f; public bool isCrawling; public bool isFast; public float jumpHeight = 3f; public float jumpCooldown = 4f; public float jumpTimer; public float isFastTimer; public float isFastCooldown = 6f; // Start is called before the first frame update void Start() { characterController = GetComponent<CharacterController>(); jumpTimer = jumpCooldown; isFastTimer = isFastCooldown; } // Update is called once per frame void Update() { MovePlayer(); Fast(); Crawl(); JumpandGravity(); } public void MovePlayer() { //Move Player //check Vector3 move = (movspeed * isFastSpeed * CrawlSpeed * (transform.right * Input.GetAxis("Horizontal") + transform.forward * Input.GetAxis("Vertical")) + transform.up * verticalVelocity); characterController.Move(move * Time.deltaTime); //test showSpeed = Mathf.Sqrt((move.x) * (move.x) + (move.z) * (move.z)); } public void Fast() { if(Input.GetKey(KeyCode.W)) { if (isFastTimer <= 0f && Input.GetKeyDown(KeyCode.LeftShift)) { isFast = true; } } else { isFast = false; } if ((isFast && Input.GetKeyDown(KeyCode.LeftShift)) || (isFastTimer >= isFastCooldown)) { isFast = false; } if (isFast) { isFastSpeed = 3f; } else { isFastSpeed = 1f; } //isFast Timer if(isFast && isFastTimer < isFastCooldown) { isFastTimer += Time.deltaTime; } if(!isFast && 0f < isFastTimer) { isFastTimer -= Time.deltaTime; } } public void Crawl() { if(!isCrawling && Input.GetKeyDown(KeyCode.LeftControl)) { isCrawling = true; } else if(isCrawling && Input.GetKeyDown(KeyCode.LeftControl)) { isCrawling = false; } if(isCrawling) { CrawlSpeed = 0.25f; } else { CrawlSpeed = 1f; } } public void JumpandGravity() { //Jump if (characterController.isGrounded) { if (Input.GetKeyDown(KeyCode.Space) && jumpTimer <= 0f) { verticalVelocity = Mathf.Sqrt(jumpHeight * -2f * gravity * gravityMultiplier); jumpTimer = jumpCooldown; } else { verticalVelocity = -1f; } } else { //Gravity verticalVelocity += gravity * gravityMultiplier * Time.deltaTime; } //Jump Cooldown if (jumpTimer > 0f) { jumpTimer -= Time.deltaTime; } if (jumpTimer < 0f) { jumpTimer = 0f; } } }
问题原因分析
- 初始计时器值错误:
Start()中把isFastTimer初始化为isFastCooldown(6f),但触发快跑的条件是isFastTimer <= 0f,导致游戏启动后无法满足触发条件,根本无法激活快跑。 - 逻辑顺序冲突:在
Fast()函数中,先判断触发快跑的条件,紧接着就判断停止快跑的条件。由于初始isFastTimer等于isFastCooldown,就算成功触发isFast = true,后续的停止判断会立刻将isFast设为false,导致快跑状态被瞬间取消。 - 计时器边界处理不严谨:当
isFastTimer刚好等于isFastCooldown时,停止逻辑会直接触发,但此时快跑状态可能刚激活,不符合需求逻辑。
修复后的代码及说明
修改Start()初始化
void Start() { characterController = GetComponent<CharacterController>(); jumpTimer = jumpCooldown; // 初始冷却完成,允许触发快跑 isFastTimer = 0f; }
修改Fast()函数
public void Fast() { // 先处理停止快跑的条件:松开W、再次按LeftShift、计时器超过冷却值 if (!Input.GetKey(KeyCode.W) || (isFast && Input.GetKeyDown(KeyCode.LeftShift)) || (isFastTimer >= isFastCooldown)) { isFast = false; } // 再处理触发快跑的条件:按住W、冷却完成、按下LeftShift else if (isFastTimer <= 0f && Input.GetKeyDown(KeyCode.LeftShift)) { isFast = true; } // 设置移动速度 isFastSpeed = isFast ? 3f : 1f; // 计时器更新逻辑:限制数值范围,避免溢出或负数 if (isFast) { isFastTimer = Mathf.Min(isFastTimer + Time.deltaTime, isFastCooldown); } else { isFastTimer = Mathf.Max(isFastTimer - Time.deltaTime, 0f); } }
修改点说明
- 调整逻辑顺序:先处理停止快跑的条件,再处理触发条件,避免刚激活就被取消的问题。
- 修正初始计时器值:将
isFastTimer初始化为0,确保游戏启动后可以直接触发快跑。 - 优化计时器更新:使用
Mathf.Min和Mathf.Max限制计时器范围,避免数值溢出或低于0的情况,逻辑更严谨。 - 简化速度赋值:用三元运算符替代if-else,代码更简洁。
内容的提问来源于stack exchange,提问作者A.A.Knightmare
相关产品推荐
相关产品推荐

