fix: скролл лицензии, отец лицом к игроку, банка-цилиндр, экран
Some checks failed
Godot CI / Import + smoke test (push) Failing after 13s
Some checks failed
Godot CI / Import + smoke test (push) Failing after 13s
АКТ 2 СКРОЛЛ: - Body RichTextLabel: fit_content=true → false, теперь label остаётся в фиксированном размере 540×220 и скроллит контент внутри. Раньше label расширялся по тексту и обрезался панелью. - scroll_following=false (не следить за концом). - mouse_filter=STOP — теперь mouse wheel над label скроллит. - font_size снижен с дефолта на 11 — больше пунктов помещается на экране, читается комфортно. - Window custom_minimum_size = 580×348 (было 560×320) — больше места под лицензию. ОТЕЦ: - FatherNPC initial transform теперь rotation_y = +π/2 (Transform3D(0,0,-1,0,1,0,1,0,0,1.7,0,0)) — лицом к игроку на запад. Игрок видит лицо отца, а не профиль. - В _walk_father_out tween поворачивает rotation_y → -π/2 (180° поворот через 0/север). Шагает на восток к двери с правильно повёрнутым корпусом. МОНИТОР: - К Desk/OldPC добавлен child Screen — BoxMesh 0.21×0.15×0.005 с эмиссивной материалом mat_screen (тёмный с голубым свечением). - Стоит на передней грани монитора, имитирует тёмный экран с легким bluish-glow CRT-вибом. ADRENALINE BANK → ЦИЛИНДР: - mesh_can: BoxMesh → CylinderMesh top=bottom=0.03 height=0.13. Теперь это реально банка по форме, а не куб. ТЕКСТУРЫ ПРЕДМЕТОВ (TextureGen новые): - adrenaline_label: синий с тёмно-синими диагональными штрихами + жёлтая молния по центру + тёмные верхняя/нижняя кромки. - lays_wrapper: жёлтый с красной волнистой лентой посередине (синус) + коричневая чипса-клякса внизу + тёмные уголки. - sock_fabric: тёмно-синий с горизонтальными светлыми полосками каждые 6 пикселей + тёмный шов. - monitor_screen: тёмное стекло с edge-glow + scanlines каждые 2 строки (CRT-вайб). - Применены в act1.gd._apply_textures на AdrenalineCan, LaysWrapper, Sock1/Sock2. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f8040fb399
commit
579df43289
4 changed files with 166 additions and 7 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=90 format=3]
|
[gd_scene load_steps=92 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/prologue/act1.gd" id="1_act1"]
|
[ext_resource type="Script" path="res://scripts/prologue/act1.gd" id="1_act1"]
|
||||||
[ext_resource type="Script" path="res://scripts/interactables/interactable.gd" id="2_int"]
|
[ext_resource type="Script" path="res://scripts/interactables/interactable.gd" id="2_int"]
|
||||||
|
|
@ -121,8 +121,21 @@ size = Vector3(0.15, 0.03, 0.08)
|
||||||
[sub_resource type="BoxMesh" id="mesh_lays"]
|
[sub_resource type="BoxMesh" id="mesh_lays"]
|
||||||
size = Vector3(0.15, 0.01, 0.1)
|
size = Vector3(0.15, 0.01, 0.1)
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="mesh_can"]
|
[sub_resource type="CylinderMesh" id="mesh_can"]
|
||||||
size = Vector3(0.06, 0.13, 0.06)
|
top_radius = 0.03
|
||||||
|
bottom_radius = 0.03
|
||||||
|
height = 0.13
|
||||||
|
radial_segments = 16
|
||||||
|
rings = 2
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="mesh_screen"]
|
||||||
|
size = Vector3(0.21, 0.15, 0.005)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="mat_screen"]
|
||||||
|
albedo_color = Color(0.04, 0.05, 0.08, 1)
|
||||||
|
emission_enabled = true
|
||||||
|
emission = Color(0.18, 0.24, 0.4, 1)
|
||||||
|
emission_energy_multiplier = 0.5
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="mesh_plant"]
|
[sub_resource type="BoxMesh" id="mesh_plant"]
|
||||||
size = Vector3(0.09, 0.13, 0.09)
|
size = Vector3(0.09, 0.13, 0.09)
|
||||||
|
|
@ -510,6 +523,11 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0.55, -0.1)
|
||||||
mesh = SubResource("mesh_old_pc")
|
mesh = SubResource("mesh_old_pc")
|
||||||
material_override = SubResource("mat_old_pc")
|
material_override = SubResource("mat_old_pc")
|
||||||
|
|
||||||
|
[node name="Screen" type="MeshInstance3D" parent="Desk/OldPC"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.153)
|
||||||
|
mesh = SubResource("mesh_screen")
|
||||||
|
material_override = SubResource("mat_screen")
|
||||||
|
|
||||||
[node name="Keyboard" type="MeshInstance3D" parent="Desk"]
|
[node name="Keyboard" type="MeshInstance3D" parent="Desk"]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0.37, 0.18)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0.37, 0.18)
|
||||||
mesh = SubResource("mesh_keyboard")
|
mesh = SubResource("mesh_keyboard")
|
||||||
|
|
@ -600,7 +618,7 @@ material_override = SubResource("mat_note")
|
||||||
shape = SubResource("shape_note")
|
shape = SubResource("shape_note")
|
||||||
|
|
||||||
[node name="FatherNPC" type="Node3D" parent="."]
|
[node name="FatherNPC" type="Node3D" parent="."]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.7, 0, 0)
|
transform = Transform3D(0, 0, -1, 0, 1, 0, 1, 0, 0, 1.7, 0, 0)
|
||||||
|
|
||||||
[node name="Head" type="MeshInstance3D" parent="FatherNPC"]
|
[node name="Head" type="MeshInstance3D" parent="FatherNPC"]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.55, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.55, 0)
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
|
|
||||||
[node name="Window" type="PanelContainer" parent="Center"]
|
[node name="Window" type="PanelContainer" parent="Center"]
|
||||||
custom_minimum_size = Vector2(560, 320)
|
custom_minimum_size = Vector2(580, 348)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_styles/panel = SubResource("style_window")
|
theme_override_styles/panel = SubResource("style_window")
|
||||||
|
|
||||||
|
|
@ -137,12 +137,18 @@ horizontal_alignment = 1
|
||||||
modulate = Color(0.94, 0.71, 0.1, 1)
|
modulate = Color(0.94, 0.71, 0.1, 1)
|
||||||
|
|
||||||
[node name="Body" type="RichTextLabel" parent="Center/Window/V"]
|
[node name="Body" type="RichTextLabel" parent="Center/Window/V"]
|
||||||
custom_minimum_size = Vector2(530, 180)
|
custom_minimum_size = Vector2(540, 220)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
bbcode_enabled = true
|
bbcode_enabled = true
|
||||||
fit_content = true
|
fit_content = false
|
||||||
scroll_active = true
|
scroll_active = true
|
||||||
|
scroll_following = false
|
||||||
|
mouse_filter = 0
|
||||||
text = "Загрузка…"
|
text = "Загрузка…"
|
||||||
|
theme_override_font_sizes/normal_font_size = 11
|
||||||
|
theme_override_font_sizes/bold_font_size = 11
|
||||||
|
theme_override_font_sizes/italics_font_size = 11
|
||||||
|
theme_override_font_sizes/mono_font_size = 11
|
||||||
|
|
||||||
[node name="Input" type="LineEdit" parent="Center/Window/V"]
|
[node name="Input" type="LineEdit" parent="Center/Window/V"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,19 @@ func _apply_textures() -> void:
|
||||||
var book_mat: BaseMaterial3D = (book_node as MeshInstance3D).material_override
|
var book_mat: BaseMaterial3D = (book_node as MeshInstance3D).material_override
|
||||||
TextureGen.apply_to_material(book_mat, TextureGen.book_color(i), Vector3(1, 1, 1))
|
TextureGen.apply_to_material(book_mat, TextureGen.book_color(i), Vector3(1, 1, 1))
|
||||||
|
|
||||||
|
# Adrenaline / Lay's / Носки
|
||||||
|
var can_mat: BaseMaterial3D = ($Desk/AdrenalineCan as MeshInstance3D).material_override
|
||||||
|
TextureGen.apply_to_material(can_mat, TextureGen.adrenaline_label(), Vector3(1, 1, 1))
|
||||||
|
|
||||||
|
var lays_mat: BaseMaterial3D = ($Desk/LaysWrapper as MeshInstance3D).material_override
|
||||||
|
TextureGen.apply_to_material(lays_mat, TextureGen.lays_wrapper(), Vector3(1, 1, 1))
|
||||||
|
|
||||||
|
for sock_name in ["Sock1", "Sock2"]:
|
||||||
|
var sock_node: Node = get_node(sock_name)
|
||||||
|
if sock_node != null and sock_node is MeshInstance3D:
|
||||||
|
var sock_mat: BaseMaterial3D = (sock_node as MeshInstance3D).material_override
|
||||||
|
TextureGen.apply_to_material(sock_mat, TextureGen.sock_fabric(), Vector3(1, 1, 1))
|
||||||
|
|
||||||
|
|
||||||
func _play_intro() -> void:
|
func _play_intro() -> void:
|
||||||
system_unit.visible = false
|
system_unit.visible = false
|
||||||
|
|
|
||||||
|
|
@ -532,6 +532,128 @@ func book_color(color_idx: int) -> ImageTexture:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Этикетка Adrenaline Rush — синий со штрихами + молния
|
||||||
|
func adrenaline_label() -> ImageTexture:
|
||||||
|
return _get_or_create("adrenaline_label", func() -> ImageTexture:
|
||||||
|
var w: int = 64
|
||||||
|
var h: int = 64
|
||||||
|
var blue_dark: Color = Color(0.08, 0.18, 0.45)
|
||||||
|
var blue: Color = Color(0.13, 0.32, 0.68)
|
||||||
|
var blue_light: Color = Color(0.3, 0.5, 0.85)
|
||||||
|
var yellow: Color = Color(0.95, 0.85, 0.2)
|
||||||
|
var img: Image = _make_image(w, h, blue)
|
||||||
|
# Диагональные полосы
|
||||||
|
for y in range(h):
|
||||||
|
for x in range(w):
|
||||||
|
var d: int = (x + y) % 12
|
||||||
|
if d < 2:
|
||||||
|
img.set_pixel(x, y, blue_dark)
|
||||||
|
elif d < 4:
|
||||||
|
img.set_pixel(x, y, blue_light)
|
||||||
|
# Молния по центру
|
||||||
|
var bolt: Array = [
|
||||||
|
[32, 10], [32, 12], [31, 14], [31, 16], [30, 18], [33, 20],
|
||||||
|
[33, 22], [32, 24], [32, 26], [31, 28], [34, 30], [34, 32],
|
||||||
|
[33, 34], [33, 36], [32, 38], [35, 40], [34, 42], [33, 44],
|
||||||
|
[32, 46], [31, 48], [30, 50], [29, 52]
|
||||||
|
]
|
||||||
|
for p in bolt:
|
||||||
|
img.set_pixel(p[0], p[1], yellow)
|
||||||
|
if p[0] + 1 < w:
|
||||||
|
img.set_pixel(p[0] + 1, p[1], yellow)
|
||||||
|
if p[0] - 1 >= 0:
|
||||||
|
img.set_pixel(p[0] - 1, p[1], yellow)
|
||||||
|
# Верх/низ — тёмные полосы
|
||||||
|
for x in range(w):
|
||||||
|
img.set_pixel(x, 0, blue_dark)
|
||||||
|
img.set_pixel(x, 1, blue_dark)
|
||||||
|
img.set_pixel(x, h - 1, blue_dark)
|
||||||
|
img.set_pixel(x, h - 2, blue_dark)
|
||||||
|
return _to_texture(img)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Обёртка Lay's — жёлтая с красной волной
|
||||||
|
func lays_wrapper() -> ImageTexture:
|
||||||
|
return _get_or_create("lays_wrapper", func() -> ImageTexture:
|
||||||
|
var w: int = 64
|
||||||
|
var h: int = 48
|
||||||
|
var yellow: Color = Color(0.96, 0.84, 0.18)
|
||||||
|
var red: Color = Color(0.78, 0.12, 0.12)
|
||||||
|
var red_dark: Color = Color(0.55, 0.08, 0.08)
|
||||||
|
var brown: Color = Color(0.35, 0.22, 0.1)
|
||||||
|
var img: Image = _make_image(w, h, yellow)
|
||||||
|
# Красная волнистая лента посередине
|
||||||
|
for x in range(w):
|
||||||
|
var wave: int = int(sin(x * 0.3) * 4.0)
|
||||||
|
var band_y: int = 20 + wave
|
||||||
|
for dy in range(-4, 5):
|
||||||
|
var y: int = band_y + dy
|
||||||
|
if y >= 0 and y < h:
|
||||||
|
if dy == -4 or dy == 4:
|
||||||
|
img.set_pixel(x, y, red_dark)
|
||||||
|
else:
|
||||||
|
img.set_pixel(x, y, red)
|
||||||
|
# Силуэт чипса (овальная коричневая клякса)
|
||||||
|
for ang in range(20):
|
||||||
|
var a: float = float(ang) * PI / 10.0
|
||||||
|
var px: int = 16 + int(cos(a) * 6.0)
|
||||||
|
var py: int = 38 + int(sin(a) * 3.0)
|
||||||
|
if px >= 0 and px < w and py >= 0 and py < h:
|
||||||
|
img.set_pixel(px, py, brown)
|
||||||
|
# Уголки обёртки темнее
|
||||||
|
for i in range(3):
|
||||||
|
img.set_pixel(i, h - 1 - i, red_dark)
|
||||||
|
img.set_pixel(w - 1 - i, h - 1 - i, red_dark)
|
||||||
|
return _to_texture(img)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Носок — тёмно-серый со светлыми полосками
|
||||||
|
func sock_fabric() -> ImageTexture:
|
||||||
|
return _get_or_create("sock_fabric", func() -> ImageTexture:
|
||||||
|
var w: int = 32
|
||||||
|
var h: int = 32
|
||||||
|
var base: Color = Color(0.18, 0.22, 0.32)
|
||||||
|
var stripe: Color = Color(0.28, 0.32, 0.42)
|
||||||
|
var dark: Color = Color(0.1, 0.13, 0.2)
|
||||||
|
var img: Image = _make_image(w, h, base)
|
||||||
|
for y in range(h):
|
||||||
|
if y % 6 == 0 or y % 6 == 1:
|
||||||
|
for x in range(w):
|
||||||
|
img.set_pixel(x, y, stripe)
|
||||||
|
elif y % 6 == 3:
|
||||||
|
for x in range(w):
|
||||||
|
img.set_pixel(x, y, dark)
|
||||||
|
return _to_texture(img)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Экран монитора — тёмное стекло с легким bluish свечением
|
||||||
|
func monitor_screen() -> ImageTexture:
|
||||||
|
return _get_or_create("monitor_screen", func() -> ImageTexture:
|
||||||
|
var w: int = 64
|
||||||
|
var h: int = 48
|
||||||
|
var dark: Color = Color(0.04, 0.05, 0.08)
|
||||||
|
var glow: Color = Color(0.15, 0.2, 0.3)
|
||||||
|
var scan: Color = Color(0.08, 0.1, 0.14)
|
||||||
|
var img: Image = _make_image(w, h, dark)
|
||||||
|
# Боковые градиенты к свечению
|
||||||
|
for y in range(h):
|
||||||
|
for x in range(w):
|
||||||
|
var dx: float = abs(float(x) - float(w) / 2.0) / (float(w) / 2.0)
|
||||||
|
var dy: float = abs(float(y) - float(h) / 2.0) / (float(h) / 2.0)
|
||||||
|
var edge: float = max(dx, dy)
|
||||||
|
var c: Color = dark.lerp(glow, (1.0 - edge) * 0.4)
|
||||||
|
img.set_pixel(x, y, c)
|
||||||
|
# Горизонтальные scanlines каждые 2 строки
|
||||||
|
for y in range(0, h, 2):
|
||||||
|
for x in range(w):
|
||||||
|
img.set_pixel(x, y, img.get_pixel(x, y).lerp(scan, 0.4))
|
||||||
|
return _to_texture(img)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Применить текстуру к материалу с заданным uv-scale + nearest filter
|
# Применить текстуру к материалу с заданным uv-scale + nearest filter
|
||||||
func apply_to_material(mat: BaseMaterial3D, texture: ImageTexture, scale: Vector3 = Vector3.ONE) -> void:
|
func apply_to_material(mat: BaseMaterial3D, texture: ImageTexture, scale: Vector3 = Vector3.ONE) -> void:
|
||||||
if mat == null:
|
if mat == null:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue