2D游戏冲刺功能异常:AddForce未实现推送效果仅产生极短距离瞬移
2D游戏冲刺功能异常:AddForce未实现推送效果仅产生极短距离瞬移
我完全懂你想复刻Celeste那种手感的心情——瞬间爆发的位移、带点向上的“拉扯感”,冲刺结束后还能自然衔接物理下落。现在你的代码里有几个关键逻辑导致冲刺失效,咱们一步步把它改对:
问题核心分析
你的代码里导致冲刺没效果的几个关键问题:
- 力的模式选错了:你用了
ForceMode2D.Force,这是持续力,需要在FixedUpdate里持续调用才会有明显效果,但你只在Update触发一次,所以13000的力其实只作用了一帧,几乎没位移。 - FixedUpdate执行顺序错误:你先调用
move()再判断isdashing,导致冲刺时普通移动的代码会覆盖冲刺速度,直接抵消了AddForce的效果。 - 缺少Celeste风格的向上分量:目前你的冲刺是纯水平的,没有那种“被拉起”的轻盈感。
- 数值逻辑不合理:13000的力值搭配默认Rigidbody2D质量(通常是1),用Force模式的话加速度小到可以忽略,而且
timedash=1秒太长了,Celeste的冲刺持续时间只有0.1-0.2秒左右。
修复后的完整代码
下面是调整后的代码,我会标注关键修改点:
public class PlayerMovement : MonoBehaviour { public float runSpeed = 5f; // 调大移动速度,和冲刺形成合理反差 public float jump = 7f; public byte a = 0; private bool isdashing; private bool candash = true; private float dashForce = 30f; // 冲量模式下无需超大数值,30搭配质量1的刚体刚好 private float dashCooldown = 2f; private float dashDuration = 0.15f; // 缩短冲刺时长,贴近Celeste的手感 private float dashUpwardForce = 0.3f; // 新增:冲刺时的向上拉力比例 private Rigidbody2D rigidbody; public Animator animator; [SerializeField] private SpriteRenderer sr; private void Start() { rigidbody = GetComponent<Rigidbody2D>(); sr = GetComponent<SpriteRenderer>(); } private void Update() { jumper(); if (Input.GetKeyDown(KeyCode.LeftAlt) && candash) { StartCoroutine(Dash()); } animator.SetFloat("Speed", Mathf.Abs(Input.GetAxis("Horizontal") * runSpeed)); if (Input.GetAxis("Horizontal") < 0) { sr.flipX = true; } else if (Input.GetAxis("Horizontal") > 0) { sr.flipX = false; } animator.SetBool("jumping", a == 0); // 简化判断逻辑 } void FixedUpdate() { // 关键修改:先判断冲刺状态,再执行移动,避免冲刺被普通移动覆盖 if (isdashing) { return; } move(); } void move() { rigidbody.linearVelocity = new Vector2(Input.GetAxis("Horizontal") * runSpeed, rigidbody.linearVelocity.y); } void jumper() { if (a > 0 && Input.GetKeyDown(KeyCode.Space)) { rigidbody.AddForce(transform.up * jump, ForceMode2D.Impulse); } } private void OnCollisionStay2D(Collision2D collision) { if (collision.gameObject.tag == "ground") { a = 1; } } private void OnCollisionExit2D(Collision2D collision) { if (collision.gameObject.tag == "ground") { a = 0; } } private IEnumerator Dash() { candash = false; isdashing = true; float originalGravity = rigidbody.gravityScale; // 保存原重力,用于后续恢复 rigidbody.gravityScale = 0.5f; // 降低重力而非设为0,冲刺结束后过渡更自然 // 构建冲刺方向:水平方向根据朝向,叠加向上分量 Vector2 dashDirection = sr.flipX ? Vector2.left : Vector2.right; dashDirection += Vector2.up * dashUpwardForce; dashDirection.Normalize(); // 归一化方向,保证水平+向上的总速度一致 // 关键修改:使用Impulse冲量模式,瞬间施加爆发性力 rigidbody.AddForce(dashDirection * dashForce, ForceMode2D.Impulse); yield return new WaitForSeconds(dashDuration); isdashing = false; rigidbody.gravityScale = originalGravity; // 恢复原重力 // 等待冷却结束 yield return new WaitForSeconds(dashCooldown); candash = true; } }
关键修改说明
- 力的模式调整:把
ForceMode2D.Force换成ForceMode2D.Impulse,冲量模式是瞬间给刚体一个速度变化,完全适合冲刺这种爆发效果,数值不用设得极大,30左右(搭配Rigidbody质量1)就能有明显的瞬间位移。 - FixedUpdate执行顺序:先判断
isdashing再调用move(),避免冲刺时普通移动的代码覆盖冲刺速度。 - 加入向上拉力:新增
dashUpwardForce变量,给冲刺方向加上向上分量,还原Celeste那种“被拉起”的轻盈手感。 - 重力控制优化:不再把重力设为0,而是临时降低,冲刺结束后恢复原重力,避免突然的重力变化导致手感突兀。
- 数值合理化:缩短
dashDuration到0.15秒,更贴近Celeste的冲刺时长;调大runSpeed到5,让移动和冲刺的速度反差更合理。
额外优化建议
- 响应输入的冲刺方向:可以让冲刺方向跟随玩家的上下输入,比如按住上方向键时增加向上分量占比,按住下时减少,让冲刺更灵活。
- 冲刺速度上限:可以在Dash协程里限制刚体的最大速度,避免冲刺速度过快超出预期。
- 精准冷却计时:用
Time.time替代WaitForSeconds记录冷却,比如lastDashTime = Time.time,然后在Update判断Time.time - lastDashTime > dashCooldown,计时更精准,不受帧速率影响。
内容来源于stack exchange
相关产品推荐
相关产品推荐

