2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

2022年自作ゲーム総括

Last updated at Posted at 2023-01-03

本題について

2022年は、自作ゲームを2つ新規・追加改修しました。

  • 昨年に引続き、趣味でグラディウス風(特にゲーセン版の3作目を意識して)のシューティングゲーム
  • Vue3ベース15Puzzle

今回は、シューティングゲームの内容をお伝えしたいと思います。

  1. 自作シューティングゲームとは
  2. 2022年自作シューティングゲーム追加・変更
  3. まとめ

1. 自作シューティングゲームとは

TypeScriptで実装したグラディウス風の横スクロールシューティングゲームです。
一部制約はありますが、基本的にPC・スマホでゲームを楽しめます。

※この動画ではiPad Pro2021, ゲームコントローラー(Xbox Elite ワイヤレス コントローラー シリーズ 2)使ってプレーしてます。

  • PCはMacOSの最新版、Windows11 Edge (Chromium)
  • スマホはiOS、iPadOSの最新版でSafari対応
  • スマホではゲームコントローラーを使ってゲーム可能(後述)
  • 2022/12/5時点で合計ファイルサイズは6.812MB(Viteによるビルド実行)
  • フレームワークはReact
  • 言語はTypeScript(2021年〜)でCanvasで描画、AudioContextで音声出力

過去にも自作ゲームに関する記事を投稿してます。

この開発は約6年ぐらいになりますが、今でも改修を続けてます。

2. 2022年自作シューティングゲーム追加・変更

2-1. ゲームコントローラー対応

GamepadAPIを実装し、ゲームコントローラーでプレーできるよう改修をしました。

iOSが16.xになり、Joy-Conサポートされました。
基本的に動作はしましたが、いくつか課題もありました。

2-1-1. 使用機材

(1). Windowsと8Bitdo アーケードスティック

PCからUSB経由でアケステに接続し、Edgeブラウザでプレーできます。
Windows側にはキーマッピングするソフトが必要になります。

(2). iPhoneとJoy-Con(これはサポート対象外)

初めて外部コントローラーに接続した感動を覚えたのですが、
致命的だったのが、ゲーム開始後操作遅延が発生し、暫くして処理が低下。
最終的にはSafariが落ちてしまう現象が発生しました。

なので、この自作ゲームではJoy-Conは対象外にしました。
iOSか、Safariアップデートによる改善を期待しつつ・・・。

(3). iPhoneとRazer Kishi V2

Joy-Conでの課題を改善するために、Bluetoothではなく、
Lightning接続コントローラーを購入。
遅延はほとんど(自分感覚)なく、スムーズにプレーできます。
ただ、状況によっては長時間プレーすると、ブラウザ(Safari)が落ちることもあります。

(4). iPadとXbox Elite ワイヤレス コントローラー シリーズ 2

当初3,000円程度のゲームコントローラーを使ってたのですが、
あまりの操作遅延で使い物にならず。
また、iPadでの有線接続方法もなかなか見つからず。

ダメもとでXboxコントローラーを購入してBluetooth接続しても、殆ど遅延は発生しませんでした。
時間経過による劣化での遅延も想定してたのですが、今のところ遅延は発生してません。

2-1-2. ゲームコントローラーの処理フロー

mdnにあるゲームパッドAPIの使用を参考に実装しました。
requestAnimationFrameを使ってゲームコントローラーからのキー情報を取得するようにしてます。

当初、ゲーム処理とゲームコントローラーそれぞれにrequestAnimationFrameを用意したのですが、処理負担を考慮(個人見解)して1つにまとめました。

2-1-3. ゲームコントローラー実行時の課題点

(1). Nintendo Switch(JoyCon)との接続では途中でSafariが落ちることがある

Nintendo Switch(JoyCon)との接続では5分も経過せずに処理がスローになり、最終的にSafariが落ちてしまいます。
requestAnimationFrameでゲームコントローラー側で処理
GamepadAPIからのキー情報取得を間引いたりしたのですが、結局変わらず・・・。
ただ、他のコントローラーではこの事象が発生しないので、Switchにおいてはゲームプレー対象外にしてます。

iOSのアップデートによって改善される可能性があるのかな・・・。

また、iPhoneとRazer Kishiとの組み合わせでもフリーズしてSafariが落ちることがありますが、
落ちるタイミングの幅が広い(だいたい30分か、それ以降)ので、善処方法が不明といった感じです。

2023/12/20
iPhone14 Plus、iOS17.1.xで検証したところ、JoyConでも動作できるようになりました。
またプロダクトコードでfpsの間引きをせず、長時間プレーでは端末に熱は発生するものの概ね問題ありませんでした。

(2). スマホで、タスク切替や画面ロックによってゲームコントローラーが反応しないことがある

iPhone、iPadで発生する事象で、特にSafariでゲームプレー中 -> Chromeでタスク切替後、再びSafariに戻すとコントローラーが全く効かなくなります。
結局Safariを再起動させるしか方法がない感じです。

2-2. 開発環境をwebpackからViteに移行

元々はwebpackを使って開発してたのですが、サーバの起動・開発においてもう少し処理時間を短縮したく。
Viteはその要望に応えられそうと思い、Viteへの移行にトライしてみました。

screencast 2022-12-22 21-55-55.gif
ファイル保存後にすぐにプレビューできて、開発の進みが早くなった気がします。
ただ、開発環境を意識した実装も考慮しないといけないなとも思いました。(後述)

2-2-1. package.jsonの変更

package.jsonで、webpackからの移行による差分を下記します。
webpack、Vite共に自身とその関連するパッケージを差し替えてます。
関連パッケージでは以下の機能を引き継いでます。

  • html、アセット系の圧縮
  • Eslintによるチェック
package.json(抜粋)

  "scripts": {
     ...
-    "build": "webpack",
-    "dev": "webpack serve",
+    "dev": "vite",
+    "preview": "vite preview",
+    "build": "vite build",
     ...
  },
  "devDependencies": {
     ...
-    "compression-webpack-plugin": "^10.0.0",
-    "copy-webpack-plugin": "^11.0.0",
-    "dotenv": "^16.0.2",
-    "dotenv-cli": "^6.0.0",
-    "dotenv-webpack": "^8.0.1",
-    "eslint-import-resolver-webpack": "^0.13.2",
-    "html-loader": "^4.1.0",
-    "html-webpack-plugin": "^5.5.0",
-    "image-minimizer-webpack-plugin": "^3.3.0",
-    "imagemin-gifsicle": "^7.0.0",
-    "imagemin-pngquant": "^9.0.2",
-    "imagemin-svgo": "^10.0.1",
-    "imagemin-webpack-plugin": "^2.4.2",
-    "jpegtran-bin": "^7.0.0",
-    "webpack": "^5.74.0",
-    "webpack-bundle-analyzer": "^4.6.1",
-    "webpack-cli": "^4.10.0",
-    "webpack-dev-server": "^4.10.1",
-    "workbox-webpack-plugin": "^6.5.4"
     ...
  }
  "dependencies": {
     ...
+    "@vitejs/plugin-react": "^2.0.1",
+    "vite": "^3.0.9",
+    "vite-plugin-compression": "^0.5.1",
+    "vite-plugin-eslint": "^1.8.1",
+    "vite-plugin-html": "^3.2.0",
+    "vite-plugin-imagemin": "^0.6.1"
     ...
  },

vite.config.tsも追加設定してますが、
上記パッケージを使った設定をしてるだけなので、ここでは省略します。

2-2-2. フォルダ構成

前回の投稿よりViteの基本設定に準じてフォルダ構成を変更しました。

├──dist/
│   ├── audios/ ・・・ ①からコピー
│   ├── images/ ・・・ ②から画像圧縮
│   ├── images-dom/ ・・・ ③から画像圧縮
│   ├── icons/ ・・・ ④から画像圧縮
│   ├── index-xxxxxxx.js ・・・ ⑥、⑦、⑧から圧縮、バンドル
│   ├── index-xxxxxxx.css ・・・ ⑤をバンドル
│   └── index.html ・・・ ⑨から圧縮
├── public/
│       ├── audios/ ・・・ ①
│       ├── images/ ・・・ ②
│       ├── images-dom/ ・・・ ③
│       └── icons/ ・・・ ④
├── src/
│   └── application/
│       ├── scss/ ・・・ ⑤
│       ├── json/ ・・・ ⑥
│       ├── ts/ ・・・ ⑦
│       └── main.tsx ・・・ ⑧
├── index.html ・・・ ⑨
└── tests/ ・・・ Jestで扱うファイル群

2-2-3. HMRを考慮した改修

webpackではソース改修後に再読込してたのですが、
ViteになってHMRにしたので、必要な箇所のみ再読込する形になりました。
この自作ゲームでは、再読込前提の実装だったので、「後始末」を全く意識してませんでした。

例を示すために簡単なソースを、以下に記載しますが、
モジュールを更新する度に、App.tsxのイベント処理が都度登録されてました。

App.tsx
window.addEventListener('touchStart', () => {
  ... // イベント処理
}, false)

export const App: React.FC = () => {
  useEffect(() => {
    ...
  }, [])
  return (
    <div>
      ...
    </div>
  )
}

そこで、イベント登録が重複されないよう、
副作用フックの利用法を参考に、クリーンアップを使ってイベント処理を見直しました。
ランタイム確認で、イベントの登録・削除の所作が思惑通りになりました。

- window.addEventListener('touchStart', () => {
-   // イベント処理
- }, false)

export const App: React.FC = () => {
-  useEffect(() => {
-    ...
-  }, [])
+  useEffect(() => {
+    const doEvent = () => {
+      // イベント処理
+    }
+    // イベント登録
+    window.addEventListener('touchStart', doEvent, false)
+    return () => {
+      // イベント削除
+      window.removeEventListener('touchStart', doEvent)
+    }
+  }, [])  
  return (
    <div>
      ...
    </div>
  )
}

2-3. テストフレームワークをJestからVitestに移行

元々テストはJestを使用して、TypeScriptで実装しました。
2022/12/05時点でのテストファイル、テスト項目数です。

  • テストファイル 119
  • テスト項目 724

今回Vitestに移行したのは、テスト実施時間の短縮が目的です。
今年だけでテストフレームワークは以下の変遷でした。
Vite導入に併せてVitestに決定した感じです。

1. Jest + ts-config
2. Jest + swc
3. Vitest ← 現在

この自作ゲームはクラスの集まりなので、テスト方針はクラスメソッドのIN・OUTチェックがベースです。

2-3-1. Vitestの設定

Vitestへの移行にあたり、ここではVitestに必要なパッケージと追加設定ファイルの内容を記載します。

package.json(抜粋)

"scripts": {
  ...
+  "test": "vitest",
+  "coverage": "vitest run --coverage",
  ...
}
"devDependencies": {
  ...
+  "jsdom": "^20.0.3",
+  "vitest": "^0.25.3",
+  "@vitejs/plugin-react": "^2.2.0",
  ...
}
vitest.config.ts
import { defineConfig } from 'vitest/config';
import path from 'path';

export default defineConfig({
  test: {
    globals: true,
    environment: 'jsdom',
  },
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '~': path.resolve(__dirname, './tests'),
    },
  },
});

2-3-2. テストソース改修

Jestと互換性があり、大幅な変更はなかったのですが、
describeit等をvitestからimportする必要があり、
全テストファイルに追加しました。
※もしかしたら追加不要の方法があったのかも・・・。

+ import { beforeEach, describe, it, expect, vi } from 'vitest';
import { SceneAnimator } from '@/application/ts/animator';

describe('SceneAnimator', () => {
  let anim: SceneAnimator;
  beforeEach(() => {
    anim = new SceneAnimator();
  });
  describe('アニメーション登録・削除', () => {
    it('アニメーションが削除されないこと', () => {
      anim.addAnimation({
        keyName: 'test',
        act: () => {},
      });
      anim.removeAnimation('test2');
      expect((<any>anim).animations.length).toBe(1);
    });
  });
});

2-3-3. テスト所要時間 (Jest+swcとVitestの比較)

Jest + swc 82.857ms
Screenshot 2022-11-23 at 15.27.59.png

Vitest 47.68ms
Screenshot 2022-11-23 at 15.22.56.png

※それぞれ2回計測してほぼ同じ経過時間でした。

2-3-4. Vitest(VSCodeプラグイン)

自分の開発環境ではVitestでのコンソール実行は設けてますが、
VSCodeのプラグインでテスト実施できるということで、公式のプラグインを導入12してみました。
(2022/12/05時点ではPreview版でした)

Screenshot 2022-12-05 at 9.05.59.png

ファイル単体でのチェック実行は問題ないですが、全ファイルで実行しようとしても動かないようです。。(2022/12/25時点)

screencast 2022-12-05 09-20-53.gif

3. まとめ

スマホではスクリーンにボタン表示させてプレーしてたのですが(以下動画参照)、
ゲームコントローラーの操作に慣れると、スクリーンボタンによる操作が億劫に感じてしまいますね・・・。

ただ、完全にサポートできたわけではないので、今回記載した問題は可能な限り対応したいなと。
あと、デバッグ方法がもう少し簡単だったらなぁ。

このゲームでは、フロントエンドに関するいろんなツールを試し、理解を深める意図もあって作成・改修を行なってます。
今回は、Vite・Vitestの導入で開発環境をまるっと差替え、それぞれの体験を通してメリット・デメリットを理解したつもりです。

2023年も、新しい技術等あればこの自作ゲームに取り込んでみたいと思ってます。

  1. Vitest公式のVSCodeプラグインがリリースされました

  2. Vitest

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?