generated from krampus/template-godot4
Projectile arc computes local gravity at each step
This commit is contained in:
parent
60dd5bf659
commit
906e161b67
|
@ -22,7 +22,7 @@ const PUTT_ATTRITION := 0.8325 # green?
|
||||||
## If enabled, project a linear putt instead of an arcing shot
|
## If enabled, project a linear putt instead of an arcing shot
|
||||||
@export var putt_projection := false
|
@export var putt_projection := false
|
||||||
|
|
||||||
@export_category("Collision")
|
@export_category("Collision & Physics")
|
||||||
## Enables collision checking. Projection will end at the point where a collision is detected.
|
## Enables collision checking. Projection will end at the point where a collision is detected.
|
||||||
## Uses continuous collision detection.
|
## Uses continuous collision detection.
|
||||||
@export var check_collision := true
|
@export var check_collision := true
|
||||||
|
@ -32,6 +32,10 @@ const PUTT_ATTRITION := 0.8325 # green?
|
||||||
## This should probably include the ball!
|
## This should probably include the ball!
|
||||||
@export var excluded_bodies: Array[CollisionObject3D] = []
|
@export var excluded_bodies: Array[CollisionObject3D] = []
|
||||||
|
|
||||||
|
## Enables checking local gravity at each point along the trajectory.
|
||||||
|
## If disabled, global gravity will be used instead.
|
||||||
|
@export var check_gravity := true
|
||||||
|
|
||||||
var _tick_counter := 0
|
var _tick_counter := 0
|
||||||
|
|
||||||
var _debug_points: Array[Vector3] = []
|
var _debug_points: Array[Vector3] = []
|
||||||
|
@ -73,8 +77,13 @@ func _process(_delta: float) -> void:
|
||||||
# TODO: smooth curve with bezier handles
|
# TODO: smooth curve with bezier handles
|
||||||
path.curve.add_point(pos - global_position)
|
path.curve.add_point(pos - global_position)
|
||||||
|
|
||||||
|
# Get local gravity if enabled
|
||||||
|
var local_gravity := gravity * gravity_vec
|
||||||
|
if check_gravity:
|
||||||
|
local_gravity = _get_gravity(pos)
|
||||||
|
|
||||||
# Integrate projectile path
|
# Integrate projectile path
|
||||||
vel += gravity * gravity_vec * time_step
|
vel += local_gravity * time_step
|
||||||
var next_pos := pos + vel * time_step
|
var next_pos := pos + vel * time_step
|
||||||
|
|
||||||
# Collision
|
# Collision
|
||||||
|
@ -110,6 +119,58 @@ func _process(_delta: float) -> void:
|
||||||
(%DebugDraw as CanvasItem).queue_redraw()
|
(%DebugDraw as CanvasItem).queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
func _get_gravity(point: Vector3) -> Vector3:
|
||||||
|
# Start with global gravity
|
||||||
|
var local_gravity := gravity * gravity_vec
|
||||||
|
|
||||||
|
# TODO this is awful, surely there has to be a better way than this!!!
|
||||||
|
# Get areas at point
|
||||||
|
var point_params := PhysicsPointQueryParameters3D.new()
|
||||||
|
point_params.collide_with_areas = true
|
||||||
|
point_params.collide_with_bodies = false
|
||||||
|
point_params.collision_mask = collision_mask
|
||||||
|
point_params.position = point
|
||||||
|
var collisions := get_world_3d().direct_space_state.intersect_point(point_params)
|
||||||
|
var gravity_areas: Array[Area3D] = []
|
||||||
|
gravity_areas.assign(
|
||||||
|
collisions.map(func(d: Dictionary) -> Area3D: return d["collider"] as Area3D)
|
||||||
|
)
|
||||||
|
gravity_areas.sort_custom(func(a: Area3D, b: Area3D) -> bool: return a.priority < b.priority)
|
||||||
|
|
||||||
|
# Iteratively integrate gravity
|
||||||
|
for area: Area3D in gravity_areas:
|
||||||
|
var point_local := point - area.global_position
|
||||||
|
var area_gravity: Vector3
|
||||||
|
if area.gravity_point:
|
||||||
|
# TODO: `point` may need to be local
|
||||||
|
var v := area.transform * area.gravity_direction - point_local
|
||||||
|
if area.gravity_point_unit_distance > 0:
|
||||||
|
var v_sq := v.length_squared()
|
||||||
|
if v_sq > 0:
|
||||||
|
area_gravity = (
|
||||||
|
v.normalized()
|
||||||
|
* area.gravity
|
||||||
|
* pow(area.gravity_point_unit_distance, 2)
|
||||||
|
/ v_sq
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
area_gravity = Vector3.ZERO
|
||||||
|
else:
|
||||||
|
area_gravity = v.normalized() * area.gravity
|
||||||
|
else:
|
||||||
|
area_gravity = area.gravity * area.gravity_direction
|
||||||
|
|
||||||
|
match area.gravity_space_override:
|
||||||
|
Area3D.SPACE_OVERRIDE_COMBINE, Area3D.SPACE_OVERRIDE_COMBINE_REPLACE:
|
||||||
|
local_gravity += area_gravity
|
||||||
|
Area3D.SPACE_OVERRIDE_REPLACE_COMBINE, Area3D.SPACE_OVERRIDE_REPLACE:
|
||||||
|
local_gravity = area_gravity
|
||||||
|
Area3D.SPACE_OVERRIDE_COMBINE_REPLACE, Area3D.SPACE_OVERRIDE_REPLACE:
|
||||||
|
break
|
||||||
|
|
||||||
|
return local_gravity
|
||||||
|
|
||||||
|
|
||||||
func _on_visibility_changed() -> void:
|
func _on_visibility_changed() -> void:
|
||||||
# Force update as soon as visible
|
# Force update as soon as visible
|
||||||
_tick_counter = 0
|
_tick_counter = 0
|
||||||
|
|
Loading…
Reference in New Issue