Anonymous
3D 3D -игровая камера управляет по -разному для всех направлений
Сообщение
Anonymous » 24 фев 2025, 23:48
Я сделал эту игру, и когда я смотрю в одном направлении, элементы управления камерой нормальны, но если я заглядываю за собой, то они обратно, и на сторону, это заставляет мою камеру рулон. Я подозреваю, что это потому, что камера только относится к исходному направлению, но я не могу ее исправить. Кто -нибудь может помочь? По какой -то причине он отображает ошибку при переполнении стека, но в другом редакторе работает нормально. Вот мой код: < /p>
Код: Выделить всё
First Person Game with Four Cameras
body { margin: 0; }
canvas { display: block; }
#minimap {
position: absolute;
top: 10px;
left: 10px;
width: 200px;
height: 200px;
border: 1px solid #000;
background-color: rgba(255, 255, 255, 0.5);
pointer-events: none;
}
#controls {
position: absolute;
top: 10px;
right: 10px;
background: rgba(255, 255, 255, 0.8);
padding: 10px;
border-radius: 5px;
}
#controls label {
display: block;
margin: 10px 0;
}
input[type=range] {
width: 100%;
height: 10px;
-webkit-appearance: none;
appearance: none;
background: #ddd;
border-radius: 5px;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
background: #4CAF50;
border-radius: 50%;
cursor: pointer;
}
input[type=range]::-moz-range-thumb {
width: 20px;
height: 20px;
background: #4CAF50;
border: none;
border-radius: 50%;
cursor: pointer;
}
Field of View:
Brightness:
Pause
let scene, renderer;
let moveForward = false, moveBackward = false, moveLeft = false, moveRight = false;
let velocity = new THREE.Vector3();
let direction = new THREE.Vector3();
let canJump = false;
let prevTime = performance.now();
let cubes = [], cubeVelocities = [];
let heldCube = null;
let aiBlock;
const speed = 150.0;
const jumpVelocity = 30.0;
const gravity = 9.8 * 5.0;
const pickUpDistance = 2.0;
const originalCubeScale = 1;
const heldCubeScale = 0.5;
const friction = 0.05;
let pitch = 0, yaw = 0;
// Day/Night cycle variables
let dayTime = 0;
const dayDuration = 10000;
let isPaused = false;
// Define four cameras for North, South, East, West
const cameras = {
north: new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000),
south: new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000),
east: new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000),
west: new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000),
};
// Initial camera positions and rotations
cameras.north.position.set(0, 1.6, -5);
cameras.south.position.set(0, 1.6, 5);
cameras.east.position.set(5, 1.6, 0);
cameras.west.position.set(-5, 1.6, 0);
cameras.north.rotation.set(0, 0, 0);
cameras.south.rotation.set(0, Math.PI, 0);
cameras.east.rotation.set(0, Math.PI / 2, 0);
cameras.west.rotation.set(0, -Math.PI / 2, 0);
// Starting camera direction
let currentCamera = cameras.north;
init();
animate();
function init() {
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const groundGeometry = new THREE.PlaneGeometry(50, 50);
const groundMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
scene.add(ground);
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0x0000ff });
for (let i = 0; i < 3; i++) {
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.set(Math.random() * 30 - 15, 1.6, Math.random() * 30 - 15);
cubes.push(cube);
cubeVelocities.push(new THREE.Vector3());
scene.add(cube);
}
const aiMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
aiBlock = new THREE.Mesh(cubeGeometry, aiMaterial);
aiBlock.position.set(Math.random() * 30 - 15, 1.6, Math.random() * 30 - 15);
scene.add(aiBlock);
document.addEventListener('keydown', onKeyDown);
document.addEventListener('keyup', onKeyUp);
document.getElementById('pause').addEventListener('click', togglePause);
document.getElementById('fov').addEventListener('input', (event) => {
for (let cam in cameras) {
cameras[cam].fov = event.target.value;
cameras[cam].updateProjectionMatrix();
}
});
document.getElementById('brightness').addEventListener('input', (event) => {
scene.background = new THREE.Color(`hsl(0, 0%, ${event.target.value * 100}%)`);
});
document.body.addEventListener('click', () => {
document.body.requestPointerLock();
});
document.addEventListener('mousemove', onMouseMove);
window.addEventListener('resize', onWindowResize);
}
function togglePause() {
isPaused = !isPaused;
const controls = document.getElementById('controls');
if (isPaused) {
controls.classList.add('paused');
} else {
controls.classList.remove('paused');
}
}
function onWindowResize() {
for (let cam in cameras) {
cameras[cam].aspect = window.innerWidth / window.innerHeight;
cameras[cam].updateProjectionMatrix();
}
renderer.setSize(window.innerWidth, window.innerHeight);
}
function onKeyDown(event) {
switch (event.code) {
case 'KeyW': moveForward = true; break;
case 'KeyS': moveBackward = true; break;
case 'KeyA': moveLeft = true; break;
case 'KeyD': moveRight = true; break;
case 'Space':
if (canJump) {
velocity.y = jumpVelocity;
canJump = false;
}
break;
case 'KeyF':
pickOrThrowCube();
break;
case 'KeyP':
togglePause();
break;
case 'Digit1':
currentCamera = cameras.north; // Switch to North camera
break;
case 'Digit2':
currentCamera = cameras.south; // Switch to South camera
break;
case 'Digit3':
currentCamera = cameras.east; // Switch to East camera
break;
case 'Digit4':
currentCamera = cameras.west; // Switch to West camera
break;
}
}
function onKeyUp(event) {
switch (event.code) {
case 'KeyW': moveForward = false; break;
case 'KeyS': moveBackward = false; break;
case 'KeyA': moveLeft = false; break;
case 'KeyD': moveRight = false; break;
}
}
function onMouseMove(event) {
if (document.pointerLockElement) {
const sensitivity = 0.002;
yaw -= event.movementX * sensitivity;
pitch -= event.movementY * sensitivity;
pitch = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, pitch));
// Apply rotation to the current camera
currentCamera.rotation.y = yaw;
currentCamera.rotation.x = pitch;
currentCamera.rotation.z = 0;
}
}
function pickOrThrowCube() {
if (heldCube) {
const throwVelocity = new THREE.Vector3();
currentCamera.getWorldDirection(throwVelocity);
throwVelocity.multiplyScalar(300);
heldCube.position.add(throwVelocity.multiplyScalar(0.04));
cubeVelocities[cubes.indexOf(heldCube)].copy(throwVelocity);
heldCube.scale.set(originalCubeScale, originalCubeScale, originalCubeScale);
heldCube = null;
} else {
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(new THREE.Vector2(0, 0), currentCamera);
const intersects = raycaster.intersectObjects(cubes.concat(aiBlock));
if (intersects.length > 0) {
const intersect = intersects[0];
if (intersect.distance < pickUpDistance) {
heldCube = intersect.object;
cubeVelocities[cubes.indexOf(heldCube)] = new THREE.Vector3();
heldCube.scale.set(heldCubeScale, heldCubeScale, heldCubeScale);
heldCube.position.copy(currentCamera.position).add(currentCamera.getWorldDirection(new THREE.Vector3()).multiplyScalar(1.5));
}
}
}
}
function animate() {
if (!isPaused) {
requestAnimationFrame(animate);
const time = performance.now();
const delta = (time - prevTime) / 1000;
dayTime += delta;
if (dayTime > dayDuration) dayTime = 0;
const brightness = (Math.sin((dayTime / dayDuration) * Math.PI) + 1) / 2;
scene.background = new THREE.Color(`hsl(200, 100%, ${brightness * 100}%)`);
direction.z = Number(moveForward) - Number(moveBackward);
direction.x = Number(moveRight) - Number(moveLeft);
direction.normalize();
velocity.x -= velocity.x * 10.0 * delta;
velocity.z -= velocity.z * 10.0 * delta;
velocity.y -= gravity * delta;
if (moveForward || moveBackward || moveLeft || moveRight) {
const frontDirection = new THREE.Vector3();
currentCamera.getWorldDirection(frontDirection);
frontDirection.y = 0;
frontDirection.normalize();
const rightDirection = new THREE.Vector3();
rightDirection.crossVectors(currentCamera.up, frontDirection).normalize();
frontDirection.multiplyScalar(direction.z * speed * delta);
rightDirection.multiplyScalar(direction.x * speed * delta);
velocity.add(frontDirection).add(rightDirection);
}
currentCamera.position.addScaledVector(velocity, delta);
currentCamera.position.x = Math.max(-24, Math.min(24, currentCamera.position.x));
currentCamera.position.z = Math.max(-24, Math.min(24, currentCamera.position.z));
if (currentCamera.position.y < 1.6) {
velocity.y = 0;
currentCamera.position.y = 1.6;
canJump = true;
}
if (heldCube) {
heldCube.position.copy(currentCamera.position).add(currentCamera.getWorldDirection(new THREE.Vector3()).multiplyScalar(1.5));
}
for (let i = 0; i < cubes.length; i++) {
if (cubes[i] !== heldCube) {
cubeVelocities[i].x *= (1 - friction);
cubeVelocities[i].z *= (1 - friction);
cubeVelocities[i].y -= gravity * delta;
cubes[i].position.addScaledVector(cubeVelocities[i], delta);
if (cubes[i].position.y < 0.5) {
cubes[i].position.y = 0.5;
cubeVelocities[i].y = Math.abs(cubeVelocities[i].y) * 0.2;
}
for (let j = 0; j < cubes.length; j++) {
if (i !== j) {
const distance = cubes[i].position.distanceTo(cubes[j].position);
if (distance < 1.5) {
const collisionDirection = new THREE.Vector3().subVectors(cubes[i].position, cubes[j].position).normalize();
const relativeVelocity = new THREE.Vector3().subVectors(cubeVelocities[i], cubeVelocities[j]);
if (relativeVelocity.dot(collisionDirection) < 0) {
const pushAmount = 0.1;
cubeVelocities[i].add(collisionDirection.clone().multiplyScalar(pushAmount));
cubeVelocities[j].sub(collisionDirection.clone().multiplyScalar(pushAmount));
}
}
}
}
}
}
aiBlock.position.y -= gravity * delta;
aiBlock.position.x += (Math.random() - 0.5) * 0.05;
aiBlock.position.z += (Math.random() - 0.5) * 0.05;
aiBlock.position.x = Math.max(-24, Math.min(24, aiBlock.position.x));
aiBlock.position.z = Math.max(-24, Math.min(24, aiBlock.position.z));
if (aiBlock.position.y < 1.6) {
aiBlock.position.y = 1.6;
}
const playerBox = new THREE.Box3().setFromCenterAndSize(currentCamera.position, new THREE.Vector3(1, 1, 1));
const aiBox = new THREE.Box3().setFromCenterAndSize(aiBlock.position, new THREE.Vector3(1, 1, 1));
if (playerBox.intersectsBox(aiBox)) {
const collisionDirection = new THREE.Vector3().subVectors(currentCamera.position, aiBlock.position).normalize();
velocity.add(collisionDirection.multiplyScalar(10));
aiBlock.position.add(collisionDirection.multiplyScalar(7));
}
renderer.render(scene, currentCamera);
prevTime = time;
updateMiniMap();
}
}
function updateMiniMap() {
const minimap = document.getElementById('minimap');
const ctx = minimap.getContext('2d');
ctx.clearRect(0, 0, minimap.width, minimap.height);
ctx.fillStyle = 'lightgreen';
ctx.fillRect(0, 0, minimap.width, minimap.height);
ctx.fillStyle = 'blue';
const playerX = (currentCamera.position.x + 25) * 4;
const playerZ = (currentCamera.position.z + 25) * 4;
ctx.fillRect(playerX, playerZ, 5, 5);
ctx.fillStyle = 'blue';
cubes.forEach(cube => {
const cubeX = (cube.position.x + 25) * 4;
const cubeZ = (cube.position.z + 25) * 4;
ctx.fillRect(cubeX, cubeZ, 5, 5);
});
ctx.fillStyle = 'red';
const aiX = (aiBlock.position.x + 25) * 4;
const aiZ = (aiBlock.position.z + 25) * 4;
ctx.fillRect(aiX, aiZ, 5, 5);
}
Подробнее здесь:
https://stackoverflow.com/questions/794 ... -direction
1740430120
Anonymous
Я сделал эту игру, и когда я смотрю в одном направлении, элементы управления камерой нормальны, но если я заглядываю за собой, то они обратно, и на сторону, это заставляет мою камеру рулон. Я подозреваю, что это потому, что камера только относится к исходному направлению, но я не могу ее исправить. Кто -нибудь может помочь? По какой -то причине он отображает ошибку при переполнении стека, но в другом редакторе работает нормально. Вот мой код: < /p> [code] First Person Game with Four Cameras body { margin: 0; } canvas { display: block; } #minimap { position: absolute; top: 10px; left: 10px; width: 200px; height: 200px; border: 1px solid #000; background-color: rgba(255, 255, 255, 0.5); pointer-events: none; } #controls { position: absolute; top: 10px; right: 10px; background: rgba(255, 255, 255, 0.8); padding: 10px; border-radius: 5px; } #controls label { display: block; margin: 10px 0; } input[type=range] { width: 100%; height: 10px; -webkit-appearance: none; appearance: none; background: #ddd; border-radius: 5px; } input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 20px; height: 20px; background: #4CAF50; border-radius: 50%; cursor: pointer; } input[type=range]::-moz-range-thumb { width: 20px; height: 20px; background: #4CAF50; border: none; border-radius: 50%; cursor: pointer; } Field of View: Brightness: Pause let scene, renderer; let moveForward = false, moveBackward = false, moveLeft = false, moveRight = false; let velocity = new THREE.Vector3(); let direction = new THREE.Vector3(); let canJump = false; let prevTime = performance.now(); let cubes = [], cubeVelocities = []; let heldCube = null; let aiBlock; const speed = 150.0; const jumpVelocity = 30.0; const gravity = 9.8 * 5.0; const pickUpDistance = 2.0; const originalCubeScale = 1; const heldCubeScale = 0.5; const friction = 0.05; let pitch = 0, yaw = 0; // Day/Night cycle variables let dayTime = 0; const dayDuration = 10000; let isPaused = false; // Define four cameras for North, South, East, West const cameras = { north: new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000), south: new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000), east: new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000), west: new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000), }; // Initial camera positions and rotations cameras.north.position.set(0, 1.6, -5); cameras.south.position.set(0, 1.6, 5); cameras.east.position.set(5, 1.6, 0); cameras.west.position.set(-5, 1.6, 0); cameras.north.rotation.set(0, 0, 0); cameras.south.rotation.set(0, Math.PI, 0); cameras.east.rotation.set(0, Math.PI / 2, 0); cameras.west.rotation.set(0, -Math.PI / 2, 0); // Starting camera direction let currentCamera = cameras.north; init(); animate(); function init() { scene = new THREE.Scene(); renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); const groundGeometry = new THREE.PlaneGeometry(50, 50); const groundMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); const ground = new THREE.Mesh(groundGeometry, groundMaterial); ground.rotation.x = -Math.PI / 2; scene.add(ground); const cubeGeometry = new THREE.BoxGeometry(1, 1, 1); const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0x0000ff }); for (let i = 0; i < 3; i++) { const cube = new THREE.Mesh(cubeGeometry, cubeMaterial); cube.position.set(Math.random() * 30 - 15, 1.6, Math.random() * 30 - 15); cubes.push(cube); cubeVelocities.push(new THREE.Vector3()); scene.add(cube); } const aiMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 }); aiBlock = new THREE.Mesh(cubeGeometry, aiMaterial); aiBlock.position.set(Math.random() * 30 - 15, 1.6, Math.random() * 30 - 15); scene.add(aiBlock); document.addEventListener('keydown', onKeyDown); document.addEventListener('keyup', onKeyUp); document.getElementById('pause').addEventListener('click', togglePause); document.getElementById('fov').addEventListener('input', (event) => { for (let cam in cameras) { cameras[cam].fov = event.target.value; cameras[cam].updateProjectionMatrix(); } }); document.getElementById('brightness').addEventListener('input', (event) => { scene.background = new THREE.Color(`hsl(0, 0%, ${event.target.value * 100}%)`); }); document.body.addEventListener('click', () => { document.body.requestPointerLock(); }); document.addEventListener('mousemove', onMouseMove); window.addEventListener('resize', onWindowResize); } function togglePause() { isPaused = !isPaused; const controls = document.getElementById('controls'); if (isPaused) { controls.classList.add('paused'); } else { controls.classList.remove('paused'); } } function onWindowResize() { for (let cam in cameras) { cameras[cam].aspect = window.innerWidth / window.innerHeight; cameras[cam].updateProjectionMatrix(); } renderer.setSize(window.innerWidth, window.innerHeight); } function onKeyDown(event) { switch (event.code) { case 'KeyW': moveForward = true; break; case 'KeyS': moveBackward = true; break; case 'KeyA': moveLeft = true; break; case 'KeyD': moveRight = true; break; case 'Space': if (canJump) { velocity.y = jumpVelocity; canJump = false; } break; case 'KeyF': pickOrThrowCube(); break; case 'KeyP': togglePause(); break; case 'Digit1': currentCamera = cameras.north; // Switch to North camera break; case 'Digit2': currentCamera = cameras.south; // Switch to South camera break; case 'Digit3': currentCamera = cameras.east; // Switch to East camera break; case 'Digit4': currentCamera = cameras.west; // Switch to West camera break; } } function onKeyUp(event) { switch (event.code) { case 'KeyW': moveForward = false; break; case 'KeyS': moveBackward = false; break; case 'KeyA': moveLeft = false; break; case 'KeyD': moveRight = false; break; } } function onMouseMove(event) { if (document.pointerLockElement) { const sensitivity = 0.002; yaw -= event.movementX * sensitivity; pitch -= event.movementY * sensitivity; pitch = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, pitch)); // Apply rotation to the current camera currentCamera.rotation.y = yaw; currentCamera.rotation.x = pitch; currentCamera.rotation.z = 0; } } function pickOrThrowCube() { if (heldCube) { const throwVelocity = new THREE.Vector3(); currentCamera.getWorldDirection(throwVelocity); throwVelocity.multiplyScalar(300); heldCube.position.add(throwVelocity.multiplyScalar(0.04)); cubeVelocities[cubes.indexOf(heldCube)].copy(throwVelocity); heldCube.scale.set(originalCubeScale, originalCubeScale, originalCubeScale); heldCube = null; } else { const raycaster = new THREE.Raycaster(); raycaster.setFromCamera(new THREE.Vector2(0, 0), currentCamera); const intersects = raycaster.intersectObjects(cubes.concat(aiBlock)); if (intersects.length > 0) { const intersect = intersects[0]; if (intersect.distance < pickUpDistance) { heldCube = intersect.object; cubeVelocities[cubes.indexOf(heldCube)] = new THREE.Vector3(); heldCube.scale.set(heldCubeScale, heldCubeScale, heldCubeScale); heldCube.position.copy(currentCamera.position).add(currentCamera.getWorldDirection(new THREE.Vector3()).multiplyScalar(1.5)); } } } } function animate() { if (!isPaused) { requestAnimationFrame(animate); const time = performance.now(); const delta = (time - prevTime) / 1000; dayTime += delta; if (dayTime > dayDuration) dayTime = 0; const brightness = (Math.sin((dayTime / dayDuration) * Math.PI) + 1) / 2; scene.background = new THREE.Color(`hsl(200, 100%, ${brightness * 100}%)`); direction.z = Number(moveForward) - Number(moveBackward); direction.x = Number(moveRight) - Number(moveLeft); direction.normalize(); velocity.x -= velocity.x * 10.0 * delta; velocity.z -= velocity.z * 10.0 * delta; velocity.y -= gravity * delta; if (moveForward || moveBackward || moveLeft || moveRight) { const frontDirection = new THREE.Vector3(); currentCamera.getWorldDirection(frontDirection); frontDirection.y = 0; frontDirection.normalize(); const rightDirection = new THREE.Vector3(); rightDirection.crossVectors(currentCamera.up, frontDirection).normalize(); frontDirection.multiplyScalar(direction.z * speed * delta); rightDirection.multiplyScalar(direction.x * speed * delta); velocity.add(frontDirection).add(rightDirection); } currentCamera.position.addScaledVector(velocity, delta); currentCamera.position.x = Math.max(-24, Math.min(24, currentCamera.position.x)); currentCamera.position.z = Math.max(-24, Math.min(24, currentCamera.position.z)); if (currentCamera.position.y < 1.6) { velocity.y = 0; currentCamera.position.y = 1.6; canJump = true; } if (heldCube) { heldCube.position.copy(currentCamera.position).add(currentCamera.getWorldDirection(new THREE.Vector3()).multiplyScalar(1.5)); } for (let i = 0; i < cubes.length; i++) { if (cubes[i] !== heldCube) { cubeVelocities[i].x *= (1 - friction); cubeVelocities[i].z *= (1 - friction); cubeVelocities[i].y -= gravity * delta; cubes[i].position.addScaledVector(cubeVelocities[i], delta); if (cubes[i].position.y < 0.5) { cubes[i].position.y = 0.5; cubeVelocities[i].y = Math.abs(cubeVelocities[i].y) * 0.2; } for (let j = 0; j < cubes.length; j++) { if (i !== j) { const distance = cubes[i].position.distanceTo(cubes[j].position); if (distance < 1.5) { const collisionDirection = new THREE.Vector3().subVectors(cubes[i].position, cubes[j].position).normalize(); const relativeVelocity = new THREE.Vector3().subVectors(cubeVelocities[i], cubeVelocities[j]); if (relativeVelocity.dot(collisionDirection) < 0) { const pushAmount = 0.1; cubeVelocities[i].add(collisionDirection.clone().multiplyScalar(pushAmount)); cubeVelocities[j].sub(collisionDirection.clone().multiplyScalar(pushAmount)); } } } } } } aiBlock.position.y -= gravity * delta; aiBlock.position.x += (Math.random() - 0.5) * 0.05; aiBlock.position.z += (Math.random() - 0.5) * 0.05; aiBlock.position.x = Math.max(-24, Math.min(24, aiBlock.position.x)); aiBlock.position.z = Math.max(-24, Math.min(24, aiBlock.position.z)); if (aiBlock.position.y < 1.6) { aiBlock.position.y = 1.6; } const playerBox = new THREE.Box3().setFromCenterAndSize(currentCamera.position, new THREE.Vector3(1, 1, 1)); const aiBox = new THREE.Box3().setFromCenterAndSize(aiBlock.position, new THREE.Vector3(1, 1, 1)); if (playerBox.intersectsBox(aiBox)) { const collisionDirection = new THREE.Vector3().subVectors(currentCamera.position, aiBlock.position).normalize(); velocity.add(collisionDirection.multiplyScalar(10)); aiBlock.position.add(collisionDirection.multiplyScalar(7)); } renderer.render(scene, currentCamera); prevTime = time; updateMiniMap(); } } function updateMiniMap() { const minimap = document.getElementById('minimap'); const ctx = minimap.getContext('2d'); ctx.clearRect(0, 0, minimap.width, minimap.height); ctx.fillStyle = 'lightgreen'; ctx.fillRect(0, 0, minimap.width, minimap.height); ctx.fillStyle = 'blue'; const playerX = (currentCamera.position.x + 25) * 4; const playerZ = (currentCamera.position.z + 25) * 4; ctx.fillRect(playerX, playerZ, 5, 5); ctx.fillStyle = 'blue'; cubes.forEach(cube => { const cubeX = (cube.position.x + 25) * 4; const cubeZ = (cube.position.z + 25) * 4; ctx.fillRect(cubeX, cubeZ, 5, 5); }); ctx.fillStyle = 'red'; const aiX = (aiBlock.position.x + 25) * 4; const aiZ = (aiBlock.position.z + 25) * 4; ctx.fillRect(aiX, aiZ, 5, 5); } [/code] Подробнее здесь: [url]https://stackoverflow.com/questions/79464769/threejs-3d-game-camera-controls-different-for-every-direction[/url]