Animate pixel unit idle stances

This commit is contained in:
2026-06-19 19:59:08 +09:00
parent 36001c8b2f
commit 8cb611ac1a
3 changed files with 98 additions and 13 deletions

View File

@@ -59,6 +59,7 @@ const MAP_FOCUS_MARGIN := 96.0
const BATTLE_PRESENTATION_STEP_GAP := 0.08
const BATTLE_PRESENTATION_FEEDBACK_LAG := 0.10
const UNIT_MOVE_ANIMATION_DURATION := 0.18
const UNIT_IDLE_PHASE_SPEED := 2.4
const TARGET_PREVIEW_BADGE_SIZE := Vector2(104, 22)
const LOW_HP_WARNING_RATIO := 0.35
const UNIT_STATUS_MARKER_RADIUS := 6.0
@@ -442,6 +443,7 @@ var ui_regular_font: Font
var ui_bold_font: Font
var board_scroll_offset := Vector2.ZERO
var minimap_dragging := false
var unit_idle_time := 0.0
func _ready() -> void:
@@ -2636,7 +2638,8 @@ func _handle_key(event: InputEventKey) -> void:
func _process(delta: float) -> void:
var needs_redraw := false
var had_sequence_presentation := _has_active_battle_presentation_sequence()
if battle_started and state.battle_status == BattleState.STATUS_ACTIVE and not _is_dialogue_visible():
if _should_animate_unit_idle():
unit_idle_time += delta
needs_redraw = true
if _update_edge_scroll(delta):
needs_redraw = true
@@ -2688,6 +2691,10 @@ func _process(delta: float) -> void:
queue_redraw()
func _should_animate_unit_idle() -> bool:
return battle_started and state.battle_status == BattleState.STATUS_ACTIVE and not _is_dialogue_visible()
func _can_select(unit: Dictionary) -> bool:
if unit.is_empty():
return false
@@ -3738,8 +3745,9 @@ func _draw_pixel_unit_sprite(rect: Rect2, unit: Dictionary, team_color: Color, m
var profile := _pixel_unit_sprite_profile(unit)
var family := str(profile.get("family", _unit_class_family(unit)))
var phase := _unit_idle_phase(unit)
var bob := _unit_idle_bob(family, phase)
var step := _unit_idle_step(family, phase)
var idle_intensity := _unit_idle_intensity(unit)
var bob := _unit_idle_bob(family, phase, idle_intensity)
var step := _unit_idle_step(family, phase, idle_intensity)
var pixel := float(profile.get("pixel", 3.0))
var safe_facing := -1 if facing < 0 else 1
var origin := Vector2(roundf(rect.position.x + 12.0), roundf(rect.position.y + 5.0 + bob))
@@ -3790,22 +3798,39 @@ func _unit_idle_phase(unit: Dictionary) -> float:
var unit_id := str(unit.get("id", "unit"))
for index in range(unit_id.length()):
seed += unit_id.unicode_at(index) * (index + 1)
return float(Time.get_ticks_msec()) * 0.0024 + float(seed % 360) * 0.01745
return unit_idle_time * UNIT_IDLE_PHASE_SPEED + float(seed % 360) * 0.01745
func _unit_idle_bob(family: String, phase: float) -> float:
func _unit_idle_intensity(unit: Dictionary) -> float:
if unit.is_empty():
return 1.0
var intensity := 1.0
if bool(unit.get("acted", false)):
intensity *= 0.34
var max_hp: int = max(1, int(unit.get("max_hp", 1)))
var hp_ratio := float(unit.get("hp", max_hp)) / float(max_hp)
if hp_ratio <= LOW_HP_WARNING_RATIO:
intensity *= 0.58
if str(unit.get("id", "")) == state.selected_unit_id and not bool(unit.get("acted", false)):
intensity *= 1.18
return clampf(intensity, 0.18, 1.22)
func _unit_idle_bob(family: String, phase: float, intensity := 1.0) -> float:
if family == "cavalry":
return roundf(sin(phase * 1.55) * 0.75)
return roundf(sin(phase * 1.55) * 0.75 * intensity)
if family == "ranged":
return roundf(sin(phase * 1.10) * 0.75)
return roundf(sin(phase * 1.10) * 0.75 * intensity)
if family == "tactic":
return roundf(sin(phase * 0.82) * 0.65)
return roundf(sin(phase * 0.82) * 0.65 * intensity)
if family == "heavy":
return roundf(sin(phase * 0.72) * 0.45)
return roundf(sin(phase) * 1.15)
return roundf(sin(phase * 0.72) * 0.45 * intensity)
return roundf(sin(phase) * 1.15 * intensity)
func _unit_idle_step(family: String, phase: float) -> float:
func _unit_idle_step(family: String, phase: float, intensity := 1.0) -> float:
if intensity < 0.40:
return 0.0
var rate := 1.65
if family == "cavalry":
rate = 2.15
@@ -5297,8 +5322,11 @@ func _edge_scroll_next_offset(current_offset: Vector2, mouse_position: Vector2,
func _update_edge_scroll(delta: float) -> bool:
if _is_input_locked():
return false
var viewport := get_viewport()
if viewport == null:
return false
var view_rect := _map_view_rect()
var mouse_position := get_viewport().get_mouse_position()
var mouse_position := viewport.get_mouse_position()
if minimap_dragging or (_is_minimap_visible() and _minimap_rect().has_point(mouse_position)):
return false
var velocity := _edge_scroll_velocity_for_position(mouse_position, view_rect)