【问题标题】:Collision detection with three.js使用three.js进行碰撞检测
【发布时间】:2019-05-02 19:20:09
【问题描述】:

我用three.js 创建了一个非常简单的世界。我正在制作一个非常基本的平台,并且当用户在硬币顶部运行以更新已触摸多少硬币的文本计数器时,我正在尝试使碰撞检测起作用。到目前为止,当我运行硬币时,什么都没有发生,也没有 JavaScript 控制台错误。任何帮助都会很棒。

我一直在尝试使用光线投射器来检测碰撞。这是我所拥有的一些 sn-ps,如果需要,我可以转储更多或全部 600 行代码。'

<div id="info">
    <h1 style="color: white">0/10</h1>
</div>

Javascript:

var coin = [];
var raycaster;
var loader = new THREE.GLTFLoader();
... //Lots more variables I've left out for readability


initThree();
initCannon();
animate();

function initThree() {

            clock = new THREE.Clock();

            //Renderer
            var width = window.innerWidth;
            var height = window.innerHeight;

            renderer = new THREE.WebGLRenderer( {antialias: true} );
            renderer.setPixelRatio( window.devicePixelRatio );
            renderer.setSize( width, height );
            document.body.appendChild( renderer.domElement );

            scene = new THREE.Scene();
            scene.background = new THREE.Color( 0xb2b2b2 );
            scene.fog = new THREE.Fog( 0x9bacc6, 0, 7000 );

            //Camera
            camera = new THREE.PerspectiveCamera( 90, width/height, 1, 10000 );
            //camera.position.set( 3000, 3000, 3000 );
            camera.position.set( 0, 10, 0 );
            camera.lookAt( scene.position );

            //Controls      
            controls = new THREE.PointerLockControls( camera );

            var blocker = document.getElementById( 'blocker' );
            var instructions = document.getElementById( 'instructions' );

            //Lock control when focused
            instructions.addEventListener( 'click', function () {

                controls.lock();

            }, false );

            //Hide overlay
            controls.addEventListener( 'lock', function () {

                instructions.style.display = 'none';
                blocker.style.display = 'none';

            } );

            controls.addEventListener( 'unlock', function () {

                blocker.style.display = 'block';
                instructions.style.display = '';

            } );
            scene.add( controls.getObject() );

            //Raycaster
            raycaster = new THREE.Raycaster( new THREE.Vector3(), new THREE.Vector3( 0, -1, 0 ), 0, 10 );   

            loadTrees();
            loadCoins();
            createLight();
            createGround();
            createWater();
            createSky();
        }

function loadCoins() {      

            var coinPath = '../models/gltf/coin/scene.gltf';
            loader.load( coinPath, function( gltf ) {
                coin[0] = gltf.scene;
                coin[0].position.set(3300,1500,1000);
                coin[0].scale.set(100,100,100);
                scene.add( coin[0] );
            });
            loader.load( coinPath, function( gltf ) {
                coin[1] = gltf.scene;
                coin[1].position.set(3300,1500,-1000);
                coin[1].scale.set(100,100,100);
                scene.add( coin[1] );
             ...
            });

    function animate() {
            requestAnimationFrame( animate );
            update();
            render();
        }

function update() {
            //controls.update();

            world.step( timeStep );

            ground.position.copy( groundBody.position );
            ground.quaternion.copy( groundBody.quaternion );

            var mixDelta = clock.getDelta();
            if( mixer != null) {
                mixer.update( mixDelta );
                mixer2.update( mixDelta );
                mixer3.update( mixDelta );
            }

            raycaster.ray.origin.copy( controls.getObject().position );
            raycaster.ray.origin.y -= 100;

            //checks to see if intersecting object array
            var intersections = raycaster.intersectObjects( coin );

            var touching = intersections.length > 0;

            var time = performance.now();
            var delta = ( time - prevTime ) / 1000;

            velocity.x -= velocity.x * 10 * delta;
            velocity.z -= velocity.z * 10 * delta;
            velocity.y -= 9.8 * 100 * delta; //100 = mass //9.8

            direction.z = Number( moveForward ) - Number( moveBackward );
            direction.x = Number( moveLeft ) - Number( moveRight );
            direction.normalize(); //consistent movement in all directions

            if( moveForward || moveBackward ) {
                velocity.z -= direction.z * 7500 * delta;
            }
            if( moveLeft || moveRight ) {
                velocity.x -= direction.x * 7500 * delta;
            }

            //Stops when runs into an object
            if ( touching === true ) {
                    coinCount += 1;
                    document.getElementById('info').innerHTML = coinCount + "/10";
            }


            controls.getObject().translateX( velocity.x * delta );
            controls.getObject().translateY( velocity.y * delta );
            controls.getObject().translateZ( velocity.z * delta );

            //Keep Player within bounds of game
            if ( controls.getObject().position.y < 200 ) {

                    velocity.y = 0;
                    controls.getObject().position.y = 200;

                    canJump = true;

            }               
            if ( controls.getObject().position.x < -4000 ) {
                velocity.x = 0;
                controls.getObject().position.x = -4000;
            }
            if ( controls.getObject().position.x > 4000 ) {
                velocity.x = 0;
                controls.getObject().position.x = 4000;
            }               
            if ( controls.getObject().position.z < -4000 ) {
                velocity.x = 0;
                controls.getObject().position.z = -4000;
            }
            if ( controls.getObject().position.z > 4000 ) {
                velocity.x = 0;
                controls.getObject().position.z = 4000;
            }

            prevTime = time;

            //Update Water
            water.material.uniforms[ "time" ].value += 1.0 / 60.0;

            //Spin Coins
            for( i=0; i<coin.length; i++ ) {
                coin[i].rotation.y += .05;
            }
        }

【问题讨论】:

    标签: javascript three.js


    【解决方案1】:

    对于此用例,光线投射不是理想的碰撞检测方法。考虑用THREE.Box3(AABB)或THREE.Sphere(边界球)等简单的边界体积来表示您的硬币。玩家本身也将用这样的边界体积来表示。然后在您的动画循环中测试玩家的边界体积是否与游戏环境中的某些对象(例如硬币)相交。这是一个比使用单条射线更可靠的测试,因为您可以更好地表示具有空间扩展的 3D 对象。

    顺便说一句:如果您还不熟悉包围体,我强烈建议您稍微研究一下这个主题。 AABB 和边界球是碰撞检测中非常重要的实体。一个很好的资源是3D Math Primer for Graphics and Game Development by Fletcher Dunn Ian Parberry, Chapter 9 Geometric Primitives

    【讨论】:

      猜你喜欢
      • 2019-04-30
      • 2013-05-29
      • 2016-06-15
      • 2014-08-05
      • 2014-03-29
      • 2010-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多