2

我正在开发我的自上而下的游戏,但我被卡住了。我试图让玩家在敌人击中他时被击退(他们的刚体碰撞)。

现在的问题是我正在使用 MovePosition 进行玩家移动,然后当我使用任何会改变玩家 RB 速度的东西(设置速度/AddForce())时,力/速度只会在一瞬间被应用。我认为这是因为我使用了 MovePosition,它以某种方式忽略或重置了速度。

有什么方法可以解决这个问题,而不必让玩家控制基于以最大速度增加力量或计算击退持续多长时间?

很快,我希望击退平稳,因为现在我必须添加一个非常高的力才能获得非常快速(基本上是即时)的运动。

4

3 回答 3

1

尝试重写它,以便物理引擎为您处理一切。您可以尝试使用AddForce和 在“击退”状态下移动对象,您可以将AddForceForce.Impulse用作参数。它应该按预期工作,并且会从你的肩膀上解决运动的问题。

于 2020-02-26T14:46:38.043 回答
0

以防万一其他人偶然发现:从技术上讲,您可以通过替换MovePosition(pos)transform.position = pos.

这将保持惯性\速度等,并且可能是您在非常特定的情况下所需要的(在我的情况下,创建一个自定义类型的非弹性铰链接头,其中强制位置变化非常小)。

此解决方案的主要缺点是,当位置转移到实体碰撞时,物理引擎可能会做出意想不到的事情。引擎仍然会尝试解决这种情况并将对象推出碰撞,但它不知道它来自哪个方向(与 MovePosition 不同),可能会朝错误的方向移动,从而让对象穿过地形。这就是为什么通常不建议在应用刚体时触摸“变换”。

于 2021-09-05T22:50:10.583 回答
0

唯一对我有用的是设置一个knockedOut临时标志来决定何时RigidBody.MovePosition()暂时停止调用以给RigidBody.AddForce()一些时间采取行动。

然后玩弄forceValue,RigidBody.massRigidBody.linearDrag得到想要的效果。

这是我的 PlayerController 的实现:

using System.Collections;
using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerController : MonoBehaviour
{
    [SerializeField] float speed = 1f;
    [SerializeField] float impactEffect = 5f;
    [SerializeField] float knockOutTime = 0.05f;

    Vector2 direction = Vector2.zero;
    Rigidbody2D rbody;
    bool knockedOut;
    IEnumerator knockOutCoroutine;

    void Awake()
    {
        rbody = GetComponent<Rigidbody2D>();
    }

    void FixedUpdate()
    {
        if(!knockedOut) // Don't call Move() if I am knockedOut
            Move();
    }

    // Triggered by the InputSystem
    void OnMove(InputValue value)
    {
        // Set the direction value
        direction = value.Get<Vector2>();
    }

    // Controls the normal movement of the Player based on the actual `direction` value
    void Move()
    {
        Vector2 adjustedMovement = direction * speed * Time.fixedDeltaTime;
        Vector2 newPos = rbody.position + adjustedMovement;
        rbody.MovePosition(newPos);
    }

    // Invoke this method when Collision
    public void Impact(Vector2 impactPosition)
    {
        Vector2 impactDirection = ((Vector2)transform.position - impactPosition).normalized;
        rbody.velocity = Vector2.zero;
        rbody.AddForce(impactDirection * impactEffect, ForceMode2D.Impulse);
        KnockOut(knockOutTime);
    }

    void KnockOut(float seconds)
    {
        if(knockOutCoroutine != null)
            StopCoroutine(knockOutCoroutine);

        knockOutCoroutine = KnockOutCoroutine(seconds);
        StartCoroutine(knockOutCoroutine);
    }

    // KnockedOut stop movement effect
    IEnumerator KnockOutCoroutine(float seconds)
    {
        direction = Vector2.zero;
        knockedOut = true;
        yield return new WaitForSeconds(seconds);
        knockedOut = false;
    }
}

于 2022-02-15T19:39:33.497 回答