I'm attempting to fire bullets or projectiles utilizing three.js:
let renderer, camera, scene, light, plane, cube, spheres;
initialize();
animate();
function initialize() {
renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight);
scene = new THREE.Scene();
light = new THREE.SpotLight("#ffffff");
light.position.y = 700;
scene.add(light);
plane = new THREE.Mesh();
plane.material = new THREE.MeshToonMaterial({ color: "#0000ff" });
plane.geometry = new THREE.PlaneGeometry(60, 30);
plane.position.z = -50;
scene.add(plane);
cube = new THREE.Mesh();
cube.material = new THREE.MeshToonMaterial({ color: "#ff0000", transparent: true, opacity: 0.85 });
cube.geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);
cube.position.y = -1;
cube.position.z = -3;
scene.add(cube);
spheres = [];
window.addEventListener("click", event => {
let mouse2d = getMouse2D(event.clientX, event.clientY);
let mouse3d = getMouse3D(mouse2d, plane.position.z);
shoot(mouse3d);
}, false);
}
function animate() {
spheres.forEach(sphere => {
// TODO: Update sphere position based on sphere.userData.target
sphere.position.z -= 1;
});
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
function shoot(target) {
let sphere = new THREE.Mesh();
sphere.material = new THREE.MeshToonMaterial({ color: "#00ff00" });
sphere.geometry = new THREE.SphereGeometry(0.25);
sphere.position.x = cube.position.x;
sphere.position.y = cube.position.y;
sphere.position.z = cube.position.z;
sphere.userData.target = target;
scene.add(sphere);
spheres.push(sphere);
}
function getMouse3D(mouse2d, z) {
let vector = new THREE.Vector3(mouse2d.x, mouse2d.y);
vector.unproject(camera);
let dir = vector.sub(camera.position).normalize();
let distance = (z - camera.position.z) / dir.z;
return camera.position.clone().add(dir.multiplyScalar(distance));
}
function getMouse2D(x, y) {
return new THREE.Vector2(
(x / renderer.domElement.clientWidth) * 2 - 1,
-(y / renderer.domElement.clientHeight) * 2 + 1
);
}
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
border: 0;
background: #eeeeee;
}
canvas {
display: block;
cursor: crosshair;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.js">
</script>
As you can observe, spheres are discharged from the cube onto the plane when the mouse is clicked.
I've developed the getMouse3D()
function to ascertain the position on the plane where the user clicked, and upon spawning a sphere, I save it in sphere.userData.target
. However, I am uncertain how to adjust the sphere's position each frame so that it advances towards the target location (see the TODO
note). In essence, by the time a sphere reaches the plane, it should intersect with sphere.userData.target
(where the user clicked).
How can this be accomplished?