155 lines
5.2 KiB
GDScript
155 lines
5.2 KiB
GDScript
extends CanvasLayer
|
||
## Şehir haritası — bir şehir location'ının içi. Prosedürel placeholder zemin
|
||
## (bina blokları + yollar) üzerinde vendor NPC pinleri. Pine tıkla → dükkan (VendorShop).
|
||
## "🗺 Dünya Haritası" ile kapanır. world.gd oluşturur; açıkken world input'u durur.
|
||
## Node adı "CityMap".
|
||
|
||
var _root: Control
|
||
var _canvas: Control
|
||
var _pins_box: Control
|
||
var _title: Label
|
||
var _shop: PanelContainer
|
||
var _vendors: Array = [] # {npc_id,name,role}
|
||
var _pin_pos: Array = [] # Vector2 ekran koordinatları (canvas _draw kullanır)
|
||
var _location_name := ""
|
||
|
||
func _ready() -> void:
|
||
name = "CityMap"
|
||
layer = 4
|
||
visible = false
|
||
_build_ui()
|
||
|
||
func is_open() -> bool:
|
||
return visible
|
||
|
||
func _build_ui() -> void:
|
||
_root = Control.new()
|
||
_root.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||
_root.mouse_filter = Control.MOUSE_FILTER_STOP
|
||
add_child(_root)
|
||
|
||
# Prosedürel zemin (buildings + yollar) — pin konumlarına göre çizilir
|
||
_canvas = CityCanvas.new()
|
||
_canvas.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||
_canvas.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||
_root.add_child(_canvas)
|
||
|
||
# Pin container (butonlar mutlak konumlu)
|
||
_pins_box = Control.new()
|
||
_pins_box.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||
_pins_box.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||
_root.add_child(_pins_box)
|
||
|
||
# Üst bar
|
||
var bar := PanelContainer.new()
|
||
bar.set_anchors_preset(Control.PRESET_TOP_WIDE)
|
||
bar.offset_bottom = 64
|
||
var sb := StyleBoxFlat.new()
|
||
sb.bg_color = Color(0.08, 0.09, 0.12, 0.95)
|
||
bar.add_theme_stylebox_override("panel", sb)
|
||
_root.add_child(bar)
|
||
var hb := HBoxContainer.new()
|
||
hb.add_theme_constant_override("separation", 10)
|
||
bar.add_child(hb)
|
||
var m := MarginContainer.new()
|
||
m.add_theme_constant_override("margin_left", 12)
|
||
m.add_theme_constant_override("margin_right", 12)
|
||
m.add_theme_constant_override("margin_top", 8)
|
||
m.add_theme_constant_override("margin_bottom", 8)
|
||
m.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
hb.add_child(m)
|
||
_title = Label.new()
|
||
_title.add_theme_font_size_override("font_size", 18)
|
||
m.add_child(_title)
|
||
var back := Button.new()
|
||
back.text = "🗺 Dünya Haritası"
|
||
back.pressed.connect(_close)
|
||
hb.add_child(back)
|
||
|
||
# Satıcı dükkanı (alt-sheet) — pinlerin üstünde
|
||
_shop = preload("res://scripts/vendor_shop.gd").new()
|
||
add_child(_shop)
|
||
|
||
func open() -> void:
|
||
visible = true
|
||
_title.text = "🏙 Yükleniyor…"
|
||
var res: Dictionary = await GameState.city_vendors()
|
||
if not res.ok or not (res.body is Dictionary):
|
||
_title.text = "🏙 Şehir yüklenemedi"
|
||
_vendors = []
|
||
else:
|
||
_location_name = str(res.body.get("location_name", "Şehir"))
|
||
_vendors = res.body.get("vendors", [])
|
||
_title.text = "🏙 %s" % _location_name
|
||
_layout_pins()
|
||
|
||
func _close() -> void:
|
||
_shop.visible = false
|
||
visible = false
|
||
|
||
func _layout_pins() -> void:
|
||
for c in _pins_box.get_children():
|
||
c.queue_free()
|
||
_pin_pos.clear()
|
||
var size := get_viewport().get_visible_rect().size
|
||
var n := _vendors.size()
|
||
if n == 0:
|
||
_canvas.queue_redraw()
|
||
return
|
||
# Zikzak yerleşim: üst bar altından alt nav üstüne kadar dağıt
|
||
var top := 110.0
|
||
var bottom := size.y - 140.0
|
||
for i in range(n):
|
||
var t := float(i) / float(maxi(1, n - 1)) if n > 1 else 0.5
|
||
var y := lerpf(top, bottom, t)
|
||
var x := size.x * (0.30 if i % 2 == 0 else 0.68)
|
||
var pos := Vector2(x, y)
|
||
_pin_pos.append(pos)
|
||
_add_pin(_vendors[i], pos)
|
||
_canvas.pins = _pin_pos
|
||
_canvas.queue_redraw()
|
||
|
||
func _add_pin(v: Dictionary, pos: Vector2) -> void:
|
||
var btn := Button.new()
|
||
var role := str(v.get("role", ""))
|
||
btn.text = "🏪\n%s" % str(v.get("name", ""))
|
||
btn.tooltip_text = role
|
||
btn.add_theme_font_size_override("font_size", 13)
|
||
btn.custom_minimum_size = Vector2(150, 64)
|
||
var sb := StyleBoxFlat.new()
|
||
sb.bg_color = Color(0.18, 0.15, 0.10, 0.96)
|
||
sb.border_color = Color(0.85, 0.7, 0.35)
|
||
sb.set_border_width_all(2)
|
||
sb.set_corner_radius_all(8)
|
||
btn.add_theme_stylebox_override("normal", sb)
|
||
_pins_box.add_child(btn)
|
||
btn.size = btn.custom_minimum_size
|
||
btn.position = pos - btn.custom_minimum_size / 2.0
|
||
var npc_id := int(v.get("npc_id", 0))
|
||
var vname := str(v.get("name", ""))
|
||
btn.pressed.connect(func() -> void: _shop.open(npc_id, vname))
|
||
|
||
|
||
## Prosedürel şehir zemini — zemin, yollar, pin altı bina blokları.
|
||
class CityCanvas extends Control:
|
||
var pins: Array = []
|
||
func _draw() -> void:
|
||
var s := size
|
||
# Zemin (toprak/çim degrade hissi)
|
||
draw_rect(Rect2(Vector2.ZERO, s), Color(0.16, 0.18, 0.13))
|
||
draw_rect(Rect2(Vector2(0, s.y * 0.5), Vector2(s.x, s.y * 0.5)), Color(0.14, 0.15, 0.11))
|
||
# Ana yol (dikey)
|
||
var road_col := Color(0.30, 0.27, 0.22)
|
||
draw_rect(Rect2(Vector2(s.x * 0.5 - 22, 90), Vector2(44, s.y - 220)), road_col)
|
||
# Pin altı bina blokları
|
||
for p in pins:
|
||
var bp: Vector2 = p
|
||
draw_line(Vector2(s.x * 0.5, bp.y), bp, road_col, 14.0)
|
||
var bsize := Vector2(120, 90)
|
||
var top_left := bp - Vector2(bsize.x / 2.0, bsize.y + 20)
|
||
draw_rect(Rect2(top_left, bsize), Color(0.28, 0.24, 0.20))
|
||
draw_rect(Rect2(top_left, bsize), Color(0.5, 0.42, 0.30), false, 2.0)
|
||
var roof := PackedVector2Array([
|
||
top_left + Vector2(-8, 0), top_left + Vector2(bsize.x + 8, 0),
|
||
top_left + Vector2(bsize.x / 2.0, -34)])
|
||
draw_colored_polygon(roof, Color(0.45, 0.22, 0.18))
|