mcpField
A
advanced-input

advanced-input

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

advanced-input について

Decentralandのシーン開発者向けに、高度な入力パターンを解説するスキルです。ポインター状態の確認、入力ポーリング、移動制限を扱い、基本的なクリックやホバーを超える操作を実装できます。

主な機能

  1. 01ポインターロック状態と変化の検出
  2. 02カーソル座標とワールドレイの取得
  3. 03エンティティ単位または全体の入力ポーリング
  4. 04タグによるエンティティ入力の一括処理
  5. 05移動制限とプレイヤーの停止
  6. 06キー入力によるカスタム移動の制御

活用シーン

  1. 01単発および継続的なキー操作の実装
  2. 02同種エンティティ群の入力処理
  3. 03カットシーン中のプレイヤー停止
  4. 04WASDによるカスタムエンティティの操作

インストール

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

$npx skills add https://github.com/dcl-regenesislabs/opendcl --skill advanced-input

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

詳細

Decentraland の高度な入力処理

基本的なクリック/ホバーイベントについては、add-interactivity スキルを参照してください。このスキルでは、高度な入力パターンを扱います。

ポインターロックの状態

カーソルがキャプチャされている(ファーストパーソンモード)か、自由に動かせるかを検出します。

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

function checkPointerLock() {
  const isLocked = PointerLock.get(engine.CameraEntity).isPointerLocked

  if (isLocked) {
    // Cursor is captured — player is in first-person control
  } else {
    // Cursor is free — player can click UI elements
  }
}

engine.addSystem(checkPointerLock)
ポインターロックの変更検出
PointerLock.onChange(engine.CameraEntity, (pointerLock) => {
  if (pointerLock?.isPointerLocked) {
    console.log('Cursor locked')
  } else {
    console.log('Cursor unlocked')
  }
})

カーソル位置とワールドレイ

カーソルの画面上の位置と、3D ワールドに向けて投射されるレイを取得します。

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

function readPointer() {
  const pointerInfo = PrimaryPointerInfo.get(engine.RootEntity)
  console.log('Cursor position:', pointerInfo.screenCoordinates)
  console.log('Cursor delta:', pointerInfo.screenDelta)
  console.log('World ray direction:', pointerInfo.worldRayDirection)
}

engine.addSystem(readPointer)

inputSystem による入力のポーリング

エンティティごとの入力コマンド

特定のエンティティに対して特定の入力アクションが発生したかを確認します。

import { engine, inputSystem, InputAction, PointerEventType } from '@dcl/sdk/ecs'

function myInputSystem() {
  // Check for click on a specific entity
  const clickData = inputSystem.getInputCommand(
    InputAction.IA_POINTER,
    PointerEventType.PET_DOWN,
    myEntity
  )

  if (clickData) {
    console.log('Entity clicked via system:', clickData.hit.entityId)
  }
}

engine.addSystem(myInputSystem)
グローバルな入力チェック

プレイヤーのカーソルがエンティティ上にあるかどうかにかかわらず、発火します。

function globalInputSystem() {
  // Was the key just pressed this frame?
  if (inputSystem.isTriggered(InputAction.IA_PRIMARY, PointerEventType.PET_DOWN)) {
    console.log('E key pressed!')
  }

  // Is the key currently held down?
  if (inputSystem.isPressed(InputAction.IA_SECONDARY)) {
    console.log('F key is held!')
  }
}

engine.addSystem(globalInputSystem)
タグベースの入力の一括処理

同じ入力に反応する似たエンティティが多数ある場合(例:すべての樽が E キーで壊れる)、Tag コンポーネントでタグ付けし、毎フレームタグクエリを反復処理します。

import { engine, Tag, inputSystem, InputAction, PointerEventType } from '@dcl/sdk/ecs'

// At setup: tag the entities (or declare Tag in main-entities.ts).
for (const barrel of [b1, b2, b3]) {
  Tag.createOrReplace(barrel, { value: 'breakable' })
}

engine.addSystem(() => {
  for (const [entity] of engine.getEntitiesByTag('breakable')) {
    const cmd = inputSystem.getInputCommand(InputAction.IA_PRIMARY, PointerEventType.PET_DOWN, entity)
    if (cmd) {
      // entity was the IA_PRIMARY target this frame
      engine.removeEntity(entity)
    }
  }
})

動作が共通している場合は、N 個の pointerEventsSystem.onPointerDown ハンドラーを個別に登録するよりも簡潔です。

すべての InputAction の値

InputActionキー/ボタン
IA_POINTERマウスの左ボタン
IA_PRIMARYE キー
IA_SECONDARYF キー
IA_ACTION_31 キー
IA_ACTION_42 キー
IA_ACTION_53 キー
IA_ACTION_64 キー
IA_JUMPSpace キー
IA_FORWARDW キー
IA_BACKWARDS キー
IA_LEFTA キー
IA_RIGHTD キー
IA_WALKShift キー

イベントの種類

PointerEventType.PET_DOWN         // Button/key pressed
PointerEventType.PET_UP           // Button/key released
PointerEventType.PET_HOVER_ENTER  // Cursor enters entity
PointerEventType.PET_HOVER_LEAVE  // Cursor leaves entity

InputModifier(移動の制限)

プレイヤーの移動を制限または停止します。

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

// Freeze player completely
InputModifier.create(engine.PlayerEntity, {
  mode: InputModifier.Mode.Standard({ disableAll: true })
})

// Restrict specific movement (every flag is optional and defaults to false)
InputModifier.createOrReplace(engine.PlayerEntity, {
  mode: InputModifier.Mode.Standard({
    disableWalk: false,
    disableJog: false,
    disableRun: true,
    disableJump: true,
    disableDoubleJump: true,
    disableGliding: true,
    disableEmote: true
  })
})

// Restore normal movement
InputModifier.deleteFrom(engine.PlayerEntity)

制限中も、重力は適用され、カメラは回転し、ポインターイベントや近接イベントも発火します。プレイヤーがシーンを離れると、すべての制限が自動的に解除されます。

重要: InputModifier は DCL 2.0 デスクトップクライアントでのみ動作します。ウェブブラウザーのエクスプローラーでは効果がありません。

カットシーンのパターン

シネマティックシーケンス中にプレイヤーを停止します。

function startCutscene() {
  // Freeze player
  InputModifier.create(engine.PlayerEntity, {
    mode: InputModifier.Mode.Standard({ disableAll: true })
  })

  // ... play cinematic with VirtualCamera ...

  // After cutscene ends, restore movement
  // InputModifier.deleteFrom(engine.PlayerEntity)
}

WASD 移動のパターン

移動キーをポーリングして、カスタムエンティティを操作します。

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

const MOVE_SPEED = 5

function customMovementSystem(dt: number) {
  const transform = Transform.getMutable(controllableEntity)
  let moveX = 0
  let moveZ = 0

  if (inputSystem.isPressed(InputAction.IA_FORWARD)) moveZ += 1
  if (inputSystem.isPressed(InputAction.IA_BACKWARD)) moveZ -= 1
  if (inputSystem.isPressed(InputAction.IA_LEFT)) moveX -= 1
  if (inputSystem.isPressed(InputAction.IA_RIGHT)) moveX += 1

  transform.position.x += moveX * MOVE_SPEED * dt
  transform.position.z += moveZ * MOVE_SPEED * dt
}

engine.addSystem(customMovementSystem)

入力パターンの組み合わせ

数字キーを使ったアクションバー
function actionBarSystem() {
  if (inputSystem.isTriggered(InputAction.IA_ACTION_3, PointerEventType.PET_DOWN)) {
    console.log('Slot 1 activated')
    useAbility(1)
  }
  if (inputSystem.isTriggered(InputAction.IA_ACTION_4, PointerEventType.PET_DOWN)) {
    console.log('Slot 2 activated')
    useAbility(2)
  }
  if (inputSystem.isTriggered(InputAction.IA_ACTION_5, PointerEventType.PET_DOWN)) {
    console.log('Slot 3 activated')
    useAbility(3)
  }
  if (inputSystem.isTriggered(InputAction.IA_ACTION_6, PointerEventType.PET_DOWN)) {
    console.log('Slot 4 activated')
    useAbility(4)
  }
}

engine.addSystem(actionBarSystem)

ベストプラクティス

  • 一度だけ実行するアクション(武器を発射する、ドアを開ける)には isTriggered() を使用します。キーが最初に押されたフレームでのみ true を返します
  • 継続的なアクション(移動、シールドを構え続ける)には isPressed() を使用します。キーを押している間、毎フレーム true を返します
  • getInputCommand() はヒットデータ(位置、エンティティ)を返します。何がクリックされたかを把握する必要がある場合に使用します
  • 単純なエンティティのクリックには pointerEventsSystem.onPointerDown() を優先し、複雑な複数キー入力やポーリングのパターンには inputSystem を使用します
  • InputModifier は DCL 2.0 デスクトップクライアントでのみ動作します。シーンがこれに依存する場合は、デスクトップクライアントでテストしてください
  • WASD キー(IA_FORWARD など)はプレイヤーの移動も制御します。これらをポーリングすると移動状態を読み取れますが、状態を上書きすることはありません

基本的なポインターイベントとクリックハンドラーについては、add-interactivity スキルを参照してください。

コメント