Стартовый хаб с порталами, песочница отдельным пакетом, присед
- World/Hub: маленькая стартовая комната (код, без ассетов) с порталами на карты; новые карты добавляются записью в PORTALS (влезает 6 порталов). - Песочница (main.tscn) вынесена в world.pck и качается при входе в портал; основной пакет игры вместо 19.7 МБ стал 2.1 МБ. Выходы из карт ведут в хаб. - Экспорт: три пресета (Web — движок и хаб, World, Backrooms). - Присед: удерживать C (на бегу Shift+C по-прежнему подкат), скорость 3.5. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -74,6 +74,8 @@ const SLIDE_COOLDOWN = 0.3
|
||||
const SLIDE_CAMERA_DROP = 0.6
|
||||
const SLIDE_HEIGHT_FACTOR = 0.5
|
||||
const CROUCH_SPEED = 2.5 # Ползём, если над головой низкий потолок
|
||||
const CROUCH_WALK_SPEED = 3.5 # Скорость в приседе (держим C; на бегу Shift+C — подкат)
|
||||
const CROUCH_CAMERA_DROP = 0.6
|
||||
const MIN_SLIDE_SPEED = 7.0 # Минимальная скорость для начала слайда
|
||||
|
||||
# --- Ступеньки ---
|
||||
@@ -123,6 +125,7 @@ var bob_time: float = 0.0
|
||||
|
||||
# Состояние подката
|
||||
var is_sliding: bool = false
|
||||
var is_crouching: bool = false
|
||||
var slide_cooldown_timer: float = 0.0
|
||||
var slide_dir: Vector3 = Vector3.ZERO
|
||||
var slide_speed: float = 0.0
|
||||
@@ -248,7 +251,7 @@ func _unhandled_input(event: InputEvent) -> void:
|
||||
# Битовые флаги состояния для сетевой синхронизации (см. Net.FLAG_*)
|
||||
func get_net_flags() -> int:
|
||||
var flags := 0
|
||||
if is_sliding: flags |= Net.FLAG_SLIDING
|
||||
if is_sliding or is_crouching: flags |= Net.FLAG_SLIDING # У призрака присед выглядит как сплюснутая капсула
|
||||
if is_wallrunning: flags |= Net.FLAG_WALLRUN
|
||||
if is_dashing: flags |= Net.FLAG_DASH
|
||||
if is_mantling: flags |= Net.FLAG_MANTLE
|
||||
@@ -277,6 +280,8 @@ func _physics_process(delta: float) -> void:
|
||||
|
||||
var space_down := Input.is_key_pressed(KEY_SPACE)
|
||||
|
||||
_update_crouch()
|
||||
|
||||
# --- Таймеры прыжка (coyote time + jump buffer) ---
|
||||
if is_on_floor():
|
||||
coyote_timer = COYOTE_TIME
|
||||
@@ -338,7 +343,9 @@ func _physics_process(delta: float) -> void:
|
||||
if is_wallrunning:
|
||||
_wall_jump(wall_normal)
|
||||
elif coyote_timer > 0.0:
|
||||
if not is_sliding or _can_stand():
|
||||
if (not is_sliding and not is_crouching) or _can_stand():
|
||||
if is_crouching:
|
||||
_end_crouch()
|
||||
velocity.y = JUMP_VELOCITY
|
||||
jump_buffer_timer = 0.0
|
||||
coyote_timer = 0.0
|
||||
@@ -360,7 +367,9 @@ func _physics_process(delta: float) -> void:
|
||||
|
||||
# 3. Скорость (Спринт)
|
||||
var current_speed := WALK_SPEED
|
||||
if Input.is_key_pressed(KEY_SHIFT):
|
||||
if is_crouching:
|
||||
current_speed = CROUCH_WALK_SPEED
|
||||
elif Input.is_key_pressed(KEY_SHIFT):
|
||||
current_speed = SPRINT_SPEED
|
||||
|
||||
# 4. Бег по стене
|
||||
@@ -714,6 +723,7 @@ func _try_start_slide() -> void:
|
||||
if horizontal.length() < MIN_SLIDE_SPEED:
|
||||
return
|
||||
|
||||
is_crouching = false
|
||||
is_sliding = true
|
||||
slide_dir = horizontal.normalized()
|
||||
slide_speed = clamp(max(horizontal.length() * SLIDE_START_MULT, SLIDE_START_SPEED), 0.0, MAX_SPEED)
|
||||
@@ -744,6 +754,23 @@ func _process_slide(delta: float, direction: Vector3, horizontal: Vector3) -> Ve
|
||||
return direction * CROUCH_SPEED
|
||||
return horizontal.move_toward(Vector3.ZERO, CROUCH_SPEED)
|
||||
|
||||
# --- ПРИСЕД ---
|
||||
|
||||
# Держим C на земле — приседаем. Встаём, когда отпустили, и над головой есть место
|
||||
func _update_crouch() -> void:
|
||||
var busy := is_sliding or is_dashing or is_wallrunning or is_mantling or not is_on_floor()
|
||||
if not is_crouching:
|
||||
if Input.is_key_pressed(KEY_C) and not busy:
|
||||
is_crouching = true
|
||||
_set_collider_crouched(true)
|
||||
elif (busy or not Input.is_key_pressed(KEY_C)) and (is_sliding or _can_stand()):
|
||||
_end_crouch()
|
||||
|
||||
func _end_crouch() -> void:
|
||||
is_crouching = false
|
||||
if not is_sliding:
|
||||
_set_collider_crouched(false)
|
||||
|
||||
func _end_slide() -> void:
|
||||
is_sliding = false
|
||||
slide_cooldown_timer = SLIDE_COOLDOWN
|
||||
@@ -784,6 +811,8 @@ func _update_camera(delta: float, input_dir: Vector2) -> void:
|
||||
var target_offset := 0.0
|
||||
if is_sliding:
|
||||
target_offset = -SLIDE_CAMERA_DROP
|
||||
elif is_crouching:
|
||||
target_offset = -CROUCH_CAMERA_DROP
|
||||
elif is_mantling:
|
||||
target_offset = -0.25
|
||||
head_offset_y = lerp(head_offset_y, target_offset, 12.0 * delta)
|
||||
@@ -879,6 +908,8 @@ func die() -> void:
|
||||
death_timer = DEATH_TIME
|
||||
if is_sliding:
|
||||
_end_slide()
|
||||
if is_crouching:
|
||||
_end_crouch()
|
||||
is_dashing = false
|
||||
is_wallrunning = false
|
||||
is_mantling = false
|
||||
|
||||
@@ -24,10 +24,10 @@ catch_height = 3.0
|
||||
sight_limited = true
|
||||
|
||||
[node name="Exit" type="Area3D" parent="." unique_id=1540431614]
|
||||
transform = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, -72, -0.15, 9)
|
||||
transform = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, -92.93203, -0.15, 10.390619)
|
||||
script = ExtResource("5_portal")
|
||||
target_map = "world"
|
||||
target_scene = "res://main.tscn"
|
||||
target_map = "hub"
|
||||
target_scene = "res://World/Hub/hub.tscn"
|
||||
title = "EXIT"
|
||||
color = Color(0.3, 1, 0.45, 1)
|
||||
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
extends Node3D
|
||||
# Стартовая комната: ничего тяжёлого, только пол, стены и порталы на карты. Сами карты качаются
|
||||
# отдельными пакетами при входе в портал (World/map_loader.gd) — поэтому игра стартует быстро.
|
||||
# Чтобы добавить карту — допиши запись в PORTALS: порталы встанут в ряд по центру (влезает 6).
|
||||
|
||||
const PORTALS := [
|
||||
{"title": "SANDBOX", "map": "world", "scene": "res://main.tscn", "pack": "world.pck", "color": Color(0.2, 0.9, 1.0)},
|
||||
{"title": "BACKROOMS", "map": "backrooms", "scene": "res://World/Backrooms/backrooms.tscn", "pack": "backrooms.pck", "color": Color(1.0, 0.85, 0.25)},
|
||||
]
|
||||
|
||||
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://World/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)
|
||||
@@ -0,0 +1 @@
|
||||
uid://dac7t22u2s6to
|
||||
@@ -0,0 +1,10 @@
|
||||
[gd_scene format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://World/Hub/hub.gd" id="1_hub"]
|
||||
[ext_resource type="PackedScene" uid="uid://c3efk6k8xnf57" path="res://Player/Player.tscn" id="2_player"]
|
||||
|
||||
[node name="Hub" type="Node3D"]
|
||||
script = ExtResource("1_hub")
|
||||
|
||||
[node name="Player" parent="." instance=ExtResource("2_player")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.2, 5)
|
||||
+51
-1
@@ -10,7 +10,7 @@ dedicated_server=false
|
||||
custom_features=""
|
||||
export_filter="all_resources"
|
||||
include_filter=""
|
||||
exclude_filter="models/backrooms/*, World/Backrooms/*"
|
||||
exclude_filter="models/backrooms/*, World/Backrooms/*, main.tscn, World/Floor/*, World/Sky/*, World/tron_01.ogg, World/forest.gd, World/birds.gd, World/levitate.gd, World/nav-bake.gd, models/building_02*, models/tower_01/*, models/house_02/*, models/cyber-office/*, models/obelisk_01/*, models/Tree_01/*, models/empire-state/*"
|
||||
export_path="../grid-world/index.html"
|
||||
patches=PackedStringArray()
|
||||
patch_delta_encoding=false
|
||||
@@ -100,3 +100,53 @@ progressive_web_app/icon_512x512=""
|
||||
progressive_web_app/background_color=Color(0, 0, 0, 1)
|
||||
threads/emscripten_pool_size=8
|
||||
threads/godot_pool_size=4
|
||||
|
||||
[preset.2]
|
||||
|
||||
name="World"
|
||||
platform="Web"
|
||||
dedicated_server=false
|
||||
custom_features=""
|
||||
export_filter="resources"
|
||||
export_files=PackedStringArray("res://main.tscn")
|
||||
include_filter=""
|
||||
exclude_filter="Player/*, models/Bochi-Rock/*, World/portal.gd"
|
||||
export_path="../grid-world/world.pck"
|
||||
patches=PackedStringArray()
|
||||
patch_delta_encoding=false
|
||||
patch_delta_compression_level_zstd=19
|
||||
patch_delta_min_reduction=0.1
|
||||
patch_delta_include_filters="*"
|
||||
patch_delta_exclude_filters=""
|
||||
encryption_include_filters=""
|
||||
encryption_exclude_filters=""
|
||||
seed=0
|
||||
encrypt_pck=false
|
||||
encrypt_directory=false
|
||||
script_export_mode=2
|
||||
|
||||
[preset.2.options]
|
||||
|
||||
custom_template/debug=""
|
||||
custom_template/release=""
|
||||
variant/extensions_support=true
|
||||
variant/thread_support=false
|
||||
vram_texture_compression/for_desktop=true
|
||||
vram_texture_compression/for_mobile=false
|
||||
html/export_icon=true
|
||||
html/custom_html_shell=""
|
||||
html/head_include=""
|
||||
html/canvas_resize_policy=2
|
||||
html/focus_canvas_on_start=true
|
||||
html/experimental_virtual_keyboard=false
|
||||
progressive_web_app/enabled=false
|
||||
progressive_web_app/ensure_cross_origin_isolation_headers=true
|
||||
progressive_web_app/offline_page=""
|
||||
progressive_web_app/display=3
|
||||
progressive_web_app/orientation=0
|
||||
progressive_web_app/icon_144x144=""
|
||||
progressive_web_app/icon_180x180=""
|
||||
progressive_web_app/icon_512x512=""
|
||||
progressive_web_app/background_color=Color(0, 0, 0, 1)
|
||||
threads/emscripten_pool_size=8
|
||||
threads/godot_pool_size=4
|
||||
|
||||
@@ -135,7 +135,10 @@ transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 188.
|
||||
script = ExtResource("18_navbake")
|
||||
exclude = Array[NodePath]([NodePath("../Architecture/rock"), NodePath("../CharacterBody3D")])
|
||||
|
||||
[node name="BackroomsPortal" type="Area3D" parent="." unique_id=982018721]
|
||||
[node name="HubPortal" type="Area3D" parent="." unique_id=982018721]
|
||||
transform = Transform3D(-0.49999985, 0, -0.8660255, 0, 1, 0, 0.8660255, 0, -0.49999985, -14.694777, 7.7547903, 22.85205)
|
||||
script = ExtResource("19_portal")
|
||||
pack_name = "backrooms.pck"
|
||||
target_map = "hub"
|
||||
target_scene = "res://World/Hub/hub.tscn"
|
||||
title = "HUB"
|
||||
color = Color(0.85, 0.9, 1, 1)
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ config_version=5
|
||||
[application]
|
||||
|
||||
config/name="world2"
|
||||
run/main_scene="uid://6vc0m7mc73f1"
|
||||
run/main_scene="res://World/Hub/hub.tscn"
|
||||
config/features=PackedStringArray("4.7", "GL Compatibility")
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user