P23-03: 生活の観察
This commit is contained in:
@@ -549,9 +549,7 @@ func _draw_contents() -> void:
|
||||
_draw_world_cells(bounds, map_rect)
|
||||
_draw_world_entity_icons()
|
||||
_draw_legacy_stairs()
|
||||
_draw_elevators()
|
||||
_draw_other_layer()
|
||||
_draw_life_badges()
|
||||
_draw_construction_labels()
|
||||
_draw_facility_labels()
|
||||
_draw_excavation_jobs()
|
||||
@@ -639,6 +637,14 @@ func _build_life_observation() -> Dictionary:
|
||||
&"at": rect.position + Vector2(2, 16), &"requests": requests,
|
||||
&"text": RoomPresentation.supply_label(requests)})
|
||||
model[&"badges"] = badges
|
||||
var obstacles: Array[Rect2] = []
|
||||
for cabin: Dictionary in model[&"cabins"]:
|
||||
obstacles.append(cabin[&"rect"])
|
||||
obstacles.append(cabin[&"badge_rect"])
|
||||
for collection: Array in [badges, model[&"landing_badges"], model.get(&"actor_aggregations", [])]:
|
||||
for badge: Dictionary in collection:
|
||||
obstacles.append(_readable_badge_rect(badge[&"at"], badge[&"text"]))
|
||||
model[&"traffic_obstacles"] = obstacles
|
||||
var traffic: Array[Dictionary] = []
|
||||
var path: Variant = _service(&"path_service")
|
||||
var bounds := _world_bounds()
|
||||
@@ -655,14 +661,39 @@ func _build_life_observation() -> Dictionary:
|
||||
var band := Rect2(Vector2(rect.position.x + rect.size.x * 0.12,
|
||||
cell_rect.end.y - 2 * world_pixel - thickness * 0.5),
|
||||
Vector2(rect.size.x * 0.76, thickness))
|
||||
traffic.append({&"cell": cell, &"traffic": row, &"rect": rect, &"band_rect": band})
|
||||
traffic.append({&"cell": cell, &"traffic": row, &"rect": rect, &"band_rect": band,
|
||||
&"segment_rects": _traffic_segments(band, rect, obstacles)})
|
||||
model[&"traffic"] = traffic
|
||||
return model
|
||||
|
||||
|
||||
func _draw_life_badges() -> void:
|
||||
## Subtract opaque observation regions, retaining a visible density mark even
|
||||
## when the ordinary floor band is completely behind a moving cabin.
|
||||
func _traffic_segments(band: Rect2, cell: Rect2, obstacles: Array[Rect2]) -> Array[Rect2]:
|
||||
for y: float in [band.position.y, cell.position.y, cell.end.y - band.size.y]:
|
||||
var pieces: Array[Rect2] = [Rect2(Vector2(band.position.x, y), band.size)]
|
||||
for obstacle: Rect2 in obstacles:
|
||||
var remaining: Array[Rect2] = []
|
||||
for piece: Rect2 in pieces:
|
||||
var cut := piece.intersection(obstacle)
|
||||
if not cut.has_area():
|
||||
remaining.append(piece)
|
||||
continue
|
||||
for part: Rect2 in [Rect2(piece.position, Vector2(piece.size.x, cut.position.y-piece.position.y)),
|
||||
Rect2(Vector2(piece.position.x, cut.end.y), Vector2(piece.size.x, piece.end.y-cut.end.y)),
|
||||
Rect2(Vector2(piece.position.x, cut.position.y), Vector2(cut.position.x-piece.position.x, cut.size.y)),
|
||||
Rect2(Vector2(cut.end.x, cut.position.y), Vector2(piece.end.x-cut.end.x, cut.size.y))]:
|
||||
if part.has_area():
|
||||
remaining.append(part)
|
||||
pieces = remaining
|
||||
if not pieces.is_empty():
|
||||
return pieces
|
||||
return []
|
||||
|
||||
|
||||
func _draw_life_badges(canvas: CanvasItem) -> void:
|
||||
for badge: Dictionary in _life_observation.get(&"badges", []):
|
||||
_draw_readable_badge(badge[&"at"], badge[&"text"])
|
||||
_draw_readable_badge(badge[&"at"], badge[&"text"], canvas)
|
||||
|
||||
|
||||
func _draw_background() -> void:
|
||||
@@ -783,6 +814,9 @@ func _draw_life_overlay() -> void:
|
||||
_life_observation[&"overlay_passes"] = []
|
||||
_life_observation[&"overlay_passes"].append(&"traffic")
|
||||
_draw_congestion_overlay(_life_overlay)
|
||||
_life_observation[&"overlay_passes"].append(&"cabins")
|
||||
_draw_elevators(_life_overlay)
|
||||
_draw_life_badges(_life_overlay)
|
||||
_life_observation[&"overlay_passes"].append(&"actors")
|
||||
for cabin: Dictionary in _life_observation.get(&"cabins", []):
|
||||
for actor: Dictionary in cabin[&"passengers"]:
|
||||
@@ -795,7 +829,6 @@ func _draw_life_overlay() -> void:
|
||||
|
||||
func _draw_congestion_overlay(canvas: CanvasItem) -> void:
|
||||
for row: Dictionary in _life_observation.get(&"traffic", []):
|
||||
var band: Rect2 = row[&"band_rect"]
|
||||
var traffic: Dictionary = row[&"traffic"]
|
||||
var density := int(traffic[&"current_density"])
|
||||
var blocked := bool(traffic[&"temporary_block"])
|
||||
@@ -803,11 +836,13 @@ func _draw_congestion_overlay(canvas: CanvasItem) -> void:
|
||||
continue
|
||||
var ratio := float(density) / maxi(int(traffic[&"base_capacity"]), 1)
|
||||
var color := Color("e34332") if blocked or ratio > 1.0 else Color("e3a62f") if ratio >= 0.65 else Color("55c96b")
|
||||
canvas.draw_rect(band, Color(color, 0.90))
|
||||
if blocked:
|
||||
var cross := band.grow(-1.0)
|
||||
canvas.draw_line(cross.position, cross.end, Color(color, 0.90), 2.0)
|
||||
canvas.draw_line(Vector2(cross.end.x, cross.position.y), Vector2(cross.position.x, cross.end.y), Color(color, 0.90), 2.0)
|
||||
# At overview zoom a whole cell can be covered by opaque badges. Still
|
||||
# submit its density band, beneath those later draws, and report no visible
|
||||
# fragments. No traffic cell or raw density row is dropped.
|
||||
if row[&"segment_rects"].is_empty():
|
||||
canvas.draw_rect(row[&"band_rect"], Color(color, 0.90))
|
||||
for segment: Rect2 in row[&"segment_rects"]:
|
||||
canvas.draw_rect(segment, Color(color, 0.90))
|
||||
|
||||
|
||||
## Visual-only level comes from the existing live FacilityInstance, not the
|
||||
@@ -920,14 +955,19 @@ func _draw_world_entity_icons() -> void:
|
||||
draw_rect(rect.grow(-p),Color("f5d582"),false,2*p)
|
||||
|
||||
|
||||
func _readable_badge_rect(at: Vector2, text: String) -> Rect2:
|
||||
# A conservative em-width box makes geometry independently reproducible.
|
||||
# Text still uses the existing fallback font and size.
|
||||
return Rect2(at, Vector2(text.length() * 10 + 6, 14))
|
||||
|
||||
|
||||
func _draw_readable_badge(at: Vector2, text: String, canvas: CanvasItem = null) -> void:
|
||||
if canvas == null:
|
||||
canvas = self
|
||||
var width := ThemeDB.fallback_font.get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, 10).x+6
|
||||
var rect := Rect2(at, Vector2(width, 14))
|
||||
var rect := _readable_badge_rect(at, text)
|
||||
if not rect.intersects(Rect2(Vector2.ZERO, size)):
|
||||
return
|
||||
canvas.draw_rect(rect, Color("34413b", 0.94))
|
||||
canvas.draw_rect(rect, Color("34413b"))
|
||||
canvas.draw_string(ThemeDB.fallback_font, at+Vector2(3, 11), text, HORIZONTAL_ALIGNMENT_LEFT, -1, 10, Color("fff2ce"))
|
||||
|
||||
|
||||
@@ -1017,7 +1057,8 @@ func _observe_queues() -> Dictionary:
|
||||
var lift_cells: Dictionary = {}
|
||||
for shaft: Dictionary in _transport_report.get(&"shafts", []):
|
||||
for stop: Vector3i in _cells_from_serialized(shaft.get(&"stops", [])):
|
||||
lift_cells[stop] = true
|
||||
for offset: int in range(maxi(int(shaft.get(&"width", 2)), 1)):
|
||||
lift_cells[stop + Vector3i(offset, 0, 0)] = true
|
||||
var reserved: Dictionary = {}
|
||||
var cells: Array = groups.keys()
|
||||
cells.sort_custom(func(a: Vector3i, b: Vector3i) -> bool: return a.y < b.y or (a.y == b.y and a.x < b.x))
|
||||
@@ -1032,6 +1073,8 @@ func _observe_queues() -> Dictionary:
|
||||
var next := cell + Vector3i(direction*distance, 0, 0)
|
||||
if world == null or not world.is_walkable(next):
|
||||
break
|
||||
if lift_cells.has(next):
|
||||
break
|
||||
var occupant: StringName = world.get_occupant(next)
|
||||
var facility: Variant = facilities.get_instance(occupant) if facilities != null else null
|
||||
if facility != null and facility.definition_id not in [&"guest_corridor", &"service_corridor"]:
|
||||
@@ -1051,7 +1094,7 @@ func _observe_queues() -> Dictionary:
|
||||
var text := RoomPresentation.queue_label(members.size(), members.size()-index)
|
||||
_landing_badges.append({&"at": get_cell_rect(cell).position + Vector2(-80 if lift_cells.has(cell) else 0, -16), &"text": text, &"cell": cell, &"members": members.duplicate(), &"visible_count": index, &"overflow": members.size()-index})
|
||||
|
||||
return {&"queue_positions": _queue_positions, &"queue_hidden": _queue_hidden, &"landing_badges": _landing_badges, &"elevators": _transport_report}
|
||||
return {&"queue_positions": _queue_positions, &"queue_hidden": _queue_hidden, &"landing_badges": _landing_badges, &"elevators": _transport_report, &"shaft_footprint": lift_cells.keys()}
|
||||
|
||||
|
||||
func _add_queue_member(groups: Dictionary, key: String, cell: Vector3i) -> void:
|
||||
@@ -1178,13 +1221,13 @@ func _draw_facility_labels() -> void:
|
||||
draw_string(ThemeDB.fallback_font,at+Vector2(4,12),label,HORIZONTAL_ALIGNMENT_CENTER,label_width-8,font_size,Color("f0e2b9"))
|
||||
|
||||
|
||||
func _draw_elevators() -> void:
|
||||
func _draw_elevators(canvas: CanvasItem) -> void:
|
||||
for row: Dictionary in _life_observation.get(&"cabins", []):
|
||||
PixelArt.elevator_cabin(self, row[&"rect"], row[&"pixel"], layer_mode == LayerMode.BACK, row[&"operational"])
|
||||
PixelArt.elevator_gate(self, row[&"rect"], row[&"pixel"], row[&"doors_open"])
|
||||
_draw_readable_badge(row[&"badge_at"], row[&"badge"])
|
||||
PixelArt.elevator_cabin(canvas, row[&"rect"], row[&"pixel"], layer_mode == LayerMode.BACK, row[&"operational"])
|
||||
PixelArt.elevator_gate(canvas, row[&"rect"], row[&"pixel"], row[&"doors_open"])
|
||||
_draw_readable_badge(row[&"badge_at"], row[&"badge"], canvas)
|
||||
for badge: Dictionary in _life_observation.get(&"landing_badges", []):
|
||||
_draw_readable_badge(badge[&"at"], badge[&"text"])
|
||||
_draw_readable_badge(badge[&"at"], badge[&"text"], canvas)
|
||||
|
||||
|
||||
func _observe_elevators(observation: Dictionary) -> Array[Dictionary]:
|
||||
@@ -1237,8 +1280,10 @@ func _observe_elevators(observation: Dictionary) -> Array[Dictionary]:
|
||||
passengers_drawn.append(_actor_drawing(center,actor_key,is_staff,state,false,carrying,&"",true,observation))
|
||||
cabins.append({&"shaft_id": shaft_id, &"rect": cabin, &"pixel": p,
|
||||
&"operational": operational, &"doors_open": doors_open,
|
||||
&"phase": phase, &"passenger_count": passengers.size(),
|
||||
&"passengers": passengers_drawn,
|
||||
&"badge_at": Vector2(cabin.position.x, cabin.position.y-14),
|
||||
&"badge_rect": _readable_badge_rect(Vector2(cabin.position.x, cabin.position.y-14), RoomPresentation.elevator_label(shaft)),
|
||||
&"badge": RoomPresentation.elevator_label(shaft)})
|
||||
|
||||
for shaft_id: Variant in _elevator_tracks.keys():
|
||||
|
||||
Reference in New Issue
Block a user