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
