feat(items): add OutfitItem, tap-to-undress, and outfit refs on Character
- Add OutfitItem (extends HoldableItem): applies outfit on drop within 80px of character body, falls back to hand slot attach if no character in range - Add apply_outfit_item / remove_outfit / _handle_outfit_tap to Character - Track item node refs in _outfit_item_refs for restoring visibility - Fix animation state: reset to idle before tap handling in _on_drag_released - Extract _ITEM_DROP_OFFSET constant (replaces magic Vector2(0,60)) - Add 5 tests in test_outfit_item.gd, 14 new tests in test_character_v2.gd
This commit is contained in:
@@ -13,7 +13,11 @@ signal state_changed(new_state: CharacterData.State)
|
||||
|
||||
var _is_held: bool = false
|
||||
var _current_anim: String = "idle"
|
||||
var _drag_start_position: Vector2 = Vector2.ZERO
|
||||
var _outfit_item_refs: Array = [null, null, null]
|
||||
|
||||
const _TAP_THRESHOLD: float = 10.0
|
||||
const _ITEM_DROP_OFFSET: Vector2 = Vector2(0.0, 60.0)
|
||||
const _STATE_COLORS: Dictionary = {
|
||||
CharacterData.State.HEALTHY: Color(0.6, 0.8, 1.0),
|
||||
CharacterData.State.SICK: Color(0.7, 0.9, 0.7),
|
||||
@@ -149,14 +153,53 @@ func _update_visual_state() -> void:
|
||||
ear_right.color = color
|
||||
|
||||
|
||||
func _on_drag_picked_up(_pos: Vector2) -> void:
|
||||
func apply_outfit_item(layer: int, item_id: String, texture: Texture2D, item_node: Node2D) -> void:
|
||||
if layer < 1 or layer > 3:
|
||||
return
|
||||
var i: int = layer - 1
|
||||
var existing: Node2D = _outfit_item_refs[i] as Node2D
|
||||
if existing != null:
|
||||
existing.global_position = global_position + _ITEM_DROP_OFFSET
|
||||
existing.visible = true
|
||||
_outfit_item_refs[i] = item_node
|
||||
set_outfit(layer, item_id, texture)
|
||||
if item_node != null:
|
||||
item_node.visible = false
|
||||
|
||||
|
||||
func remove_outfit(layer: int) -> void:
|
||||
if layer < 1 or layer > 3:
|
||||
return
|
||||
var i: int = layer - 1
|
||||
clear_outfit(layer)
|
||||
var item_ref: Node2D = _outfit_item_refs[i] as Node2D
|
||||
if item_ref != null:
|
||||
_outfit_item_refs[i] = null
|
||||
item_ref.global_position = global_position + _ITEM_DROP_OFFSET
|
||||
item_ref.visible = true
|
||||
|
||||
|
||||
func _handle_outfit_tap() -> void:
|
||||
for layer: int in range(3, 0, -1):
|
||||
if not get_outfit(layer).is_empty():
|
||||
remove_outfit(layer)
|
||||
return
|
||||
|
||||
|
||||
func _on_drag_picked_up(pos: Vector2) -> void:
|
||||
_is_held = true
|
||||
_drag_start_position = pos
|
||||
set_animation_state("held")
|
||||
character_picked_up.emit(self)
|
||||
|
||||
|
||||
func _on_drag_released(pos: Vector2) -> void:
|
||||
_is_held = false
|
||||
var drag_distance: float = pos.distance_to(_drag_start_position)
|
||||
if drag_distance < _TAP_THRESHOLD:
|
||||
set_animation_state("idle")
|
||||
_handle_outfit_tap()
|
||||
return
|
||||
set_animation_state("idle")
|
||||
if data == null or data.id.is_empty():
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user