0

We are creating a three.js based game where players can eat food, currently we have a collision script but it is not working properly. Any help to get it working so our players can eat would be greatly appreciated.

The code is below.

Code snippet:

//sorry in advance for the crazy code structure o.o
			
//variables
var scene, renderer, rayCaster;
var WORLD, floor, FOOD, MWORLD;
var plr, camera, controls;
			
			function debugupdate()
			{
			window.plr = plr
			window.floor = floor
			window.WORLD = WORLD
			window.camera = camera
			window.controls = controls
			window.scene = scene
			window.FOOD = FOOD
			}
			setInterval(debugupdate, 1000)
			

			
//setup scene for gameplay
function InitGame()
{


scene = new THREE.Scene();

renderer = new THREE.WebGLRenderer();
rayCaster = new THREE.Raycaster();

renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.y = 8;
camera.position.z = 8;

controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.autoRotate = false;
controls.enablePan = false;
	
//controls.update() must be called after any manual changes to the camera's transform
//camera.position.set( 0, 20, 100 );
//controls.update();
//MWORLD = stuff mouse can detect
MWORLD = new THREE.Object3D();
MWORLD.name = 'MWORLD'
var floorgeo = new THREE.BoxGeometry(30, 0.5, 30);
var floormat = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
floor = new THREE.Mesh( floorgeo, floormat );
MWORLD.add(floor)
	WORLD = new THREE.Object3D();
    WORLD.add( MWORLD );
    WORLD.name = 'WORLD';
    scene.add(WORLD);
}

InitGame();

			//Mouse Stuff
			var MousePos;
			var PlrTarget;
				document.addEventListener('mousemove', MouseToWorld, false);
function MouseToWorld(event) {
	event.preventDefault();
	var mouse = {};
	mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
	mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
  var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
	vector.unproject( camera );
	var dir = vector.sub( camera.position ).normalize();
	var distance = - camera.position.z / dir.z;
	 MousePos = camera.position.clone().add( dir.multiplyScalar( distance ) );
	//console.log(MousePos)
  
    rayCaster.setFromCamera(mouse, camera);
    var intersects = rayCaster.intersectObjects(WORLD.getObjectByName('MWORLD').children, true);
    if (intersects.length > 0)
    //    console.log(intersects[0].point);
PlrTarget = intersects[0].point
	// Make the sphere follow the mouse
//	mouseMesh.position.set(event.clientX, event.clientY, 0);
};


			//Food Parent
			 FOOD = new THREE.Object3D();
			FOOD.name = 'FOOD'
			WORLD.add(FOOD)
			
			var fid = -1
			
			//Add Food Object should this be different?
	function AddFood()
	{
		fid = fid + 1
	var colors = ['red', 'blue', 'orange', 'yellow', 'pink', 'cyan'];

	var geometry = new THREE.SphereGeometry( 0.05 * 1.5, 32 / 4, 32 / 4 );
var material = new THREE.MeshBasicMaterial( {color: colors[Math.floor(Math.random() * colors.length)]} );
var sphere = new THREE.Mesh( geometry, material );
var geometry = new THREE.BoxGeometry( 0.1 * 1.5, 10, 0.1 * 1.5);//BoxGeometry for collision detection spheres were lagging like crazy :(
var material = new THREE.MeshBasicMaterial( {color: 'red'} );
		material.transparent = true
material.opacity = 0.2
var cube = new THREE.Mesh( geometry, material );
var foodrange = 15
cube.add(sphere);
cube.position.y = 0.25
cube.position.z = ((Math.random() * foodrange + 1) * (Math.round(Math.random()) * 2 - 1));
cube.position.x = ((Math.random() * foodrange + 1) * (Math.round(Math.random()) * 2 - 1));

cube.name = 'f' + fid
WORLD.getObjectByName('FOOD').add(cube)
	}

			//adds lots of food
    function InitFood()
	{
	var i
	for(i = 0; i < 150; i++)
	{
		AddFood();
	}
	}
			InitFood();

			
			
//Eats the food working I think...
function ConsumeFood(fid)
{
FOOD.remove(FOOD.getObjectByName(fid))
	plr.scale.x = plr.scale.x + 0.01
			plr.scale.y = plr.scale.y + 0.01
			plr.scale.z = plr.scale.z + 0.01
}

			
			//Creates Player
			function CreatePlr()
			{
			
			var geometry = new THREE.SphereGeometry( 0.5, 32, 32);//32 / 2
var material = new THREE.MeshBasicMaterial( {color: 0xffff00} );
var sphere = new THREE.Mesh( geometry, material );
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( {color: 'blue'} );
				material.transparent = true
material.opacity = 0.2
var cube = new THREE.Mesh( geometry, material );
				plr = new THREE.Object3D();
			plr.add(sphere);
			plr.add(cube);	
			scene.add(plr)
controls.target = plr.position

			}

CreatePlr();
setTimeout(Eat, 1500)

			
			//DETECT FOOD PLEASE HELP :(
			//sometimes works ok you have to have the food fairly deep within the player to detect
			//never eats as soon as you touch it
			//sometimes totally fails to detect piece of food until you go over it multiple times
			//sometimes random pieces of food are eaten even though they are not touched
			function Eat() {

var originPoint = plr.position.clone();

	
	for (var vertexIndex = 0; vertexIndex < plr.children[1].geometry.vertices.length; vertexIndex++)
	{		
		var localVertex = plr.children[1].geometry.vertices[vertexIndex].clone();
		var globalVertex = localVertex.applyMatrix4( plr.children[1].matrix );
		var directionVector = globalVertex.sub( plr.position );
		
		var ray = new THREE.Raycaster( originPoint, directionVector.clone().normalize() );
		var collisionResults = ray.intersectObjects( FOOD.children );
		if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() ) //if your touching the food or its in your player eat it
			
		collisionResults.forEach(function(food){
			console.log(food.object)//shows in console that food was detected and what piece of food it was
		ConsumeFood(food.object.name)//consume food based on name (f1, f2, f3)
		})
	
	}	

				
	setTimeout(Eat, 50)
			

} 
			
			var Time = new THREE.Clock();
			function PlrLerpSpeed(speed)
			{
					 var distance = plr.position.distanceTo(PlrTarget);
         var finalSpeed = (distance / speed);
         return Time.deltaTime / finalSpeed
				
			}
			
			var animate = function () {
				requestAnimationFrame( animate );
				if(PlrTarget){
				plr.lookAt(PlrTarget)
				//plr.position.lerp(PlrTarget, PlrLerpSpeed(1));
				plr.position.lerp(PlrTarget, 0.01 / (plr.position.distanceTo(PlrTarget) / 2));
				}
controls.update();
//plr.position = MousePos
/*var speed = 5; // units a second, the speed we want
var currentPoint = new THREE.Vector3();  // we will re-use it


// this part is in a function of event listener of, for example, a button
currentPoint.copy(plr.position); // cube is the object to move
var distance = currentPoint.distanceTo(MousePos)
var duration = (distance / speed) * 1000; // in milliseconds
new TWEEN.Tween(plr.position)
  .to(MousePos, duration) // destinationPoint is the object of destination
  .start();
	*/		

	renderer.render( scene, camera );
			};

			animate();
body { margin: 0; }
canvas { display: block; }
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

1
  • 2
    is not working properly is not very descriptive. You should provide more debugging details and trim the code to a minimal sample. Commented May 16, 2020 at 11:07

1 Answer 1

1

Since your player and food objects are basically spheres, you can implement a super fast and accurate collision detection with bounding spheres. Try it like so:

//variables
var scene, renderer, rayCaster;
var WORLD, floor, FOOD, MWORLD;
var plr, camera, controls;

function debugupdate() {
  window.plr = plr
  window.floor = floor
  window.WORLD = WORLD
  window.camera = camera
  window.controls = controls
  window.scene = scene
  window.FOOD = FOOD
}
setInterval(debugupdate, 1000)



//setup scene for gameplay
function InitGame() {


  scene = new THREE.Scene();

  renderer = new THREE.WebGLRenderer();
  rayCaster = new THREE.Raycaster();

  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  camera.position.y = 8;
  camera.position.z = 8;

  controls = new THREE.OrbitControls(camera, renderer.domElement);
  controls.autoRotate = false;
  controls.enablePan = false;

  //controls.update() must be called after any manual changes to the camera's transform
  //camera.position.set( 0, 20, 100 );
  //controls.update();
  //MWORLD = stuff mouse can detect
  MWORLD = new THREE.Object3D();
  MWORLD.name = 'MWORLD'
  var floorgeo = new THREE.BoxGeometry(30, 0.5, 30);
  var floormat = new THREE.MeshBasicMaterial({
    color: 0x00ff00
  });
  floor = new THREE.Mesh(floorgeo, floormat);
  MWORLD.add(floor)
  WORLD = new THREE.Object3D();
  WORLD.add(MWORLD);
  WORLD.name = 'WORLD';
  scene.add(WORLD);
}

InitGame();

//Mouse Stuff
var MousePos;
var PlrTarget;
document.addEventListener('mousemove', MouseToWorld, false);

function MouseToWorld(event) {
  event.preventDefault();
  var mouse = {};
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
  vector.unproject(camera);
  var dir = vector.sub(camera.position).normalize();
  var distance = -camera.position.z / dir.z;
  MousePos = camera.position.clone().add(dir.multiplyScalar(distance));
  //console.log(MousePos)

  rayCaster.setFromCamera(mouse, camera);
  var intersects = rayCaster.intersectObjects(WORLD.getObjectByName('MWORLD').children, true);
  if (intersects.length > 0)
    //    console.log(intersects[0].point);
    PlrTarget = intersects[0].point
  // Make the sphere follow the mouse
  //	mouseMesh.position.set(event.clientX, event.clientY, 0);
};


//Food Parent
FOOD = new THREE.Object3D();
FOOD.name = 'FOOD'
WORLD.add(FOOD)

var fid = -1

//Add Food Object should this be different?
function AddFood() {
  fid = fid + 1
  var colors = ['red', 'blue', 'orange', 'yellow', 'pink', 'cyan'];

  var geometry = new THREE.SphereGeometry(0.05 * 1.5, 32 / 4, 32 / 4);
  var material = new THREE.MeshBasicMaterial({
    color: colors[Math.floor(Math.random() * colors.length)]
  });
  var sphere = new THREE.Mesh(geometry, material);

  var foodrange = 15
  sphere.position.y = 0.25
  sphere.position.z = ((Math.random() * foodrange + 1) * (Math.round(Math.random()) * 2 - 1));
  sphere.position.x = ((Math.random() * foodrange + 1) * (Math.round(Math.random()) * 2 - 1));

  sphere.name = 'f' + fid
  WORLD.getObjectByName('FOOD').add(sphere)
}

//adds lots of food
function InitFood() {
  var i
  for (i = 0; i < 150; i++) {
    AddFood();
  }
}
InitFood();



//Eats the food working I think...
function ConsumeFood(fid) {
  FOOD.remove(FOOD.getObjectByName(fid))
  plr.scale.x = plr.scale.x + 0.01
  plr.scale.y = plr.scale.y + 0.01
  plr.scale.z = plr.scale.z + 0.01
}


//Creates Player
function CreatePlr() {

  var geometry = new THREE.SphereGeometry(0.5, 32, 32); //32 / 2
  var material = new THREE.MeshBasicMaterial({
    color: 0xffff00
  });
  plr = new THREE.Mesh(geometry, material);
  scene.add(plr)
  controls.target = plr.position

}

CreatePlr();
setTimeout(Eat, 1500)

var spherePlayer = new THREE.Sphere();
var sphereFood = new THREE.Sphere();

//DETECT FOOD PLEASE HELP :(
//sometimes works ok you have to have the food fairly deep within the player to detect
//never eats as soon as you touch it
//sometimes totally fails to detect piece of food until you go over it multiple times
//sometimes random pieces of food are eaten even though they are not touched
function Eat() {

	spherePlayer.copy( plr.geometry.boundingSphere ).applyMatrix4( plr.matrixWorld );
	
	for ( var i = 0; i < FOOD.children.length; i ++ ) {
		
		var food = FOOD.children[ i ];
		
		sphereFood.copy( food.geometry.boundingSphere ).applyMatrix4( food.matrixWorld );
		
		if ( spherePlayer.intersectsSphere( sphereFood ) === true ) {
		
			ConsumeFood(food.name);
		
		}
		
	
	}

  setTimeout(Eat, 50)

}

var Time = new THREE.Clock();

function PlrLerpSpeed(speed) {
  var distance = plr.position.distanceTo(PlrTarget);
  var finalSpeed = (distance / speed);
  return Time.deltaTime / finalSpeed

}

var animate = function() {
  requestAnimationFrame(animate);
  if (PlrTarget) {
    plr.lookAt(PlrTarget)
    //plr.position.lerp(PlrTarget, PlrLerpSpeed(1));
    plr.position.lerp(PlrTarget, 0.01 / (plr.position.distanceTo(PlrTarget) / 2));
  }
  controls.update();
  //plr.position = MousePos
  /*var speed = 5; // units a second, the speed we want
  var currentPoint = new THREE.Vector3();  // we will re-use it


  // this part is in a function of event listener of, for example, a button
  currentPoint.copy(plr.position); // cube is the object to move
  var distance = currentPoint.distanceTo(MousePos)
  var duration = (distance / speed) * 1000; // in milliseconds
  new TWEEN.Tween(plr.position)
    .to(MousePos, duration) // destinationPoint is the object of destination
    .start();
  	*/

  renderer.render(scene, camera);
};

animate();
body { margin: 0; }
canvas { display: block; }
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.