From 70da540e25dd6d77bf90010cdfa15f6152c006a0 Mon Sep 17 00:00:00 2001 From: Rob Kelly Date: Tue, 19 Nov 2024 21:52:04 -0700 Subject: [PATCH] Added plasma ball --- asset_dev/particles/plasma.xcf | Bin 0 -> 16220 bytes assets/sprites/particles/plasma.png | 3 + assets/sprites/particles/plasma.png.import | 35 ++++++++++ src/equipment/balls/physics_ball/game_ball.gd | 5 ++ .../balls/physics_ball/physics_ball.tscn | 31 ++++++++- .../balls/plasma_ball/plasma_ball.gd | 16 +++++ .../balls/plasma_ball/plasma_ball.tscn | 64 ++++++++++++++++++ src/player/shot_setup/shot_setup.gd | 64 +++++++++--------- src/player/shot_setup/shot_setup.tscn | 16 +++-- src/ui/shot_hud/shot_hud.tscn | 4 +- 10 files changed, 198 insertions(+), 40 deletions(-) create mode 100644 asset_dev/particles/plasma.xcf create mode 100644 assets/sprites/particles/plasma.png create mode 100644 assets/sprites/particles/plasma.png.import create mode 100644 src/equipment/balls/plasma_ball/plasma_ball.gd create mode 100644 src/equipment/balls/plasma_ball/plasma_ball.tscn diff --git a/asset_dev/particles/plasma.xcf b/asset_dev/particles/plasma.xcf new file mode 100644 index 0000000000000000000000000000000000000000..3f2cd1f3f7b5e275fa12bff7f742a80e0792eded GIT binary patch literal 16220 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 void: @@ -54,6 +57,8 @@ func _integrate_forces(state: PhysicsDirectBodyState3D) -> void: damping = _total_terrain_angular_damping() if damping <= TERRAIN_DAMPING_EPSILON: damping = rough_damping + last_contact_normal = state.get_contact_local_normal(0) + _debug_draw.queue_redraw() angular_damp = damping diff --git a/src/equipment/balls/physics_ball/physics_ball.tscn b/src/equipment/balls/physics_ball/physics_ball.tscn index f026442..ea64613 100644 --- a/src/equipment/balls/physics_ball/physics_ball.tscn +++ b/src/equipment/balls/physics_ball/physics_ball.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=8 format=3 uid="uid://dfttci386ohip"] +[gd_scene load_steps=9 format=3 uid="uid://dfttci386ohip"] [ext_resource type="Script" path="res://src/equipment/balls/physics_ball/game_ball.gd" id="1_iwh2u"] [ext_resource type="PhysicsMaterial" uid="uid://3bih72l068ic" path="res://src/equipment/balls/physics_ball/normal_physics.tres" id="1_l23pw"] @@ -27,9 +27,27 @@ rings = 6 [sub_resource type="SphereShape3D" id="SphereShape3D_0hvq6"] radius = 0.05 +[sub_resource type="GDScript" id="GDScript_p4v7o"] +resource_name = "debug_draw" +script/source = "extends Control + +const COLOR := Color(0, 1, 0) +const WIDTH := 4 + +@onready var physics_ball: GameBall = $\"..\" + +func _draw() -> void: + if physics_ball.last_contact_normal != null: + var camera := get_viewport().get_camera_3d() + var start := camera.unproject_position(physics_ball.global_transform.origin) + var end := camera.unproject_position(physics_ball.global_transform.origin + physics_ball.last_contact_normal) + draw_line(start, end, COLOR, WIDTH) +" + [node name="PhysicsBall" type="RigidBody3D"] mass = 0.05 physics_material_override = ExtResource("1_l23pw") +freeze = true continuous_cd = true contact_monitor = true max_contacts_reported = 1 @@ -44,3 +62,14 @@ mesh = SubResource("SphereMesh_y0d13") [node name="CollisionShape3D" type="CollisionShape3D" parent="."] shape = SubResource("SphereShape3D_0hvq6") + +[node name="DebugDraw" type="Control" parent="."] +unique_name_in_owner = true +visible = false +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = SubResource("GDScript_p4v7o") diff --git a/src/equipment/balls/plasma_ball/plasma_ball.gd b/src/equipment/balls/plasma_ball/plasma_ball.gd new file mode 100644 index 0000000..50316e0 --- /dev/null +++ b/src/equipment/balls/plasma_ball/plasma_ball.gd @@ -0,0 +1,16 @@ +extends GameBall +## The plasma ball sticks to the first surface it hits + +@onready var manual_sleep_timer: Timer = %ManualSleepTimer + + +func _on_body_entered(_body: Node) -> void: + print_debug("Plasma ball stuck to ", _body) + # Freeze physics as soon as we hit something + freeze = true + sleeping = true + manual_sleep_timer.start() + + +func _fire_sleep_signal() -> void: + sleeping_state_changed.emit() diff --git a/src/equipment/balls/plasma_ball/plasma_ball.tscn b/src/equipment/balls/plasma_ball/plasma_ball.tscn new file mode 100644 index 0000000..a0ae8de --- /dev/null +++ b/src/equipment/balls/plasma_ball/plasma_ball.tscn @@ -0,0 +1,64 @@ +[gd_scene load_steps=11 format=3 uid="uid://dcqxlbsrubapk"] + +[ext_resource type="PackedScene" uid="uid://dfttci386ohip" path="res://src/equipment/balls/physics_ball/physics_ball.tscn" id="1_yh4fp"] +[ext_resource type="Texture2D" uid="uid://c47bkx508biqr" path="res://assets/sprites/particles/plasma.png" id="2_8fdyx"] +[ext_resource type="Script" path="res://src/equipment/balls/plasma_ball/plasma_ball.gd" id="2_pdts3"] + +[sub_resource type="Curve" id="Curve_kabhn"] +max_value = 2.0 +_data = [Vector2(0, 2), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="CurveTexture" id="CurveTexture_oxhrr"] +curve = SubResource("Curve_kabhn") + +[sub_resource type="Curve" id="Curve_77lhu"] +_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(0.249135, 1), 0.0, 0.0, 0, 0, Vector2(1, 0.598878), -0.922125, -0.922125, 0, 0] +point_count = 3 + +[sub_resource type="CurveTexture" id="CurveTexture_vfusk"] +curve = SubResource("Curve_77lhu") + +[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_uffe8"] +angle_min = -720.0 +angle_max = 720.0 +direction = Vector3(0, 1, 0) +spread = 10.0 +initial_velocity_max = 0.1 +gravity = Vector3(0, 2, 0) +scale_curve = SubResource("CurveTexture_vfusk") +emission_curve = SubResource("CurveTexture_oxhrr") + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_7ptri"] +transparency = 1 +vertex_color_use_as_albedo = true +albedo_color = Color(0.48, 1, 1, 0.384314) +albedo_texture = ExtResource("2_8fdyx") +emission_enabled = true +emission = Color(0.42, 1, 1, 1) +billboard_mode = 3 +billboard_keep_scale = true +particles_anim_h_frames = 1 +particles_anim_v_frames = 1 +particles_anim_loop = false +grow_amount = -0.6 + +[sub_resource type="QuadMesh" id="QuadMesh_go8iw"] +material = SubResource("StandardMaterial3D_7ptri") +size = Vector2(0.4, 0.4) + +[node name="PlasmaBall" instance=ExtResource("1_yh4fp")] +script = ExtResource("2_pdts3") + +[node name="PlasmaFireEffect" type="GPUParticles3D" parent="BallMesh" index="0"] +amount = 20 +lifetime = 0.6 +process_material = SubResource("ParticleProcessMaterial_uffe8") +draw_pass_1 = SubResource("QuadMesh_go8iw") + +[node name="ManualSleepTimer" type="Timer" parent="." index="3"] +unique_name_in_owner = true +one_shot = true + +[connection signal="body_entered" from="." to="." method="_on_body_entered"] +[connection signal="timeout" from="ManualSleepTimer" to="." method="_fire_sleep_signal"] diff --git a/src/player/shot_setup/shot_setup.gd b/src/player/shot_setup/shot_setup.gd index 72957b4..8cad5e1 100644 --- a/src/player/shot_setup/shot_setup.gd +++ b/src/player/shot_setup/shot_setup.gd @@ -22,6 +22,7 @@ const ZOOM_MAX := 12.0 const ARROW_ACCELERATION := 8.0 const PLAYER_ACCELERATION := 2.0 +const FREE_CAM_GIMBAL_TWEEN_TIME := 0.2 const FREE_CAM_RETURN_TIME := 0.618 const BALL_RETURN_TIME := 0.618 const CAMERA_SNAP_TIME := 0.3 @@ -45,8 +46,6 @@ const WATER_DAMAGE := 10.0 @export var base_curve := 0.0 @export_category("Debug") -## When enabled, the game will pause and enter free cam mode when the ball has a collision. -@export var debug_ball_impact := false ## When enabled, ignore curve meter and hit a perfect shot every time. @export var perfect_aim := false ## Keep projection visible @@ -125,7 +124,8 @@ var _tracking_camera: OrbitalCamera @onready var shot_projection: ProjectileArc = %ShotProjection @onready var ball_point: Node3D = %BallPoint -@onready var physics_ball: GameBall = %PhysicsBall +# @onready var game_ball: GameBall = %PhysicsBall +@onready var game_ball: GameBall = %PlasmaBall @onready var drive_ref: RayCast3D = %DriveRef @onready var drive_arrow: Node3D = %DriveArrow @@ -143,8 +143,6 @@ var _tracking_camera: OrbitalCamera @onready var camera_distance := zoom.position.z: set = _set_camera_distance -@onready var phys_ball_scene := preload("res://src/equipment/balls/physics_ball/physics_ball.tscn") - @onready var world: World = get_tree().get_first_node_in_group(World.group) @onready var game: Game = get_tree().get_first_node_in_group(Game.group) @@ -229,15 +227,15 @@ func take_shot() -> void: Transform3D.IDENTITY.scaled(Vector3.ONE * impulse.length()).looking_at(impulse) ) - physics_ball.freeze = false - physics_ball.apply_central_impulse(impulse) + game_ball.freeze = false + game_ball.apply_central_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.orthonormalized() - var shot_speed := get_shot_impulse(1.0).length() / physics_ball.mass + var shot_speed := get_shot_impulse(1.0).length() / game_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 @@ -251,6 +249,9 @@ func insert_free_cam() -> void: hud.hide_hud() _free_camera = FreeCamera.create(camera) add_sibling(_free_camera) + # Un-gimbal-lock ourselves: quickly tween Z rotation to 0 + var tween := get_tree().create_tween() + tween.tween_property(_free_camera, "rotation:z", 0, FREE_CAM_GIMBAL_TWEEN_TIME) control_disabled = true camera.current = false @@ -271,12 +272,12 @@ func return_free_cam() -> void: func return_ball() -> void: - physics_ball.freeze = true + game_ball.freeze = true var tween := get_tree().create_tween() ( tween . tween_property( - physics_ball, + game_ball, "global_transform", ball_point.global_transform, BALL_RETURN_TIME, @@ -287,14 +288,26 @@ func return_ball() -> void: func travel_to_ball() -> void: - physics_ball.freeze = true - global_position = physics_ball.global_position - physics_ball.global_transform = ball_point.global_transform + game_ball.freeze = true + global_position = game_ball.global_position + + # Re-orient to the ball's last contact normal if there is one. + # Normally this will just be Vector3.UP or something close to it. + var normal := game_ball.last_contact_normal + if normal == null: + normal = Vector3.UP + var up := Vector3.BACK + if not normal.cross(up): + up = Vector3.RIGHT + look_at(global_position + normal, up) + rotate_object_local(Vector3.RIGHT, -PI / 2) + + game_ball.global_transform = ball_point.global_transform func start_shot_track() -> void: if phase == Phase.SHOT: - _tracking_camera = OrbitalCamera.create(physics_ball) + _tracking_camera = OrbitalCamera.create(game_ball) _tracking_camera.rotation.y = randf_range(0.0, TAU) add_sibling(_tracking_camera) _tracking_camera.global_transform = ball_point.global_transform @@ -322,7 +335,7 @@ func _on_club_change(new_club_type: Club.Type) -> void: wedge_arrow.hide() iron_arrow.hide() putt_arrow.hide() - physics_ball.iron_ball = false + game_ball.iron_ball = false hud.club_selector.value = new_club_type # TODO club change animation character.hold_right(new_club.get_model()) @@ -339,7 +352,7 @@ func _on_club_change(new_club_type: Club.Type) -> void: Club.Type.IRON: shot_ref = iron_ref iron_arrow.show() - physics_ball.iron_ball = true + game_ball.iron_ball = true Club.Type.SPECIAL: # TODO figure this out shot_ref = drive_ref @@ -488,33 +501,20 @@ func _process(delta: float) -> void: phase = Phase.AIM -func _on_physics_ball_sleeping_state_changed() -> void: - if physics_ball.sleeping and phase == Phase.SHOT: +func _on_ball_sleeping_state_changed() -> void: + if game_ball.sleeping and phase == Phase.SHOT: end_shot_track() 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: - physics_ball.freeze = true + game_ball.freeze = true hud.play_wasted_animation() player.life -= WATER_DAMAGE ball_return_timer.start(WASTED_BALL_RETURN_DELAY) -func _on_physics_ball_body_entered(_body: Node) -> void: - print_debug("BONK!") - if debug_ball_impact: - get_tree().paused = true - var snap_point: Node3D = camera - if _tracking_camera: - snap_point = _tracking_camera - _free_camera = FreeCamera.create(snap_point) - add_sibling(_free_camera) - control_disabled = true - camera.current = false - - func _on_ball_return_timer_timeout() -> void: return_ball() diff --git a/src/player/shot_setup/shot_setup.tscn b/src/player/shot_setup/shot_setup.tscn index f9e5d2a..ad0ad5d 100644 --- a/src/player/shot_setup/shot_setup.tscn +++ b/src/player/shot_setup/shot_setup.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=19 format=3 uid="uid://cy7t2tc4y3b4"] +[gd_scene load_steps=20 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/equipment/balls/physics_ball/physics_ball.tscn" id="2_1i5j5"] [ext_resource type="PackedScene" uid="uid://c2k88ns0h5ie1" path="res://src/ui/3d/arrow/arrow.tscn" id="2_s70wl"] +[ext_resource type="PackedScene" uid="uid://dcqxlbsrubapk" path="res://src/equipment/balls/plasma_ball/plasma_ball.tscn" id="3_8dte7"] [ext_resource type="PackedScene" uid="uid://1s3gywmoi20e" path="res://src/characters/player_characters/gfolf_girl/gfolf_girl.tscn" id="3_e4aur"] [ext_resource type="PackedScene" uid="uid://fht6j87o8ecr" path="res://src/ui/3d/projectile_arc/projectile_arc.tscn" id="4_ry2ho"] [ext_resource type="PackedScene" uid="uid://dbdul15c4oblg" path="res://src/ui/3d/projected_target.tscn" id="6_mynqj"] @@ -216,8 +217,12 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.08, 0) [node name="PhysicsBall" parent="BallPoint" instance=ExtResource("2_1i5j5")] unique_name_in_owner = true +process_mode = 4 transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0) -freeze = true +visible = false + +[node name="PlasmaBall" parent="BallPoint" instance=ExtResource("3_8dte7")] +unique_name_in_owner = true [node name="BallImpulseDebug" type="Node3D" parent="BallPoint"] unique_name_in_owner = true @@ -369,14 +374,15 @@ one_shot = true [node name="Hitbox" type="Area3D" parent="." node_paths=PackedStringArray("ignored_balls")] script = ExtResource("7_uh8kn") -ignored_balls = [NodePath("../BallPoint/PhysicsBall")] +ignored_balls = [NodePath("../BallPoint/PhysicsBall"), NodePath("../BallPoint/PlasmaBall")] [node name="CollisionShape3D" type="CollisionShape3D" parent="Hitbox"] shape = SubResource("SphereShape3D_xvvdi") -[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"] +[connection signal="sleeping_state_changed" from="BallPoint/PhysicsBall" to="." method="_on_ball_sleeping_state_changed"] +[connection signal="entered_water" from="BallPoint/PlasmaBall" to="." method="_on_ball_entered_water"] +[connection signal="sleeping_state_changed" from="BallPoint/PlasmaBall" to="." method="_on_ball_sleeping_state_changed"] [connection signal="timeout" from="BallReturnTimer" to="." method="_on_ball_return_timer_timeout"] [connection signal="ball_collision" from="Hitbox" to="." method="_on_hitbox_ball_collision"] [connection signal="body_entered" from="Hitbox" to="Hitbox" method="_on_body_entered"] diff --git a/src/ui/shot_hud/shot_hud.tscn b/src/ui/shot_hud/shot_hud.tscn index 73c1f07..6071088 100644 --- a/src/ui/shot_hud/shot_hud.tscn +++ b/src/ui/shot_hud/shot_hud.tscn @@ -691,9 +691,9 @@ anchors_preset = -1 anchor_top = 1.0 anchor_right = 0.333 anchor_bottom = 1.0 -offset_top = 20.0 +offset_top = 18.6812 offset_right = 40.0 -offset_bottom = 118.0 +offset_bottom = 116.681 grow_vertical = 0 theme_override_constants/margin_left = 16 theme_override_constants/margin_bottom = 16