generated from krampus/template-godot4
Terrain physics uses surface drag model
This commit is contained in:
parent
2f4801dbaa
commit
9bef191bda
|
@ -1,6 +1,6 @@
|
||||||
extends GameBall
|
extends GameBall
|
||||||
|
|
||||||
const INFO_FMT := "speed: {0} m/s\nlin.damp: {1}\nang.spd: {2}\nang.damp: {3}\ntime: {4} s\nsurface decay: {5}"
|
const INFO_FMT := "speed: {0} m/s\nang.spd: {1}\nsurface: {2}\ntime: {3} s"
|
||||||
|
|
||||||
@onready var debug_info: Label3D = %DebugInfo
|
@onready var debug_info: Label3D = %DebugInfo
|
||||||
|
|
||||||
|
@ -11,10 +11,8 @@ func _physics_process(delta: float) -> void:
|
||||||
debug_info.text = INFO_FMT.format(
|
debug_info.text = INFO_FMT.format(
|
||||||
[
|
[
|
||||||
linear_velocity.length(),
|
linear_velocity.length(),
|
||||||
linear_damp,
|
|
||||||
angular_velocity.length(),
|
angular_velocity.length(),
|
||||||
angular_damp,
|
Terrain.Type.keys()[_surface_terrain],
|
||||||
_shot_time_s,
|
_shot_time_s
|
||||||
terrain_physics.get_decay_factor(_surface_time_s)
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -19,6 +19,7 @@ size = Vector2(0.05, 0.05)
|
||||||
|
|
||||||
[sub_resource type="SystemFont" id="SystemFont_td87w"]
|
[sub_resource type="SystemFont" id="SystemFont_td87w"]
|
||||||
font_names = PackedStringArray("Monospace")
|
font_names = PackedStringArray("Monospace")
|
||||||
|
subpixel_positioning = 0
|
||||||
|
|
||||||
[node name="DebugBall" instance=ExtResource("1_gcsxs")]
|
[node name="DebugBall" instance=ExtResource("1_gcsxs")]
|
||||||
script = ExtResource("2_edye5")
|
script = ExtResource("2_edye5")
|
||||||
|
|
|
@ -14,18 +14,12 @@ enum Type {
|
||||||
POWER,
|
POWER,
|
||||||
}
|
}
|
||||||
|
|
||||||
const TERRAIN_DAMPING_EPSILON := 1e-6
|
const VELOCITY_SQ_EPSILON := 1e-4
|
||||||
const MAGNUS_EPSILON := 1e-3
|
const MAGNUS_SQ_EPSILON := 1e-3
|
||||||
|
|
||||||
## If enabled, ball ability cooldown is only reset at end of shot.
|
## If enabled, ball ability cooldown is only reset at end of shot.
|
||||||
@export var once_per_shot_ability := false
|
@export var once_per_shot_ability := false
|
||||||
|
|
||||||
## Linear damping while in the air.
|
|
||||||
@export var aerial_linear_damping := 0.0
|
|
||||||
|
|
||||||
## Angular damping while in the air.
|
|
||||||
@export var aerial_angular_damping := 0.0
|
|
||||||
|
|
||||||
## Material physics configuration for this ball.
|
## Material physics configuration for this ball.
|
||||||
@export var terrain_physics: TerrainPhysics
|
@export var terrain_physics: TerrainPhysics
|
||||||
|
|
||||||
|
@ -64,6 +58,7 @@ var _ability_triggered := false
|
||||||
var _zones: Array[BallZone] = []
|
var _zones: Array[BallZone] = []
|
||||||
var _shot_time_s := 0.0
|
var _shot_time_s := 0.0
|
||||||
var _surface_time_s := 0.0
|
var _surface_time_s := 0.0
|
||||||
|
var _surface_terrain: Terrain.Type
|
||||||
|
|
||||||
@onready var ability_cooldown: Timer = %AbilityCooldown
|
@onready var ability_cooldown: Timer = %AbilityCooldown
|
||||||
@onready var manual_sleep_timer: Timer = %ManualSleepTimer
|
@onready var manual_sleep_timer: Timer = %ManualSleepTimer
|
||||||
|
@ -74,9 +69,6 @@ var _surface_time_s := 0.0
|
||||||
"res://src/equipment/balls/physics_ball/normal_physics.tres"
|
"res://src/equipment/balls/physics_ball/normal_physics.tres"
|
||||||
)
|
)
|
||||||
|
|
||||||
@onready var default_surface_linear_damping := linear_damp
|
|
||||||
@onready var default_surface_angular_damping := angular_damp
|
|
||||||
|
|
||||||
|
|
||||||
## Should this ball stick to surfaces, rather than bounce?
|
## Should this ball stick to surfaces, rather than bounce?
|
||||||
func is_sticky() -> bool:
|
func is_sticky() -> bool:
|
||||||
|
@ -131,43 +123,45 @@ func _integrate_forces(state: PhysicsDirectBodyState3D) -> void:
|
||||||
|
|
||||||
# We want the contact normal which minimizes the angle to the up vector
|
# We want the contact normal which minimizes the angle to the up vector
|
||||||
var min_dot := -1.0
|
var min_dot := -1.0
|
||||||
|
var primary_body: Node
|
||||||
for i: int in range(state.get_contact_count()):
|
for i: int in range(state.get_contact_count()):
|
||||||
var norm := state.get_contact_local_normal(i)
|
var norm := state.get_contact_local_normal(i)
|
||||||
var dot := norm.dot(Vector3.UP)
|
var dot := norm.dot(Vector3.UP)
|
||||||
if dot > min_dot:
|
if dot > min_dot:
|
||||||
min_dot = dot
|
min_dot = dot
|
||||||
_last_contact_normal = norm
|
_last_contact_normal = norm
|
||||||
|
primary_body = state.get_contact_collider_object(i)
|
||||||
|
|
||||||
# Use first contact to determine terrain properties
|
_surface_terrain = Terrain.from_collision(global_position, primary_body)
|
||||||
var primary_body: Node = state.get_contact_collider_object(0)
|
|
||||||
|
|
||||||
var terrain := Terrain.from_collision(global_position, primary_body)
|
|
||||||
var params := terrain_physics.get_params(terrain)
|
|
||||||
if params:
|
|
||||||
linear_damp = params.linear_damping
|
|
||||||
angular_damp = params.angular_damping
|
|
||||||
else:
|
|
||||||
linear_damp = default_surface_linear_damping
|
|
||||||
angular_damp = default_surface_angular_damping
|
|
||||||
|
|
||||||
var decay := 1.0 + terrain_physics.get_decay_factor(_surface_time_s)
|
|
||||||
#linear_damp *= decay
|
|
||||||
#angular_damp *= decay
|
|
||||||
|
|
||||||
_surface_time_s += state.step
|
_surface_time_s += state.step
|
||||||
else:
|
else:
|
||||||
# Ball is in the air
|
# Ball is in the air
|
||||||
linear_damp = aerial_linear_damping
|
_surface_terrain = Terrain.Type.NONE
|
||||||
angular_damp = aerial_angular_damping
|
|
||||||
_surface_time_s = 0.0
|
_surface_time_s = 0.0
|
||||||
|
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
# Simulate magnus effect
|
# Simulate magnus effect
|
||||||
var magnus := _magnus_force()
|
var magnus := _magnus_force()
|
||||||
if magnus.length_squared() > MAGNUS_EPSILON:
|
if magnus.length_squared() > MAGNUS_SQ_EPSILON:
|
||||||
apply_central_force(magnus)
|
apply_central_force(magnus)
|
||||||
|
|
||||||
|
# Apply drag
|
||||||
|
var params := terrain_physics.get_params(_surface_terrain)
|
||||||
|
if linear_velocity.length() > params.linear_drag:
|
||||||
|
linear_velocity -= params.linear_drag * linear_velocity.normalized()
|
||||||
|
else:
|
||||||
|
linear_velocity = Vector3.ZERO
|
||||||
|
if angular_velocity.length() > params.angular_drag:
|
||||||
|
angular_velocity -= params.angular_drag * angular_velocity.normalized()
|
||||||
|
else:
|
||||||
|
angular_velocity = Vector3.ZERO
|
||||||
|
|
||||||
|
if linear_velocity.length_squared() < VELOCITY_SQ_EPSILON:
|
||||||
|
linear_velocity = Vector3.ZERO
|
||||||
|
if angular_velocity.length_squared() < VELOCITY_SQ_EPSILON:
|
||||||
|
angular_velocity = Vector3.ZERO
|
||||||
|
|
||||||
# Keep shot time
|
# Keep shot time
|
||||||
_shot_time_s += delta
|
_shot_time_s += delta
|
||||||
|
|
||||||
|
|
|
@ -19,58 +19,56 @@
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_casfi"]
|
[sub_resource type="Resource" id="Resource_casfi"]
|
||||||
script = ExtResource("4_onl6o")
|
script = ExtResource("4_onl6o")
|
||||||
linear_damping = 0.0
|
linear_drag = 0.0
|
||||||
angular_damping = 0.5
|
angular_drag = 1.0
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_3k63c"]
|
[sub_resource type="Resource" id="Resource_3k63c"]
|
||||||
script = ExtResource("4_onl6o")
|
script = ExtResource("4_onl6o")
|
||||||
linear_damping = 0.0
|
linear_drag = 0.0
|
||||||
angular_damping = 8.0
|
angular_drag = 0.0
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_xf73q"]
|
[sub_resource type="Resource" id="Resource_xf73q"]
|
||||||
script = ExtResource("4_onl6o")
|
script = ExtResource("4_onl6o")
|
||||||
linear_damping = 0.0
|
linear_drag = 0.0
|
||||||
angular_damping = 2.0
|
angular_drag = 1.0
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_nhn3l"]
|
[sub_resource type="Resource" id="Resource_nhn3l"]
|
||||||
script = ExtResource("4_onl6o")
|
script = ExtResource("4_onl6o")
|
||||||
linear_damping = 0.0
|
linear_drag = 0.0
|
||||||
angular_damping = 0.1
|
angular_drag = 1.0
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_m3wjo"]
|
[sub_resource type="Resource" id="Resource_m3wjo"]
|
||||||
script = ExtResource("4_onl6o")
|
script = ExtResource("4_onl6o")
|
||||||
linear_damping = 0.0
|
linear_drag = 0.0
|
||||||
angular_damping = 1.0
|
angular_drag = 1.0
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_h4rld"]
|
[sub_resource type="Resource" id="Resource_h4rld"]
|
||||||
script = ExtResource("4_onl6o")
|
script = ExtResource("4_onl6o")
|
||||||
linear_damping = 0.0
|
linear_drag = 0.0
|
||||||
angular_damping = 0.1
|
angular_drag = 1.0
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_j6lib"]
|
[sub_resource type="Resource" id="Resource_j6lib"]
|
||||||
script = ExtResource("4_onl6o")
|
script = ExtResource("4_onl6o")
|
||||||
linear_damping = 0.0
|
linear_drag = 0.0
|
||||||
angular_damping = 2.0
|
angular_drag = 1.0
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_7f7ql"]
|
[sub_resource type="Resource" id="Resource_7f7ql"]
|
||||||
script = ExtResource("4_onl6o")
|
script = ExtResource("4_onl6o")
|
||||||
linear_damping = 0.0
|
linear_drag = 0.0
|
||||||
angular_damping = 8.0
|
angular_drag = 3.0
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_pusmf"]
|
[sub_resource type="Resource" id="Resource_pusmf"]
|
||||||
script = ExtResource("4_onl6o")
|
script = ExtResource("4_onl6o")
|
||||||
linear_damping = 1.0
|
linear_drag = 1.0
|
||||||
angular_damping = 24.0
|
angular_drag = 10.0
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_edkxb"]
|
[sub_resource type="Resource" id="Resource_edkxb"]
|
||||||
script = ExtResource("4_onl6o")
|
script = ExtResource("4_onl6o")
|
||||||
linear_damping = 0.0
|
linear_drag = 0.0
|
||||||
angular_damping = 1.0
|
angular_drag = 1.0
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_3ngau"]
|
[sub_resource type="Resource" id="Resource_3ngau"]
|
||||||
script = ExtResource("3_52hui")
|
script = ExtResource("3_52hui")
|
||||||
damping_decay_curve = 12.0
|
|
||||||
damping_decay_scale = 8.0
|
|
||||||
default = SubResource("Resource_3k63c")
|
default = SubResource("Resource_3k63c")
|
||||||
rough = SubResource("Resource_7f7ql")
|
rough = SubResource("Resource_7f7ql")
|
||||||
fairway = SubResource("Resource_xf73q")
|
fairway = SubResource("Resource_xf73q")
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
class_name TerrainParameters extends Resource
|
class_name TerrainParameters extends Resource
|
||||||
## Physical parameters for an individual terrain type.
|
## Physical parameters for an individual terrain type.
|
||||||
|
|
||||||
@export var linear_damping := 0.0
|
@export var linear_drag := 0.0
|
||||||
@export var angular_damping := 0.0
|
@export var angular_drag := 0.0
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
class_name TerrainPhysics extends Resource
|
class_name TerrainPhysics extends Resource
|
||||||
## Container for ball behavior parameters when in contact with different terrain types
|
## Container for ball behavior parameters when in contact with different terrain types
|
||||||
|
|
||||||
@export_exp_easing() var damping_decay_curve := 1.0
|
|
||||||
@export var damping_decay_scale := 8.0
|
|
||||||
|
|
||||||
@export var default: TerrainParameters
|
@export var default: TerrainParameters
|
||||||
|
|
||||||
@export var rough: TerrainParameters
|
@export var rough: TerrainParameters
|
||||||
|
@ -41,10 +38,3 @@ func get_params(type: Terrain.Type) -> TerrainParameters:
|
||||||
return glass
|
return glass
|
||||||
_:
|
_:
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
func get_decay_factor(time: float) -> float:
|
|
||||||
var x := time / damping_decay_scale
|
|
||||||
if damping_decay_curve < 1.0:
|
|
||||||
return 1.0 - pow(1.0 - x, 1.0 / damping_decay_curve)
|
|
||||||
return pow(x, damping_decay_curve)
|
|
||||||
|
|
Loading…
Reference in New Issue