Созданные объекты проваливаются сквозь плоскость пола (CANNON.js + Three.js)
У меня есть такой код:
let scene = new THREE.Scene();
let redAsyk, yellowAsyk;
let bitka1, bitka2, bitka3;
let isRedAsykLoaded = false;
let isYellowAsykLoaded = false;
let camera, renderer, controls;
let redAsykBody, yellowAsykBody, bitka1Body, bitka2Body, bitka3Body, floorBody;
let redAsykShape, yellowAsykShape, bitka1Shape, bitka2Shape, bitka3Shape, floorShape;
let currentAsyk = null;
const world = new CANNON.World();
let isStoped = false;
let redAsykThrows = 0;
let yellowAsykThrows = 0;
const maxThrows = 3;
const modelsToLoad = [
{ name: 'red_asyk', objPath: 'models/red_asyk/red_asyk.obj', mtlPath: 'models/red_asyk/red_asyk.mtl', position: new THREE.Vector3(0, 0, 25) },
{ name: 'yellow_asyk', objPath: 'models/yellow_asyk/yellow_asyk.obj', mtlPath: 'models/yellow_asyk/yellow_asyk.mtl', position: new THREE.Vector3(0, 0, 20) },
{ name: 'bitka1', objPath: 'models/bitka/bitka.obj', mtlPath: 'models/bitka/bitka.mtl', position: new THREE.Vector3(10, 0, 0) },
{ name: 'bitka2', objPath: 'models/bitka/bitka.obj', mtlPath: 'models/bitka/bitka.mtl', position: new THREE.Vector3(0, 0, 0) },
{ name: 'bitka3', objPath: 'models/bitka/bitka.obj', mtlPath: 'models/bitka/bitka.mtl', position: new THREE.Vector3(-10, 0, 0) },
];
function init() {
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0xb3e8ff, 0.003);
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 12, 38);
camera.lookAt(scene.position);
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
world.gravity.set(0, -9.82, 0);
createLights();
createSky();
createFloor();
addCircleTexture();
loadModels(modelsToLoad);
animate();
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
world.step(1 / 60);
if (currentAsyk) {
currentAsyk.position.copy(currentAsyk.userData.physicsBody.position);
currentAsyk.quaternion.copy(currentAsyk.userData.physicsBody.quaternion);
}
}
function loadModels(models) {
let loadedCount = 0;
models.forEach(model => {
let mtlLoader = new THREE.MTLLoader();
mtlLoader.load(model.mtlPath, function(materials) {
materials.preload();
let objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.load(model.objPath, function(object) {
object.position.copy(model.position);
if (model.name === 'red_asyk') {
redAsyk = object;
redAsyk.scale.set(0.05, 0.05, 0.05);
scene.add(redAsyk);
isRedAsykLoaded = true;
redAsykShape = new CANNON.Box(new CANNON.Vec3(1, 1, 1));
redAsykBody = new CANNON.Body({ mass: 1, redAsykShape });
world.addBody(redAsykBody);
redAsyk.userData.physicsBody = redAsykBody;
redAsykBody.threeObject = redAsyk;
currentAsyk = redAsyk;
} else if (model.name === 'yellow_asyk') {
yellowAsyk = object;
yellowAsyk.scale.set(0.05, 0.05, 0.05);
yellowAsyk.visible = false;
scene.add(yellowAsyk);
isYellowAsykLoaded = true;
yellowAsykShape = new CANNON.Box(new CANNON.Vec3(1, 1, 1));
yellowAsykBody = new CANNON.Body({ mass: 1, yellowAsykShape });
world.addBody(yellowAsykBody);
yellowAsyk.userData.physicsBody = yellowAsykBody;
yellowAsykBody.threeObject = yellowAsyk;
} else if (model.name === 'bitka1') {
bitka1 = object;
bitka1.scale.set(0.05, 0.05, 0.05);
scene.add(bitka1);
let bitka1Shape = new CANNON.Box(new CANNON.Vec3(1, 1, 1));
let bitka1Body = new CANNON.Body({ mass: 1, bitka1Shape });
world.addBody(bitka1Body);
bitka1.userData.physicsBody = bitka1Body;
bitka1Body.threeObject = bitka1;
} else if (model.name === 'bitka2') {
bitka2 = object;
bitka2.scale.set(0.05, 0.05, 0.05);
scene.add(bitka2);
bitka2Shape = new CANNON.Box(new CANNON.Vec3(1, 1, 1));
bitka2Body = new CANNON.Body({ mass: 1, bitka2Shape });
world.addBody(bitka2Body);
bitka2.userData.physicsBody = bitka2Body;
bitka2Body.threeObject = bitka2;
} else if (model.name === 'bitka3') {
bitka3 = object;
bitka3.scale.set(0.05, 0.05, 0.05);
scene.add(bitka3);
bitka3Shape = new CANNON.Box(new CANNON.Vec3(1, 1, 1));
bitka3Body = new CANNON.Body({ mass: 1, bitka3Shape });
world.addBody(bitka3Body);
bitka3.userData.physicsBody = bitka3Body;
bitka3Body.threeObject = bitka3;
}
loadedCount++;
if (loadedCount === models.length) {
$('canvas').css('display', 'block');
$('.loading-screen').css('display', 'none');
}
});
});
});
}
function createLights() {
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(0, 100, 50);
scene.add(directionalLight);
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
}
function createSky() {
let sphereGeometry = new THREE.SphereBufferGeometry(1000, 32, 32);
let texture = new THREE.TextureLoader().load('images/sky.jpg');
let skyMaterial = new THREE.MeshStandardMaterial({ map: texture, side: THREE.BackSide });
let sky = new THREE.Mesh(sphereGeometry, skyMaterial);
scene.add(sky);
}
function createFloor() {
const textureLoader = new THREE.TextureLoader();
const floorTexture = textureLoader.load('images/floor.jpg');
floorTexture.wrapS = THREE.RepeatWrapping;
floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set(25, 25);
const floorMaterial = new THREE.MeshBasicMaterial({ map: floorTexture, side: THREE.DoubleSide });
const floorGeometry = new THREE.PlaneGeometry(1000, 1000);
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.rotation.x = -Math.PI / 2;
floor.position.y = 0;
scene.add(floor);
// Физическое тело пола в Cannon.js
const floorShape = new CANNON.Plane();
const floorBody = new CANNON.Body({
mass: 0,
shape: floorShape,
position: new CANNON.Vec3(0, 0, 0),
quaternion: new CANNON.Quaternion().setFromAxisAngle(new CANNON.Vec3(-1, 0, 0), Math.PI / 2)
});
world.addBody(floorBody);
}
function addCircleTexture() {
let circleTexture = new THREE.TextureLoader().load('images/arena_background.png');
let circleMaterial = new THREE.MeshBasicMaterial({ map: circleTexture, transparent: true });
let circleGeometry = new THREE.PlaneGeometry(40, 40);
let circle = new THREE.Mesh(circleGeometry, circleMaterial);
circle.rotation.x = -Math.PI / 2;
circle.position.set(0, 0, 0);
scene.add(circle);
}
function resetAsykThrow() {
const physicsBody = currentAsyk.userData.physicsBody;
physicsBody.velocity.set(0, 0, 0);
physicsBody.angularVelocity.set(0, 0, 0);
physicsBody.position.set(0, 0, 0);
currentAsyk.quaternion.set(0, 0, 0, 1);
currentAsyk.position.set(0, 0, 0);
}
function switchAsyk() {
if (currentAsyk === redAsyk) {
redAsyk.visible = false;
yellowAsyk.visible = true;
currentAsyk = yellowAsyk;
} else if (currentAsyk === yellowAsyk) {
yellowAsyk.visible = false;
redAsyk.visible = true;
currentAsyk = redAsyk;
}
resetAsykThrow();
}
function initControls() {
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
}
window.addEventListener('keydown', function (event) {
if (event.key === 'Enter') {
switchAsyk();
}
});
window.addEventListener('load', function () {
init();
initControls();
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- <link rel="stylesheet" href="src/css/main.css"> -->
<script src="scripts/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/FBXLoader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/MTLLoader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/OBJLoader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/libs/fflate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/21.0.0/tween.umd.js" integrity="sha512-iPPs+A0ew4z+jybQ1r6HPj5b8zV8zaw6TpfGn/qqntA480gp6HDfUJGp1ni46LXrItwnTvYlg80h1NIkC4pf6g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.min.js" integrity="sha512-avLcnGxl5mqAX/wIKERdb1gFNkOLHh2W5JNCfJm5OugpEPBz7LNXJJ3BDjjwO00AxEY1MqdNjtEmiYhKC0ld7g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<title>Asyk 3D Game</title>
<style>
body {
margin: 0;
padding: 0;
box-sizing: border-box;
}
canvas {
width: 100%;
height: 100%;
display: none;
}
.loading-screen {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
background: url(images/background.jpg);
background-size: cover;
background-position: 50% 50%;
}
</style>
</head>
<body>
<div class="loading-screen">
<h1>Загрузка...</h1>
</div>
<script src="main.js"></script>
</body>
</html>
Я создаю плоскость пола, на ней есть круг, небо, на котором будет происходить некоторые действия, подсветку, создаю объекты redAsyk, yellowAsyk, bitka1, bitka2 и bitka3. Почему-то эти 5 объектов проваливаются сквозь плоскость пола. Физические тела начинают падать, хотя вроде как я устанавливаю физику для пола. Уже много вариация создания пола перепробовал, но всё равно объекты продолжают падать.