Files
my-world/maps/hub/hub.gd
T
aibrashandClaude Sonnet 5.5 9130202a51 Карта Race: гонка на ногах по киберпанк-антиутопии, 8 игроков
- maps/race: трасса 633 м из Blender (три развилки: срез по контейнерам, каньон со стенами
  против нижней дороги, труба с лазерами против коридора), запечённый свет, небо, дождь, гул;
  фоновая песня (Ogg Vorbis, ~0,6 МБ) включается на «СТАРТ!»
- Правила (race_rules.gd): R — готов; когда готовы все — отсчёт 6 с, заморозка в слотах,
  ворота строго по порядку, сплиты, место, итоги, личный рекорд (user://race_best.cfg)
- Сеть: Net.submit_race / recv_race / race_event (RACE_READY, START, CP, FINISH, STATE).
  ВНИМАНИЕ: набор RPC изменён — клиент и сервер выкладываются вместе, старый клиент
  с новым сервером не работает (rpc node checksum failed)
- player.gd: input_frozen и place() для режимов карт; project.godot: действие ready (R)
- Портал RACE в хабе, пресет экспорта Race (include_filter для ресурсов, грузимых строкой)
- tools/test: двухклиентный тест гонки на локальном сервере, бот, облёт, проверка пакета
- README: правила гонки, события, проверки, заметки

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WxZo3ekR5m1af437Qzqwc1
2026-10-28 17:28:05 +05:00

122 lines
4.7 KiB
GDScript

extends Node3D
# Стартовая комната: ничего тяжёлого, только пол, стены и порталы на карты. Сами карты качаются
# отдельными пакетами при входе в портал (World/map_loader.gd) — поэтому игра стартует быстро.
# Чтобы добавить карту — допиши запись в PORTALS: порталы встанут в ряд по центру (влезает 6).
const PORTALS := [
{"title": "SANDBOX", "map": "world", "scene": "res://maps/sandbox/sandbox.tscn", "pack": "world.pck", "color": Color(0.2, 0.9, 1.0)},
{"title": "BACKROOMS", "map": "backrooms", "scene": "res://maps/backrooms/backrooms.tscn", "pack": "backrooms.pck", "color": Color(1.0, 0.85, 0.25)},
{"title": "PARKOUR", "map": "parkour", "scene": "res://maps/parkour/parkour.tscn", "pack": "parkour.pck", "color": Color(1.0, 0.2, 0.65)},
{"title": "RACE", "map": "race", "scene": "res://maps/race/race.tscn", "pack": "race.pck", "color": Color(1.0, 0.55, 0.12)},
]
const ROOM_WIDTH := 28.0
const ROOM_DEPTH := 18.0
const ROOM_HEIGHT := 6.0
const WALL := 0.5
const PORTAL_SPACING := 4.5
const GRID_SHADER := """
shader_type spatial;
varying vec3 wpos;
void vertex() { wpos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; }
void fragment() {
vec2 cell = wpos.xz / 2.0;
vec2 g = abs(fract(cell - 0.5) - 0.5) / fwidth(cell);
float line = 1.0 - min(min(g.x, g.y), 1.0);
ALBEDO = mix(vec3(0.03, 0.04, 0.06), vec3(0.1, 0.65, 0.85), line * 0.8);
EMISSION = vec3(0.04, 0.3, 0.4) * line;
ROUGHNESS = 0.9;
}
"""
func _ready() -> void:
Net.enter_map("hub")
_build_room()
_build_portals()
_build_environment()
func _build_room() -> void:
var body := StaticBody3D.new()
body.name = "Room"
add_child(body)
var floor_mat := ShaderMaterial.new()
floor_mat.shader = Shader.new()
floor_mat.shader.code = GRID_SHADER
var wall_mat := StandardMaterial3D.new()
wall_mat.albedo_color = Color(0.09, 0.1, 0.14)
wall_mat.roughness = 1.0
var ceiling_mat := StandardMaterial3D.new()
ceiling_mat.albedo_color = Color(0.05, 0.055, 0.08)
var hw := ROOM_WIDTH * 0.5
var hd := ROOM_DEPTH * 0.5
_add_box(body, Vector3(ROOM_WIDTH + WALL * 2, 0.5, ROOM_DEPTH + WALL * 2), Vector3(0, -0.25, 0), floor_mat)
_add_box(body, Vector3(ROOM_WIDTH + WALL * 2, 0.5, ROOM_DEPTH + WALL * 2), Vector3(0, ROOM_HEIGHT + 0.25, 0), ceiling_mat)
_add_box(body, Vector3(ROOM_WIDTH + WALL * 2, ROOM_HEIGHT, WALL), Vector3(0, ROOM_HEIGHT * 0.5, -hd - WALL * 0.5), wall_mat)
_add_box(body, Vector3(ROOM_WIDTH + WALL * 2, ROOM_HEIGHT, WALL), Vector3(0, ROOM_HEIGHT * 0.5, hd + WALL * 0.5), wall_mat)
_add_box(body, Vector3(WALL, ROOM_HEIGHT, ROOM_DEPTH), Vector3(-hw - WALL * 0.5, ROOM_HEIGHT * 0.5, 0), wall_mat)
_add_box(body, Vector3(WALL, ROOM_HEIGHT, ROOM_DEPTH), Vector3(hw + WALL * 0.5, ROOM_HEIGHT * 0.5, 0), wall_mat)
func _add_box(body: StaticBody3D, size: Vector3, pos: Vector3, mat: Material) -> void:
var shape := BoxShape3D.new()
shape.size = size
var cs := CollisionShape3D.new()
cs.shape = shape
cs.position = pos
body.add_child(cs)
var mesh := BoxMesh.new()
mesh.size = size
mesh.material = mat
var mi := MeshInstance3D.new()
mi.mesh = mesh
mi.position = pos
mi.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
add_child(mi)
# Порталы вдоль северной стены лицом в комнату, по центру
func _build_portals() -> void:
var portal_script := load("res://objects/portal.gd")
var z := -ROOM_DEPTH * 0.5 + 1.0
for i in PORTALS.size():
var info: Dictionary = PORTALS[i]
var portal := Area3D.new()
portal.set_script(portal_script)
portal.target_map = info.map
portal.target_scene = info.scene
portal.pack_name = info.pack
portal.title = info.title
portal.color = info.color
portal.position = Vector3((i - (PORTALS.size() - 1) * 0.5) * PORTAL_SPACING, 0.0, z)
add_child(portal)
var label := Label3D.new()
label.text = "CHOOSE A MAP"
label.pixel_size = 0.012
label.font_size = 64
label.outline_size = 12
label.modulate = Color(0.7, 0.9, 1.0)
label.position = Vector3(0, ROOM_HEIGHT - 0.35, -ROOM_DEPTH * 0.5 + 0.1)
add_child(label)
func _build_environment() -> void:
var env := Environment.new()
env.background_mode = Environment.BG_COLOR
env.background_color = Color(0.02, 0.025, 0.04)
env.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR
env.ambient_light_color = Color(0.5, 0.58, 0.75)
env.ambient_light_energy = 0.55
var we := WorldEnvironment.new()
we.environment = env
add_child(we)
var lamp := OmniLight3D.new()
lamp.position = Vector3(0, ROOM_HEIGHT - 0.6, 2.0)
lamp.omni_range = 22.0
lamp.light_energy = 0.8
lamp.light_color = Color(0.8, 0.9, 1.0)
lamp.shadow_enabled = false
add_child(lamp)