Add modular character customization
This commit is contained in:
parent
70d6205ec1
commit
2bcb4a3c93
34 changed files with 761 additions and 76 deletions
|
|
@ -227,6 +227,8 @@ func setup(
|
|||
world_time: WorldTimeServiceType,
|
||||
world_weather: WorldWeatherServiceType,
|
||||
player_jobs: PlayerJobService,
|
||||
world_environment: WorldEnvironment,
|
||||
world_sun: DirectionalLight3D,
|
||||
) -> void:
|
||||
_player = player
|
||||
_fishing_spot = fishing_spot
|
||||
|
|
@ -285,6 +287,8 @@ func setup(
|
|||
network_player_list,
|
||||
player_jobs,
|
||||
world_time,
|
||||
world_environment,
|
||||
world_sun,
|
||||
)
|
||||
_hotbar_ui.setup(hotbar, bag, item_catalog, fishing_spot, inventory)
|
||||
_fishing_shop.setup(
|
||||
|
|
|
|||
|
|
@ -508,6 +508,8 @@ func setup(
|
|||
network_player_list: NetworkPlayerListService,
|
||||
player_jobs: PlayerJobService,
|
||||
world_time: WorldTimeService,
|
||||
world_environment: WorldEnvironment,
|
||||
world_sun: DirectionalLight3D,
|
||||
) -> void:
|
||||
_player = player
|
||||
_inventory = inventory
|
||||
|
|
@ -530,7 +532,12 @@ func setup(
|
|||
_mail_page.setup(
|
||||
network_mail_service, reservations, inventory, wallet, bag, item_catalog
|
||||
)
|
||||
_profile_page.setup(network_profile_service, experience)
|
||||
_profile_page.setup(
|
||||
network_profile_service,
|
||||
experience,
|
||||
world_environment,
|
||||
world_sun,
|
||||
)
|
||||
_players_page.setup(network_player_list)
|
||||
_catalog_logbook.setup(collection_log, inventory, catalog)
|
||||
_the_net_page.setup(player_jobs, world_time)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ var _revert_button: Button
|
|||
var _discard_confirmation: PanelContainer
|
||||
var _confirmation_label: Label
|
||||
var _confirmation_confirm: Button
|
||||
var _keep_editing_button: Button
|
||||
var _confirmation_action: String = ""
|
||||
var _debounce: Timer
|
||||
var _experience_level: Label
|
||||
|
|
@ -47,6 +48,8 @@ func _ready() -> void:
|
|||
func setup(
|
||||
service: NetworkProfileService,
|
||||
experience: PlayerExperience,
|
||||
world_environment: WorldEnvironment,
|
||||
world_sun: DirectionalLight3D,
|
||||
) -> void:
|
||||
_service = service
|
||||
_experience = experience
|
||||
|
|
@ -62,6 +65,7 @@ func setup(
|
|||
_experience.experience_changed.connect(_on_experience_changed)
|
||||
_load_persisted()
|
||||
_refresh_experience()
|
||||
_preview.setup_world_lighting(world_environment, world_sun)
|
||||
var identity_value := find_child("IdentityFingerprint", true, false) as Label
|
||||
if identity_value != null:
|
||||
var fingerprint := _service.get_identity_fingerprint()
|
||||
|
|
@ -344,16 +348,14 @@ func _build_ui() -> void:
|
|||
_confirmation_confirm.pressed.connect(_confirm_pending_action)
|
||||
UtilityPageStyle.apply_ocean_button(_confirmation_confirm)
|
||||
confirm_buttons.add_child(_confirmation_confirm)
|
||||
var keep := Button.new()
|
||||
keep.name = "KeepEditing"
|
||||
keep.unique_name_in_owner = true
|
||||
keep.text = "keep editing"
|
||||
keep.pressed.connect(func() -> void:
|
||||
_keep_editing_button = Button.new()
|
||||
_keep_editing_button.text = "keep editing"
|
||||
_keep_editing_button.pressed.connect(func() -> void:
|
||||
_discard_confirmation.visible = false
|
||||
_name_edit.grab_focus()
|
||||
)
|
||||
UtilityPageStyle.apply_ocean_button(keep)
|
||||
confirm_buttons.add_child(keep)
|
||||
UtilityPageStyle.apply_ocean_button(_keep_editing_button)
|
||||
confirm_buttons.add_child(_keep_editing_button)
|
||||
|
||||
_build_categories()
|
||||
|
||||
|
|
@ -394,13 +396,16 @@ func _refresh_options() -> void:
|
|||
"font_color", UtilityPageStyle.OCEAN_TEXT_PRIMARY
|
||||
)
|
||||
_option_list.add_child(title)
|
||||
var options := CharacterCustomizationCatalog.options_for(_category_id)
|
||||
var options: Array = CharacterCustomizationCatalog.options_for(_category_id)
|
||||
if options.is_empty():
|
||||
var empty := Label.new()
|
||||
empty.text = "More options coming later."
|
||||
empty.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
_option_list.add_child(empty)
|
||||
return
|
||||
if _category_id == "fur_pattern":
|
||||
_build_fur_color_options(options)
|
||||
return
|
||||
for option: Dictionary in options:
|
||||
var option_id := str(option["id"])
|
||||
var button := Button.new()
|
||||
|
|
@ -413,6 +418,49 @@ func _refresh_options() -> void:
|
|||
_option_list.add_child(button)
|
||||
|
||||
|
||||
func _build_fur_color_options(options: Array) -> void:
|
||||
var grid := GridContainer.new()
|
||||
grid.columns = 4
|
||||
grid.add_theme_constant_override("h_separation", 10)
|
||||
grid.add_theme_constant_override("v_separation", 10)
|
||||
_option_list.add_child(grid)
|
||||
var selected_id: String = CharacterCustomizationCatalog.canonical_option_id(
|
||||
"fur_pattern", str(_draft_appearance.get("fur_pattern", "white"))
|
||||
)
|
||||
for option: Dictionary in options:
|
||||
var option_id: String = str(option.get("id", ""))
|
||||
var color: Color = CharacterCustomizationCatalog.option_color(
|
||||
"fur_pattern", option_id
|
||||
)
|
||||
var button := Button.new()
|
||||
button.text = ""
|
||||
button.tooltip_text = str(option.get("label", option_id))
|
||||
button.toggle_mode = true
|
||||
button.custom_minimum_size = Vector2(44.0, 44.0)
|
||||
button.button_pressed = selected_id == option_id
|
||||
button.pressed.connect(_select_option.bind("fur_pattern", option_id))
|
||||
_apply_fur_swatch_style(button, color, button.button_pressed)
|
||||
grid.add_child(button)
|
||||
|
||||
|
||||
func _apply_fur_swatch_style(
|
||||
button: Button,
|
||||
color: Color,
|
||||
selected: bool,
|
||||
) -> void:
|
||||
var normal: StyleBoxFlat = UtilityPageStyle.rounded_style(color, 999)
|
||||
var hover: StyleBoxFlat = UtilityPageStyle.rounded_style(
|
||||
color.lightened(0.12), 999
|
||||
)
|
||||
var selected_style: StyleBoxFlat = UtilityPageStyle.rounded_style(color, 999)
|
||||
selected_style.border_color = UtilityPageStyle.OCEAN_TEXT_PRIMARY
|
||||
selected_style.set_border_width_all(3 if selected else 2)
|
||||
button.add_theme_stylebox_override("normal", normal)
|
||||
button.add_theme_stylebox_override("hover", hover)
|
||||
button.add_theme_stylebox_override("pressed", selected_style)
|
||||
button.add_theme_stylebox_override("focus", selected_style)
|
||||
|
||||
|
||||
func _select_option(category_id: String, option_id: String) -> void:
|
||||
_draft_appearance[category_id] = option_id
|
||||
_preview.apply_appearance_profile(_draft_appearance)
|
||||
|
|
@ -546,7 +594,7 @@ func _show_confirmation(action: String) -> void:
|
|||
else:
|
||||
_confirmation_label.text = "Discard unsaved profile changes?"
|
||||
_confirmation_confirm.text = "discard changes"
|
||||
_discard_confirmation.get_node("%KeepEditing").grab_focus()
|
||||
_keep_editing_button.grab_focus()
|
||||
|
||||
|
||||
func _confirm_pending_action() -> void:
|
||||
|
|
|
|||
|
|
@ -4,15 +4,20 @@ extends SubViewportContainer
|
|||
const ControllerMappingManagerType = preload(
|
||||
"res://settings/controller_mapping_manager.gd"
|
||||
)
|
||||
const FRONT_FACING_YAW: float = PI
|
||||
|
||||
@export_range(0.1, 2.0, 0.05) var drag_sensitivity: float = 0.012
|
||||
@export_range(0.1, 4.0, 0.1) var keyboard_speed: float = 1.8
|
||||
|
||||
@onready var _preview_root: Node3D = %PreviewRoot
|
||||
@onready var _preview_environment: WorldEnvironment = %WorldEnvironment
|
||||
@onready var _preview_sun: DirectionalLight3D = %KeyLight
|
||||
|
||||
var _dragging: bool = false
|
||||
var _visuals: Node3D
|
||||
var _controller_mapping_manager: ControllerMappingManagerType
|
||||
var _source_environment: WorldEnvironment
|
||||
var _source_sun: DirectionalLight3D
|
||||
|
||||
|
||||
func setup_controller_mapping(
|
||||
|
|
@ -21,9 +26,19 @@ func setup_controller_mapping(
|
|||
_controller_mapping_manager = mapping_manager
|
||||
|
||||
|
||||
func setup_world_lighting(
|
||||
world_environment: WorldEnvironment,
|
||||
world_sun: DirectionalLight3D,
|
||||
) -> void:
|
||||
_source_environment = world_environment
|
||||
_source_sun = world_sun
|
||||
_sync_world_lighting()
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
focus_mode = Control.FOCUS_ALL
|
||||
gui_input.connect(_on_gui_input)
|
||||
reset_view()
|
||||
_visuals = PlayerVisualPresenter.instantiate_visuals()
|
||||
_preview_root.add_child(_visuals)
|
||||
var rod := _visuals.find_child("FishingRod", true, false) as Node3D
|
||||
|
|
@ -40,10 +55,11 @@ func apply_appearance_profile(profile: Dictionary) -> void:
|
|||
|
||||
|
||||
func reset_view() -> void:
|
||||
_preview_root.rotation.y = 0.0
|
||||
_preview_root.rotation.y = FRONT_FACING_YAW
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
_sync_world_lighting()
|
||||
if not has_focus():
|
||||
return
|
||||
var axis := Input.get_axis("ui_left", "ui_right")
|
||||
|
|
@ -78,3 +94,19 @@ func _notification(what: int) -> void:
|
|||
|
||||
func _rotate(amount: float) -> void:
|
||||
_preview_root.rotation.y = fposmod(_preview_root.rotation.y + amount, TAU)
|
||||
|
||||
|
||||
func _sync_world_lighting() -> void:
|
||||
if (
|
||||
_preview_environment == null
|
||||
or _preview_sun == null
|
||||
or _source_environment == null
|
||||
or _source_sun == null
|
||||
):
|
||||
return
|
||||
_preview_environment.environment = _source_environment.environment
|
||||
_preview_sun.rotation = _source_sun.global_rotation
|
||||
_preview_sun.light_color = _source_sun.light_color
|
||||
_preview_sun.light_energy = _source_sun.light_energy
|
||||
_preview_sun.light_indirect_energy = _source_sun.light_indirect_energy
|
||||
_preview_sun.shadow_enabled = _source_sun.shadow_enabled
|
||||
|
|
|
|||
|
|
@ -1,16 +1,8 @@
|
|||
[gd_scene load_steps=4 format=3]
|
||||
[gd_scene load_steps=3 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/profile_preview.gd" id="1"]
|
||||
|
||||
[sub_resource type="Environment" id="Environment"]
|
||||
background_mode = 1
|
||||
background_color = Color(0.075, 0.13, 0.16, 1)
|
||||
ambient_light_source = 3
|
||||
ambient_light_color = Color(0.72, 0.82, 0.86, 1)
|
||||
ambient_light_energy = 0.65
|
||||
|
||||
[sub_resource type="World3D" id="PreviewWorld"]
|
||||
environment = SubResource("Environment")
|
||||
|
||||
[node name="ProfilePreview" type="SubViewportContainer"]
|
||||
custom_minimum_size = Vector2(300, 220)
|
||||
|
|
@ -24,18 +16,12 @@ render_target_update_mode = 4
|
|||
world_3d = SubResource("PreviewWorld")
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="Viewport"]
|
||||
environment = SubResource("Environment")
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="KeyLight" type="DirectionalLight3D" parent="Viewport"]
|
||||
rotation_degrees = Vector3(-38, -32, 0)
|
||||
light_energy = 1.15
|
||||
shadow_enabled = true
|
||||
|
||||
[node name="FillLight" type="OmniLight3D" parent="Viewport"]
|
||||
position = Vector3(-1.8, 1.6, 2.2)
|
||||
light_color = Color(0.72, 0.84, 1, 1)
|
||||
omni_range = 5.0
|
||||
light_energy = 1.3
|
||||
unique_name_in_owner = true
|
||||
light_energy = 0.1
|
||||
shadow_enabled = false
|
||||
|
||||
[node name="PreviewRoot" type="Node3D" parent="Viewport"]
|
||||
unique_name_in_owner = true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue