Skip to content

Commit

Permalink
Merge pull request #2983 from Poobslag/creature-editor-flicker
Browse files Browse the repository at this point in the history
Bug: Creature editor shows black pixels when selecting feature
  • Loading branch information
Poobslag authored Jan 10, 2025
2 parents 5a1f3b7 + 6ed7da5 commit bb75162
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 6 deletions.
78 changes: 76 additions & 2 deletions project/src/main/editor/creature/allele-buttons.gd
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ onready var _overworld_environment: OverworldEnvironment = get_node(overworld_en
onready var _creature_saver: CreatureSaver = get_node(creature_saver_path)
onready var _creature_editor_library := Global.get_creature_editor_library()

func _ready() -> void:
for creature in [_player(), _player_swap()]:
# Disable physics processing for both the player and their doppelganger. Creatures are KinematicBody2D
# instances, and their physics interferes with the swapping process.
creature.set_physics_process(false)

creature.connect("dna_loaded", self, "_on_Creature_dna_loaded", [creature])


## Deletes and recreates all buttons for the specified category.
func _refresh_allele_buttons(category: int) -> void:
# calculate whether to grab focus
Expand Down Expand Up @@ -297,6 +306,17 @@ func _assign_focus_neighbours(category: int) -> void:
allele_button.focus_neighbour_bottom = allele_button.get_path_to(get_node(top_system_button_path))


func _find_operation_button(id: String) -> OperationButton:
if not is_inside_tree():
return null
var result: OperationButton
for operation_button in get_tree().get_nodes_in_group("operation_buttons"):
if operation_button.id == id:
result = operation_button
break
return result


## Refreshes the enabled/disabled state of all CreatureColorButtons based on the creature's properties.
##
## Certain color buttons are disabled if they are not relevant to the creature's appearance. For example, if the
Expand All @@ -318,6 +338,14 @@ func _player() -> Creature:
return _overworld_environment.player


## Returns the player's offscreen doppelganger.
##
## Changing a creature's appearance forces all their textures and shaders to regenerate, making them look strange for
## a moment. We apply these changes to a doppelganger and then swap them in after the changes are applied.
func _player_swap() -> Creature:
return _overworld_environment.get_creature_by_id(CreatureEditorLibrary.PLAYER_SWAP_ID)


## When the player chooses an allele, we update the UI and update the creature's appearance.
func _on_AlleleButton_pressed(allele_button: AlleleButton) -> void:
if not _player():
Expand All @@ -343,34 +371,80 @@ func _on_AlleleButton_pressed(allele_button: AlleleButton) -> void:
invalid_allele_value = DnaUtils.invalid_allele_value(_player().dna, allele_id, allele_value)
if not invalid_allele_value:
break
_player().suppress_refresh_dna = true
_player().dna[invalid_allele_value] = "0"
_player().suppress_refresh_dna = false

# update the creature's appearance
for allele_string in allele_button.allele_combo.split(" "):
var allele_id: String = allele_string.split("_")[0]
var allele_value: String = allele_string.split("_")[1]
_player().suppress_refresh_dna = true
_player().dna[allele_id] = allele_value
_player().refresh_dna()
_player().suppress_refresh_dna = false
_player_swap().dna = _player().dna

# refresh the enabled/disabled state of all CreatureColorButtons
_refresh_color_buttons()


## When the doppelganger's dna is fully loaded, we swap them in for the main creature.
##
## Changing a creature's appearance forces all their textures and shaders to regenerate, making them look strange for
## a moment. We apply these changes to a doppelganger and then swap them in after the changes are applied.
func _on_Creature_dna_loaded(creature: Creature) -> void:
if creature != _player_swap():
## we only run these steps when the doppelganger is loaded; not when the main creature is loaded
return

var player := _player()
var player_position := _player().position
var player_swap := _player_swap()
var player_swap_position := _player_swap().position

# copy properties from player to their doppelganger
player_swap.chat_theme = player.chat_theme
player_swap.creature_name = player.creature_name
player_swap.creature_short_name = player.creature_short_name
player_swap.creature_visuals.rescale(0.60 if player_swap.creature_visuals.dna.get("body") == "2" else 1.00)
player_swap.fatness = player.fatness
player_swap.min_fatness = player.min_fatness
player_swap.visual_fatness = player.visual_fatness

# replace player with doppelganger
player_swap.position = player_position
player_swap.suppress_refresh_creature_id = true
player_swap.creature_id = CreatureLibrary.PLAYER_ID
player_swap.suppress_refresh_creature_id = false

# replace doppelganger with player
player.position = player_swap_position
player.suppress_refresh_creature_id = true
player.creature_id = CreatureEditorLibrary.PLAYER_SWAP_ID
player.suppress_refresh_creature_id = false


## When the player uses a CreatureColorButton, we update the creature's appearance
func _on_CreatureColorButton_color_changed(color: Color, color_property: String) -> void:
if not _player():
return

_player().suppress_refresh_dna = true
_player().dna[color_property] = color.to_html(false).to_lower()
_player().refresh_dna()
_player().suppress_refresh_dna = false
_player().chat_theme = CreatureLoader.chat_theme(_player().dna) # generate a new chat theme
_player_swap().dna = _player().dna
_player_swap().chat_theme = _player().chat_theme


func _on_CreatureNameButton_name_changed(new_name: String) -> void:
if not _player():
return

_player().rename(new_name)
var save_button := _find_operation_button("save")
if save_button:
save_button.set_disabled(not _creature_saver.has_unsaved_changes())


func _on_CategorySelector_category_selected(category: int) -> void:
Expand Down
6 changes: 6 additions & 0 deletions project/src/main/editor/creature/creature-editor-library.gd
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ const COLOR_PRESETS_BY_COLOR_PROPERTY := {
],
}

## Unique creature ID for the player's offscreen doppelganger in the creature editor.
##
## Changing a creature's appearance forces all their textures and shaders to regenerate, making them look strange for
## a moment. We apply these changes to a doppelganger and then swap them in after the changes are applied.
const PLAYER_SWAP_ID := "#player_swap#"

## List of Category instances with information about the creature editor categories.
var categories: Array = []

Expand Down
17 changes: 13 additions & 4 deletions project/src/main/editor/creature/creature-editor-nametag.gd
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ export (NodePath) var overworld_environment_path: NodePath
onready var _overworld_environment: OverworldEnvironment = get_node(overworld_environment_path)

func _ready() -> void:
_player().connect("creature_name_changed", self, "_on_Creature_creature_name_changed")
_player().connect("dna_loaded", self, "_on_Creature_dna_loaded")
for creature in [_player(), _player_swap()]:
creature.connect("creature_name_changed", self, "_on_Creature_creature_name_changed", [creature])
creature.connect("dna_loaded", self, "_on_Creature_dna_loaded", [creature])
_refresh()


Expand All @@ -20,9 +21,17 @@ func _player() -> Creature:
return _overworld_environment.player


func _on_Creature_creature_name_changed() -> void:
func _player_swap() -> Creature:
return _overworld_environment.get_creature_by_id(CreatureEditorLibrary.PLAYER_SWAP_ID)


func _on_Creature_creature_name_changed(creature: Creature) -> void:
if creature != _player():
return
_refresh()


func _on_Creature_dna_loaded() -> void:
func _on_Creature_dna_loaded(creature: Creature) -> void:
if creature != _player():
return
_refresh()
12 changes: 12 additions & 0 deletions project/src/main/world/creature/creature.gd
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ var creature_visuals: CreatureVisuals
## Virtual property; value is only exposed through getters/setters
var fatness: float setget set_fatness, get_fatness

## If 'true', the 'refresh_creature_id' method will have no effect, and changing the creature's id will not update
## their appearance.
var suppress_refresh_creature_id: bool = false

## If 'true', the 'refresh_dna' method will have no effect, and changing the creature's dna will not update their
## appearance.
var suppress_refresh_dna: bool = false

## Virtual property; value is only exposed through getters/setters
var visual_fatness: float setget set_visual_fatness, get_visual_fatness

Expand Down Expand Up @@ -396,6 +404,8 @@ func get_creature_def() -> CreatureDef:
func refresh_dna() -> void:
if not is_inside_tree():
return
if suppress_refresh_dna:
return

if dna:
dna = DnaUtils.fill_dna(dna)
Expand Down Expand Up @@ -514,6 +524,8 @@ func _launch_fade_tween(new_alpha: float, duration: float) -> void:
func _refresh_creature_id() -> void:
if not is_inside_tree():
return
if suppress_refresh_creature_id:
return

var new_creature_def: CreatureDef = PlayerData.creature_library.get_creature_def(creature_id)
if new_creature_def:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,9 @@ cell_shadow_mapping = {
position = Vector2( -2, 32 )
creature_id = "#player#"
orientation = 1

[node name="PlayerSwap" parent="Obstacles" instance=ExtResource( 28 )]
visible = false
position = Vector2( 88000, 32 )
creature_id = "#player_swap#"
orientation = 1

0 comments on commit bb75162

Please sign in to comment.