どうもです、タドスケです。
【Three.js】矩形同士の当たり判定 | しぬまでワクワクしていたい
どうもです、タドスケです。 Three.js を使ったサンプル作りが楽しい今日この頃。 今回は矩形(四角)同士の当たり判定を実装してみました。 マウスカーソルに合わせて矩形…
前回、矩形同士の当たり判定を作ったので、今回はマウスカーソルとの当たり判定を作ってみました。
目次
完成品
ボックスが格子状に配置されており、マウスカーソルで触れると色が変わります。
コード
コードは以下です。
(実装には ChatGPT を使用しています)
<!DOCTYPE html>
<html>
<head>
<title>Raycasting with Lighting in Three.js</title>
<style>
body { margin: 0; }
canvas { display: block; }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// Three.jsの設定の初期化
function initializeThreeJS() {
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
return { scene, camera, renderer };
}
// 光源の追加
function addLights(scene) {
var directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
var ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
}
// オブジェクトの生成と配置
function createAndPlaceBoxes(scene) {
var boxGeometry = new THREE.BoxGeometry();
var boxMaterial = new THREE.MeshLambertMaterial({ color: 0x00ff00 });
var boxSpacing = 1.5;
var gridSize = 3;
var boxes = [];
for (let x = 0; x < gridSize; x++) {
for (let y = 0; y < gridSize; y++) {
var box = new THREE.Mesh(boxGeometry, boxMaterial.clone());
box.position.x = x * boxSpacing - (gridSize - 1) * boxSpacing / 2;
box.position.y = y * boxSpacing - (gridSize - 1) * boxSpacing / 2;
box.position.z = 0;
scene.add(box);
boxes.push(box);
}
}
return boxes;
}
// レイキャスターの設定
function setupRaycaster() {
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
return { raycaster, mouse };
}
// イベントハンドラーの定義
function setupMouseEventHandler(raycaster, mouse, camera, boxes) {
function onMouseMove(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(boxes);
boxes.forEach(box => box.material.color.set(0x00ff00));
intersects.forEach(intersect => intersect.object.material.color.set(0xff0000));
}
window.addEventListener('mousemove', onMouseMove, false);
}
// アニメーションの設定
function animate(renderer, scene, camera) {
function loop() {
requestAnimationFrame(loop);
renderer.render(scene, camera);
}
loop();
}
// Three.jsの設定、オブジェクトの生成、イベントハンドラーとアニメーションの設定
var { scene, camera, renderer } = initializeThreeJS();
addLights(scene);
var boxes = createAndPlaceBoxes(scene);
var { raycaster, mouse } = setupRaycaster();
setupMouseEventHandler(raycaster, mouse, camera, boxes);
animate(renderer, scene, camera);
// カメラの位置設定
camera.position.z = 5;
</script>
</body>
</html>
実装のポイント
シーン内のボックスは 3D オブジェクトですが、マウスカーソルの座標は 2D なので奥行きを持ちません。
これを解決する一般的な方法に、レイキャスティングがあります。
レイとは光線のことで、カメラの位置からマウスの位置に向かって一直線にレイを飛ばし、途中で当たったものを記録しておきます。
今回のプログラムでは、当たったボックスの色を変えています。
これを、マウスカーソルが移動するたびに行います。
コードでは以下の部分です。
function onMouseMove(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(boxes);
boxes.forEach(box => box.material.color.set(0x00ff00));
intersects.forEach(intersect => intersect.object.material.color.set(0xff0000));
}
本来ならベクトルの計算などが必要なのですが、Three.js では Raycaster クラスの内部でやってくれており、とても簡単にレイキャスティングが実装できるようになっていますね✨
今回はカメラ→マウスカーソル位置にレイを飛ばしましたが、これを応用すれば、敵キャラクター→プレイヤーにレイを飛ばして、「敵からプレイヤーが見えているか」を判定することもできます。
ただしレイキャスティングはそこそこ重い処理なので、飛ばし過ぎには注意が必要です。
たくさんの敵が出るようなゲームでは、レイを毎フレームではなく一定間隔で飛ばすようにしたり、もっと簡略化した方法を使うこともあります。
コメント
コメント一覧 (1件)
[…] 【Three.js】マウスカーソルとの当たり判定 | しぬまでワクワクしていたい どうもです、タドスケです。 […]