Unity-在使用MovePosition()进行移动时添加Force()



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

现在的问题是,我使用MovePosition来进行球员移动,当我使用任何会改变球员RB速度的东西(设置velocity/AddForce(((时,力/速度只会在瞬间施加。我想这是因为我使用了MovePosition,它以某种方式忽略或重置了速度。

有没有什么方法可以绕过这一点,而不必让玩家根据最大速度的力量进行控制,或者计算击退会持续多久?

很快,我希望反击平稳,因为现在我必须添加一个非常高的力才能有非常快(基本上是瞬间(的移动。

试着重写它,让物理引擎为您处理一切。您可以尝试使用AddForce移动对象,而在"击退"状态下,您可以使用AddForceForce.Impulse作为参数。它应该按预期工作,并将消除肩部的运动问题。

以防其他人偶然发现:从技术上讲,您可以通过用transform.position = pos替换MovePosition(pos)来完成TE最初想要的操作。

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

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

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

然后用forceValueRigidBody.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;
}
}

最新更新