diff --git a/src/items/extra_ball/extra_ball.gd b/src/items/extra_ball/extra_ball.gd index 7a74410..72c7f82 100644 --- a/src/items/extra_ball/extra_ball.gd +++ b/src/items/extra_ball/extra_ball.gd @@ -11,3 +11,6 @@ func _collect(player: WorldPlayer) -> void: player.set_balls(ball_type, -1) else: player.mutate_balls(ball_type, amount) + + player.shot_setup.hud.peek_club_selector() + player.shot_setup.hud.emit_ball_particles(maxi(amount, 1), screen_location()) diff --git a/src/items/item/item.gd b/src/items/item/item.gd index 890f551..1ab3376 100644 --- a/src/items/item/item.gd +++ b/src/items/item/item.gd @@ -10,6 +10,14 @@ signal on_collect(player: WorldPlayer) @onready var explosion_player: AnimationPlayer = %ExplosionPlayer +## Relative location of this item in screen coordinates. +## Useful for particle effects +func screen_location() -> Vector2: + var location := get_viewport().get_camera_3d().unproject_position(global_position) + # TODO: what if this is off-screen? + return location + + func collect(player: WorldPlayer) -> void: # Note that this animation will call `queue_free` in 5 seconds! explosion_player.play("explode") diff --git a/src/items/item/item.tscn b/src/items/item/item.tscn index ff0a4db..6ec8ebc 100644 --- a/src/items/item/item.tscn +++ b/src/items/item/item.tscn @@ -323,6 +323,39 @@ tracks/2/keys = { "update": 1, "values": [true] } +tracks/3/type = "bezier" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("Pivot/Octahedron/ItemMeshContainer:scale:x") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"handle_modes": PackedInt32Array(0), +"points": PackedFloat32Array(1, -0.25, 0, 0.25, 0), +"times": PackedFloat32Array(0) +} +tracks/4/type = "bezier" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("Pivot/Octahedron/ItemMeshContainer:scale:y") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"handle_modes": PackedInt32Array(0), +"points": PackedFloat32Array(1, -0.25, 0, 0.25, 0), +"times": PackedFloat32Array(0) +} +tracks/5/type = "bezier" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("Pivot/Octahedron/ItemMeshContainer:scale:z") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"handle_modes": PackedInt32Array(0), +"points": PackedFloat32Array(1, -0.25, 0, 0.25, 0), +"times": PackedFloat32Array(0) +} [sub_resource type="Animation" id="Animation_niure"] resource_name = "explode" @@ -377,6 +410,39 @@ tracks/3/keys = { "method": &"queue_free" }] } +tracks/4/type = "bezier" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("Pivot/Octahedron/ItemMeshContainer:scale:x") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"handle_modes": PackedInt32Array(0, 0), +"points": PackedFloat32Array(1, -0.25, 0, 0.2, 0.8, 0, -0.25, 0, 0.25, 0), +"times": PackedFloat32Array(0.0333333, 0.333333) +} +tracks/5/type = "bezier" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("Pivot/Octahedron/ItemMeshContainer:scale:y") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"handle_modes": PackedInt32Array(0, 0), +"points": PackedFloat32Array(1, -0.25, 0, 0.2, 0.8, 0, -0.25, 0, 0.25, 0), +"times": PackedFloat32Array(0, 0.3) +} +tracks/6/type = "bezier" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("Pivot/Octahedron/ItemMeshContainer:scale:z") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"handle_modes": PackedInt32Array(0, 0), +"points": PackedFloat32Array(1, -0.25, 0, 0.2, 0.8, 0, -0.25, 0, 0.25, 0), +"times": PackedFloat32Array(0.0666667, 0.366667) +} [sub_resource type="AnimationLibrary" id="AnimationLibrary_lqra6"] _data = { diff --git a/src/player/world_player.gd b/src/player/world_player.gd index 463726a..c35f6e9 100644 --- a/src/player/world_player.gd +++ b/src/player/world_player.gd @@ -30,8 +30,6 @@ signal on_death(player: WorldPlayer) GameBall.Type.PLASMA: -1, } -# TODO balls, pickups, etc - var shot_setup: ShotSetup: get: if not shot_setup: diff --git a/src/ui/shot_hud/shot_hud.gd b/src/ui/shot_hud/shot_hud.gd index 77a044b..c5edf8d 100644 --- a/src/ui/shot_hud/shot_hud.gd +++ b/src/ui/shot_hud/shot_hud.gd @@ -16,6 +16,7 @@ var player: WorldPlayer @onready var club_selector: ClubSelector = %ClubSelector @onready var ball_selector: BallSelector = %BallSelector +@onready var _ball_particles: GPUParticles2D = %BallParticles @onready var _curve_animation: AnimationPlayer = %CurveAnimation @onready var _power_animation: AnimationPlayer = %PowerAnimation @@ -57,6 +58,10 @@ func hide_hud() -> void: _sw_animation.play("hide") +func peek_club_selector() -> void: + _club_selector_animation.play("peek") + + func peek_life_bar() -> void: _sw_animation.play("peek") @@ -105,6 +110,13 @@ func hide_reset_prompt() -> void: _reset_prompt_animation.play_backwards("show") +func emit_ball_particles(amount: int, location: Vector2) -> void: + var particle_mat: ParticleProcessMaterial = _ball_particles.process_material + particle_mat.emission_shape_offset = Vector3(location.x, location.y, 0) + _ball_particles.amount = amount + _ball_particles.emitting = true + + ## Set the value of the life bar, potentially playing some kind of effect in response. ## ## To set the life bar without triggering an effect, set it directly with `life_bar.value` diff --git a/src/ui/shot_hud/shot_hud.tscn b/src/ui/shot_hud/shot_hud.tscn index 8ae512f..79a2124 100644 --- a/src/ui/shot_hud/shot_hud.tscn +++ b/src/ui/shot_hud/shot_hud.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=41 format=3 uid="uid://c4ifdiohng830"] +[gd_scene load_steps=49 format=3 uid="uid://c4ifdiohng830"] [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"] @@ -282,6 +282,23 @@ tracks/0/keys = { "values": [0.0, 0.0872665, -1.5708] } +[sub_resource type="Animation" id="Animation_hmxtr"] +resource_name = "peek" +length = 2.4 +step = 0.02 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:rotation") +tracks/0/interp = 3 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.14, 0.2, 2.2, 2.26, 2.4), +"transitions": PackedFloat32Array(1.618, 1.618, 1, 1, 1.618, 1.618), +"update": 0, +"values": [-1.5708, 0.0872665, 0.0, 0.0, 0.0872665, -1.5708] +} + [sub_resource type="Animation" id="Animation_x6kyr"] resource_name = "show" length = 0.4 @@ -303,9 +320,55 @@ tracks/0/keys = { _data = { "RESET": SubResource("Animation_4h8gq"), "hide": SubResource("Animation_w7dmn"), +"peek": SubResource("Animation_hmxtr"), "show": SubResource("Animation_x6kyr") } +[sub_resource type="Curve" id="Curve_mp3bg"] +max_value = 100.0 +_data = [Vector2(0.0431211, 0), 0.0, 21.2919, 0, 0, Vector2(1, 100), 336.968, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="CurveTexture" id="CurveTexture_satut"] +curve = SubResource("Curve_mp3bg") + +[sub_resource type="Curve" id="Curve_a5ydw"] +max_value = 200.0 +_data = [Vector2(0, 9.02831), 0.0, 0.618766, 0, 0, Vector2(1, 200), 450.985, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="CurveTexture" id="CurveTexture_oynpa"] +curve = SubResource("Curve_a5ydw") + +[sub_resource type="Curve" id="Curve_53gso"] +_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.0616016, 1), 0.0, 0.0, 0, 0, Vector2(0.761807, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 4 + +[sub_resource type="CurveTexture" id="CurveTexture_a05qh"] +curve = SubResource("Curve_53gso") + +[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_besmx"] +particle_flag_disable_z = true +emission_shape_offset = Vector3(800, 600, 0) +angle_min = -720.0 +angle_max = 720.0 +direction = Vector3(0, 0, 0) +spread = 180.0 +initial_velocity_min = 400.0 +initial_velocity_max = 600.0 +angular_velocity_min = -100.0 +angular_velocity_max = 100.0 +gravity = Vector3(0, 0, 0) +radial_accel_min = -100.0 +radial_accel_max = -100.0 +radial_accel_curve = SubResource("CurveTexture_oynpa") +damping_min = 200.0 +damping_max = 200.0 +damping_curve = SubResource("CurveTexture_satut") +scale_min = 0.4 +scale_max = 0.4 +scale_curve = SubResource("CurveTexture_a05qh") + [sub_resource type="Animation" id="Animation_3cn2c"] resource_name = "RESET" length = 0.001 @@ -714,6 +777,26 @@ anchor_right = 0.7 offset_right = 108.0 grow_horizontal = 1 +[node name="BallParticleContainer" type="Control" parent="ClubSelector/TextureRect"] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="BallParticles" type="GPUParticles2D" parent="ClubSelector/TextureRect/BallParticleContainer"] +unique_name_in_owner = true +emitting = false +amount = 32 +process_material = SubResource("ParticleProcessMaterial_besmx") +texture = ExtResource("8_tt8i3") +lifetime = 1.4 +one_shot = true +explosiveness = 0.7 + [node name="SouthWest" type="MarginContainer" parent="."] layout_mode = 1 anchors_preset = -1