获取没有滑动因子的Rigidbody2D碰撞速度



我有一辆飞行汽车,我想在与物体碰撞时损失一些HP。

我将car的RigidBody2D连接到这个函数来做这个

func _on_Car_body_entered(body):
var force = linear_velocity.length()
var dmg = pow(force / 100, 2) - 0.25
if dmg <= 0: return
Health = Health - dmg

现在,因为我不需要精确,我只是使用当前速度作为力,尽管这是可以改变的。

在得到我的"冲击力"后,我把它放入伤害计算公式中,如果伤害大于0,则按伤害减少HP。

在大多数情况下

我注意到,如果汽车在水平方向快速行驶,几乎没有碰到地面(这是完全水平的),汽车会受到很大的伤害,因为我使用的是速度矢量的长度。

当然,这种情况可以通过只使用速度矢量的Y分量来管理,但这样就消除了任何水平碰撞,反之亦然,这也使我走上了编程垂直和水平碰撞的道路,当然这并不是我需要的唯一两个碰撞方向。

有没有办法从这个方程中去除滑动因子?

你可以得到你的速度和碰撞法线之间夹角的正弦值,然后取其绝对值.

# 0 When sliding along the wall. 1 when hitting the wall head on
var slide_factor = abs(cos(vel_last_frame.angle_to(collision_normal)))

这将给你一个从0到1的值。当你只是沿着墙壁滑动时,这个值将为0,当你直接碰到墙壁时,它将为1。

我在这里使用最后一帧的速度,这样它就得到了碰撞前的速度。我通过在_physics_process函数中设置vel_last_framelinear_velocity来得到它。

您只能使用PhysicsDirectBodyState.get_local_contact_normal()在_integrate_forces函数中获得碰撞法线,因此您需要创建一个可以在该函数和_on_Car_body_entered函数中访问的变量。注意,您需要将contact_monitor设置为trueandcontacts_reportedto至少1要使这个函数工作

var collision_normal
func _integrate_forces(state):
# Check if there is a collision
if state.get_contact_count():
# contact_monitor must be true and contacts_reported must be at least 1 for this to work
collision_normal = state.get_contact_local_normal(0)

现在在_on_Car_body_entered_function中,你可以用dmg乘以sliding_factor来缩小它的比例,这取决于你在墙上滑动的程度。

func _on_Car_body_entered(body):
var force = linear_velocity.length()
# 0 When sliding along the wall. 1 when hitting the wall head on
var slide_factor = abs(cos(vel_last_frame.angle_to(collision_normal)))
var dmg = pow(force / 100, 2) - 0.25
# Reduce dmg depending on how much you are sliding against the wall
dmg *= slide_factor

if dmg <= 0: return
Health = Health - dmg

找到了我的问题的解决方案

这给了我一个可预测的力范围。

我复制了2D碰撞的所有代码,只是添加了伤害计算

我的物体产生的力的范围是<3000小碰撞,如划痕和颠簸,~10k初学者友好的伤害,和20k+当我真的猛踩油门,所以我只是把力转换成我想要的伤害。

最好的部分是我不需要使用RigidBody2D中的body_entered,因为现在我所有的车都有这个计算,所以当它们中的2个碰撞时,它们都被损坏了。

extends RigidBody2D
var collision_force : Vector2 = Vector2.ZERO
var previous_linear_velocity : Vector2 = Vector2.ZERO
func _integrate_forces(state : Physics2DDirectBodyState)->void:
collision_force = Vector2.ZERO
if state.get_contact_count() > 0:
var dv : Vector2 = state.linear_velocity - previous_linear_velocity
collision_force = dv / (state.inverse_mass * state.step)
var dmg = collision_force.length() / 2000 - 2
if dmg > 0:
set_hp(Health - dmg)
emit_signal("Damaged")

previous_linear_velocity = state.linear_velocity

* * * *老回答橡皮鸭在这里

在car的脚本中,我添加了一个新的变量var last_linear_velocity = Vector2()

将最后的速度存储在_process

func _process(delta):
last_linear_velocity = linear_velocity

_integrate_forces中没有,因为如果我把它放在那里,那么新速度和最后速度是相同的。

只是改变了力在上面提到的函数中的计算方式,所以它看起来像这样

func _on_Car_body_entered(body):
var force = last_linear_velocity.length() - linear_velocity.length()
var dmg = pow(force / 100, 2) - 0.25
if dmg <= 0: return
Health = Health - dmg

现在我得到了一个很好的可预测的数值范围,并可以将其转换为伤害。

注意

我注意到,有时当发生碰撞时,上一个和当前的速度长度之差是负的,因为车内正在加速。

无论如何,这对我来说是可行的。

如果你找到一个更好的解决方案,请贴出来,因为我在其他地方找不到这个问题的解决方案。

最新更新