Compare commits

...

3 Commits

Author SHA1 Message Date
Rob Kelly 75d08d0dc2 Glint on the 'woah nice' message 2024-12-04 19:17:17 -07:00
Rob Kelly 872aad090e Ball sand particle effect 2024-12-04 19:06:18 -07:00
Rob Kelly ce6c9b3aac Magnetic effect is sticky like plasma ball 2024-12-04 17:59:44 -07:00
9 changed files with 181 additions and 63 deletions

Binary file not shown.

View File

@ -0,0 +1,16 @@
class_name BallParticleEffects extends Node3D
## Controller for ball particle effects.
@onready var sand_particles: GPUParticles3D = %SandParticles
@onready var ball: GameBall = $".."
func play_effect(terrain: Terrain.Type) -> void:
global_rotation = Vector3.ZERO
match terrain:
Terrain.Type.SAND:
# Adjust sand particle direction
var material: ParticleProcessMaterial = sand_particles.process_material
material.direction = -ball.linear_velocity.normalized()
sand_particles.emitting = true

View File

@ -13,14 +13,11 @@ enum Type {
const TERRAIN_DAMPING_EPSILON := 1e-6 const TERRAIN_DAMPING_EPSILON := 1e-6
const MAGNUS_EPSILON := 1e-3 const MAGNUS_EPSILON := 1e-3
const IRON_DAMPING := 9999.0
## Angular damping while in air ## Angular damping while in air
@export var air_damping := 0.0 @export var air_damping := 0.0
## Angular damping while in collision with rough terrain ## Angular damping while in collision with rough terrain
@export var rough_damping := 8.0 @export var rough_damping := 8.0
## Angular damping for iron balls
@export var iron_damping := 9999.0
#@export var fluid_density := 1.225 #@export var fluid_density := 1.225
#@export var lift_coefficient := 0.05 #@export var lift_coefficient := 0.05
@ -32,14 +29,8 @@ const IRON_DAMPING := 9999.0
## and `r` is the radius of the ball, which is 5cm. ## and `r` is the radius of the ball, which is 5cm.
@export var magnus_coefficient := 0.00024 @export var magnus_coefficient := 0.00024
## Causes the ball to act more like a brick ## Causes the ball to stick to surfaces
@export var iron_ball := false: @export var magnetic := false
set(value):
if value:
physics_material_override = iron_physics
else:
physics_material_override = normal_physics
iron_ball = value
## Base damage inflicted on impact with a player ## Base damage inflicted on impact with a player
@export var base_damage := 15.0 @export var base_damage := 15.0
@ -52,18 +43,22 @@ var _position_on_last_wake: Vector3
var _awake := false var _awake := false
var _zones: Array[BallZone] = [] var _zones: Array[BallZone] = []
@onready var manual_sleep_timer: Timer = %ManualSleepTimer
@onready var sfx: BallSFX = %SFX @onready var sfx: BallSFX = %SFX
@onready var effects: BallParticleEffects = %ParticleEffects
@onready var normal_physics: PhysicsMaterial = preload( @onready var normal_physics: PhysicsMaterial = preload(
"res://src/equipment/balls/physics_ball/normal_physics.tres" "res://src/equipment/balls/physics_ball/normal_physics.tres"
) )
@onready var iron_physics: PhysicsMaterial = preload(
"res://src/equipment/balls/physics_ball/iron_physics.tres"
)
@onready var _debug_draw: Control = %DebugDraw @onready var _debug_draw: Control = %DebugDraw
## Should this ball stick to surfaces, rather than bounce?
func is_sticky() -> bool:
return magnetic
## Called by a water area when this ball enters it ## Called by a water area when this ball enters it
func enter_water() -> void: func enter_water() -> void:
entered_water.emit() entered_water.emit()
@ -108,8 +103,6 @@ func _integrate_forces(state: PhysicsDirectBodyState3D) -> void:
damping = _total_terrain_angular_damping() damping = _total_terrain_angular_damping()
if damping <= TERRAIN_DAMPING_EPSILON: if damping <= TERRAIN_DAMPING_EPSILON:
damping = rough_damping damping = rough_damping
if iron_ball:
damping = iron_damping
angular_damp = damping angular_damp = damping
@ -147,11 +140,26 @@ func _on_sleeping_state_changed() -> void:
func _on_collision(body: Node) -> void: func _on_collision(body: Node) -> void:
if is_sticky():
# Freeze physics as soon as we hit something
freeze = true
manual_sleep_timer.start()
var terrain: Terrain.Type
if body is Terrain3D: if body is Terrain3D:
sfx.play_sfx(Terrain.at_position(global_position, body as Terrain3D)) terrain = Terrain.at_position(global_position, body as Terrain3D)
elif body is CSGShape3D: elif body is CSGShape3D:
sfx.play_sfx(Terrain.from_physical_layer((body as CSGShape3D).collision_layer)) terrain = Terrain.from_physical_layer((body as CSGShape3D).collision_layer)
elif body is CollisionObject3D: elif body is CollisionObject3D:
sfx.play_sfx(Terrain.from_physical_layer((body as CollisionObject3D).collision_layer)) terrain = Terrain.from_physical_layer((body as CollisionObject3D).collision_layer)
else: else:
print_debug("COLLIDER: ", body) print_debug("COLLIDER: ", body)
if terrain:
sfx.play_sfx(terrain)
effects.play_effect(terrain)
func _fire_sleep_signal() -> void:
sleeping = true
sleeping_state_changed.emit()

View File

@ -1,7 +0,0 @@
[gd_resource type="PhysicsMaterial" format=3 uid="uid://cfd56nhaods5a"]
[resource]
friction = 0.8
rough = true
bounce = 1.0
absorbent = true

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=19 format=3 uid="uid://dfttci386ohip"] [gd_scene load_steps=24 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="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"] [ext_resource type="PhysicsMaterial" uid="uid://3bih72l068ic" path="res://src/equipment/balls/physics_ball/normal_physics.tres" id="1_l23pw"]
@ -11,6 +11,8 @@
[ext_resource type="AudioStream" uid="uid://3csnnhxndt67" path="res://assets/sound/sfx/ball/concrete5.wav" id="9_p0lmw"] [ext_resource type="AudioStream" uid="uid://3csnnhxndt67" path="res://assets/sound/sfx/ball/concrete5.wav" id="9_p0lmw"]
[ext_resource type="AudioStream" uid="uid://bbbp6wrkuhkek" path="res://assets/sound/sfx/ball/sand1.wav" id="10_b64mx"] [ext_resource type="AudioStream" uid="uid://bbbp6wrkuhkek" path="res://assets/sound/sfx/ball/sand1.wav" id="10_b64mx"]
[ext_resource type="AudioStream" uid="uid://b5xx5t050i4p" path="res://assets/sound/sfx/ball/sand2.wav" id="11_ed8je"] [ext_resource type="AudioStream" uid="uid://b5xx5t050i4p" path="res://assets/sound/sfx/ball/sand2.wav" id="11_ed8je"]
[ext_resource type="Script" path="res://src/equipment/balls/physics_ball/ball_particle_effects.gd" id="12_7krl6"]
[ext_resource type="Texture2D" uid="uid://c47bkx508biqr" path="res://assets/sprites/particles/plasma.png" id="12_guipt"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_xqofq"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_xqofq"]
albedo_texture = ExtResource("1_y3q5j") albedo_texture = ExtResource("1_y3q5j")
@ -92,6 +94,33 @@ streams_count = 2
stream_0/stream = ExtResource("10_b64mx") stream_0/stream = ExtResource("10_b64mx")
stream_1/stream = ExtResource("11_ed8je") stream_1/stream = ExtResource("11_ed8je")
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_mwiw1"]
angle_min = -720.0
angle_max = 720.0
spread = 20.0
initial_velocity_min = 1.0
initial_velocity_max = 3.0
gravity = Vector3(0, -3, 0)
scale_min = 0.0
hue_variation_min = -0.02
hue_variation_max = -2.23517e-08
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_v1i8b"]
transparency = 1
vertex_color_use_as_albedo = true
albedo_color = Color(0.78, 0.70928, 0.5304, 1)
albedo_texture = ExtResource("12_guipt")
texture_filter = 4
billboard_mode = 3
billboard_keep_scale = true
particles_anim_h_frames = 1
particles_anim_v_frames = 1
particles_anim_loop = false
[sub_resource type="QuadMesh" id="QuadMesh_xkteo"]
material = SubResource("StandardMaterial3D_v1i8b")
size = Vector2(0.2, 0.2)
[node name="PhysicsBall" type="RigidBody3D"] [node name="PhysicsBall" type="RigidBody3D"]
mass = 0.05 mass = 0.05
physics_material_override = ExtResource("1_l23pw") physics_material_override = ExtResource("1_l23pw")
@ -103,7 +132,6 @@ linear_damp_mode = 1
angular_damp_mode = 1 angular_damp_mode = 1
angular_damp = 8.0 angular_damp = 8.0
script = ExtResource("1_iwh2u") script = ExtResource("1_iwh2u")
iron_damping = 1e+07
[node name="BallMesh" type="MeshInstance3D" parent="."] [node name="BallMesh" type="MeshInstance3D" parent="."]
mesh = SubResource("SphereMesh_y0d13") mesh = SubResource("SphereMesh_y0d13")
@ -146,5 +174,23 @@ unit_size = 40.0
max_db = 0.0 max_db = 0.0
bus = &"SFX" bus = &"SFX"
[node name="ManualSleepTimer" type="Timer" parent="."]
unique_name_in_owner = true
one_shot = true
[node name="ParticleEffects" type="Node3D" parent="."]
unique_name_in_owner = true
script = ExtResource("12_7krl6")
[node name="SandParticles" type="GPUParticles3D" parent="ParticleEffects"]
unique_name_in_owner = true
emitting = false
amount = 24
one_shot = true
explosiveness = 0.9
process_material = SubResource("ParticleProcessMaterial_mwiw1")
draw_pass_1 = SubResource("QuadMesh_xkteo")
[connection signal="body_entered" from="." to="." method="_on_collision"] [connection signal="body_entered" from="." to="." method="_on_collision"]
[connection signal="sleeping_state_changed" from="." to="." method="_on_sleeping_state_changed"] [connection signal="sleeping_state_changed" from="." to="." method="_on_sleeping_state_changed"]
[connection signal="timeout" from="ManualSleepTimer" to="." method="_fire_sleep_signal"]

View File

@ -1,16 +1,6 @@
extends GameBall extends GameBall
## The plasma ball sticks to the first surface it hits ## Plasma ball always sticks to surfaces
@onready var manual_sleep_timer: Timer = %ManualSleepTimer
func _on_body_entered(_body: Node) -> void: func is_sticky() -> bool:
print_debug("Plasma ball stuck to ", _body) return true
# Freeze physics as soon as we hit something
freeze = true
manual_sleep_timer.start()
func _fire_sleep_signal() -> void:
sleeping = true
sleeping_state_changed.emit()

View File

@ -2,7 +2,7 @@
[ext_resource type="PackedScene" uid="uid://dfttci386ohip" path="res://src/equipment/balls/physics_ball/physics_ball.tscn" id="1_yh4fp"] [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="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"] [ext_resource type="Script" path="res://src/equipment/balls/plasma_ball/plasma_ball.gd" id="2_16fhh"]
[sub_resource type="Curve" id="Curve_kabhn"] [sub_resource type="Curve" id="Curve_kabhn"]
max_value = 2.0 max_value = 2.0
@ -48,8 +48,8 @@ material = SubResource("StandardMaterial3D_7ptri")
size = Vector2(0.4, 0.4) size = Vector2(0.4, 0.4)
[node name="PlasmaBall" instance=ExtResource("1_yh4fp")] [node name="PlasmaBall" instance=ExtResource("1_yh4fp")]
script = ExtResource("2_pdts3") script = ExtResource("2_16fhh")
base_damage = 30.0 magnetic = true
[node name="PlasmaFireEffect" type="GPUParticles3D" parent="BallMesh" index="0"] [node name="PlasmaFireEffect" type="GPUParticles3D" parent="BallMesh" index="0"]
amount = 20 amount = 20
@ -57,9 +57,4 @@ lifetime = 0.6
process_material = SubResource("ParticleProcessMaterial_uffe8") process_material = SubResource("ParticleProcessMaterial_uffe8")
draw_pass_1 = SubResource("QuadMesh_go8iw") 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="body_entered" from="." to="." method="_on_body_entered"]
[connection signal="timeout" from="ManualSleepTimer" to="." method="_fire_sleep_signal"]

View File

@ -96,10 +96,7 @@ var phase: Phase = Phase.FINISHED:
var hud: ShotHUD var hud: ShotHUD
var club_type: Club.Type: var club_type: Club.Type:
set(value): set = _set_club_type
if value != club_type:
_on_club_change(value)
club_type = value
var club: Club: var club: Club:
get: get:
@ -272,7 +269,7 @@ func take_shot() -> void:
print_debug("Shot offset: ", offset, "; ", offset.length(), " m") print_debug("Shot offset: ", offset, "; ", offset.length(), " m")
if game_ball: if game_ball:
game_ball.iron_ball = club_type == Club.Type.IRON game_ball.magnetic = club_type == Club.Type.IRON
game_ball.freeze = false game_ball.freeze = false
game_ball.apply_impulse(impulse, offset) game_ball.apply_impulse(impulse, offset)
@ -382,8 +379,10 @@ func end_shot_track() -> void:
phase = Phase.FINISHED phase = Phase.FINISHED
## Called immediately before `club` is mutated. func _set_club_type(new_club_type: Club.Type) -> void:
func _on_club_change(new_club_type: Club.Type) -> void: if new_club_type == club_type:
return
var new_club := player.get_club(new_club_type) var new_club := player.get_club(new_club_type)
if not new_club: if not new_club:
# `new_club` will be null if player has no club in the given slot # `new_club` will be null if player has no club in the given slot
@ -414,6 +413,8 @@ func _on_club_change(new_club_type: Club.Type) -> void:
_: _:
print_debug("Not sure how to equip club type: ", new_club) print_debug("Not sure how to equip club type: ", new_club)
club_type = new_club_type
## Called immediately before `phase` is mutated. ## Called immediately before `phase` is mutated.
func _on_phase_change(new_phase: Phase) -> void: func _on_phase_change(new_phase: Phase) -> void:

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=36 format=3 uid="uid://c4ifdiohng830"] [gd_scene load_steps=38 format=3 uid="uid://c4ifdiohng830"]
[ext_resource type="Script" path="res://src/ui/shot_hud/shot_hud.gd" id="1_x5b4c"] [ext_resource type="Script" path="res://src/ui/shot_hud/shot_hud.gd" id="1_x5b4c"]
[ext_resource type="Shader" path="res://src/shaders/canvas_retro.gdshader" id="1_ybxxp"] [ext_resource type="Shader" path="res://src/shaders/canvas_retro.gdshader" id="1_ybxxp"]
@ -87,6 +87,30 @@ tracks/5/keys = {
"update": 1, "update": 1,
"values": [true] "values": [true]
} }
tracks/6/type = "value"
tracks/6/imported = false
tracks/6/enabled = true
tracks/6/path = NodePath("Glint:anchor_left")
tracks/6/interp = 1
tracks/6/loop_wrap = true
tracks/6/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [-1.0]
}
tracks/7/type = "value"
tracks/7/imported = false
tracks/7/enabled = true
tracks/7/path = NodePath("Glint:anchor_right")
tracks/7/interp = 1
tracks/7/loop_wrap = true
tracks/7/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [0.0]
}
[sub_resource type="Animation" id="Animation_cwotn"] [sub_resource type="Animation" id="Animation_cwotn"]
resource_name = "display" resource_name = "display"
@ -162,6 +186,30 @@ tracks/5/keys = {
"update": 1, "update": 1,
"values": [true] "values": [true]
} }
tracks/6/type = "value"
tracks/6/imported = false
tracks/6/enabled = true
tracks/6/path = NodePath("Glint:anchor_left")
tracks/6/interp = 1
tracks/6/loop_wrap = true
tracks/6/keys = {
"times": PackedFloat32Array(0.7, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [-1.0, 1.0]
}
tracks/7/type = "value"
tracks/7/imported = false
tracks/7/enabled = true
tracks/7/path = NodePath("Glint:anchor_right")
tracks/7/interp = 1
tracks/7/loop_wrap = true
tracks/7/keys = {
"times": PackedFloat32Array(0.7, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [0.0, 2.0]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_2a0gn"] [sub_resource type="AnimationLibrary" id="AnimationLibrary_2a0gn"]
_data = { _data = {
@ -169,6 +217,16 @@ _data = {
"display": SubResource("Animation_cwotn") "display": SubResource("Animation_cwotn")
} }
[sub_resource type="Gradient" id="Gradient_xp0wp"]
offsets = PackedFloat32Array(0, 0.482857, 1)
colors = PackedColorArray(1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0)
[sub_resource type="GradientTexture2D" id="GradientTexture2D_knygn"]
gradient = SubResource("Gradient_xp0wp")
fill_from = Vector2(0, 0.4)
fill_to = Vector2(1, 0.6)
metadata/_snap_enabled = true
[sub_resource type="Animation" id="Animation_2gt87"] [sub_resource type="Animation" id="Animation_2gt87"]
resource_name = "RESET" resource_name = "RESET"
length = 0.001 length = 0.001
@ -596,6 +654,7 @@ script = ExtResource("1_x5b4c")
[node name="WoahNiceFeedback" type="RichTextLabel" parent="."] [node name="WoahNiceFeedback" type="RichTextLabel" parent="."]
visible = false visible = false
clip_children = 2
custom_minimum_size = Vector2(1200, 0) custom_minimum_size = Vector2(1200, 0)
layout_mode = 1 layout_mode = 1
anchors_preset = -1 anchors_preset = -1
@ -603,10 +662,10 @@ anchor_left = 0.5
anchor_top = 0.5 anchor_top = 0.5
anchor_right = 0.5 anchor_right = 0.5
anchor_bottom = 0.5 anchor_bottom = 0.5
offset_left = -350.0 offset_left = -600.0
offset_top = -66.0 offset_top = -136.5
offset_right = 350.0 offset_right = 600.0
offset_bottom = 66.0 offset_bottom = 136.5
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
mouse_filter = 2 mouse_filter = 2
@ -628,6 +687,16 @@ stream = ExtResource("2_5f3rs")
volume_db = -16.0 volume_db = -16.0
bus = &"SFX" bus = &"SFX"
[node name="Glint" type="TextureRect" parent="WoahNiceFeedback"]
clip_children = 2
layout_mode = 1
anchors_preset = -1
anchor_left = -1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
texture = SubResource("GradientTexture2D_knygn")
[node name="WastedFeedback" type="RichTextLabel" parent="."] [node name="WastedFeedback" type="RichTextLabel" parent="."]
visible = false visible = false
custom_minimum_size = Vector2(1400, 0) custom_minimum_size = Vector2(1400, 0)