Shot projection for putting

This commit is contained in:
Rob Kelly 2024-11-21 11:27:35 -07:00
parent e723e0c022
commit 9d6821962b
4 changed files with 57 additions and 8 deletions

View File

@ -1,5 +1,4 @@
[gd_resource type="PhysicsMaterial" format=3 uid="uid://3bih72l068ic"]
[resource]
friction = 0.8
bounce = 0.5

View File

@ -241,13 +241,14 @@ func take_shot() -> void:
var impulse := get_shot_impulse(shot_power)
print_debug("Shot impulse: ", impulse, "; ", impulse.length(), " N*s")
# Curve the curve
var curve := shot_ref.global_basis.x.normalized() * shot_curve
# Position where the ball is hit (imparts spin)
var offset := curve * 0.001
print_debug("Shot offset: ", offset, "; ", offset.length(), " m")
# Rotate impulse
impulse = impulse.rotated(Vector3.UP, -shot_curve * CURVE_INFLUENCE)
impulse = impulse.rotated(Vector3.UP, -shot_curve * CURVE_INFLUENCE * shot_power)
if game_ball:
game_ball.iron_ball = club == Club.Type.IRON
@ -264,6 +265,7 @@ func _show_shot_projection() -> void:
if not game_ball:
return
shot_projection.putt_projection = club == Club.Type.PUTTER
shot_projection.initial_speed = 1
shot_projection.basis = shot_ref.basis.orthonormalized()
var shot_speed := get_shot_impulse(1.0).length() / game_ball.mass

View File

@ -3,6 +3,11 @@ class_name ProjectileArc extends Node3D
##
## If this node has any children, they will be positioned wherever the projection ends.
## Constant attrition factor for putting collisions
## The actual velocity attrition is dependent on lots of factors
#const PUTT_ATTRITION := 0.75 # rough?
const PUTT_ATTRITION := 0.8325 # green?
## Initial speed of the projectile, in m/s.
## The projectile's initial direction vector is the negative Z direction relative to this node.
@export var initial_speed := 1.0
@ -14,6 +19,8 @@ class_name ProjectileArc extends Node3D
@export var max_steps := 50
## Ticks between each projection update. 0 means update every tick.
@export var ticks_per_update := 0
## If enabled, project a linear putt instead of an arcing shot
@export var putt_projection := false
@export_category("Collision")
## Enables collision checking. Projection will end at the point where a collision is detected.
@ -27,12 +34,16 @@ class_name ProjectileArc extends Node3D
var _tick_counter := 0
var _debug_points: Array[Vector3] = []
@onready var polygon: CSGPolygon3D = %Polygon
@onready var path: Path3D = %Path
@onready var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity")
@onready var gravity_vec: Vector3 = ProjectSettings.get_setting("physics/3d/default_gravity_vector")
@onready var debug_draw: Control = %DebugDraw
func _process(_delta: float) -> void:
if not visible:
@ -45,6 +56,8 @@ func _process(_delta: float) -> void:
return
_tick_counter = ticks_per_update
_debug_points = []
# Rebuild path curve
path.global_basis = Basis.IDENTITY
path.curve.clear_points()
@ -72,10 +85,15 @@ func _process(_delta: float) -> void:
var collision := space.intersect_ray(ray_params)
if collision:
# Set current position to collision point, so it will be added to the path
# TODO: we could project further using the surface normal here...
pos = collision["position"]
# End projection!
break
_debug_points.append(pos)
if putt_projection:
var norm: Vector3 = (collision["normal"] as Vector3).normalized()
next_pos = pos + norm * 0.05
vel = PUTT_ATTRITION * (vel - 2 * norm * vel.dot(norm))
else:
# End projection!
break
pos = next_pos
@ -89,6 +107,8 @@ func _process(_delta: float) -> void:
node_3d.global_position = pos
node_3d.global_basis = Basis.IDENTITY
(%DebugDraw as CanvasItem).queue_redraw()
func _on_visibility_changed() -> void:
# Force update as soon as visible

View File

@ -1,9 +1,9 @@
[gd_scene load_steps=9 format=3 uid="uid://fht6j87o8ecr"]
[gd_scene load_steps=10 format=3 uid="uid://fht6j87o8ecr"]
[ext_resource type="Script" path="res://src/ui/3d/projectile_arc/projectile_arc.gd" id="1_vafqi"]
[ext_resource type="Shader" path="res://src/shaders/plasma.gdshader" id="2_pi36v"]
[sub_resource type="Curve3D" id="Curve3D_rfv3d"]
[sub_resource type="Curve3D" id="Curve3D_sj0rs"]
[sub_resource type="Gradient" id="Gradient_28hbf"]
offsets = PackedFloat32Array(0, 0.37193, 0.838596, 1)
@ -34,12 +34,31 @@ shader_parameter/pulse_speed = 0.3
shader_parameter/wave_gradient = SubResource("GradientTexture1D_l8ond")
shader_parameter/pulse_gradient = SubResource("GradientTexture1D_8xhfy")
[sub_resource type="GDScript" id="GDScript_hbqgy"]
script/source = "extends Control
const COLOR := Color(0, 1, 0)
const WIDTH := 4
const RADIUS := 16
@onready var root: ProjectileArc = owner
func _draw() -> void:
if not visible:
return
var camera := get_viewport().get_camera_3d()
for p: Vector3 in root._debug_points:
var pos := camera.unproject_position(p)
draw_circle(pos, RADIUS, COLOR, false, WIDTH, true)
"
[node name="ProjectileArc" type="Node3D"]
script = ExtResource("1_vafqi")
[node name="Path" type="Path3D" parent="."]
unique_name_in_owner = true
curve = SubResource("Curve3D_rfv3d")
curve = SubResource("Curve3D_sj0rs")
[node name="Polygon" type="CSGPolygon3D" parent="Path"]
unique_name_in_owner = true
@ -56,4 +75,13 @@ path_u_distance = 1.0
path_joined = false
material = SubResource("ShaderMaterial_ahf42")
[node name="DebugDraw" type="Control" parent="."]
unique_name_in_owner = true
visible = false
layout_mode = 3
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
script = SubResource("GDScript_hbqgy")
[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"]