1
votes

I'm creating a game in three.js. I'm new in this field but I've read a lot of collision documentation. I used raycast to get a collision between my boat contained in the cube and the islands contained in cubes. I tried to solve the problem this way.

collision2 = false;

    var originPoint = MovingCube.position.clone();
    clearText();
    for (var vertexIndex = 0; vertexIndex < MovingCube.geometry.vertices.length; vertexIndex++)
        {       
            var localVertex = MovingCube.geometry.vertices[vertexIndex].clone();
            var globalVertex = localVertex.applyMatrix4( MovingCube.matrix );
            var directionVector = globalVertex.sub( MovingCube.position );

            var ray = new THREE.Raycaster( originPoint, directionVector.clone().normalize() );
            var collisionResults = ray.intersectObjects( collidableMeshList );
            if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() ) {
                appendText(" Hit "),
                collision2 = true;
            }
}

    if ( keyboard.pressed("W") ){
        obj.translateZ( moveDistance ),
    if (collision2==true){
        obj.translateZ( -moveDistance*4 ),
        }
    }
    if ( keyboard.pressed("S") ){
        obj.translateZ( - moveDistance ),;
    if (collision2==true){
        obj.translateZ( moveDistance*4 ),
        }
    }
    if ( keyboard.pressed("A") ){
        obj.rotateOnAxis( new THREE.Vector3(0,1,0), rotateAngle),
    if (collision2==true){
        obj.rotateOnAxis( new THREE.Vector3(0,1,0), -rotateAngle*3),
        }
    }
    if ( keyboard.pressed("D") ){
        obj.rotateOnAxis( new THREE.Vector3(0,1,0), -rotateAngle),
    if (collision2==true){
        obj.rotateOnAxis( new THREE.Vector3(0,1,0), rotateAngle*3),
        }
    }    

Multiply by 3 "moveDistance" and "rotateAngle" so as not to crash my ship in the rays launched by the raycat during the collision. It often works, but sometimes the ship gets stuck or enters the island. I thought about moving the ship a few pixels when it collides with the island based on the face of the cube. Example: Ship collide with the face of the cube on the positive X axis, subtract pixels from the cube position to make the boat move away. But I do not know how to do something like that, it would be a good solution for me. How could I solve the problem of collisions with walls? (I do not want to use any physical engine right now) Thanks for those who will give me help!

screenshot

EDIT:
I would like to point out which side of the cube (island) collided with the ship. If the face is facing the X axis (positive) then move the boat 40 pixels backwards (obj.position = + 40), this for each face. So you can never let the boat in the cube. I was looking at this example that I think could be useful, but I did not understand how to solve it yet.
https://stemkoski.github.io/Three.js/Mouse-Click.html

This is my cube that contains the boat.

var mats2 = [];

    var cubeGeometry = new THREE.CubeGeometry(25,135,121,10,10,10);
    for (var i = 0; i < 6; i ++) {
    mats2.push(new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe:true } ));

}
    MovingCube = new THREE.Mesh( cubeGeometry, mats2 );
    scene.add( MovingCube );
    collidableMeshList0.push(MovingCube);
2
Are you trying to build a game or a physics engine? Because it looks like you are trying to build a physics engine... - manthrax
I want to create a game without a physical engine. At first I thought about using physijs to implement collisions with walls and missiles but I saw that I would have to modify a few things in my code. So I decided to detect the collisions with the raycasting. For missiles it works well. Do you know how I can use it correctly for walls? @manthrax - Alee
I do know.. and it's pretty tricky, and you end up writing a bunch of code to handle all the special cases, and once you've handled all those special cases, you have something that is less flexible and extendable than if you used an existing library like ammo.js. Ammo.js is a webasm port of the Bullet physics engine which is a commercial quality engine. - manthrax

2 Answers

1
votes

There are infinite ways to do a half assed job of solving this with raycasts.. but one of the most effective I've made work is to make a simple point mass system, with 3 point masses arranged in a triangle, connected with 3 springs and do a simple verlet style simulation to keep them in a triangular configuration.. you then reconstruct the object matrix by taking the vectors of this triangle, and compose an orthonormal basis and plug that into your three.js object. Then per frame, you apply a gravitational force to your point masses, and if they are below your sea level, apply an arbitrary buoyancy force proportional to the points' depth below sea level. Then for each point mass, you raycast downward from the center of the point, and adjust the point masses position to maintain a distance from the ground height of your height map.

Here's a prototype of something similar I made a long time ago: http://vectorslave.com/webgl/zbox.html (ASWD + Arrow keys to control the chopper)

1
votes

I think I got a good solution.
Every time a collision occurs, the affected face can be known. Using .face.normal. For example: if the collided face is the face facing the -x axis you will have: x: -1, y: 0, z: 0. If the collided face is the face facing the + x axis you will have: x: +1, y: 0, z: 0. The same principle applies to the other axes. So I solved the following way. Now the boat is no longer stuck in the walls!

var originPoint = MovingCube.position.clone();
clearText();
for (var vertexIndex = 0; vertexIndex < MovingCube.geometry.vertices.length; vertexIndex++)
    {       
        var localVertex = MovingCube.geometry.vertices[vertexIndex].clone();
        var globalVertex = localVertex.applyMatrix4( MovingCube.matrix );
        var directionVector = globalVertex.sub( MovingCube.position );

        var ray = new THREE.Raycaster( originPoint, directionVector.clone().normalize() );
         collisionResults1 = ray.intersectObjects( collidableMeshList );
        if ( collisionResults1.length > 0 && collisionResults1[0].distance < directionVector.length() ) {
            appendText(" Hit "),
            faccia = collisionResults1[0].face.normal;
            if (faccia.x <=-0.9 ){
                obj.position.x = originPoint.x -30,
            }
            if (faccia.x >=0.9 ){
                obj.position.x = originPoint.x +30,
            }
            if (faccia.z <=-0.9 ){,
                obj.position.z = originPoint.z -30,
            }
            if (faccia.z >=0.9 ){
                obj.position.z = originPoint.z +30,
            }