我正在进行自上而下的游戏,但我被卡住了。我试图让玩家在敌人击中他(他们的刚体碰撞(时被击倒。
现在的问题是,我使用MovePosition来进行球员移动,当我使用任何会改变球员RB速度的东西(设置velocity/AddForce(((时,力/速度只会在瞬间施加。我想这是因为我使用了MovePosition,它以某种方式忽略或重置了速度。
有没有什么方法可以绕过这一点,而不必让玩家根据最大速度的力量进行控制,或者计算击退会持续多久?
很快,我希望反击平稳,因为现在我必须添加一个非常高的力才能有非常快(基本上是瞬间(的移动。
试着重写它,让物理引擎为您处理一切。您可以尝试使用AddForce
移动对象,而在"击退"状态下,您可以使用AddForce
和Force.Impulse
作为参数。它应该按预期工作,并将消除肩部的运动问题。
以防其他人偶然发现:从技术上讲,您可以通过用transform.position = pos
替换MovePosition(pos)
来完成TE最初想要的操作。
这将保持惯性\速度等,并且可能是您在非常特定的情况下所需要的(在我的情况下,创建一种自定义类型的非弹性铰链关节,强制位置变化非常小(。
这种解决方案的主要缺点是,当位置转换为固体碰撞时,物理引擎可能会做出意想不到的事情。引擎仍然会试图解决这种情况,并将对象从碰撞中推出,但它不知道它来自哪个方向(与MovePosition不同(,可能会向错误的方向移动,从而让对象在地形中穿行。这就是为什么在应用刚体时,通常不建议触摸"变换"。
唯一对我有用的是设置一个knockedOut
临时标志来决定何时暂时停止调用RigidBody.MovePosition()
,以便给RigidBody.AddForce()
一些时间采取行动。
然后用forceValue
、RigidBody.mass
和RigidBody.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;
}
}