diff --git a/levels/debug_level/debug_level.tscn b/levels/debug_level/debug_level.tscn index 1be60c4..a052afa 100644 --- a/levels/debug_level/debug_level.tscn +++ b/levels/debug_level/debug_level.tscn @@ -1,9 +1,10 @@ -[gd_scene load_steps=63 format=3 uid="uid://bm2o3mex10v11"] +[gd_scene load_steps=64 format=3 uid="uid://bm2o3mex10v11"] [ext_resource type="Terrain3DAssets" uid="uid://cwl34gstabgrx" path="res://levels/debug_level/terrain_assets.res" id="1_5smdk"] [ext_resource type="Shader" path="res://src/shaders/psx_water.gdshader" id="6_0efu4"] [ext_resource type="Texture2D" uid="uid://c47ern0l2d50r" path="res://assets/vista_2.png" id="6_ectru"] [ext_resource type="Texture2D" uid="uid://con5a36t6n6sq" path="res://assets/textures/clear_sea_water_2048x2048.png" id="7_t86h2"] +[ext_resource type="Script" path="res://src/items/item_spawner.gd" id="8_5kaye"] [ext_resource type="Script" path="res://src/world/ball_zone/ball_zone.gd" id="9_jwlau"] [ext_resource type="PackedScene" uid="uid://1s3gywmoi20e" path="res://src/characters/player_characters/gfolf_girl/gfolf_girl.tscn" id="10_8tu3b"] [ext_resource type="PackedScene" uid="uid://dagh38vap4t1d" path="res://src/props/scenery/city/concrete_building_1.tscn" id="10_lf15j"] @@ -353,6 +354,29 @@ transform = Transform3D(-0.74629, 0, -0.665621, 0, 1, 0, 0.665621, 0, -0.74629, [node name="Flag" parent="Course" instance=ExtResource("13_6jtao")] transform = Transform3D(-0.777146, 0, -0.629321, 0, 1, 0, 0.629321, 0, -0.777146, 540, 4, 452) +[node name="TestSpawners" type="Node3D" parent="Course"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 228.164, 4, 274.211) + +[node name="ItemSpawner" type="Marker3D" parent="Course/TestSpawners"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -16.5034, 1.1, 12.0222) +script = ExtResource("8_5kaye") +item = ExtResource("13_ydvlu") +spawn_time = 5.0 + +[node name="ItemSpawner2" type="Marker3D" parent="Course/TestSpawners"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -14.1577, 1.1, 9.89978) +script = ExtResource("8_5kaye") +item = ExtResource("13_ydvlu") +spawn_on_ready = true +spawn_turns = 1 + +[node name="ItemSpawner3" type="Marker3D" parent="Course/TestSpawners"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -11.9586, 1.1, 7.47653) +script = ExtResource("8_5kaye") +item = ExtResource("13_ydvlu") +one_shot = true +spawn_turns = 2 + [node name="PlayerSpawn1" type="Marker3D" parent="Course" groups=["PlayerSpawn"]] transform = Transform3D(-0.842697, 0, -0.538388, 0, 1, 0, 0.538388, 0, -0.842697, 212.717, 4, 294.073) diff --git a/src/items/item/item.tscn b/src/items/item/item.tscn index 782e239..0d33b7f 100644 --- a/src/items/item/item.tscn +++ b/src/items/item/item.tscn @@ -250,7 +250,7 @@ material = SubResource("ShaderMaterial_wolv7") size = Vector2(3, 3) [sub_resource type="SphereShape3D" id="SphereShape3D_munrb"] -radius = 1.0 +radius = 2.0 [sub_resource type="Curve" id="Curve_4pwcs"] _data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(0.248421, 1), 0.0, 0.0, 0, 0, Vector2(0.549474, 0.555075), 5.83005, 5.83005, 0, 0, Vector2(0.80421, 0.232888), 7.10071, 7.10071, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] diff --git a/src/items/item_spawner.gd b/src/items/item_spawner.gd new file mode 100644 index 0000000..81886bb --- /dev/null +++ b/src/items/item_spawner.gd @@ -0,0 +1,73 @@ +class_name ItemSpawner extends Marker3D +## Entity that spawns a given item when conditions are met. + +signal item_spawned(item: Item) + +const POP_IN_TIME := 1.618 + +## Item to be spawned +@export var item: PackedScene + +@export_category("Spawn Conditions") +## Spawn an item when the tree is loaded. +@export var spawn_on_ready: bool = false + +## After spawning one item, don't spawn any more. +@export var one_shot: bool = false + +## Spawn an item after this many turns. +## 1 indicates the item should be spawned on the next turn. +## 0 indicates the item should not be spawned based on turns. +@export var spawn_turns: int = 0 + +## Spawn an item after this many seconds. +## Make sure this is long enough that a player won't just keep picking it up! +## Values < 0 indicate the item should not be spawned based on time. +@export var spawn_time: float = -1 + +var turns_to_spawn := -1 + + +func _ready() -> void: + var world: World = get_tree().get_first_node_in_group(World.group) + if world: + world.manager.turn_started.connect(_on_turn_started) + + if spawn_on_ready: + spawn() + else: + _set_spawn_conditions() + + +## Spawn the item! +## This can be called manually if an item needs complex spawning logic. +func spawn() -> void: + var instance: Item = item.instantiate() + instance.on_collect.connect(_on_item_collected) + add_child(instance) + + # Pop-in animation + instance.scale = Vector3.ZERO + var tween := create_tween() + tween.tween_property(instance, "scale", Vector3.ONE, POP_IN_TIME).set_trans(Tween.TRANS_SPRING) + + item_spawned.emit(instance) + + +func _set_spawn_conditions() -> void: + if spawn_time >= 0: + get_tree().create_timer(spawn_time).timeout.connect(spawn) + + if spawn_turns > 0: + turns_to_spawn = spawn_turns + + +func _on_item_collected(_player: WorldPlayer) -> void: + if not one_shot: + _set_spawn_conditions() + + +func _on_turn_started(_player: WorldPlayer) -> void: + turns_to_spawn -= 1 + if turns_to_spawn == 0: + spawn() diff --git a/src/player/shot_setup/ball_point.gd b/src/player/shot_setup/ball_point.gd index cb5fc45..67cea7c 100644 --- a/src/player/shot_setup/ball_point.gd +++ b/src/player/shot_setup/ball_point.gd @@ -24,9 +24,9 @@ const SCENE_MAP: Dictionary = { func get_instance(type: GameBall.Type) -> GameBall: if type in SCENE_MAP: var scene: PackedScene = SCENE_MAP.get(type) - var ball: GameBall = scene.instantiate() - ball.player = shot_setup.player - return ball + var instance: GameBall = scene.instantiate() + instance.player = shot_setup.player + return instance return null diff --git a/src/world/play_manager/play_manager.gd b/src/world/play_manager/play_manager.gd index d1e33c5..fe96f70 100644 --- a/src/world/play_manager/play_manager.gd +++ b/src/world/play_manager/play_manager.gd @@ -1,6 +1,9 @@ class_name PlayManager extends Resource ## Abstract base type for strategies to manage the flow of gameplay +## Emitted at the start of each new turn +signal turn_started(player: WorldPlayer) + ## List of game player instances @export var players: Array[WorldPlayer] = [] diff --git a/src/world/play_manager/round_robin_manager.gd b/src/world/play_manager/round_robin_manager.gd index c27f2bd..b66d404 100644 --- a/src/world/play_manager/round_robin_manager.gd +++ b/src/world/play_manager/round_robin_manager.gd @@ -11,6 +11,7 @@ func on_turn_finished(source: ShotSetup) -> void: print_debug("Shot finished for ", source.player.name) players.push_back(players.pop_front()) players[0].shot_setup.queue_restart() + turn_started.emit(players[0]) func on_player_death(player: WorldPlayer) -> void: