Files
assets-generator/preview/scene_schrein.gd
2026-10-10 16:35:28 +02:00

262 lines
12 KiB
GDScript

extends "res://scene_base.gd"
## Szene Schrein: schwebende Steinplattformen im Nebel, Leuchtkanten, Kristall in der Mitte.
## Licht kommt aus den Dingen selbst (Glühen), dazu kaltes Streiflicht von oben rechts.
const VOID := Color("0c0a16")
const NEBULA := Color("3a2a6a")
const SLAB := Color("2a2438")
const SLAB_DARK := Color("161222")
const TEAL := Color("4ad8d0")
const INK := Color("eef0ff")
const MUTED := Color("9a98c0")
const PLAT_OPP := Rect2(300, 150, 700, 190)
const PLAT_OWN := Rect2(280, 430, 700, 190)
const PLAT_HAND := Rect2(360, 650, 560, 140)
func build_env() -> void:
light_dir = Vector2(0, 12)
layer(linear_tex(darker(NEBULA, 0.5), VOID), Rect2(Vector2.ZERO, size))
layer(noise_tex(320, 200, "simplex", 0.02, 21), Rect2(Vector2.ZERO, size), Color(NEBULA, 0.6))
layer(noise_tex(640, 400, "simplex", 0.12, 22), Rect2(Vector2.ZERO, size), Color("204050"), true)
layer(noise_tex(640, 400, "simplex", 0.12, 22), Rect2(Vector2.ZERO, size), Color(0, 0, 0, 0.45))
# Sterne
var img := Image.create(640, 400, false, Image.FORMAT_RGBA8)
img.fill(Color(0, 0, 0, 0))
var rng := RandomNumberGenerator.new()
rng.seed = 9
for i in 220:
var p := Vector2i(rng.randi_range(0, 639), rng.randi_range(0, 399))
img.set_pixelv(p, Color(1, 1, 1, rng.randf_range(0.2, 0.9)))
layer(ImageTexture.create_from_image(img), Rect2(Vector2.ZERO, size), Color(0.8, 0.85, 1.0, 0.5))
# Glühen unter den Plattformen und um den Kristall
for r in [PLAT_OPP, PLAT_OWN, PLAT_HAND]:
light(Vector2(r.get_center().x, r.end.y + 10), r.size.x * 0.55, TEAL, 0.18)
light(Vector2(640, 392), 180, Color("a0e0ff"), 0.45)
light(Vector2(1100, 60), 500, Color("8090ff"), 0.18)
vignette_layer(0.6)
func _draw() -> void:
_platforms()
_opponent()
_boards()
_player()
_preview()
txt("Dinger · Szene: Schrein", 12, MUTED, Vector2(20, 782), "midleft")
# --- Plattformen ------------------------------------------------------------------------------
func platform(rect: Rect2, edge: Color) -> void:
# Unterseite als dickere Platte mit Bruchkante
var under := Rect2(rect.position + Vector2(6, rect.size.y - 10), Vector2(rect.size.x - 12, 26))
draw_colored_polygon(PackedVector2Array([under.position, Vector2(under.end.x, under.position.y), Vector2(under.end.x - 14, under.end.y), Vector2(under.position.x + 20, under.end.y - 6)]), SLAB_DARK)
shadow(rect, 8, 18, 0.7, Vector2(0, 16))
grad(rect, 8, lighter(SLAB, 0.06), darker(SLAB, 0.7))
border(rect, 8, Color(0, 0, 0, 0.6), 2)
# Leuchtkante oben
draw_line(rect.position + Vector2(10, 2), Vector2(rect.end.x - 10, rect.position.y + 2), Color(edge, 0.9), 2, true)
draw_line(rect.position + Vector2(10, 4), Vector2(rect.end.x - 10, rect.position.y + 4), Color(edge, 0.25), 4, true)
# Runenlinie
for i in range(int(rect.size.x / 46)):
var x := rect.position.x + 24 + i * 46
draw_line(Vector2(x, rect.end.y - 7), Vector2(x + 18, rect.end.y - 7), Color(edge, 0.35), 1.5, true)
func _platforms() -> void:
platform(PLAT_OPP, Color("d06060"))
platform(PLAT_OWN, TEAL)
platform(PLAT_HAND, TEAL)
# Leylinie und Kristall
var c := Vector2(640, 392)
draw_line(Vector2(640, 340), Vector2(640, 430), Color(TEAL, 0.35), 4, true)
draw_line(Vector2(640, 340), Vector2(640, 430), Color("c0ffff"), 1.5, true)
var pts := PackedVector2Array([c + Vector2(0, -44), c + Vector2(22, -12), c + Vector2(16, 30), c + Vector2(0, 46), c + Vector2(-16, 30), c + Vector2(-22, -12)])
draw_colored_polygon(pts, Color("a8e8ff"))
draw_colored_polygon(PackedVector2Array([c + Vector2(0, -44), c + Vector2(22, -12), c + Vector2(0, 0)]), Color(1, 1, 1, 0.5))
draw_colored_polygon(PackedVector2Array([c + Vector2(0, 0), c + Vector2(16, 30), c + Vector2(0, 46), c + Vector2(-16, 30)]), Color("4090c0"))
var closed := pts.duplicate()
closed.append(pts[0])
draw_polyline(closed, Color("e0ffff"), 1.5, true)
var i := 0
for e in ["Feuer", "Luft", "Wasser", "Erde"]:
var a := -PI / 2 + i * PI / 2
var p := c + Vector2(cos(a), sin(a)) * 74
circle(p, 12, Color(ELEM[e], 0.35))
circle(p, 7, lighter(ELEM[e], 0.3))
circle(p + Vector2(-2, -2), 2.5, Color(1, 1, 1, 0.7))
i += 1
func slot(rect: Rect2) -> void:
rr(rect, 6, Color(0, 0, 0, 0.35))
border(rect, 6, Color(TEAL, 0.25), 1)
for k in 4:
var p := rect.position + Vector2(10 + (k % 2) * (rect.size.x - 20), 10 + (k / 2) * (rect.size.y - 20))
circle(p, 2, Color(TEAL, 0.5))
# --- Karten aus Obsidian mit Leuchtrand --------------------------------------------------------------
func card(rect: Rect2, name: String, elem: String, cost: int, atk: int, hp: int, big := false, rare_col = null) -> void:
var base: Color = ELEM[elem]
var edge: Color = rare_col if rare_col != null else lighter(base, 0.25)
var rad := 10 if big else 8
glow(rect, rad, edge, 12 if big else 8, 0.6)
shadow(rect, rad, 14, 0.6, Vector2(0, 10))
grad(rect, rad, lighter(SLAB, 0.04), darker(SLAB, 0.55))
border(rect, rad, Color(edge, 0.9), 2)
border(rect.grow(-2), rad - 2, Color(0, 0, 0, 0.5), 1)
var inner := rect.grow(-6)
var pic := Rect2(inner.position, Vector2(inner.size.x, inner.size.y * (0.42 if big else 0.52)))
rr(pic, rad - 4, darker(base, 0.25))
inset(pic, rad - 4, 0.8)
var gc := pic.get_center()
var gs := pic.size.x * (0.55 if big else 0.6)
for k in 3:
circle(gc, gs * (0.55 - k * 0.12), Color(lighter(base, 0.5), 0.12))
glyph(elem, gc, gs, lighter(base, 0.55))
glyph(elem, gc, gs * 0.6, Color(1, 1, 1, 0.35))
var fs := 14 if big else 11
var band := Rect2(inner.position.x, pic.end.y + 4, inner.size.x, fs + 10)
rr(band, 3, Color(0, 0, 0, 0.45))
draw_line(band.position + Vector2(6, band.size.y - 1), Vector2(band.end.x - 6, band.end.y - 1), Color(edge, 0.8), 1.5, true)
txt(fit(name, fs, band.size.x - 12), fs, INK, band.get_center(), "center", true)
if big:
var y := band.end.y + 14
keyword_icon(Vector2(inner.position.x + 24, y), 9, KW[elem], lighter(base, 0.45), Color(0, 0, 0, 0.6))
txt(KW[elem], 12, INK, Vector2(inner.position.x + 40, y), "midleft")
var box := Rect2(inner.position.x + 4, y + 14, inner.size.x - 8, rect.end.y - 52 - (y + 14))
rr(box, 4, Color(0, 0, 0, 0.45))
txt("Greift zweimal je Zug", 11, INK, box.get_center())
var r := 15.0 if big else 11.0
var fsz := 17 if big else 13
var m := r + 8
badge(rect.position + Vector2(m, rect.size.y - m), r, str(atk), Color("e0a020"), fsz, Color("6a6a80"))
badge(rect.position + Vector2(rect.size.x - m, rect.size.y - m), r, str(hp), Color("3a78d8"), fsz, Color("6a6a80"))
crystal(rect.position + Vector2(m, m), r + 1, str(cost), fsz, Color("3a6ad0"), Color("9ad8ff"))
func card_back(rect: Rect2) -> void:
glow(rect, 8, Color("8060d0"), 8, 0.5)
shadow(rect, 8, 10, 0.6, Vector2(0, 8))
grad(rect, 8, lighter(SLAB, 0.04), darker(SLAB, 0.55))
border(rect, 8, Color("a080ff"), 2)
var c := rect.get_center()
for k in 3:
circle(c, 30 - k * 8, Color("8060d0", 0.18))
var pts := PackedVector2Array([c + Vector2(0, -22), c + Vector2(11, -6), c + Vector2(8, 15), c + Vector2(0, 23), c + Vector2(-8, 15), c + Vector2(-11, -6)])
draw_colored_polygon(pts, Color("c0a8ff"))
draw_colored_polygon(PackedVector2Array([c + Vector2(0, -22), c + Vector2(11, -6), c]), Color(1, 1, 1, 0.4))
var closed := pts.duplicate()
closed.append(pts[0])
draw_polyline(closed, Color("e8e0ff"), 1.2, true)
func obelisk(rect: Rect2, count: String, label := "") -> void:
for i in range(5, 0, -1):
var r := Rect2(rect.position + Vector2(0, -i * 2.2), rect.size)
rr(r, 8, Color("1c1828"))
border(r, 8, Color("5040a0", 0.5), 1)
card_back(Rect2(rect.position + Vector2(0, -12), rect.size))
if label != "":
rr(Rect2(rect.position.x + 12, rect.end.y - 76, rect.size.x - 24, 44), 4, Color(0, 0, 0, 0.55))
txt_shadow(label, 15, INK, Vector2(rect.get_center().x, rect.end.y - 64), "center", true)
txt("◆ 0", 14, Color("8ab8ff"), Vector2(rect.get_center().x, rect.end.y - 44))
pill(Rect2(rect.position.x + 30, rect.end.y - 4, rect.size.x - 60, 22), count, Color("a080ff"))
func pill(rect: Rect2, label: String, edge: Color, fs := 13) -> void:
rr(rect, int(rect.size.y / 2), Color(0, 0, 0, 0.55))
border(rect, int(rect.size.y / 2), Color(edge, 0.7), 1)
txt(label, fs, INK, rect.get_center(), "center", true)
func orb(c: Vector2, name: String, life: String, elem: String, mana_full: int, active := false) -> void:
var col: Color = ELEM[elem]
for k in 4:
circle(c, 56 + k * 8, Color(col, 0.07))
circle(c, 44, darker(SLAB, 0.8))
circle(c, 42, Color(col, 0.45))
for k in 3:
circle(c, 40 - k * 10, Color(lighter(col, 0.3), 0.12))
glyph(elem, c + Vector2(0, 2), 46, lighter(col, 0.5), Color(0, 0, 0, 0.4))
circle(c + Vector2(-14, -16), 10, Color(1, 1, 1, 0.22))
ring(c, 44, lighter(col, 0.35) if active else Color(col, 0.6), 3)
if active:
ring(c, 50, Color(TEAL, 0.7), 1.5)
pill(Rect2(c.x - 60, c.y + 52, 120, 24), name, lighter(col, 0.3), 14)
badge(c + Vector2(-40, 34), 16, life, Color("c83030"), 15, Color("6a6a80"))
for i in 3:
var p := Vector2(c.x - 20 + i * 20, c.y + 92)
circle(p, 6, Color("3a6ad0") if i < mana_full else Color("1a1a30"))
ring(p, 6, Color("9ad8ff", 0.8 if i < mana_full else 0.3), 1.5)
func rune_pill(rect: Rect2, elem: String, filled: int, played: String) -> void:
var col: Color = ELEM[elem]
pill(rect, "", lighter(col, 0.2))
circle(Vector2(rect.position.x + 18, rect.get_center().y), 11, Color(col, 0.35))
glyph(elem, Vector2(rect.position.x + 18, rect.get_center().y), 16, lighter(col, 0.45))
txt(elem, 13, INK, Vector2(rect.position.x + 36, rect.get_center().y), "midleft", true)
for k in 2:
keyword_icon(Vector2(rect.position.x + 114 + k * 24, rect.get_center().y), 8, KW[elem], lighter(col, 0.4) if k < filled else Color(col, 0.3), Color(0, 0, 0, 0.6))
txt(played, 15, lighter(col, 0.4), Vector2(rect.end.x - 14, rect.get_center().y), "midright", true)
func button(rect: Rect2, label: String) -> void:
glow(rect, 6, TEAL, 5, 0.3)
grad(rect, 6, lighter(SLAB, 0.1), darker(SLAB, 0.6), 8)
border(rect, 6, Color(TEAL, 0.7), 1)
txt_shadow(label, 13, INK, rect.get_center(), "center", true)
# --- Anordnung ---------------------------------------------------------------------------------------
func _opponent() -> void:
orb(Vector2(130, 110), "Gegner", "35", "Feuer", 0)
rune_pill(Rect2(30, 232, 210, 32), "Feuer", 1, "1")
button(Rect2(30, 276, 210, 30), "Überspringen")
for i in 4:
var t := i - 1.5
var r := Rect2(430 + i * 112, 10, 100, 128)
draw_set_transform(r.get_center() + Vector2(0, t * t * 2), deg_to_rad(-t * 2))
card_back(Rect2(-r.size / 2, r.size))
draw_set_transform(Vector2.ZERO)
obelisk(Rect2(1090, 40, 110, 150), "35")
func _boards() -> void:
for j in 5:
var r := Rect2(352 + j * 122, 172, 110, 140)
if j == 0:
card(r, "Schwelender Drache", "Feuer", 1, 0, 5)
else:
slot(r)
for j in 5:
var r := Rect2(332 + j * 122, 452, 110, 140)
if j == 0:
card(r, "Rieselnder Geist", "Wasser", 1, 1, 2)
else:
slot(r)
func _player() -> void:
orb(Vector2(130, 600), "Spieler", "30", "Wasser", 1, true)
rune_pill(Rect2(30, 476, 210, 32), "Wasser", 1, "1")
var hand := [["Leiser Hauch", "Luft", 0, 0, 1, null], ["Glimmender Wolf", "Feuer", 1, 1, 3, Color("d0d8e4")],
["Stiller Tropfen", "Wasser", 0, 0, 1, null], ["Fester Kiesel", "Erde", 1, 1, 1, Color("f0b030")], ["Rieselnder Geist", "Wasser", 1, 1, 2, null]]
for i in hand.size():
var h = hand[i]
var t := i - 2.0
var c := Vector2(640 + t * 104, 700 + t * t * 2)
draw_set_transform(c, deg_to_rad(t * 4))
card(Rect2(-55, -70, 110, 140), h[0], h[1], h[2], h[3], h[4], false, h[5])
draw_set_transform(Vector2.ZERO)
obelisk(Rect2(1090, 616, 110, 150), "35", "Ziehen")
func _preview() -> void:
card(Rect2(1062, 250, 176, 246), "Glimmender Wolf", "Feuer", 1, 1, 3, true, Color("d0d8e4"))