feat(engine): ✨ Optimize village/lair placement logic and unit rendering performance with improved distribution algorithms and visual enhancements
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
3ffefc9057
commit
85abaf3a38
3 changed files with 62 additions and 3 deletions
|
|
@ -221,10 +221,11 @@ func place_resources(game_map: RefCounted, multiplier: float) -> void:
|
|||
tile_idx = _rng.randi_range(0, candidates.size() - 1)
|
||||
var pos: Vector2i = candidates[tile_idx]
|
||||
|
||||
var tile: Variant = game_map.get_tile(pos)
|
||||
var tile: Resource = game_map.get_tile(pos)
|
||||
if tile == null or tile.resource_id != "":
|
||||
candidates.remove_at(tile_idx)
|
||||
cand_weights.remove_at(tile_idx)
|
||||
eligible_weights[res_id] = cand_weights # PackedArray is value type — write back
|
||||
continue
|
||||
|
||||
tile.resource_id = res_id
|
||||
|
|
@ -234,11 +235,16 @@ func place_resources(game_map: RefCounted, multiplier: float) -> void:
|
|||
var other_cands: Array = eligible[other_id]
|
||||
var other_weights: PackedFloat32Array = eligible_weights[other_id]
|
||||
var i_cand: int = other_cands.size() - 1
|
||||
var weights_dirty: bool = false
|
||||
while i_cand >= 0:
|
||||
if HexUtilsScript.hex_distance(other_cands[i_cand], pos) < min_resource_distance:
|
||||
if i_cand < other_weights.size():
|
||||
other_weights.remove_at(i_cand)
|
||||
weights_dirty = true
|
||||
other_cands.remove_at(i_cand)
|
||||
other_weights.remove_at(i_cand)
|
||||
i_cand -= 1
|
||||
if weights_dirty:
|
||||
eligible_weights[other_id] = other_weights
|
||||
|
||||
|
||||
# -- Density multiplier lookup --
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ func _get_wilds_data() -> Dictionary:
|
|||
return data
|
||||
return {
|
||||
"lair_density_per_land_tile": 0.0083,
|
||||
"min_distance_from_start": 5,
|
||||
"min_distance_from_start": 8,
|
||||
"min_distance_between": 4,
|
||||
"lair_types": [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,12 @@ const SELECTION_COLOR: Color = Color(1.0, 1.0, 0.0, 0.9)
|
|||
const MOVE_RANGE_COLOR: Color = Color(0.2, 0.4, 0.9, 0.25)
|
||||
const MOVE_RANGE_BORDER_COLOR: Color = Color(0.3, 0.5, 1.0, 0.5)
|
||||
|
||||
## HP bar dimensions and position (below unit sprite)
|
||||
const HP_BAR_WIDTH: float = 36.0
|
||||
const HP_BAR_HEIGHT: float = 4.0
|
||||
const HP_BAR_OFFSET_Y: float = 20.0
|
||||
const HP_BAR_BG_COLOR: Color = Color(0.15, 0.15, 0.15, 0.8)
|
||||
|
||||
## Combat type to marker label mapping for placeholder rendering.
|
||||
const COMBAT_TYPE_LABELS: Dictionary = {
|
||||
"founder": "F",
|
||||
|
|
@ -54,6 +60,8 @@ func _ready() -> void:
|
|||
EventBus.unit_moved.connect(_on_unit_moved)
|
||||
EventBus.unit_created.connect(_on_unit_created)
|
||||
EventBus.unit_destroyed.connect(_on_unit_destroyed)
|
||||
EventBus.unit_healed.connect(_on_unit_hp_changed)
|
||||
EventBus.combat_resolved.connect(_on_combat_resolved)
|
||||
|
||||
|
||||
func sync_units(units: Array) -> void:
|
||||
|
|
@ -73,6 +81,8 @@ func sync_units(units: Array) -> void:
|
|||
"color": _get_unit_color(unit),
|
||||
"label": _get_unit_label(unit),
|
||||
"type_id": tid,
|
||||
"hp": unit.hp,
|
||||
"max_hp": unit.max_hp,
|
||||
}
|
||||
_cache_unit_sprite(tid)
|
||||
queue_redraw()
|
||||
|
|
@ -165,11 +175,31 @@ func _draw() -> void:
|
|||
HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color.WHITE,
|
||||
)
|
||||
|
||||
# Draw HP bar if damaged
|
||||
_draw_hp_bar(pixel, data)
|
||||
|
||||
# Draw selection ring
|
||||
if uid == _selected_id:
|
||||
draw_arc(pixel, SELECTION_RADIUS, 0.0, TAU, 32, SELECTION_COLOR, SELECTION_WIDTH)
|
||||
|
||||
|
||||
func _draw_hp_bar(pixel: Vector2, data: Dictionary) -> void:
|
||||
## Draw an HP bar below the unit when damaged. Green/yellow/red by fraction.
|
||||
var max_hp: int = int(data.get("max_hp", 0))
|
||||
var hp: int = int(data.get("hp", 0))
|
||||
if max_hp <= 0 or hp >= max_hp:
|
||||
return
|
||||
var origin: Vector2 = Vector2(pixel.x - HP_BAR_WIDTH * 0.5, pixel.y + HP_BAR_OFFSET_Y)
|
||||
draw_rect(Rect2(origin, Vector2(HP_BAR_WIDTH, HP_BAR_HEIGHT)), HP_BAR_BG_COLOR)
|
||||
var frac: float = clampf(float(hp) / float(max_hp), 0.0, 1.0)
|
||||
var bar_color: Color = Color.GREEN
|
||||
if frac < 0.3:
|
||||
bar_color = Color.RED
|
||||
elif frac < 0.6:
|
||||
bar_color = Color.YELLOW
|
||||
draw_rect(Rect2(origin, Vector2(HP_BAR_WIDTH * frac, HP_BAR_HEIGHT)), bar_color)
|
||||
|
||||
|
||||
func _draw_movement_range() -> void:
|
||||
if _movement_range.is_empty():
|
||||
return
|
||||
|
|
@ -194,6 +224,8 @@ func _draw_movement_range() -> void:
|
|||
|
||||
func _get_unit_color(unit: UnitScript) -> Color:
|
||||
## Get the player color for this unit.
|
||||
if unit.owner < 0:
|
||||
return Color(0.6, 0.6, 0.6)
|
||||
var player: RefCounted = GameState.get_player(unit.owner)
|
||||
if player != null:
|
||||
var p: PlayerScript = player as PlayerScript
|
||||
|
|
@ -282,6 +314,27 @@ func _on_unit_created(unit: RefCounted, _player_index: int) -> void:
|
|||
queue_redraw()
|
||||
|
||||
|
||||
func _on_unit_hp_changed(unit: Variant, _amount: int) -> void:
|
||||
_refresh_unit_hp(unit)
|
||||
|
||||
|
||||
func _on_combat_resolved(attacker: Variant, defender: Variant, _result: Dictionary) -> void:
|
||||
_refresh_unit_hp(attacker)
|
||||
_refresh_unit_hp(defender)
|
||||
|
||||
|
||||
func _refresh_unit_hp(unit: Variant) -> void:
|
||||
var u: UnitScript = unit as UnitScript
|
||||
if u == null:
|
||||
return
|
||||
var uid: String = _resolve_unit_id(u)
|
||||
if uid == "" or not _units.has(uid):
|
||||
return
|
||||
_units[uid]["hp"] = u.hp
|
||||
_units[uid]["max_hp"] = u.max_hp
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _on_unit_destroyed(unit: RefCounted, _killer: RefCounted) -> void:
|
||||
var u: UnitScript = unit as UnitScript
|
||||
if u == null:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue