Skip to content

バーチャルパッドを作る

バーチャルパッドとは

バーチャルパッドとは、スマートフォンなどのタッチスクリーンデバイスで使用される、仮想的なゲームコントローラーのことを指します。 画面上に表示されるスティックやボタンなどを操作し、実際のゲーム機に近い挙動を可能にします。

ここでは、下記画像のようなバーチャルパッドを作成します。中央の濃い円部分をタッチで動かせて、外側の薄い円が可動範囲です。

virtual-pad.png

バーチャルパッドを作る

バーチャルパッドは g.SpriteonPointMove 等のトリガーを利用し実現します。

最初に、スティックの背景画像とスティック画像の g.Sprite を作成し g.E へ追加します。

この gameStick.png を組み合わせて作成します。外側の薄い円もこの画像の透明度と大きさを変更して作成しています。

gameStick.png

javascript
const padSize = 100; // パッドのサイズ
const stickSize = 72; // スティックのサイズ
const margin = 12; // バーチャルパッドと画面端の間の余白
const stickInitialX = Math.round(padSize / 2); // スティックX座標の初期位置
const stickInitialY = Math.round(padSize / 2); // スティックY座標の初期位置
const padPosition = {
  x: g.game.width - padSize - margin,
  y: g.game.height - padSize - margin
};

// スティックをまとめる親エンティティ
const pad = new g.E({
  scene, // 現在のシーンが代入されている変数
  x: padPosition.x,
  y: padPosition.y,
  width: padSize,
  height: padSize
});
const gameStickImage = scene.asset.getImage("/image/gameStick.png");
// g.Sprite を利用したスティックの背景部分
const stickBack = new g.Sprite({
  scene,
  src: gameStickImage,
  x: stickInitialX,
  y: stickInitialY,
  scaleX: padSize / gameStickImage.width,
  scaleY: padSize / gameStickImage.height,
  anchorX: 0.5,
  anchorY: 0.5,
  opacity: 0.5
});
pad.append(stickBack);

// g.Sprite を利用したスティックの部分
const stick = new g.Sprite({
  scene,
  src: gameStickImage,
  x: stickInitialX,
  y: stickInitialY,
  scaleX: stickSize / gameStickImage.width,
  scaleY: stickSize / gameStickImage.height,
  anchorX: 0.5, // 座標の基準をスプライトの中央にする
  anchorY: 0.5,
  touchable: true
});
pad.append(stick);

スティックがドラッグされた時の処理を onPointMove を利用し実装します。 スティックの画像となる stickonPointMove でドラッグ時の動作を追加し、ドラッグの移動距離に応じてスティック画像を移動しています。

ev.prevDelta から直近の PointMoveEvent からの移動距離を取得し、moveBy() で対象を相対的に移動させます。stickBack の半径の二乗を stick の移動範囲とし、範囲を超えた場合には角度から座標を求め stick 位置を変更しています。

javascript
// スティックがドラッグされた時の処理
stick.onPointMove.add((ev) => {
  // ev.prevDelta から直近の PointMoveEvent からの移動量を取得。
  const dx = ev.prevDelta.x;
  const dy = ev.prevDelta.y;

  const radius = (stickBack.width * (stickSize / gameStickImage.width)) / 2; // stickBack の半径
  const squareRadius = radius ** 2; // stickBack の半径の二乗
  const distanceX = stickInitialX - (stick.x + dx); // X 方向の移動距離
  const distanceY = stickInitialY - (stick.y + dy); // Y 方向の移動距離
  const squareDistance = distanceX ** 2 + distanceY ** 2; // X, Y の移動距離を二乗し加算した値
  // (中心からのX軸移動距離)^2 + (中心からのY軸移動距離)^2 < squareRadius を stick の制限範囲とする
  if (squareDistance > squareRadius) {
    // 範囲外の場合、角度から座標を求め、stick.x と y の値へ代入。
    const angle = Math.atan2(distanceY, distanceX);
    const pointX = radius * Math.cos(angle);
    const pointY = radius * Math.sin(angle);

    stick.x = stickInitialX - pointX;
    stick.y = stickInitialY - pointY;
    stick.modified();
    return;
  }
  stick.moveBy(dx, dy);
  stick.modified();
});

スティックから指が離れた時の処理を onPointUp を利用し実装します。 stickInitialXstickInitialY はスティックの初期位置で、指が離れた時にスティックを初期位置に戻します。

javascript
// スティックから指が離れた時の処理
stick.onPointUp.add(() => {
  stick.moveTo(stickInitialX, stickInitialY);
  stick.modified();
});

スティックの 1 フレーム分の時間経過時の処理を onUpdate を利用し実装します。スティックの位置に応じた処理を記述します。

javascript
// 1フレーム分の時間経過時の処理
stick.onUpdate.add(() => {
  // スティックの初期位置からの離れ具合 (-1.0 〜 +1.0)
  const stickX = (stick.x - stickInitialX) / (padSize / 2);
  const scickY = (stick.y - stickInitialY) / (padSize / 2);
  // スティックの位置 (stickX, stickY) に応じて行いたい処理をここに書きます
});

サンプル

次のコンテンツでは、スティックの操作に合わせて画像が動きます。

関連情報