[JavaScript] キャラクターの自動散歩と衝突判定の実装

はじめに

プレイヤー以外のキャラクターに徒歩アニメションを追加して、フィールド内を自動で散歩するアニメーションを実装してみたので、そのメモです。

衝突判定で、ポップアップメッセージを出せば、街で村人との会話のような実装も可能だと思います。

かなり大変ですが、 Three.jsでRPGゲームの作成も可能ですね…。

その他、VRに対応しようとしてたのですが、うまくいかなくて先送りになってます。

1. キャラクターの自動散歩の実装

1.1 キャラクターの基本的な移動

まず、キャラクターを指定された経路(path)に沿って自動で移動させます。キャラクターは指定されたルートを順番に進み、ターゲット地点に到達したら次のターゲットに進むようにします。以下にその基本的なコードを示します。

class CharacterWalk {
  constructor(name, model, path) {
    this.name = name;  // キャラクターの名前
    this.model = model;  // モデル(THREE.jsオブジェクト)
    this.path = path;  // 移動するターゲットポイントの配列
    this.speed = 2;  // 移動速度
    this.currentTargetIndex = 0;  // 現在のターゲットインデックス
  }

  update(deltaTime) {
    if (this.path.length < 2) return;  // 2つ以上のポイントがない場合、移動しない

    const target = this.path[this.currentTargetIndex];
    const direction = new THREE.Vector3().subVectors(target, this.model.position).normalize();
    const distance = this.model.position.distanceTo(target);

    // 目標地点に近づいたら次のターゲットへ
    if (distance < this.speed * deltaTime) {
      this.model.position.copy(target);
      this.setNextTarget();
    } else {
      // 進行方向に回転させる
      this.model.lookAt(target);  // モデルをターゲットの方向に向ける
      const moveDistance = direction.multiplyScalar(this.speed * deltaTime);
      this.model.position.add(moveDistance);
    }
  }

  setNextTarget() {
    this.currentTargetIndex++;
    if (this.currentTargetIndex >= this.path.length) {
      this.currentTargetIndex = 0;  // 最後のターゲットに到達したら先頭に戻る
    }
  }
}

解説

  • path: 進むべきターゲットポイントの配列です。キャラクターはこの配列に沿って移動します。
  • update(deltaTime): このメソッドはキャラクターを移動させるために呼び出されます。deltaTimeはフレームごとの経過時間です。
  • setNextTarget(): キャラクターが次のターゲットへ進むために使用されるメソッドです。

1.2 自動回転

キャラクターが進行方向に回転するためには、lookAt()メソッドを使います。これにより、キャラクターはターゲットの方向に自動的に向きます。

this.model.lookAt(target);  // モデルをターゲットの方向に向ける

lookAt()メソッドは、キャラクターがターゲットに向かって回転するため、キャラクターが進行方向に向かって動きます。


2. 衝突判定の実装

キャラクターが自動で移動する際、周囲に障害物があるかどうかを確認する必要があります。そこで、Three.jsのBox3(3Dボックス)を使用して、衝突判定を行います。

2.1 衝突判定ボックスの生成

Box3を使用して、キャラクターの周囲の空間を表現します。ボックスは、最小点(min)と最大点(max)を使用して定義されます。

const box = new THREE.Box3();
const boundingBox = modelData.boundingBox;
box.set(
  new THREE.Vector3(
    position[0] + boundingBox.min[0],
    position[1] + boundingBox.min[1],
    position[2] + boundingBox.min[2]
  ),
  new THREE.Vector3(
    position[0] + boundingBox.max[0],
    position[1] + boundingBox.max[1],
    position[2] + boundingBox.max[2]
  )
);

ここでは、boundingBoxminmaxを使用して、モデルの周囲の衝突判定ボックスを作成しています。

2.2 衝突判定ボックスの更新

キャラクターが移動するたびに、衝突判定用のボックスを更新する必要があります。ボックスの位置はキャラクターの位置に基づいて動的に更新されます。

updateCollisionBox() {
  const box = config.model.wallBoxes.filter((box) => box.name === this.name)[0];

  if (box) {
    // ボックスの位置を移動分だけ更新
    const moveDistance = this.model.position.clone().sub(box.min);  // 移動量
    box.min.add(moveDistance);
    box.max.add(moveDistance);
  }
}

このメソッドは、キャラクターの移動に応じて、衝突判定ボックスを動的に更新します。


3. 衝突判定の実行

衝突判定を実行するためには、Box3同士が交差しているかをチェックする必要があります。これには、intersectsBox()メソッドを使用します。

if (box1.intersectsBox(box2)) {
  console.log('Collision detected!');
}

このコードで、box1box2が交差している場合に衝突が検出され、Collision detected!がコンソールに出力されます。


4. まとめ

この記事では、Three.jsを使ってキャラクターの自動移動と衝突判定を実装する方法について説明しました。キャラクターが指定されたルートを自動で歩き、その動きに応じて衝突判定ボックスを更新し、周囲の障害物と衝突しないようにしています。この実装により、3D空間で動くキャラクターの基本的な動作を実現しました。