524 lines
22 KiB
JavaScript
524 lines
22 KiB
JavaScript
import * as THREE from 'three';
|
||
|
||
export class Interiors {
|
||
constructor(game) {
|
||
this.game = game;
|
||
this.isInside = false;
|
||
this.currentBuilding = null;
|
||
this.savedPosition = null;
|
||
this.interiorObjects = [];
|
||
this.interiorColliders = [];
|
||
this.interiorInteractables = [];
|
||
this.built = false;
|
||
}
|
||
|
||
buildInteriors() {
|
||
if (this.built) return;
|
||
this.built = true;
|
||
|
||
this.buildShop();
|
||
this.buildHospital();
|
||
this.buildChurch();
|
||
}
|
||
|
||
createInteriorNPC(group, x, y, z, bodyColor, hasApron) {
|
||
// Тело
|
||
const bodyMat = new THREE.MeshStandardMaterial({ color: bodyColor });
|
||
const body = new THREE.Mesh(new THREE.CylinderGeometry(0.28, 0.32, 1.0, 8), bodyMat);
|
||
body.position.set(x, 0.8, z);
|
||
body.castShadow = true;
|
||
group.add(body);
|
||
|
||
// Голова
|
||
const head = new THREE.Mesh(
|
||
new THREE.SphereGeometry(0.2, 8, 6),
|
||
new THREE.MeshStandardMaterial({ color: 0xd4a574 })
|
||
);
|
||
head.position.set(x, 1.45, z);
|
||
group.add(head);
|
||
|
||
// Ноги
|
||
const legMat = new THREE.MeshStandardMaterial({ color: 0x333344 });
|
||
[-0.1, 0.1].forEach(side => {
|
||
const leg = new THREE.Mesh(new THREE.CylinderGeometry(0.07, 0.07, 0.4, 6), legMat);
|
||
leg.position.set(x + side, 0.2, z);
|
||
group.add(leg);
|
||
});
|
||
|
||
// Фартук (для продавца)
|
||
if (hasApron) {
|
||
const apron = new THREE.Mesh(
|
||
new THREE.BoxGeometry(0.5, 0.6, 0.05),
|
||
new THREE.MeshStandardMaterial({ color: 0xeeeeee })
|
||
);
|
||
apron.position.set(x, 0.7, z + 0.28);
|
||
group.add(apron);
|
||
}
|
||
}
|
||
|
||
addDoorFrame(group, ox, oz, d) {
|
||
const doorMat = new THREE.MeshStandardMaterial({ color: 0x6b3a1f });
|
||
// Дверная рама (ширина проёма 2.4)
|
||
const frameLeft = new THREE.Mesh(new THREE.BoxGeometry(0.12, 2.4, 0.25), doorMat);
|
||
frameLeft.position.set(ox - 1.2, 1.2, oz + d / 2);
|
||
group.add(frameLeft);
|
||
const frameRight = new THREE.Mesh(new THREE.BoxGeometry(0.12, 2.4, 0.25), doorMat);
|
||
frameRight.position.set(ox + 1.2, 1.2, oz + d / 2);
|
||
group.add(frameRight);
|
||
const frameTop = new THREE.Mesh(new THREE.BoxGeometry(2.5, 0.12, 0.25), doorMat);
|
||
frameTop.position.set(ox, 2.4, oz + d / 2);
|
||
group.add(frameTop);
|
||
|
||
// Табличка "ВЫХОД" (зелёная, светящаяся)
|
||
const signMat = new THREE.MeshStandardMaterial({ color: 0x22cc44, emissive: 0x22cc44, emissiveIntensity: 0.8 });
|
||
const sign = new THREE.Mesh(new THREE.BoxGeometry(1.2, 0.3, 0.05), signMat);
|
||
sign.position.set(ox, 2.7, oz + d / 2 - 0.05);
|
||
group.add(sign);
|
||
|
||
// Подсветка у двери
|
||
const doorLight = new THREE.PointLight(0x44ff66, 0.3, 4);
|
||
doorLight.position.set(ox, 2.5, oz + d / 2 - 0.5);
|
||
group.add(doorLight);
|
||
|
||
// Коврик у двери
|
||
const matFloor = new THREE.Mesh(
|
||
new THREE.PlaneGeometry(2, 1),
|
||
new THREE.MeshStandardMaterial({ color: 0x886644 })
|
||
);
|
||
matFloor.rotation.x = -Math.PI / 2;
|
||
matFloor.position.set(ox, 0.02, oz + d / 2 - 0.5);
|
||
group.add(matFloor);
|
||
}
|
||
|
||
buildShop() {
|
||
const ox = 500, oz = 0;
|
||
const w = 10, d = 8, h = 3.5;
|
||
const group = new THREE.Group();
|
||
|
||
// Пол
|
||
const floorMat = new THREE.MeshStandardMaterial({ color: 0xddccaa });
|
||
const floor = new THREE.Mesh(new THREE.PlaneGeometry(w, d), floorMat);
|
||
floor.rotation.x = -Math.PI / 2;
|
||
floor.position.set(ox, 0.01, oz);
|
||
floor.receiveShadow = true;
|
||
group.add(floor);
|
||
|
||
// Потолок
|
||
const ceilMat = new THREE.MeshStandardMaterial({ color: 0xeeeeee, side: THREE.BackSide });
|
||
const ceil = new THREE.Mesh(new THREE.PlaneGeometry(w, d), ceilMat);
|
||
ceil.rotation.x = -Math.PI / 2;
|
||
ceil.position.set(ox, h, oz);
|
||
group.add(ceil);
|
||
|
||
// Стены
|
||
const wallMat = new THREE.MeshStandardMaterial({ color: 0xf5e6cc });
|
||
// Задняя стена
|
||
const backWall = new THREE.Mesh(new THREE.BoxGeometry(w, h, 0.2), wallMat);
|
||
backWall.position.set(ox, h / 2, oz - d / 2);
|
||
backWall.castShadow = true;
|
||
group.add(backWall);
|
||
// Левая стена
|
||
const leftWall = new THREE.Mesh(new THREE.BoxGeometry(0.2, h, d), wallMat);
|
||
leftWall.position.set(ox - w / 2, h / 2, oz);
|
||
group.add(leftWall);
|
||
// Правая стена
|
||
const rightWall = new THREE.Mesh(new THREE.BoxGeometry(0.2, h, d), wallMat);
|
||
rightWall.position.set(ox + w / 2, h / 2, oz);
|
||
group.add(rightWall);
|
||
// Передняя стена с проёмом (дверь)
|
||
const frontLeft = new THREE.Mesh(new THREE.BoxGeometry(w / 2 - 1.4, h, 0.2), wallMat);
|
||
frontLeft.position.set(ox - w / 4 - 0.7, h / 2, oz + d / 2);
|
||
group.add(frontLeft);
|
||
const frontRight = new THREE.Mesh(new THREE.BoxGeometry(w / 2 - 1.4, h, 0.2), wallMat);
|
||
frontRight.position.set(ox + w / 4 + 0.7, h / 2, oz + d / 2);
|
||
group.add(frontRight);
|
||
|
||
// Прилавок
|
||
const counterMat = new THREE.MeshStandardMaterial({ color: 0x8b6914 });
|
||
const counter = new THREE.Mesh(new THREE.BoxGeometry(5, 1, 0.6), counterMat);
|
||
counter.position.set(ox, 0.5, oz - 1.5);
|
||
counter.castShadow = true;
|
||
group.add(counter);
|
||
|
||
// Продавец за прилавком
|
||
this.createInteriorNPC(group, ox + 1, 0, oz - 2.2, 0x336633, true);
|
||
|
||
// Полки на стене
|
||
const shelfMat = new THREE.MeshStandardMaterial({ color: 0x9b7b3c });
|
||
for (let i = 0; i < 3; i++) {
|
||
const shelf = new THREE.Mesh(new THREE.BoxGeometry(2.5, 0.08, 0.5), shelfMat);
|
||
shelf.position.set(ox - 3 + i * 3, 1.5, oz - d / 2 + 0.35);
|
||
group.add(shelf);
|
||
// Товары на полках
|
||
for (let j = 0; j < 3; j++) {
|
||
const item = new THREE.Mesh(
|
||
new THREE.BoxGeometry(0.3, 0.4, 0.3),
|
||
new THREE.MeshStandardMaterial({ color: [0xe8a030, 0x4488cc, 0xcc4444][j] })
|
||
);
|
||
item.position.set(ox - 3.5 + i * 3 + j * 0.5, 1.75, oz - d / 2 + 0.35);
|
||
group.add(item);
|
||
}
|
||
}
|
||
|
||
// Дверная рама и табличка
|
||
this.addDoorFrame(group, ox, oz, d);
|
||
|
||
// Свет
|
||
const light = new THREE.PointLight(0xffe8c0, 1, 15);
|
||
light.position.set(ox, h - 0.3, oz);
|
||
group.add(light);
|
||
|
||
this.game.scene.add(group);
|
||
this.interiorObjects.push(group);
|
||
|
||
// Коллайдеры
|
||
this.interiorColliders.push(
|
||
new THREE.Box3(new THREE.Vector3(ox - w / 2 - 0.1, 0, oz - d / 2 - 0.2), new THREE.Vector3(ox + w / 2 + 0.1, h, oz - d / 2)),
|
||
new THREE.Box3(new THREE.Vector3(ox - w / 2 - 0.2, 0, oz - d / 2), new THREE.Vector3(ox - w / 2, h, oz + d / 2)),
|
||
new THREE.Box3(new THREE.Vector3(ox + w / 2, 0, oz - d / 2), new THREE.Vector3(ox + w / 2 + 0.2, h, oz + d / 2)),
|
||
// Передняя стена левая часть
|
||
new THREE.Box3(new THREE.Vector3(ox - w / 2, 0, oz + d / 2 - 0.1), new THREE.Vector3(ox - 1.3, h, oz + d / 2 + 0.1)),
|
||
new THREE.Box3(new THREE.Vector3(ox + 1.3, 0, oz + d / 2 - 0.1), new THREE.Vector3(ox + w / 2, h, oz + d / 2 + 0.1)),
|
||
// Прилавок коллайдер
|
||
new THREE.Box3(new THREE.Vector3(ox - 2.5, 0, oz - 1.8), new THREE.Vector3(ox + 2.5, 1, oz - 1.2)),
|
||
);
|
||
|
||
// Интерактивные объекты внутри
|
||
this.interiorInteractables.push(
|
||
{
|
||
position: new THREE.Vector3(ox, 0, oz - 1.5),
|
||
radius: 2.5,
|
||
type: 'shop_counter',
|
||
label: 'Купить / Продать',
|
||
building: 'shop'
|
||
},
|
||
{
|
||
position: new THREE.Vector3(ox, 0, oz + d / 2 - 0.5),
|
||
radius: 2,
|
||
type: 'exit_door',
|
||
label: 'Выйти на улицу',
|
||
building: 'shop'
|
||
}
|
||
);
|
||
}
|
||
|
||
buildHospital() {
|
||
const ox = 500, oz = 50;
|
||
const w = 12, d = 10, h = 3.5;
|
||
const group = new THREE.Group();
|
||
|
||
// Пол
|
||
const floorMat = new THREE.MeshStandardMaterial({ color: 0xe8e8e8 });
|
||
const floor = new THREE.Mesh(new THREE.PlaneGeometry(w, d), floorMat);
|
||
floor.rotation.x = -Math.PI / 2;
|
||
floor.position.set(ox, 0.01, oz);
|
||
floor.receiveShadow = true;
|
||
group.add(floor);
|
||
|
||
// Потолок
|
||
const ceilMat = new THREE.MeshStandardMaterial({ color: 0xffffff, side: THREE.BackSide });
|
||
const ceil = new THREE.Mesh(new THREE.PlaneGeometry(w, d), ceilMat);
|
||
ceil.rotation.x = -Math.PI / 2;
|
||
ceil.position.set(ox, h, oz);
|
||
group.add(ceil);
|
||
|
||
// Стены (белые)
|
||
const wallMat = new THREE.MeshStandardMaterial({ color: 0xf0f0f0 });
|
||
const backWall = new THREE.Mesh(new THREE.BoxGeometry(w, h, 0.2), wallMat);
|
||
backWall.position.set(ox, h / 2, oz - d / 2);
|
||
group.add(backWall);
|
||
const leftWall = new THREE.Mesh(new THREE.BoxGeometry(0.2, h, d), wallMat);
|
||
leftWall.position.set(ox - w / 2, h / 2, oz);
|
||
group.add(leftWall);
|
||
const rightWall = new THREE.Mesh(new THREE.BoxGeometry(0.2, h, d), wallMat);
|
||
rightWall.position.set(ox + w / 2, h / 2, oz);
|
||
group.add(rightWall);
|
||
const frontLeft = new THREE.Mesh(new THREE.BoxGeometry(w / 2 - 1.4, h, 0.2), wallMat);
|
||
frontLeft.position.set(ox - w / 4 - 0.7, h / 2, oz + d / 2);
|
||
group.add(frontLeft);
|
||
const frontRight = new THREE.Mesh(new THREE.BoxGeometry(w / 2 - 1.4, h, 0.2), wallMat);
|
||
frontRight.position.set(ox + w / 4 + 0.7, h / 2, oz + d / 2);
|
||
group.add(frontRight);
|
||
|
||
// Кровати
|
||
const bedMat = new THREE.MeshStandardMaterial({ color: 0xffffff });
|
||
const frameMat = new THREE.MeshStandardMaterial({ color: 0xaabbcc });
|
||
for (let i = 0; i < 3; i++) {
|
||
const frame = new THREE.Mesh(new THREE.BoxGeometry(1.8, 0.4, 0.9), frameMat);
|
||
frame.position.set(ox - 4 + i * 3.5, 0.25, oz - 3);
|
||
frame.castShadow = true;
|
||
group.add(frame);
|
||
const mattress = new THREE.Mesh(new THREE.BoxGeometry(1.6, 0.1, 0.7), bedMat);
|
||
mattress.position.set(ox - 4 + i * 3.5, 0.5, oz - 3);
|
||
group.add(mattress);
|
||
}
|
||
|
||
// Стол врача
|
||
const desk = new THREE.Mesh(
|
||
new THREE.BoxGeometry(2, 0.8, 1),
|
||
new THREE.MeshStandardMaterial({ color: 0xccccdd })
|
||
);
|
||
desk.position.set(ox + 3, 0.4, oz + 2);
|
||
desk.castShadow = true;
|
||
group.add(desk);
|
||
|
||
// Врач за столом
|
||
this.createInteriorNPC(group, ox + 3, 0, oz + 1.2, 0xeeeeee, false);
|
||
|
||
// Красный крест на стене
|
||
const crossMat = new THREE.MeshStandardMaterial({ color: 0xff3333 });
|
||
const crossH = new THREE.Mesh(new THREE.BoxGeometry(1.2, 0.2, 0.05), crossMat);
|
||
crossH.position.set(ox, 2.5, oz - d / 2 + 0.15);
|
||
group.add(crossH);
|
||
const crossV = new THREE.Mesh(new THREE.BoxGeometry(0.2, 1.2, 0.05), crossMat);
|
||
crossV.position.set(ox, 2.5, oz - d / 2 + 0.15);
|
||
group.add(crossV);
|
||
|
||
// Дверная рама и табличка
|
||
this.addDoorFrame(group, ox, oz, d);
|
||
|
||
// Свет
|
||
const light = new THREE.PointLight(0xffffff, 1.2, 18);
|
||
light.position.set(ox, h - 0.3, oz);
|
||
group.add(light);
|
||
|
||
this.game.scene.add(group);
|
||
this.interiorObjects.push(group);
|
||
|
||
this.interiorColliders.push(
|
||
new THREE.Box3(new THREE.Vector3(ox - w / 2 - 0.1, 0, oz - d / 2 - 0.2), new THREE.Vector3(ox + w / 2 + 0.1, h, oz - d / 2)),
|
||
new THREE.Box3(new THREE.Vector3(ox - w / 2 - 0.2, 0, oz - d / 2), new THREE.Vector3(ox - w / 2, h, oz + d / 2)),
|
||
new THREE.Box3(new THREE.Vector3(ox + w / 2, 0, oz - d / 2), new THREE.Vector3(ox + w / 2 + 0.2, h, oz + d / 2)),
|
||
new THREE.Box3(new THREE.Vector3(ox - w / 2, 0, oz + d / 2 - 0.1), new THREE.Vector3(ox - 0.8, h, oz + d / 2 + 0.1)),
|
||
new THREE.Box3(new THREE.Vector3(ox + 0.8, 0, oz + d / 2 - 0.1), new THREE.Vector3(ox + w / 2, h, oz + d / 2 + 0.1)),
|
||
new THREE.Box3(new THREE.Vector3(ox + 2, 0, oz + 1.5), new THREE.Vector3(ox + 4, 0.8, oz + 2.5)),
|
||
);
|
||
|
||
this.interiorInteractables.push(
|
||
{
|
||
position: new THREE.Vector3(ox + 3, 0, oz + 2),
|
||
radius: 2.5,
|
||
type: 'hospital_desk',
|
||
label: 'Лечение',
|
||
building: 'hospital'
|
||
},
|
||
{
|
||
position: new THREE.Vector3(ox, 0, oz + d / 2 - 0.5),
|
||
radius: 2,
|
||
type: 'exit_door',
|
||
label: 'Выйти на улицу',
|
||
building: 'hospital'
|
||
}
|
||
);
|
||
}
|
||
|
||
buildChurch() {
|
||
const ox = 500, oz = 100;
|
||
const w = 10, d = 14, h = 5;
|
||
const group = new THREE.Group();
|
||
|
||
// Пол (деревянный)
|
||
const floorMat = new THREE.MeshStandardMaterial({ color: 0xb89060 });
|
||
const floor = new THREE.Mesh(new THREE.PlaneGeometry(w, d), floorMat);
|
||
floor.rotation.x = -Math.PI / 2;
|
||
floor.position.set(ox, 0.01, oz);
|
||
floor.receiveShadow = true;
|
||
group.add(floor);
|
||
|
||
// Потолок
|
||
const ceilMat = new THREE.MeshStandardMaterial({ color: 0xddd8c0, side: THREE.BackSide });
|
||
const ceil = new THREE.Mesh(new THREE.PlaneGeometry(w, d), ceilMat);
|
||
ceil.rotation.x = -Math.PI / 2;
|
||
ceil.position.set(ox, h, oz);
|
||
group.add(ceil);
|
||
|
||
// Стены
|
||
const wallMat = new THREE.MeshStandardMaterial({ color: 0xf0e8d0 });
|
||
const backWall = new THREE.Mesh(new THREE.BoxGeometry(w, h, 0.2), wallMat);
|
||
backWall.position.set(ox, h / 2, oz - d / 2);
|
||
group.add(backWall);
|
||
const leftWall = new THREE.Mesh(new THREE.BoxGeometry(0.2, h, d), wallMat);
|
||
leftWall.position.set(ox - w / 2, h / 2, oz);
|
||
group.add(leftWall);
|
||
const rightWall = new THREE.Mesh(new THREE.BoxGeometry(0.2, h, d), wallMat);
|
||
rightWall.position.set(ox + w / 2, h / 2, oz);
|
||
group.add(rightWall);
|
||
const frontLeft = new THREE.Mesh(new THREE.BoxGeometry(w / 2 - 1.4, h, 0.2), wallMat);
|
||
frontLeft.position.set(ox - w / 4 - 0.7, h / 2, oz + d / 2);
|
||
group.add(frontLeft);
|
||
const frontRight = new THREE.Mesh(new THREE.BoxGeometry(w / 2 - 1.4, h, 0.2), wallMat);
|
||
frontRight.position.set(ox + w / 4 + 0.7, h / 2, oz + d / 2);
|
||
group.add(frontRight);
|
||
|
||
// Скамьи (ряды)
|
||
const benchMat = new THREE.MeshStandardMaterial({ color: 0x8b6914 });
|
||
for (let row = 0; row < 4; row++) {
|
||
for (let side = -1; side <= 1; side += 2) {
|
||
const bench = new THREE.Mesh(new THREE.BoxGeometry(3, 0.4, 0.5), benchMat);
|
||
bench.position.set(ox + side * 2, 0.25, oz - 3 + row * 2.5);
|
||
bench.castShadow = true;
|
||
group.add(bench);
|
||
}
|
||
}
|
||
|
||
// Алтарь
|
||
const altarMat = new THREE.MeshStandardMaterial({ color: 0xf5e6cc });
|
||
const altar = new THREE.Mesh(new THREE.BoxGeometry(2, 1, 0.8), altarMat);
|
||
altar.position.set(ox, 0.5, oz - d / 2 + 1.5);
|
||
altar.castShadow = true;
|
||
group.add(altar);
|
||
|
||
// Крест на стене
|
||
const crossMat = new THREE.MeshStandardMaterial({ color: 0xdaa520 });
|
||
const crossH = new THREE.Mesh(new THREE.BoxGeometry(1.5, 0.15, 0.05), crossMat);
|
||
crossH.position.set(ox, 3.5, oz - d / 2 + 0.15);
|
||
group.add(crossH);
|
||
const crossV = new THREE.Mesh(new THREE.BoxGeometry(0.15, 2, 0.05), crossMat);
|
||
crossV.position.set(ox, 3.5, oz - d / 2 + 0.15);
|
||
group.add(crossV);
|
||
|
||
// Свечи
|
||
const candleMat = new THREE.MeshStandardMaterial({ color: 0xfff8dc });
|
||
for (let i = -1; i <= 1; i++) {
|
||
const candle = new THREE.Mesh(new THREE.CylinderGeometry(0.03, 0.03, 0.2, 6), candleMat);
|
||
candle.position.set(ox + i * 0.4, 1.15, oz - d / 2 + 1.5);
|
||
group.add(candle);
|
||
}
|
||
|
||
// Отец Михаил у алтаря
|
||
this.createInteriorNPC(group, ox + 1.5, 0, oz - d / 2 + 2, 0x222244, false);
|
||
// Борода
|
||
const beard = new THREE.Mesh(
|
||
new THREE.BoxGeometry(0.22, 0.2, 0.12),
|
||
new THREE.MeshStandardMaterial({ color: 0x555555 })
|
||
);
|
||
beard.position.set(ox + 1.5, 1.3, oz - d / 2 + 2 + 0.15);
|
||
group.add(beard);
|
||
// Нагрудный крест
|
||
const priestCrossH = new THREE.Mesh(
|
||
new THREE.BoxGeometry(0.12, 0.03, 0.03),
|
||
new THREE.MeshStandardMaterial({ color: 0xdaa520 })
|
||
);
|
||
priestCrossH.position.set(ox + 1.5, 1.0, oz - d / 2 + 2 + 0.3);
|
||
group.add(priestCrossH);
|
||
const priestCrossV = new THREE.Mesh(
|
||
new THREE.BoxGeometry(0.03, 0.18, 0.03),
|
||
new THREE.MeshStandardMaterial({ color: 0xdaa520 })
|
||
);
|
||
priestCrossV.position.set(ox + 1.5, 1.0, oz - d / 2 + 2 + 0.3);
|
||
group.add(priestCrossV);
|
||
|
||
// Дверная рама и табличка
|
||
this.addDoorFrame(group, ox, oz, d);
|
||
|
||
// Тёплый свет
|
||
const light = new THREE.PointLight(0xffe0a0, 0.8, 20);
|
||
light.position.set(ox, h - 0.5, oz);
|
||
group.add(light);
|
||
const altarLight = new THREE.PointLight(0xffcc66, 0.5, 8);
|
||
altarLight.position.set(ox, 1.5, oz - d / 2 + 1.5);
|
||
group.add(altarLight);
|
||
|
||
this.game.scene.add(group);
|
||
this.interiorObjects.push(group);
|
||
|
||
this.interiorColliders.push(
|
||
new THREE.Box3(new THREE.Vector3(ox - w / 2 - 0.1, 0, oz - d / 2 - 0.2), new THREE.Vector3(ox + w / 2 + 0.1, h, oz - d / 2)),
|
||
new THREE.Box3(new THREE.Vector3(ox - w / 2 - 0.2, 0, oz - d / 2), new THREE.Vector3(ox - w / 2, h, oz + d / 2)),
|
||
new THREE.Box3(new THREE.Vector3(ox + w / 2, 0, oz - d / 2), new THREE.Vector3(ox + w / 2 + 0.2, h, oz + d / 2)),
|
||
new THREE.Box3(new THREE.Vector3(ox - w / 2, 0, oz + d / 2 - 0.1), new THREE.Vector3(ox - 0.8, h, oz + d / 2 + 0.1)),
|
||
new THREE.Box3(new THREE.Vector3(ox + 0.8, 0, oz + d / 2 - 0.1), new THREE.Vector3(ox + w / 2, h, oz + d / 2 + 0.1)),
|
||
new THREE.Box3(new THREE.Vector3(ox - 1, 0, oz - d / 2 + 1.1), new THREE.Vector3(ox + 1, 1, oz - d / 2 + 1.9)),
|
||
);
|
||
|
||
this.interiorInteractables.push(
|
||
{
|
||
position: new THREE.Vector3(ox, 0, oz - d / 2 + 1.5),
|
||
radius: 2.5,
|
||
type: 'church_altar',
|
||
label: 'Помолиться / Еда',
|
||
building: 'church'
|
||
},
|
||
{
|
||
position: new THREE.Vector3(ox, 0, oz + d / 2 - 0.5),
|
||
radius: 2,
|
||
type: 'exit_door',
|
||
label: 'Выйти на улицу',
|
||
building: 'church'
|
||
}
|
||
);
|
||
}
|
||
|
||
enterBuilding(type) {
|
||
if (this.isInside) return;
|
||
|
||
if (!this.built) this.buildInteriors();
|
||
|
||
this.savedPosition = this.game.player.position.clone();
|
||
this.currentBuilding = type;
|
||
this.isInside = true;
|
||
|
||
// Позиция входа в интерьер
|
||
const entries = {
|
||
shop: new THREE.Vector3(500, 0, 3),
|
||
hospital: new THREE.Vector3(500, 0, 53),
|
||
church: new THREE.Vector3(500, 0, 106),
|
||
};
|
||
|
||
const entry = entries[type];
|
||
if (entry) {
|
||
this.game.player.position.copy(entry);
|
||
this.game.player.mesh.position.copy(entry);
|
||
}
|
||
|
||
// Зафиксировать погоду/освещение
|
||
this.game.scene.fog = null;
|
||
|
||
// Подключить интерьерные коллайдеры и интерактивные объекты
|
||
this._origColliders = this.game.world.colliders;
|
||
this._origInteractables = this.game.world.interactables;
|
||
this.game.world.colliders = this.interiorColliders;
|
||
this.game.world.interactables = this.interiorInteractables.filter(i => i.building === type);
|
||
|
||
// Скрыть наружные объекты для производительности
|
||
this.game.player.position.x = THREE.MathUtils.clamp(this.game.player.position.x, 490, 510);
|
||
this.game.player.position.z = THREE.MathUtils.clamp(this.game.player.position.z, -10, 120);
|
||
|
||
const names = { shop: 'Магазин', hospital: 'Больница', church: 'Церковь' };
|
||
this.game.notify(`Вы вошли: ${names[type] || type}`);
|
||
}
|
||
|
||
exitBuilding() {
|
||
if (!this.isInside) return;
|
||
|
||
this.isInside = false;
|
||
|
||
// Восстановить позицию
|
||
if (this.savedPosition) {
|
||
this.game.player.position.copy(this.savedPosition);
|
||
this.game.player.mesh.position.copy(this.savedPosition);
|
||
}
|
||
|
||
// Восстановить туман
|
||
this.game.scene.fog = new THREE.Fog(0x87CEEB, 80, 200);
|
||
|
||
// Восстановить коллайдеры
|
||
if (this._origColliders) this.game.world.colliders = this._origColliders;
|
||
if (this._origInteractables) this.game.world.interactables = this._origInteractables;
|
||
|
||
this.currentBuilding = null;
|
||
this.game.notify('Вы вышли на улицу.');
|
||
}
|
||
|
||
reset() {
|
||
if (this.isInside) {
|
||
this.exitBuilding();
|
||
}
|
||
this.interiorObjects.forEach(obj => this.game.scene.remove(obj));
|
||
this.interiorObjects = [];
|
||
this.interiorColliders = [];
|
||
this.interiorInteractables = [];
|
||
this.built = false;
|
||
}
|
||
}
|