diff --git a/move_utils.gd b/move_utils.gd new file mode 100644 index 0000000..54d7c9c --- /dev/null +++ b/move_utils.gd @@ -0,0 +1,48 @@ +extends RefCounted +class_name MoveUtils +## 角色的质量,单位 kg +var weight = 60.0 +## 角色前进的动力,同样先简化处理,单位 +var power = 1000.0 +## 冲销系数,当角色的指令方向当前实际方向不同时,有多少的力用来冲销原有的冲量以更快转向指令方向 +## 冲销还是要仔细设计。仔细想想,假如当前力方向和指令方向完全相同时,肯定就不需要冲销 +var offset_coefficient := 0.5 +## 刹车系数,在没有明确指令时,用多少的动力来刹车 +var brake = 0.7 +## 一个最简单的阻尼系数[br] +## 阻力计算公式 速度² × 阻尼系数[br] +## 假设最高速度是慢跑 10km/h , 2.77m/s,那么阻力需要在这个速度下维持和动力平衡。也就是...104.3 +var damping = 10.0 + +func _init() -> void: + return + +func get_horizontal_velocity( cmd_direction: Vector3, velocity: Vector3, delta: float ) -> Vector3: + var target_velocity + var velocity_direction: Vector3 = velocity.normalized() + # 当前阻力向量 + var damping_vector: Vector3 = -velocity_direction * velocity.length_squared() * damping + if cmd_direction == Vector3.ZERO: + # 为什么这里要加上动力呢?我是这样思考的。 + # 当用户停止输入指令的话,我认用户的意思是“现在不需要移动”。既然现在不需要移动,那当然应该把力用来刹车。对吧? + # 当然,此处可以考虑。哪怕你正常走路时,如果想要停下也不会全力急停的。理论上应该乘个小于 1 的系数。但是先这样试试效果。 + var speed = ( damping_vector.length() + power * brake ) / weight * delta + # 目前产生的阻力速度大于当前速度。直接降为 0 + if speed * speed > velocity.length_squared(): + target_velocity = Vector3.ZERO + else: + var speed_velocity = damping_vector.normalized() * speed + target_velocity = velocity + speed_velocity + else: + # 这里来考虑转向问题。需要一个转向系数来来冲销当前的速度,让运动方向更快改变 + var diff_coefficient = velocity.angle_to(cmd_direction) / PI * offset_coefficient + # 冲销力 + var offset_vector = -velocity.normalized() * sqrt(power * power * diff_coefficient) + # 指令力 + var cmd_vector = cmd_direction * sqrt(power * power * ( 1 - diff_coefficient )) + # 阻力 + 指令力合力 + var result_vector: Vector3 = offset_vector + cmd_vector + damping_vector + # 合力下发生的速度变化 + var speed_vector = result_vector.normalized() * result_vector.length() / weight * delta + target_velocity = velocity + speed_vector + return target_velocity diff --git a/move_utils.gd.uid b/move_utils.gd.uid new file mode 100644 index 0000000..ba56c23 --- /dev/null +++ b/move_utils.gd.uid @@ -0,0 +1 @@ +uid://pikse04q3mns diff --git a/palyer.gd b/palyer.gd index 52c5fb0..657c2fd 100644 --- a/palyer.gd +++ b/palyer.gd @@ -1,37 +1,18 @@ extends CharacterBody3D -## 角色的质量,单位 kg -const weight := 40.0 -## 角色前进的动力,同样先简化处理,单位 -const power := 1800.0 -## 一个最简单的阻尼系数[br] -## 阻力计算公式 速度² × 阻尼系数 + 库仑阻尼系数[br] -## 假设最高速度是慢跑 10km/h , 2.77m/s,那么阻力需要在这个速度下维持和动力平衡。也就是...84.3 -const damping := 10.0 -## 补充库仑阻尼系数[br] -## 我们不希望角色慢慢接近静止。所以还需要一个库仑阻尼提供某个速度下的快速停止效果 -const coulomb_damping = 1.0 -## TODO 目前并不能稳定收束到静止状态。阻尼仍然需要继续设计 -## TODO 转向手感不好。但是如果操作时手动加一个目前移动方向的反向指令手感会好的多。 -## 仔细想想也是,指令代表的是“希望的方向”,而不是“操作的方向”,所以这个反向力其实应该是程序手动加上的。现在还没有想好怎么调整这个转向手感。 -## 顺便一体,角色的灵活程度很大程度上不取决于阻尼的设计,而是角色本身推重比。角色不够灵动需要调整推重比而不是阻尼 +var moveUtils = MoveUtils.new() var fall_acceleration = 75 var target_velocity = Vector3.ZERO func _physics_process(delta: float) -> void: - var velocity_direction: Vector3 = velocity.normalized() - var cmd_direction: Vector3 = get_cmd_direction() - # 当前阻力 - var damping_vector: Vector3 = -velocity_direction * ( velocity.length_squared() * damping + coulomb_damping ) - # 阻力 + 指令力合力 - var result_vector: Vector3 = cmd_direction * power + damping_vector - # 合力下发生的速度变化 - var acceleration = result_vector.normalized() * result_vector.length() / weight * delta - target_velocity = velocity + acceleration + + target_velocity = moveUtils.get_horizontal_velocity(get_cmd_direction(), velocity, delta) + if target_velocity != Vector3.ZERO: $pivot.basis = Basis.looking_at(target_velocity.normalized()) + if !is_on_floor(): target_velocity.y = target_velocity.y - ( fall_acceleration * delta ) @@ -51,4 +32,3 @@ func get_cmd_direction() -> Vector3: if Input.is_action_pressed("move_right"): vector.x += 1 return vector.normalized() -