mcpField
C
camera-control

camera-control

github.com/dcl-regenesislabs開発1737 回インストール21 週間前に更新
リポジトリ

camera-control について

Decentralandのシーン開発者向けカメラ制御スキルです。エリアごとのカメラモード設定、仮想カメラの実行時有効化、カメラ状態の取得、壁を通り抜けないためのコライダー設定を解説します。

主な機能

  1. 01エリアごとのカメラモード設定
  2. 02仮想カメラの作成と有効化
  3. 03カメラ位置とモードの取得
  4. 04カメラ遮蔽用コライダーの設定

活用シーン

  1. 01屋内で一人称視点を強制
  2. 02カットシーン用カメラの設定
  3. 03NPC追従やカメライベントの起動

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dcl-regenesislabs/opendcl --skill camera-control

インストール後、Claude Code で/camera-controlを入力して読み込まれたか確認します。

詳細

Decentraland のカメラ制御

作成先の振り分け

CameraModeArea と VirtualCamera は main-entities.ts でサポートされています。どちらも本質的に静的なコンポーネントなので、ここに配置します。MainCamera は予約済みの engine.CameraEntity に存在するため、サポートされていません。実行時に仮想カメラを有効化するには、src/index.ts を使用してください。

VirtualCamera.lookAtEntity は、main-entities.ts でエンティティの名前を受け取ります(Transform.parent と同様に、ビルド時に Entity ID に解決されます)。

// main-entities.ts
cinematic_cam: {
  components: {
    Transform: {
      position: { x: 12, y: 4, z: 8 },
      rotation: { x: 0, y: 0.7071, z: 0, w: 0.7071 }
    },
    VirtualCamera: {
      defaultTransition: { transitionMode: { $case: 'time', time: 2 } },
      lookAtEntity: 'shopkeeper'  // name of another entity in this file
    }
  }
},
first_person_zone: {
  components: {
    Transform: { position: { x: 8, y: 1, z: 8 } },
    CameraModeArea: {
      area: { x: 16, y: 2, z: 16 },
      mode: 0  // CameraType.CT_FIRST_PERSON
    }
  }
}

実行時にシネマティックカメラを有効化します。

// src/index.ts
import { engine, MainCamera } from '@dcl/sdk/ecs'

export function main() {
  const cam = engine.getEntityOrNullByName('cinematic_cam')
  if (cam) MainCamera.createOrReplace(engine.CameraEntity, { virtualCameraEntity: cam })
}

予約済みの engine.CameraEntity と engine.PlayerEntity はエンジンによって管理されており、main-entities.ts には対応する表現がありません。

CameraModeArea.mode の CameraType の値
値列挙値意味
0CT_FIRST_PERSONゾーン内で一人称視点を強制します
1CT_THIRD_PERSONゾーン内で三人称視点を強制します
2CT_CINEMATICゾーン内でシネマティックカメラを強制します

カメラの状態を読み取る

予約済みの engine.CameraEntity を使って、カメラの現在の位置と回転にアクセスします。

import { engine, Transform } from '@dcl/sdk/ecs'

function trackCamera() {
  if (!Transform.has(engine.CameraEntity)) return

  const cameraTransform = Transform.get(engine.CameraEntity)
  console.log('Camera position:', cameraTransform.position)
  console.log('Camera rotation:', cameraTransform.rotation)
}

engine.addSystem(trackCamera)

カメラモードの検出

プレイヤーが一人称視点か三人称視点かを確認します。

import { engine, CameraMode, CameraType } from '@dcl/sdk/ecs'

function checkCameraMode() {
  if (!CameraMode.has(engine.CameraEntity)) return

  const cameraMode = CameraMode.get(engine.CameraEntity)
  if (cameraMode.mode === CameraType.CT_FIRST_PERSON) {
    console.log('First person camera')
  } else if (cameraMode.mode === CameraType.CT_THIRD_PERSON) {
    console.log('Third person camera')
  }
}

engine.addSystem(checkCameraMode)
カメラモードの値
CameraType.CT_FIRST_PERSON  // First-person view
CameraType.CT_THIRD_PERSON  // Third-person view (default)

CameraModeArea(領域内でカメラを固定)

プレイヤーが領域に入ったときに、特定のカメラモードを強制します。

import { engine, Transform, CameraModeArea, CameraType } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

const fpArea = engine.addEntity()
Transform.create(fpArea, { position: Vector3.create(8, 1.5, 8) })

CameraModeArea.create(fpArea, {
  area: Vector3.create(6, 4, 6),         // 6x4x6 meter box
  mode: CameraType.CT_FIRST_PERSON       // Force first-person inside
})

プレイヤーが領域から出ると、カメラはプレイヤーが設定したモードに戻ります。

VirtualCamera(シネマティックカメラ)

カットシーンや特別な視点用に、スクリプトでカメラ位置を作成します。

import { engine, Transform, VirtualCamera, MainCamera } from '@dcl/sdk/ecs'
import { Vector3, Quaternion } from '@dcl/sdk/math'

const cinematicCam = engine.addEntity()
Transform.create(cinematicCam, {
  position: Vector3.create(8, 5, 2),
  rotation: Quaternion.fromEulerDegrees(-20, 0, 0)
})

VirtualCamera.create(cinematicCam, {
  defaultTransition: {
    transitionMode: VirtualCamera.Transition.Speed(1.0)
  }
})

// Activate the virtual camera
MainCamera.getMutable(engine.CameraEntity).virtualCameraEntity = cinematicCam

// Return to normal camera
MainCamera.getMutable(engine.CameraEntity).virtualCameraEntity = undefined
トランジションモード
VirtualCamera.Transition.Speed(1.0)  // Speed-based smooth transition
VirtualCamera.Transition.Time(2)     // Time-based transition (2 seconds)
注視対象

仮想カメラでエンティティを追跡します。

const target = engine.addEntity()
Transform.create(target, { position: Vector3.create(8, 1, 8) })

VirtualCamera.create(cinematicCam, {
  lookAtEntity: target,
  defaultTransition: {
    transitionMode: VirtualCamera.Transition.Speed(2.0)
  }
})

// Activate
MainCamera.getMutable(engine.CameraEntity).virtualCameraEntity = cinematicCam

カメラ位置の追跡

カメラをトリガーとするイベントのために、毎フレームカメラ位置を取得します。

import { engine, Transform } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

let lastNotifiedZone = ''

function cameraZoneSystem() {
  if (!Transform.has(engine.CameraEntity)) return

  const camPos = Transform.get(engine.CameraEntity).position
  let currentZone = ''

  if (camPos.y > 10) {
    currentZone = 'sky'
  } else if (camPos.x < 4) {
    currentZone = 'west'
  } else {
    currentZone = 'center'
  }

  if (currentZone !== lastNotifiedZone) {
    lastNotifiedZone = currentZone
    console.log('Camera entered zone:', currentZone)
  }
}

engine.addSystem(cameraZoneSystem)

よく使われるパターン

カメラをトリガーとするイベント

カメラ位置を使って、プレイヤーが特定の領域を見たときにアクションをトリガーします。

function cameraLookTrigger() {
  const camTransform = Transform.get(engine.CameraEntity)
  const targetPos = Vector3.create(8, 2, 8)
  const distance = Vector3.distance(camTransform.position, targetPos)

  if (distance < 5) {
    // Player is close — check if camera is pointing at target
    // Use raycasting for precise look detection (see add-interactivity skill)
  }
}

engine.addSystem(cameraLookTrigger)
NPC の追従

VirtualCamera の Transform を更新して、NPC を追跡するようにカメラを移動します。

function followNpcCamera(dt: number) {
  const npcPos = Transform.get(npcEntity).position
  const camTransform = Transform.getMutable(cinematicCam)

  // Position camera behind and above the NPC
  camTransform.position = Vector3.create(
    npcPos.x - 2,
    npcPos.y + 3,
    npcPos.z - 2
  )
}

engine.addSystem(followNpcCamera)

カットシーン中にプレイヤーを動けなくしますか? VirtualCamera と、advanced-input スキルの InputModifier を組み合わせると、シネマティックシーケンス中のプレイヤーの移動を防止できます。

カメラとコライダー(カメラが壁を通り抜けないようにする)

三人称視点では、壁のコライダーマスクに CL_POINTER が含まれていないと、プレイヤーのカメラが壁をすり抜けることがあります。カメラは遮蔽チェックに CL_PHYSICS ではなく、ポインターのコライダーマスクを使用します。カメラが跳ね返るべき壁や建築物には、両方のマスクを設定してください。

// main-entities.ts
wall: {
  components: {
    Transform: { position: { x: 8, y: 1.5, z: 16 } },
    GltfContainer: {
      src: 'models/wall.glb',
      visibleMeshesCollisionMask: 3   // CL_PHYSICS | CL_POINTER
    }
  }
}

非表示のコライダーメッシュが含まれる GLB(Creator Hub のアセットパックなど)では、代わりに invisibleMeshesCollisionMask: 3 を設定してください。既定値の CL_PHYSICS だけでは、カメラが通り抜けてしまいます。

ベストプラクティス

  • 一度にアクティブにする VirtualCamera は 1 つだけにしてください。
  • 狭い屋内空間では、CameraModeArea を使って一人称視点を強制してください。
  • 快適なカメラ移動のため、トランジション速度は 0.5~3.0 にしてください。
  • カメラの状態は engine.CameraEntity 経由で読み取ってください。直接書き込もうとしてはいけません。
  • 注視対象の検出には、カメラ位置とレイキャスティングを組み合わせてください(add-interactivity スキルを参照)。
  • VirtualCamera と CameraModeArea 以外では、カメラ制御は読み取り専用です。プレイヤーのカメラを直接移動することはできません。

コメント