Added practice mode

This commit is contained in:
Rob Kelly 2024-12-19 19:48:58 -07:00
parent a5bbb098c0
commit ddef4c8736
12 changed files with 334 additions and 8 deletions

View File

@ -31,6 +31,9 @@ DM_PLAYERS,Gfolfers
DM_ADD_PLAYER,"Add a Gfolfer" DM_ADD_PLAYER,"Add a Gfolfer"
DM_NAME_PLACEHOLDER,"Enter a name" DM_NAME_PLACEHOLDER,"Enter a name"
, ,
PRACTICE_HEADING,"Practice your GFOLFing"
PRACTICE_MAP,"Select a Map"
,
PAUSE_HEADING,Paused PAUSE_HEADING,Paused
PAUSE_RESUME,Resume PAUSE_RESUME,Resume
PAUSE_SETTINGS,Settings PAUSE_SETTINGS,Settings

1 keys en
31 DM_ADD_PLAYER Add a Gfolfer
32 DM_NAME_PLACEHOLDER Enter a name
33
34 PRACTICE_HEADING Practice your GFOLFing
35 PRACTICE_MAP Select a Map
36
37 PAUSE_HEADING Paused
38 PAUSE_RESUME Resume
39 PAUSE_SETTINGS Settings

View File

@ -1,9 +1,11 @@
[gd_resource type="Resource" script_class="Level" load_steps=3 format=3 uid="uid://cfsy1nlfo4inx"] [gd_resource type="Resource" script_class="Level" load_steps=4 format=3 uid="uid://cfsy1nlfo4inx"]
[ext_resource type="PackedScene" uid="uid://x2bqqlrnno28" path="res://levels/oneill/oneill.tscn" id="1_431yv"] [ext_resource type="PackedScene" uid="uid://x2bqqlrnno28" path="res://levels/oneill/oneill.tscn" id="1_431yv"]
[ext_resource type="Texture2D" uid="uid://dlq6b8frq21o2" path="res://levels/oneill/preview.jpg" id="1_n552e"]
[ext_resource type="Script" path="res://src/world/level/level.gd" id="2_fnj1e"] [ext_resource type="Script" path="res://src/world/level/level.gd" id="2_fnj1e"]
[resource] [resource]
script = ExtResource("2_fnj1e") script = ExtResource("2_fnj1e")
scene = ExtResource("1_431yv") scene = ExtResource("1_431yv")
level_name = "MAP_ONEILL" level_name = "MAP_ONEILL"
preview = ExtResource("1_n552e")

BIN
levels/oneill/preview.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dlq6b8frq21o2"
path="res://.godot/imported/preview.jpg-15d3a679d46e9934ca032ccdfbdfe6af.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://levels/oneill/preview.jpg"
dest_files=["res://.godot/imported/preview.jpg-15d3a679d46e9934ca032ccdfbdfe6af.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View File

@ -119,7 +119,6 @@ _data = {
[node name="Game" type="Node" groups=["GameGroup"]] [node name="Game" type="Node" groups=["GameGroup"]]
process_mode = 3 process_mode = 3
script = ExtResource("1_4qa87") script = ExtResource("1_4qa87")
start_scene = "res://src/world/world.tscn"
[node name="RootControl" type="Control" parent="."] [node name="RootControl" type="Control" parent="."]
unique_name_in_owner = true unique_name_in_owner = true

View File

@ -1,7 +1,5 @@
extends PanelContainer extends PanelContainer
const WORLD_SCENE_PATH := "res://src/world/world.tscn"
const RANDOM_PLAYER_COLORS := [ const RANDOM_PLAYER_COLORS := [
Color.LIGHT_CORAL, Color.LIGHT_CORAL,
Color.GOLDENROD, Color.GOLDENROD,
@ -54,7 +52,7 @@ func start() -> void:
world.manager = RoundRobinManager.new() world.manager = RoundRobinManager.new()
world.manager.players = player_list world.manager.players = player_list
world.initial_level = level.scene world.initial_level = level.scene
game.queue_scene(WORLD_SCENE_PATH).then(init_world) game.queue_scene(World.SCENE).then(init_world)
## Returns the `Level` selected by the user if there is one, or `null` if no level is selected. ## Returns the `Level` selected by the user if there is one, or `null` if no level is selected.

View File

@ -0,0 +1,55 @@
extends PanelContainer
@export var practice_player: WorldPlayer
@onready var map_select: ItemList = %MapSelect
@onready var start_button: Button = %Start
@onready var game: Game = get_tree().get_first_node_in_group(Game.group)
func play_chime() -> void:
game.sfx.chime.play()
func _ready() -> void:
# Populate map selection
for level: Level in Level.catalog.levels:
map_select.add_item(level.level_name, level.preview)
check_start_conditions()
## Close menu without starting game.
func cancel() -> void:
queue_free()
## Start with the current game configuration.
func start() -> void:
var manager := PracticeManager.new()
manager.players = [practice_player]
var level := selected_level()
var init_world := func(world: World) -> void:
world.manager = manager
world.initial_level = level.scene
game.queue_scene(World.SCENE).then(init_world)
## Returns the `Level` selected by the user if there is one, or `null` if no level is selected.
func selected_level() -> Level:
var selections := map_select.get_selected_items()
if selections:
return Level.catalog.levels[selections[0]]
return null
func _can_start() -> bool:
return selected_level() != null
## Check if the game can be started with the current selection,
## and set the start button status appropriately.
func check_start_conditions() -> void:
start_button.disabled = not _can_start()

View File

@ -0,0 +1,197 @@
[gd_scene load_steps=11 format=3 uid="uid://5soelwtn4v34"]
[ext_resource type="Script" path="res://src/ui/menus/title_screen/practice_setup/practice_setup.gd" id="1_jgggo"]
[ext_resource type="Resource" uid="uid://c1pnqsddvey3m" path="res://src/equipment/clubs/drivers/debug_driver.tres" id="2_47376"]
[ext_resource type="Resource" uid="uid://ck17u5yn6k0bi" path="res://src/equipment/clubs/irons/debug_iron.tres" id="3_veaoo"]
[ext_resource type="Resource" uid="uid://dagld0q5krapu" path="res://src/equipment/clubs/putters/debug_putter.tres" id="4_mixgr"]
[ext_resource type="Script" path="res://src/player/world_player.gd" id="5_btf7p"]
[ext_resource type="Resource" uid="uid://dthtc1no2c4wy" path="res://src/equipment/clubs/wedges/debug_wedge.tres" id="6_8yfm7"]
[sub_resource type="Resource" id="Resource_4ls7o"]
script = ExtResource("5_btf7p")
life = 100.0
name = "Practice Gfolfer"
color = Color(0.955, 0.7, 1, 1)
driver = ExtResource("2_47376")
iron = ExtResource("3_veaoo")
wedge = ExtResource("6_8yfm7")
putter = ExtResource("4_mixgr")
_balls = {
1: -1,
2: -1,
3: -1,
4: -1,
5: -1
}
[sub_resource type="Animation" id="Animation_x4wqc"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:disabled")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [false]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath(".:modulate")
tracks/1/interp = 2
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Color(1, 1, 1, 1)]
}
[sub_resource type="Animation" id="Animation_560ro"]
resource_name = "fade_out"
length = 0.6
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:modulate")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.0666667, 0.133333, 0.2, 0.266667, 0.333333, 0.4, 0.466667, 0.533333, 0.6),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 0), Color(1, 1, 1, 0.5), Color(1, 1, 1, 0), Color(1, 1, 1, 0.25), Color(1, 1, 1, 0), Color(1, 1, 1, 0.125), Color(1, 1, 1, 0)]
}
tracks/1/type = "method"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("../../..")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.6),
"transitions": PackedFloat32Array(1, 1),
"values": [{
"args": [],
"method": &"play_chime"
}, {
"args": [],
"method": &"start"
}]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath(".:disabled")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [true]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_s1eyj"]
_data = {
"RESET": SubResource("Animation_x4wqc"),
"fade_out": SubResource("Animation_560ro")
}
[node name="PracticeSetup" type="PanelContainer"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_jgggo")
practice_player = SubResource("Resource_4ls7o")
[node name="MarginContainer" type="MarginContainer" parent="."]
layout_mode = 2
theme_override_constants/margin_left = 32
theme_override_constants/margin_top = 32
theme_override_constants/margin_right = 32
theme_override_constants/margin_bottom = 80
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
theme_type_variation = &"HeaderXLarge"
text = "PRACTICE_HEADING"
[node name="MapSelectContainer" type="PanelContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/MapSelectContainer"]
layout_mode = 2
theme_override_constants/margin_left = 16
theme_override_constants/margin_top = 16
theme_override_constants/margin_right = 16
theme_override_constants/margin_bottom = 16
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/MapSelectContainer/MarginContainer"]
layout_mode = 2
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer/MapSelectContainer/MarginContainer/VBoxContainer"]
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/MapSelectContainer/MarginContainer/VBoxContainer/HBoxContainer"]
layout_mode = 2
theme_type_variation = &"HeaderLarge"
text = "PRACTICE_MAP"
[node name="HSeparator" type="HSeparator" parent="MarginContainer/VBoxContainer/MapSelectContainer/MarginContainer/VBoxContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="MapSelect" type="ItemList" parent="MarginContainer/VBoxContainer/MapSelectContainer/MarginContainer/VBoxContainer"]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 130)
layout_mode = 2
size_flags_vertical = 3
theme_override_constants/v_separation = 32
theme_override_constants/h_separation = 32
max_columns = 8
icon_mode = 0
fixed_icon_size = Vector2i(64, 64)
[node name="SouthEast" type="MarginContainer" parent="."]
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 8
theme_override_constants/margin_left = 16
theme_override_constants/margin_top = 16
theme_override_constants/margin_right = 32
theme_override_constants/margin_bottom = 16
[node name="HBoxContainer" type="HBoxContainer" parent="SouthEast"]
layout_mode = 2
theme_override_constants/separation = 16
[node name="Cancel" type="Button" parent="SouthEast/HBoxContainer"]
layout_mode = 2
theme_type_variation = &"CancelButton"
text = "UI_CANCEL"
[node name="Start" type="Button" parent="SouthEast/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
theme_type_variation = &"AlertButton"
text = "UI_START"
[node name="AnimationPlayer" type="AnimationPlayer" parent="SouthEast/HBoxContainer/Start"]
libraries = {
"": SubResource("AnimationLibrary_s1eyj")
}
[connection signal="item_selected" from="MarginContainer/VBoxContainer/MapSelectContainer/MarginContainer/VBoxContainer/MapSelect" to="." method="check_start_conditions" unbinds=1]
[connection signal="pressed" from="SouthEast/HBoxContainer/Cancel" to="." method="cancel"]
[connection signal="pressed" from="SouthEast/HBoxContainer/Start" to="SouthEast/HBoxContainer/Start/AnimationPlayer" method="play" binds= ["fade_out"]]

View File

@ -5,6 +5,7 @@ const SCENE := "res://src/ui/menus/title_screen/title_screen.tscn"
@export var title_crawl_scene: PackedScene @export var title_crawl_scene: PackedScene
@export var settings_scene: PackedScene @export var settings_scene: PackedScene
@export var local_deathmatch_setup_scene: PackedScene @export var local_deathmatch_setup_scene: PackedScene
@export var practice_setup_scene: PackedScene
@onready var menu: Control = %Menu @onready var menu: Control = %Menu
@onready var settings_container: MarginContainer = %SettingsContainer @onready var settings_container: MarginContainer = %SettingsContainer
@ -84,3 +85,10 @@ func _open_local_deathmatch_setup() -> void:
deathmatch_setup_container.add_child(instance) deathmatch_setup_container.add_child(instance)
instance.tree_exited.connect(_unhide) instance.tree_exited.connect(_unhide)
_hide() _hide()
func _open_practice_setup() -> void:
var instance: Control = practice_setup_scene.instantiate()
deathmatch_setup_container.add_child(instance)
instance.tree_exited.connect(_unhide)
_hide()

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=86 format=3 uid="uid://7fsgocmdas7i"] [gd_scene load_steps=87 format=3 uid="uid://7fsgocmdas7i"]
[ext_resource type="Script" path="res://src/ui/menus/title_screen/title_screen.gd" id="1_2qtlb"] [ext_resource type="Script" path="res://src/ui/menus/title_screen/title_screen.gd" id="1_2qtlb"]
[ext_resource type="Texture2D" uid="uid://880x5n8j3b5l" path="res://assets/logo/title.png" id="1_pm82i"] [ext_resource type="Texture2D" uid="uid://880x5n8j3b5l" path="res://assets/logo/title.png" id="1_pm82i"]
@ -6,6 +6,7 @@
[ext_resource type="Texture2D" uid="uid://clesl8lljs6of" path="res://assets/logo/subtitle.png" id="2_y0ulk"] [ext_resource type="Texture2D" uid="uid://clesl8lljs6of" path="res://assets/logo/subtitle.png" id="2_y0ulk"]
[ext_resource type="PackedScene" uid="uid://ccx2u5oli6men" path="res://src/ui/menus/title_screen/deathmatch_setup/deathmatch_setup.tscn" id="3_bo4ty"] [ext_resource type="PackedScene" uid="uid://ccx2u5oli6men" path="res://src/ui/menus/title_screen/deathmatch_setup/deathmatch_setup.tscn" id="3_bo4ty"]
[ext_resource type="Material" uid="uid://dpsmjlhjpc7vs" path="res://assets/materials/basic_ball_material.tres" id="5_5q83g"] [ext_resource type="Material" uid="uid://dpsmjlhjpc7vs" path="res://assets/materials/basic_ball_material.tres" id="5_5q83g"]
[ext_resource type="PackedScene" uid="uid://5soelwtn4v34" path="res://src/ui/menus/title_screen/practice_setup/practice_setup.tscn" id="5_hws1o"]
[ext_resource type="PackedScene" uid="uid://cqu315hviu72n" path="res://src/ui/menus/title_screen/title_crawl.tscn" id="7_r26eu"] [ext_resource type="PackedScene" uid="uid://cqu315hviu72n" path="res://src/ui/menus/title_screen/title_crawl.tscn" id="7_r26eu"]
[sub_resource type="Environment" id="Environment_ardux"] [sub_resource type="Environment" id="Environment_ardux"]
@ -1362,6 +1363,7 @@ script = ExtResource("1_2qtlb")
title_crawl_scene = ExtResource("7_r26eu") title_crawl_scene = ExtResource("7_r26eu")
settings_scene = ExtResource("2_g5q2v") settings_scene = ExtResource("2_g5q2v")
local_deathmatch_setup_scene = ExtResource("3_bo4ty") local_deathmatch_setup_scene = ExtResource("3_bo4ty")
practice_setup_scene = ExtResource("5_hws1o")
[node name="SceneRoot" type="Node3D" parent="."] [node name="SceneRoot" type="Node3D" parent="."]
@ -1480,7 +1482,7 @@ grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
[node name="PressStart" type="Label" parent="Menu"] [node name="PressStart" type="Label" parent="Menu"]
modulate = Color(1, 1, 1, 0.850113) modulate = Color(1, 1, 1, 0.936746)
layout_mode = 1 layout_mode = 1
anchors_preset = 8 anchors_preset = 8
anchor_left = 0.5 anchor_left = 0.5
@ -1576,7 +1578,6 @@ text = "TITLE_ROGUELIKE"
[node name="Practice" type="Button" parent="Menu/SingleplayerMenu"] [node name="Practice" type="Button" parent="Menu/SingleplayerMenu"]
layout_mode = 2 layout_mode = 2
theme_type_variation = &"PauseMenuButton" theme_type_variation = &"PauseMenuButton"
disabled = true
text = "TITLE_PRACTICE" text = "TITLE_PRACTICE"
[node name="Back" type="Button" parent="Menu/SingleplayerMenu"] [node name="Back" type="Button" parent="Menu/SingleplayerMenu"]
@ -1743,6 +1744,7 @@ autostart = true
[connection signal="pressed" from="Menu/MainMenu/MultiPlayer" to="." method="_to_multi_player"] [connection signal="pressed" from="Menu/MainMenu/MultiPlayer" to="." method="_to_multi_player"]
[connection signal="pressed" from="Menu/MainMenu/Settings" to="." method="_open_settings"] [connection signal="pressed" from="Menu/MainMenu/Settings" to="." method="_open_settings"]
[connection signal="pressed" from="Menu/MainMenu/Quit" to="Menu/MainMenu/Quit/AnimationPlayer" method="play" binds= ["fade_out"]] [connection signal="pressed" from="Menu/MainMenu/Quit" to="Menu/MainMenu/Quit/AnimationPlayer" method="play" binds= ["fade_out"]]
[connection signal="pressed" from="Menu/SingleplayerMenu/Practice" to="." method="_open_practice_setup"]
[connection signal="pressed" from="Menu/SingleplayerMenu/Back" to="." method="_to_main_menu"] [connection signal="pressed" from="Menu/SingleplayerMenu/Back" to="." method="_to_main_menu"]
[connection signal="pressed" from="Menu/MultiplayerMenu/LocalMultiplayer" to="." method="_to_local_multi"] [connection signal="pressed" from="Menu/MultiplayerMenu/LocalMultiplayer" to="." method="_to_local_multi"]
[connection signal="pressed" from="Menu/MultiplayerMenu/NetMultiplayer" to="." method="_to_network_multi"] [connection signal="pressed" from="Menu/MultiplayerMenu/NetMultiplayer" to="." method="_to_network_multi"]

View File

@ -0,0 +1,23 @@
class_name PracticeManager extends PlayManager
## A single player can just kind of chill out and vibe...
var player: WorldPlayer:
get:
return players[0]
set(value):
players[0] = value
func on_initialization() -> void:
# Set first player as active
player.shot_setup.phase = ShotSetup.Phase.AIM
func on_turn_finished(source: ShotSetup) -> void:
player.shot_setup.queue_restart()
turn_started.emit(player)
func on_player_death(player: WorldPlayer) -> void:
# TODO game over screen
winner.emit(player)

View File

@ -4,6 +4,8 @@ class_name World extends Node
## A world contains player(s) and the active level, manages player states, ## A world contains player(s) and the active level, manages player states,
## and transitions between active levels. ## and transitions between active levels.
const SCENE := "res://src/world/world.tscn"
@export var initial_level: PackedScene @export var initial_level: PackedScene
@export var manager: PlayManager @export var manager: PlayManager