diff --git a/assets/textures/grass_fairway/grass_fairway.png.import b/assets/textures/grass_fairway/grass_fairway.png.import index afa3313..2b721e3 100644 --- a/assets/textures/grass_fairway/grass_fairway.png.import +++ b/assets/textures/grass_fairway/grass_fairway.png.import @@ -3,20 +3,19 @@ importer="texture" type="CompressedTexture2D" uid="uid://dr7so4lvqiftc" -path.s3tc="res://.godot/imported/grass_fairway.png-c6748aa9af191257973d3e582b17c659.s3tc.ctex" +path="res://.godot/imported/grass_fairway.png-c6748aa9af191257973d3e582b17c659.ctex" metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true +"vram_texture": false } [deps] source_file="res://assets/textures/grass_fairway/grass_fairway.png" -dest_files=["res://.godot/imported/grass_fairway.png-c6748aa9af191257973d3e582b17c659.s3tc.ctex"] +dest_files=["res://.godot/imported/grass_fairway.png-c6748aa9af191257973d3e582b17c659.ctex"] [params] -compress/mode=2 +compress/mode=0 compress/high_quality=false compress/lossy_quality=0.7 compress/hdr_compression=1 diff --git a/project.godot b/project.godot index 2c81295..022c1d2 100644 --- a/project.godot +++ b/project.godot @@ -21,6 +21,7 @@ run/max_fps=60 GameRuntime="*res://src/game/game_runtime.gd" ClubCatalog="*res://src/equipment/clubs/club_catalog.tscn" +CharacterCatalog="*res://src/characters/player_characters/character/character_catalog.tscn" LevelCatalog="*res://src/world/level/level_catalog.tscn" GameSettings="*res://src/game/game_settings.gd" diff --git a/src/characters/player_characters/character/character.gd b/src/characters/player_characters/character/character.gd new file mode 100644 index 0000000..32498c9 --- /dev/null +++ b/src/characters/player_characters/character/character.gd @@ -0,0 +1,13 @@ +class_name Character extends Resource +## Container for a playable character scene & associated data. + +## Scene file of this character's controller. +@export var controller_scene: PackedScene + +## Human-readable name of the character (or corresponding i18n key) +@export var name: String + +## Global typesafe accessor for character catalog +static var catalog: CharacterCatalogType: + get: + return CharacterCatalog diff --git a/src/characters/player_characters/character/character_catalog.gd b/src/characters/player_characters/character/character_catalog.gd new file mode 100644 index 0000000..ff3e9d3 --- /dev/null +++ b/src/characters/player_characters/character/character_catalog.gd @@ -0,0 +1,4 @@ +class_name CharacterCatalogType extends Node +## Provides access to levels. + +@export var characters: Array[Character] diff --git a/src/characters/player_characters/character/character_catalog.tscn b/src/characters/player_characters/character/character_catalog.tscn new file mode 100644 index 0000000..27b66a3 --- /dev/null +++ b/src/characters/player_characters/character/character_catalog.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=4 format=3 uid="uid://c3at6645rg8i3"] + +[ext_resource type="Script" path="res://src/characters/player_characters/character/character_catalog.gd" id="1_lnhxq"] +[ext_resource type="Script" path="res://src/characters/player_characters/character/character.gd" id="2_ct428"] +[ext_resource type="Resource" uid="uid://dy2f0k6edrixe" path="res://src/characters/player_characters/gfolf_girl/debug_girl.tres" id="3_djrp2"] + +[node name="CharacterCatalog" type="Node"] +script = ExtResource("1_lnhxq") +characters = Array[ExtResource("2_ct428")]([ExtResource("3_djrp2")]) diff --git a/src/characters/player_characters/gfolf_girl/debug_girl.tres b/src/characters/player_characters/gfolf_girl/debug_girl.tres new file mode 100644 index 0000000..3748877 --- /dev/null +++ b/src/characters/player_characters/gfolf_girl/debug_girl.tres @@ -0,0 +1,9 @@ +[gd_resource type="Resource" script_class="Character" load_steps=3 format=3 uid="uid://dy2f0k6edrixe"] + +[ext_resource type="PackedScene" uid="uid://1s3gywmoi20e" path="res://src/characters/player_characters/gfolf_girl/gfolf_girl.tscn" id="1_m8n4f"] +[ext_resource type="Script" path="res://src/characters/player_characters/character/character.gd" id="2_rx8x8"] + +[resource] +script = ExtResource("2_rx8x8") +controller_scene = ExtResource("1_m8n4f") +name = "Debug Girl" diff --git a/src/shaders/backdrop_sky.gdshader b/src/shaders/backdrop_sky.gdshader new file mode 100644 index 0000000..7e4594e --- /dev/null +++ b/src/shaders/backdrop_sky.gdshader @@ -0,0 +1,17 @@ +shader_type sky; + +uniform sampler2D backdrop: filter_nearest_mipmap_anisotropic; + +uniform vec3 cubemap_color: source_color = vec3(1.0); + +uniform vec2 uv_offset = vec2(0.0); +uniform vec2 uv_scale = vec2(1.0); + +void sky() { + if (AT_CUBEMAP_PASS) { + COLOR = cubemap_color; + } else { + vec2 uv_mapped = SCREEN_UV * uv_scale + uv_offset; + COLOR = texture(backdrop, uv_mapped).rgb; + } +} diff --git a/src/ui/menus/pause_menu/pause_menu.tscn b/src/ui/menus/pause_menu/pause_menu.tscn index 3037a76..a6ebf7b 100644 --- a/src/ui/menus/pause_menu/pause_menu.tscn +++ b/src/ui/menus/pause_menu/pause_menu.tscn @@ -4,6 +4,33 @@ [ext_resource type="Script" path="res://src/ui/menus/pause_menu/pause_menu.gd" id="1_rd0j2"] [ext_resource type="PackedScene" uid="uid://d3eaqw2rdurct" path="res://src/ui/menus/settings_menu/settings_menu.tscn" id="2_kjr35"] +[sub_resource type="Animation" id="Animation_qmmn2"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("TransitionAnimation/TransitionShade:color") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(0, 0, 0, 0)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("TransitionAnimation/TransitionShade:visible") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [false] +} + [sub_resource type="Animation" id="Animation_rq4bw"] resource_name = "fade_to_black" length = 0.6 @@ -46,33 +73,6 @@ tracks/2/keys = { "values": [true] } -[sub_resource type="Animation" id="Animation_qmmn2"] -length = 0.001 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath("TransitionAnimation/TransitionShade:color") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Color(0, 0, 0, 0)] -} -tracks/1/type = "value" -tracks/1/imported = false -tracks/1/enabled = true -tracks/1/path = NodePath("TransitionAnimation/TransitionShade:visible") -tracks/1/interp = 1 -tracks/1/loop_wrap = true -tracks/1/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [false] -} - [sub_resource type="AnimationLibrary" id="AnimationLibrary_7b7fo"] _data = { "RESET": SubResource("Animation_qmmn2"), diff --git a/src/ui/menus/title_screen/deathmatch_setup/player_setup/player_setup.gd b/src/ui/menus/title_screen/deathmatch_setup/player_setup/player_setup.gd index 74bd205..0e7ebfd 100644 --- a/src/ui/menus/title_screen/deathmatch_setup/player_setup/player_setup.gd +++ b/src/ui/menus/title_screen/deathmatch_setup/player_setup/player_setup.gd @@ -13,18 +13,26 @@ const DEFAULT_PLAYER_BALLS := { @export var player_name: String: set(value): - await ready + if not is_instance_valid(name_input): + await ready name_input.text = value get: return name_input.text @export var player_color: Color: set(value): - await ready + if not is_instance_valid(color_input): + await ready color_input.color = value + color_input.color_changed.emit(value) get: return color_input.color +var character_controller: CharacterController + +var selected_character_index := 0: + set = _set_selected_character_index + @onready var keyboard_symbol: Label = %KeyboardSymbol @onready var gamepad_symbol: Label = %GamepadSymbol @onready var sony_symbol: Label = %SonySymbol @@ -32,10 +40,18 @@ const DEFAULT_PLAYER_BALLS := { @onready var name_input: LineEdit = %Name @onready var color_input: ColorPickerButton = %Color @onready var char_name: Label = %CharName +@onready var character_container: Node3D = %CharacterContainer + +# TODO genericize for selectable characters + + +func _ready() -> void: + selected_character_index = selected_character_index func _set_input_method(value: InputMethod.Type) -> void: - await ready + if not is_instance_valid(keyboard_symbol): + await ready keyboard_symbol.hide() gamepad_symbol.hide() sony_symbol.hide() @@ -54,6 +70,32 @@ func _set_input_method(value: InputMethod.Type) -> void: input_method = value +func _set_selected_character_index(value: int) -> void: + selected_character_index = wrapi(value, 0, len(Character.catalog.characters)) + + # Remove any existing character preview + for child: Node in character_container.get_children(): + child.queue_free() + + # Get new character and instantiate preview + character_controller = get_selected_character().controller_scene.instantiate() + + character_container.add_child(character_controller) + character_controller.set_color(player_color) + + +func get_selected_character() -> Character: + return Character.catalog.characters[selected_character_index] + + +func select_next_character() -> void: + selected_character_index += 1 + + +func select_previous_character() -> void: + selected_character_index -= 1 + + ## Build a `WorldPlayer` representing the selections made here. func build_player() -> WorldPlayer: var player := WorldPlayer.new() @@ -71,6 +113,8 @@ func build_player() -> WorldPlayer: # TODO ball selection maybe? player._balls = DEFAULT_PLAYER_BALLS.duplicate(true) + # TODO set character selection + # TODO set input method return player @@ -78,3 +122,8 @@ func build_player() -> WorldPlayer: func _on_remove_button_pressed() -> void: queue_free() + + +func _on_color_changed(color: Color) -> void: + if character_controller: + character_controller.set_color(color) diff --git a/src/ui/menus/title_screen/deathmatch_setup/player_setup/player_setup.tscn b/src/ui/menus/title_screen/deathmatch_setup/player_setup/player_setup.tscn index 1c8602d..edbc271 100644 --- a/src/ui/menus/title_screen/deathmatch_setup/player_setup/player_setup.tscn +++ b/src/ui/menus/title_screen/deathmatch_setup/player_setup/player_setup.tscn @@ -1,6 +1,76 @@ -[gd_scene load_steps=2 format=3 uid="uid://cr13d4p235b5y"] +[gd_scene load_steps=12 format=3 uid="uid://cr13d4p235b5y"] [ext_resource type="Script" path="res://src/ui/menus/title_screen/deathmatch_setup/player_setup/player_setup.gd" id="1_l1wxd"] +[ext_resource type="PackedScene" uid="uid://1s3gywmoi20e" path="res://src/characters/player_characters/gfolf_girl/gfolf_girl.tscn" id="2_mj4s7"] +[ext_resource type="Shader" path="res://src/shaders/backdrop_sky.gdshader" id="2_nak5u"] + +[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_lhni8"] +load_path = "res://.godot/imported/grass_fairway.png-c6748aa9af191257973d3e582b17c659.ctex" + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_8q2ni"] +shader = ExtResource("2_nak5u") +shader_parameter/cubemap_color = Color(1, 1, 1, 1) +shader_parameter/uv_offset = Vector2(0, 0) +shader_parameter/uv_scale = Vector2(1, 1.391) +shader_parameter/backdrop = SubResource("CompressedTexture2D_lhni8") + +[sub_resource type="Sky" id="Sky_nw57n"] +sky_material = SubResource("ShaderMaterial_8q2ni") + +[sub_resource type="Environment" id="Environment_7vrth"] +background_mode = 2 +sky = SubResource("Sky_nw57n") +ambient_light_source = 2 +ambient_light_color = Color(1, 1, 1, 1) +ssao_enabled = true +ssao_intensity = 1.7 +glow_bloom = 0.05 +volumetric_fog_enabled = true +volumetric_fog_density = 0.001 +volumetric_fog_emission = Color(0.6, 1, 1, 1) +volumetric_fog_length = 1024.0 +volumetric_fog_sky_affect = 0.0 + +[sub_resource type="World3D" id="World3D_u3xql"] +environment = SubResource("Environment_7vrth") + +[sub_resource type="Animation" id="Animation_peo4y"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:rotation") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector3(0, 0, 0)] +} + +[sub_resource type="Animation" id="Animation_sdxcw"] +resource_name = "rotate" +length = 16.0 +loop_mode = 1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:rotation") +tracks/0/interp = 1 +tracks/0/loop_wrap = false +tracks/0/keys = { +"times": PackedFloat32Array(0, 16), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector3(0, 0, 0), Vector3(0, 6.28319, 0)] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_ltul5"] +_data = { +"RESET": SubResource("Animation_peo4y"), +"rotate": SubResource("Animation_sdxcw") +} [node name="PlayerSetup" type="PanelContainer"] custom_minimum_size = Vector2(400, 0) @@ -65,17 +135,21 @@ theme_type_variation = &"IconXL" text = "⑂" horizontal_alignment = 1 -[node name="Name" type="LineEdit" parent="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer"] +[node name="NameAndColor" type="HBoxContainer" parent="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="Name" type="LineEdit" parent="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer/NameAndColor"] unique_name_in_owner = true layout_mode = 2 +size_flags_horizontal = 3 theme_type_variation = &"PlayerNameInput" text = "Gfolfer" placeholder_text = "DM_NAME_PLACEHOLDER" alignment = 1 -[node name="Color" type="ColorPickerButton" parent="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer"] +[node name="Color" type="ColorPickerButton" parent="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer/NameAndColor"] unique_name_in_owner = true -custom_minimum_size = Vector2(0, 64) +custom_minimum_size = Vector2(64, 64) layout_mode = 2 edit_alpha = false @@ -86,6 +160,8 @@ layout_mode = 2 layout_mode = 2 [node name="SubViewport" type="SubViewport" parent="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer/CharacterSelectContainer/SubViewportContainer"] +own_world_3d = true +world_3d = SubResource("World3D_u3xql") handle_input_locally = false msaa_3d = 3 screen_space_aa = 1 @@ -94,6 +170,27 @@ use_debanding = true size = Vector2i(368, 512) render_target_update_mode = 4 +[node name="CharacterPreview" type="Node3D" parent="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer/CharacterSelectContainer/SubViewportContainer/SubViewport"] + +[node name="CharacterPivot" type="Node3D" parent="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer/CharacterSelectContainer/SubViewportContainer/SubViewport/CharacterPreview"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.75, 0) + +[node name="CharacterContainer" type="Node3D" parent="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer/CharacterSelectContainer/SubViewportContainer/SubViewport/CharacterPreview/CharacterPivot"] +unique_name_in_owner = true +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.365) + +[node name="GfolfGirl" parent="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer/CharacterSelectContainer/SubViewportContainer/SubViewport/CharacterPreview/CharacterPivot/CharacterContainer" instance=ExtResource("2_mj4s7")] +unique_name_in_owner = true + +[node name="AnimationPlayer" type="AnimationPlayer" parent="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer/CharacterSelectContainer/SubViewportContainer/SubViewport/CharacterPreview/CharacterPivot"] +libraries = { +"": SubResource("AnimationLibrary_ltul5") +} +autoplay = "rotate" + +[node name="Camera3D" type="Camera3D" parent="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer/CharacterSelectContainer/SubViewportContainer/SubViewport/CharacterPreview"] +transform = Transform3D(0.999889, 0.00165718, -0.0147791, 0, 0.993772, 0.111432, 0.0148717, -0.11142, 0.993662, -0.0147003, 0.232996, 1.68475) + [node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer/CharacterSelectContainer"] layout_mode = 2 @@ -126,4 +223,7 @@ theme_override_colors/font_color = Color(0.819608, 0.196078, 0.196078, 1) text = "✗" flat = true +[connection signal="color_changed" from="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer/NameAndColor/Color" to="." method="_on_color_changed"] +[connection signal="pressed" from="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer/CharacterSelectContainer/HBoxContainer/PrevCharButton" to="." method="select_next_character"] +[connection signal="pressed" from="MarginContainer/ScrollContainer/MarginContainer/VBoxContainer/CharacterSelectContainer/HBoxContainer/NextCharButton" to="." method="select_previous_character"] [connection signal="pressed" from="MarginContainer/ScrollContainer/MarginContainer/RemoveButton" to="." method="_on_remove_button_pressed"]