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
|
||||
@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.
|
||||
## Uses continuous collision detection.
|
||||
@export var check_collision := true
|
||||
|
@ -32,6 +32,10 @@ const PUTT_ATTRITION := 0.8325 # green?
|
|||
## This should probably include the ball!
|
||||
@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 _debug_points: Array[Vector3] = []
|
||||
|
@ -73,8 +77,13 @@ func _process(_delta: float) -> void:
|
|||
# TODO: smooth curve with bezier handles
|
||||
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
|
||||
vel += gravity * gravity_vec * time_step
|
||||
vel += local_gravity * time_step
|
||||
var next_pos := pos + vel * time_step
|
||||
|
||||
# Collision
|
||||
|
@ -110,6 +119,58 @@ func _process(_delta: float) -> void:
|
|||
(%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:
|
||||
# Force update as soon as visible
|
||||
_tick_counter = 0
|
||||
|
|
Loading…
Reference in New Issue