Initial commit: 3D Hommie RPG game
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
523
js/game/Interiors.js
Normal file
523
js/game/Interiors.js
Normal file
@@ -0,0 +1,523 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user