Reputation: 376
I have a pretty simple world I've created with three.js. I'm making a really basic plat-former and I'm trying to get collision detection to work when a user runs on top of a coin to update a text counter of how many coins have been touched. As of right now nothing occurs when i run over the coins, no JavaScript console errors either. Any help would be amazing.
I've been trying to use a raycaster to detect the collision. Here's some snippets of what I have, I can dump more or all 600ish lines of code if requested.'
<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;
}
}
Upvotes: 0
Views: 992
Reputation: 31076
Raycasting is not an ideal collision detection approach for this use case. Consider to represent your coins with simple bounding volumes like THREE.Box3 (an AABB) or THREE.Sphere (a bounding sphere). The player itself will be represented with such a bounding volume, too. In your animation loop you then test if the player's bounding volume intersects with certain objects in your game environment like your coins. This is a much more reliable test than working with a single ray since you can better represent 3D objects with a spatial extension.
BTW: If you are not yet familiar with bounding volumes, I highly recommend to study this topic a bit. AABBs and bounding spheres are very important entities in context of collision detection. A good resource for this is 3D Math Primer for Graphics and Game Development by Fletcher Dunn Ian Parberry, Chapter 9 Geometric Primitives.
Upvotes: 1