Shot projection preview

This commit is contained in:
Rob Kelly 2024-11-12 16:18:57 -07:00
parent 361e51d714
commit cd1111d514
16 changed files with 445 additions and 29 deletions

View File

@ -14,7 +14,7 @@ dest_files=["res://.godot/imported/Geo-Italic.ttf-fff5102e64e08d3e98dbbd3b01b471
Rendering=null
antialiasing=1
generate_mipmaps=false
generate_mipmaps=true
disable_embedded_bitmaps=true
multichannel_signed_distance_field=false
msdf_pixel_range=8

View File

@ -14,7 +14,7 @@ dest_files=["res://.godot/imported/Geo-Regular.ttf-ea6aa4330b08d367c3a4134ebd69f
Rendering=null
antialiasing=1
generate_mipmaps=false
generate_mipmaps=true
disable_embedded_bitmaps=true
multichannel_signed_distance_field=false
msdf_pixel_range=8

View File

@ -168,7 +168,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1.2, 0)
shape = SubResource("BoxShape3D_x3wvm")
[node name="ShotSetup" parent="." instance=ExtResource("8_h44v5")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 218.499, 4, 294.341)
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 212.717, 4, 294.073)
[node name="Buildings" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 129.404, -9.53674e-07, 309.4)

BIN
levels/debug_level/terrain_3d_storage.res (Stored with Git LFS)

Binary file not shown.

View File

@ -169,7 +169,7 @@ bones/23/scale = Vector3(1, 1, 1)
visible = false
[node name="BoneAttachment3D" type="BoneAttachment3D" parent="Armature/Skeleton3D" index="6"]
transform = Transform3D(-0.944824, 0.316851, -0.0831416, -0.326581, -0.930889, 0.163676, -0.0255346, 0.181798, 0.983005, -0.1687, 3.14336, 0.866657)
transform = Transform3D(-0.944824, 0.316851, -0.0831417, -0.326595, -0.930784, 0.164246, -0.0253454, 0.182337, 0.982909, -0.1687, 3.13128, 0.867055)
bone_name = "Hand.R"
bone_idx = 11

View File

@ -5,6 +5,7 @@
[sub_resource type="SphereShape3D" id="SphereShape3D_wmusx"]
[node name="FreeCamera" type="CharacterBody3D"]
process_mode = 3
collision_layer = 0
script = ExtResource("1_3gm3q")

View File

@ -34,6 +34,9 @@ const CAMERA_SNAP_TIME := 0.3
@export var base_power := 2.5
@export var base_curve := 0.0
@export_category("Debug")
@export var debug_ball_impact := false
var base_speed: float = ProjectSettings.get_setting("game/config/controls/camera/free_camera_speed")
var x_sensitivity: float = ProjectSettings.get_setting(
@ -85,7 +88,9 @@ var _tracking_camera: OrbitalCamera
@onready var shot_animation: AnimationPlayer = %ShotAnimation
@onready var arrow: Node3D = %Arrow
@onready var arrow_pivot: Node3D = %ArrowPivot
@onready var arrow_animation: AnimationPlayer = %ArrowAnimation
@onready var shot_projection: ProjectileArc = %ShotProjection
@onready var power_bar: ProgressBar = %PowerBar
@onready var power_animation: AnimationPlayer = %PowerAnimation
@ -160,24 +165,42 @@ func finish_downswing() -> void:
phase = Phase.SHOT
func get_shot_impulse(meter_pct: float) -> Vector3:
return -shot_ref.global_basis.z * base_power * meter_pct
func take_shot() -> void:
print("WHACK!")
print("Power: ", power_bar.value)
print("Curve: ", curve_bar.value)
var impulse := shot_ref.global_basis.z * base_power * power_bar.value
print("Shot impulse: ", impulse)
var impulse := get_shot_impulse(power_bar.value)
print("Shot impulse: ", impulse, "; ", impulse.length(), " N*s")
ball_impulse_debug.transform = (
Transform3D.IDENTITY.scaled(Vector3.ONE * impulse.length()).looking_at(impulse)
)
physics_ball.freeze = false
physics_ball.apply_central_impulse(impulse)
#physics_ball.apply_central_impulse(impulse)
physics_ball.apply_impulse(impulse)
## Make the shot projection widget visible, with animated transition
func _show_shot_projection() -> void:
shot_projection.initial_speed = 1
shot_projection.basis = shot_ref.basis
var shot_speed := get_shot_impulse(1.0).length() / physics_ball.mass
var tween := get_tree().create_tween()
tween.tween_property(shot_projection, "initial_speed", shot_speed, CAMERA_SNAP_TIME).set_trans(
Tween.TRANS_QUAD
)
shot_projection.show()
func insert_free_cam() -> void:
arrow_animation.play("hide")
_show_shot_projection()
hud_state.travel("hidden")
_free_camera = FreeCamera.create(camera)
add_sibling(_free_camera)
@ -188,6 +211,7 @@ func insert_free_cam() -> void:
func return_free_cam() -> void:
# TODO alter shot aim based on free camera selection
arrow_animation.play("show")
shot_projection.hide()
hud_state.travel("visible")
_free_camera.queue_free()
_free_camera = null
@ -322,7 +346,9 @@ func _process(delta: float) -> void:
pitch.rotation.x = lerp_angle(pitch.rotation.x, _target_rotation.x, delta * y_acceleration)
# Arrow lags behind camera control
arrow.rotation.y = lerp_angle(arrow.rotation.y, _target_rotation.y, delta * ARROW_ACCELERATION)
arrow_pivot.rotation.y = lerp_angle(
arrow_pivot.rotation.y, _target_rotation.y, delta * ARROW_ACCELERATION
)
# Player lags further behind
player_pivot.rotation.y = lerp_angle(
player_pivot.rotation.y, _target_rotation.y, delta * PLAYER_ACCELERATION
@ -414,6 +440,17 @@ func _on_physics_ball_sleeping_state_changed() -> void:
func _on_ball_entered_water() -> void:
# Should only be possible during SHOT phase, but let's check just to be sure...
if phase == Phase.SHOT:
print("INTO THE DRINK!!")
physics_ball.freeze = true
wasted_animation.play("display")
func _on_physics_ball_body_entered(_body: Node) -> void:
print_debug("BONK!")
if debug_ball_impact:
get_tree().paused = true
_free_camera = FreeCamera.create(
(_tracking_camera if _tracking_camera else camera) as Node3D
)
add_sibling(_free_camera)
control_disabled = true
camera.current = false

View File

@ -1,10 +1,12 @@
[gd_scene load_steps=38 format=3 uid="uid://cy7t2tc4y3b4"]
[gd_scene load_steps=40 format=3 uid="uid://cy7t2tc4y3b4"]
[ext_resource type="Script" path="res://src/player/shot_setup/shot_setup.gd" id="1_r6ei4"]
[ext_resource type="PackedScene" uid="uid://dfttci386ohip" path="res://src/player/physics_ball/physics_ball.tscn" id="2_1i5j5"]
[ext_resource type="PackedScene" uid="uid://c2k88ns0h5ie1" path="res://src/ui/arrow.tscn" id="2_s70wl"]
[ext_resource type="PackedScene" uid="uid://c2k88ns0h5ie1" path="res://src/ui/arrow/arrow.tscn" id="2_s70wl"]
[ext_resource type="PackedScene" uid="uid://1s3gywmoi20e" path="res://src/characters/gfolf_girl/gfolf_girl.tscn" id="3_e4aur"]
[ext_resource type="PackedScene" uid="uid://445qd7m4qe2j" path="res://src/player/shot_setup/club_selector/club_selector.tscn" id="4_56ape"]
[ext_resource type="PackedScene" uid="uid://fht6j87o8ecr" path="res://src/ui/projectile_arc/projectile_arc.tscn" id="4_ry2ho"]
[ext_resource type="PackedScene" uid="uid://dbdul15c4oblg" path="res://src/ui/projected_target.tscn" id="6_mynqj"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_lnol1"]
albedo_color = Color(0, 0.537255, 1, 1)
@ -639,6 +641,8 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.08, 0)
unique_name_in_owner = true
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0)
freeze = true
contact_monitor = true
max_contacts_reported = 1
[node name="BallImpulseDebug" type="Node3D" parent="BallPoint"]
unique_name_in_owner = true
@ -660,27 +664,27 @@ unique_name_in_owner = true
[node name="DriveRef" type="RayCast3D" parent="Direction"]
unique_name_in_owner = true
transform = Transform3D(-1, 6.18172e-08, -6.18172e-08, 0, 0.707107, 0.707107, 8.74228e-08, 0.707107, -0.707107, 0, 0.08, 0)
transform = Transform3D(1, 0, 0, 0, 0.707107, -0.707107, 0, 0.707107, 0.707107, 0, 0.08, 0)
enabled = false
target_position = Vector3(0, 0, 1)
target_position = Vector3(0, 0, -1)
collision_mask = 0
collide_with_bodies = false
debug_shape_thickness = 4
[node name="WedgeRef" type="RayCast3D" parent="Direction"]
unique_name_in_owner = true
transform = Transform3D(-0.7, -5.29972e-08, 3.0598e-08, 0, 0.35, 0.606218, -6.11959e-08, 0.606218, -0.35, 0, 0.08, 0)
transform = Transform3D(0.7, 0, 0, 0, 0.35, -0.606218, 0, 0.606218, 0.35, 0, 0.08, 0)
enabled = false
target_position = Vector3(0, 0, 1)
target_position = Vector3(0, 0, -1)
collision_mask = 0
collide_with_bodies = false
debug_shape_thickness = 4
[node name="PuttRef" type="RayCast3D" parent="Direction"]
unique_name_in_owner = true
transform = Transform3D(-1, 0, -1.50996e-07, 0, 1, 0, 1.50996e-07, 0, -1, 0, 0.08, 0)
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.08, 0)
enabled = false
target_position = Vector3(0, 0, 1)
target_position = Vector3(0, 0, -1)
collision_mask = 0
collide_with_bodies = false
debug_shape_thickness = 4
@ -702,35 +706,50 @@ unique_name_in_owner = true
transform = Transform3D(1, 0, 0, 0, 1, 2.98023e-08, 0, -2.98023e-08, 1, 0, 0, 0)
current = true
[node name="Arrow" type="Node3D" parent="."]
[node name="ArrowPivot" type="Node3D" parent="."]
unique_name_in_owner = true
transform = Transform3D(0.001, 0, 0, 0, 0.001, 0, 0, 0, 0.001, 0, 0.1, 0)
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0)
[node name="ArrowAnimation" type="AnimationPlayer" parent="Arrow"]
[node name="Arrow" type="Node3D" parent="ArrowPivot"]
unique_name_in_owner = true
transform = Transform3D(0.001, 0, 0, 0, 0.001, 0, 0, 0, 0.001, 0, 0, 0)
[node name="ArrowAnimation" type="AnimationPlayer" parent="ArrowPivot/Arrow"]
unique_name_in_owner = true
libraries = {
"": SubResource("AnimationLibrary_rw0cf")
}
autoplay = "show"
[node name="DriveArrow" type="Node3D" parent="Arrow"]
[node name="DriveArrow" type="Node3D" parent="ArrowPivot/Arrow"]
unique_name_in_owner = true
transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 0, 0)
visible = false
[node name="ArrowMesh" parent="Arrow/DriveArrow" instance=ExtResource("2_s70wl")]
[node name="ArrowMesh" parent="ArrowPivot/Arrow/DriveArrow" instance=ExtResource("2_s70wl")]
transform = Transform3D(0.2, 0, 0, 0, 0.4, 0, 0, 0, 0.2, 0, 1, 0)
loop_animation = 1
[node name="PuttArrow" type="Node3D" parent="Arrow"]
[node name="PuttArrow" type="Node3D" parent="ArrowPivot/Arrow"]
unique_name_in_owner = true
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0, 0)
visible = false
[node name="ArrowMesh" parent="Arrow/PuttArrow" instance=ExtResource("2_s70wl")]
[node name="ArrowMesh" parent="ArrowPivot/Arrow/PuttArrow" instance=ExtResource("2_s70wl")]
transform = Transform3D(0.2, 0, 0, 0, 0.4, 0, 0, 0, 0.2, 0, 1, 0)
loop_animation = 1
[node name="ShotProjection" parent="ArrowPivot" node_paths=PackedStringArray("excluded_bodies") instance=ExtResource("4_ry2ho")]
unique_name_in_owner = true
transform = Transform3D(1, 0, 0, 0, 0.707107, -0.707107, 0, 0.707107, 0.707107, 0, -0.02, 0)
visible = false
initial_speed = 50.0
time_step = 0.01
max_steps = 800
excluded_bodies = [NodePath("../../BallPoint/PhysicsBall")]
[node name="ProjectedTarget" parent="ArrowPivot/ShotProjection" instance=ExtResource("6_mynqj")]
[node name="ShotAnimation" type="AnimationPlayer" parent="."]
unique_name_in_owner = true
root_node = NodePath("../Direction/Elevation/Pitch/Zoom/Camera")
@ -908,5 +927,6 @@ root_node = NodePath("%HUDStateMachine/..")
tree_root = SubResource("AnimationNodeStateMachine_osrbp")
anim_player = NodePath("../HUDAnimation")
[connection signal="body_entered" from="BallPoint/PhysicsBall" to="." method="_on_physics_ball_body_entered"]
[connection signal="entered_water" from="BallPoint/PhysicsBall" to="." method="_on_ball_entered_water"]
[connection signal="sleeping_state_changed" from="BallPoint/PhysicsBall" to="." method="_on_physics_ball_sleeping_state_changed"]

View File

@ -0,0 +1,47 @@
// Hologram shader
// Adapted from https://godotshaders.com/shader/scifi-hologram/
shader_type spatial;
render_mode unshaded;
uniform sampler2D texture_image;
uniform mediump vec4 line_color : source_color = vec4(0.0, 1.0, 0.0, 1.0);
uniform mediump float line_width : hint_range(0, 1) = 0.005;
uniform mediump float line_blur : hint_range(0, 1) = 0.2;
uniform mediump float line_speed : hint_range(-1, 1) = 0.02;
uniform bool straight_lines = true;
uniform mediump float interrupt_width : hint_range(0, 1) = 0.5;
uniform mediump float interrupt_blur : hint_range(0, 1) = 0.25;
uniform mediump float interrupt_speed : hint_range(-1, 1) = 0.2;
uniform mediump vec4 glow_color : source_color = vec4(0.5, 0.75, 1.0, 1.0);
uniform lowp float glow_itensity : hint_range(0, 20) = 4.5;
uniform lowp float glow_amount : hint_range(0, 20) = 4.5;
uniform lowp float flickering : hint_range(0, 1) = 0.55;
vec3 fresnel_glow(float amount, float intensity, vec3 color, vec3 normal, vec3 view) {
return pow((1.0 - dot(normalize(normal), normalize(view))), amount) * color * intensity;
}
void fragment () {
vec2 canvas;
if (straight_lines) {
canvas = SCREEN_UV;
} else {
canvas = vec2(VIEW.x, VIEW.y);
}
vec2 lines = vec2(clamp(sin((TIME * line_speed + canvas.y) / line_width), line_blur, 1.0 - line_blur), canvas.x);
vec2 interupts = vec2(clamp(sin((TIME * interrupt_speed + canvas.y) / interrupt_width * 3.0), interrupt_blur, 1.0 - interrupt_blur), canvas.x);
float flicker = clamp(fract(cos(TIME) * 43758.5453123), flickering, 1.0);
vec4 imgtex = flicker * line_color * texture(texture_image, lines * interupts);
vec3 imgtex_color = vec3(imgtex.r, imgtex.g, imgtex.b);
vec3 fresnel_color = vec3(glow_color.r, glow_color.g, glow_color.b);
vec3 fresnel = fresnel_glow(glow_amount, glow_itensity, fresnel_color, NORMAL, VIEW);
ALBEDO = imgtex_color + fresnel;
EMISSION = glow_amount * vec3(glow_color.r, glow_color.g, glow_color.b);
ALPHA = lines.x * interupts.x;
}

View File

@ -0,0 +1,41 @@
// Plasma Pulse shader
// Adapted from https://godotshaders.com/shader/scifi-hologram/
shader_type spatial;
render_mode unshaded, cull_back;
uniform mediump vec3 albedo: source_color = vec3(0.9, 0.0, 0.7);
uniform bool transpose_axis = false;
uniform mediump sampler2D wave_gradient;
uniform mediump float wave_width: hint_range(0, 10) = 1;
uniform mediump float wave_speed: hint_range(-1, 1) = 0.4;
uniform mediump vec4 glow_color: source_color = vec4(0.5, 0.75, 1.0, 1.0);
uniform lowp float glow_intensity: hint_range(0, 20) = 0.618;
uniform lowp float glow_amount: hint_range(0, 20) = 4.5;
uniform mediump sampler2D pulse_gradient;
uniform mediump float pulse_speed: hint_range(0, 10) = 0.3;
vec3 fresnel_glow(float amount, float intensity, vec3 color, vec3 normal, vec3 view) {
return pow((1.0 - dot(normalize(normal), normalize(view))), amount) * color * intensity;
}
void fragment () {
float canvas = -UV.x;
if(transpose_axis) {
canvas = -UV.y;
}
float wave_value = texture(wave_gradient, vec2((canvas + TIME * wave_speed) / wave_width, 0)).r;
vec3 fresnel_color = vec3(glow_color.r, glow_color.g, glow_color.b);
vec3 fresnel = fresnel_glow(glow_amount, glow_intensity, fresnel_color, NORMAL, VIEW);
float pulse_value = texture(pulse_gradient, vec2(TIME * pulse_speed, 0)).r;
ALBEDO = albedo + fresnel;
EMISSION = glow_amount * vec3(glow_color.r, glow_color.g, glow_color.b);
ALPHA = wave_value * pulse_value;
}

View File

@ -1,7 +1,7 @@
[gd_scene load_steps=9 format=3 uid="uid://c2k88ns0h5ie1"]
[ext_resource type="PackedScene" uid="uid://bw54bi35myvpg" path="res://assets/models/ui/arrow/arrow.glb" id="1_xifl6"]
[ext_resource type="Script" path="res://src/ui/arrow.gd" id="2_0viam"]
[ext_resource type="Script" path="res://src/ui/arrow/arrow.gd" id="2_0viam"]
[ext_resource type="Material" uid="uid://d3ka0yjhxu5ks" path="res://assets/materials/gummy_material.tres" id="3_g7vwe"]
[sub_resource type="Animation" id="Animation_hsqkd"]

View File

@ -0,0 +1,117 @@
[gd_scene load_steps=10 format=3 uid="uid://dbdul15c4oblg"]
[ext_resource type="Shader" path="res://src/shaders/plasma.gdshader" id="1_nf38g"]
[ext_resource type="FontFile" uid="uid://b6gxwgomstkgu" path="res://assets/fonts/Geo/Geo-Italic.ttf" id="2_ckdn3"]
[sub_resource type="Gradient" id="Gradient_3oor7"]
interpolation_mode = 2
offsets = PackedFloat32Array(0, 0.5, 1)
colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1)
[sub_resource type="GradientTexture1D" id="GradientTexture1D_ic835"]
gradient = SubResource("Gradient_3oor7")
[sub_resource type="ShaderMaterial" id="ShaderMaterial_msl6u"]
render_priority = 0
shader = ExtResource("1_nf38g")
shader_parameter/albedo = Color(1, 0.19, 0.2035, 1)
shader_parameter/transpose_axis = true
shader_parameter/wave_width = 0.4
shader_parameter/wave_speed = -0.3
shader_parameter/glow_color = Color(0.5, 0.75, 1, 1)
shader_parameter/glow_intensity = 0.618
shader_parameter/glow_amount = 4.5
shader_parameter/pulse_speed = 0.3
shader_parameter/wave_gradient = SubResource("GradientTexture1D_ic835")
[sub_resource type="SphereMesh" id="SphereMesh_dbo5p"]
material = SubResource("ShaderMaterial_msl6u")
radial_segments = 16
rings = 16
[sub_resource type="Animation" id="Animation_npp1f"]
resource_name = "rotate"
length = 3.236
loop_mode = 1
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:rotation")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 3.236),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, -3.14159, 0)]
}
[sub_resource type="Animation" id="Animation_yu68k"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:rotation")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_vm52d"]
_data = {
"RESET": SubResource("Animation_yu68k"),
"rotate": SubResource("Animation_npp1f")
}
[node name="ProjectedTarget" type="MeshInstance3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
mesh = SubResource("SphereMesh_dbo5p")
[node name="Pivot" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.02, 0)
[node name="Label3D" type="Label3D" parent="Pivot"]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0, 0.55)
pixel_size = 0.001
texture_filter = 5
modulate = Color(1, 0.188235, 0.203922, 1)
text = "DANGER"
font = ExtResource("2_ckdn3")
font_size = 64
[node name="Label3D2" type="Label3D" parent="Pivot"]
transform = Transform3D(-1, 8.74228e-08, 3.82137e-15, 0, -4.37114e-08, 1, 8.74228e-08, 1, 4.37114e-08, 0, 0, -0.55)
pixel_size = 0.001
texture_filter = 5
modulate = Color(1, 0.188235, 0.203922, 1)
text = "DANGER"
font = ExtResource("2_ckdn3")
font_size = 64
[node name="Label3D3" type="Label3D" parent="Pivot"]
transform = Transform3D(-4.37114e-08, -1, -4.37114e-08, 0, -4.37114e-08, 1, -1, 4.37114e-08, 1.91069e-15, 0.55, 0, 0)
pixel_size = 0.001
texture_filter = 5
modulate = Color(1, 0.188235, 0.203922, 1)
text = "DANGER"
font = ExtResource("2_ckdn3")
font_size = 64
[node name="Label3D4" type="Label3D" parent="Pivot"]
transform = Transform3D(-4.37114e-08, 1, 4.37114e-08, 0, -4.37114e-08, 1, 1, 4.37114e-08, 1.91069e-15, -0.55, 0, 0)
pixel_size = 0.001
texture_filter = 5
modulate = Color(1, 0.188235, 0.203922, 1)
text = "DANGER"
font = ExtResource("2_ckdn3")
font_size = 64
[node name="AnimationPlayer" type="AnimationPlayer" parent="Pivot"]
libraries = {
"": SubResource("AnimationLibrary_vm52d")
}
autoplay = "rotate"

View File

@ -0,0 +1,95 @@
class_name ProjectileArc extends Node3D
## Visually project the arc of a projectile through space.
##
## If this node has any children, they will be positioned wherever the projection ends.
## 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
@export_category("Projection")
## Time between projection steps, in seconds.
@export var time_step := 0.2
## Maximum number of steps to predict before stopping.
@export var max_steps := 50
## Ticks between each projection update. 0 means update every tick.
@export var ticks_per_update := 0
@export_category("Collision")
## Enables collision checking. Projection will end at the point where a collision is detected.
## Uses continuous collision detection.
@export var check_collision := true
## Mask for collision checking.
@export_flags_3d_physics var collision_mask := 1
## Bodies excluded from collision checking.
## This should probably include the ball!
@export var excluded_bodies: Array[CollisionObject3D] = []
var _tick_counter := 0
@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")
func _process(_delta: float) -> void:
if not visible:
# Don't bother if we're not visible
return
# Short-circuit if we need to wait more ticks
if _tick_counter > 0:
_tick_counter -= 1
return
_tick_counter = ticks_per_update
# Rebuild path curve
path.global_basis = Basis.IDENTITY
path.curve.clear_points()
var space := get_world_3d().direct_space_state
var excluded_rid: Array[RID] = []
excluded_rid.assign(excluded_bodies.map(func(k: CollisionObject3D) -> RID: return k.get_rid()))
var pos := global_position
var vel := -global_basis.z * initial_speed
for t in range(0, max_steps):
# TODO: smooth curve with bezier handles
path.curve.add_point(pos - global_position)
# Integrate projectile path
vel += gravity * gravity_vec * time_step
var next_pos := pos + vel * time_step
# Collision
if check_collision:
var ray_params := PhysicsRayQueryParameters3D.create(
pos, next_pos, collision_mask, excluded_rid
)
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
pos = next_pos
# Add terminal point (possibly collision point)
path.curve.add_point(pos - global_position)
# Reposition any children
for n: Node in get_children():
if n is Node3D and n != path:
var node_3d: Node3D = n
node_3d.global_position = pos
node_3d.global_basis = Basis.IDENTITY
func _on_visibility_changed() -> void:
# Force update as soon as visible
_tick_counter = 0

View File

@ -0,0 +1,59 @@
[gd_scene load_steps=9 format=3 uid="uid://fht6j87o8ecr"]
[ext_resource type="Script" path="res://src/ui/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="Gradient" id="Gradient_28hbf"]
offsets = PackedFloat32Array(0, 0.37193, 0.838596, 1)
colors = PackedColorArray(0.197937, 0.197937, 0.197937, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.197937, 0.197937, 0.197937, 1)
[sub_resource type="GradientTexture1D" id="GradientTexture1D_8xhfy"]
gradient = SubResource("Gradient_28hbf")
[sub_resource type="Gradient" id="Gradient_yx8sm"]
interpolation_mode = 2
offsets = PackedFloat32Array(0.0666667, 0.287719, 1)
colors = PackedColorArray(1, 1, 1, 1, 0.485904, 0.485904, 0.485904, 1, 0, 0, 0, 1)
[sub_resource type="GradientTexture1D" id="GradientTexture1D_l8ond"]
gradient = SubResource("Gradient_yx8sm")
[sub_resource type="ShaderMaterial" id="ShaderMaterial_ahf42"]
render_priority = 0
shader = ExtResource("2_pi36v")
shader_parameter/albedo = Color(0.9, 0, 0.7, 1)
shader_parameter/transpose_axis = false
shader_parameter/wave_width = 2.0
shader_parameter/wave_speed = 0.6
shader_parameter/glow_color = Color(0.5, 0.75, 1, 1)
shader_parameter/glow_intensity = 0.618
shader_parameter/glow_amount = 4.5
shader_parameter/pulse_speed = 0.3
shader_parameter/wave_gradient = SubResource("GradientTexture1D_l8ond")
shader_parameter/pulse_gradient = SubResource("GradientTexture1D_8xhfy")
[node name="ProjectileArc" type="Node3D"]
script = ExtResource("1_vafqi")
[node name="Path" type="Path3D" parent="."]
unique_name_in_owner = true
curve = SubResource("Curve3D_rfv3d")
[node name="Polygon" type="CSGPolygon3D" parent="Path"]
unique_name_in_owner = true
polygon = PackedVector2Array(0, -0.1, -0.2, 0, 0, 0.1, 0.2, 0)
mode = 2
path_node = NodePath("..")
path_interval_type = 0
path_interval = 1.0
path_simplify_angle = 0.0
path_rotation = 2
path_local = true
path_continuous_u = true
path_u_distance = 1.0
path_joined = false
material = SubResource("ShaderMaterial_ahf42")
[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"]

View File

@ -14,12 +14,11 @@ func on_ball_entered(ball: GameBall) -> void:
ball.entered_water.emit()
func on_ball_exited(ball: GameBall) -> void:
func on_ball_exited(_ball: GameBall) -> void:
pass
func _on_body_entered(body: Node3D) -> void:
print("BODY ENTERED ZONE: ", body)
if body is GameBall:
on_ball_entered(body as GameBall)