各ゲームの実装
6 ゲームの状態・ルール・描画・操作・難易度設計の要点。各ゲームは games/<name>/ に Run(*Console, *IMU) として実装。共通操作は概要を参照。
Snake — games/snake
- 状態: グリッド 15×24。ヘビは座標の配列(プリアロケート+インプレースシフトで無確保更新)、リンゴ1個。
- 操作: A=左回転 / B=右回転(相対回転なので逆走が起きない)。2ボタンとも操舵に使うためサウンド切替なし(例外)。
- 描画: 部分再描画(移動した先頭・消える末尾のセルだけ)。
- 難易度: 食べると伸びて自己衝突リスク増。固定速度。
2048 — games/2048
- 状態: 4×4 盤。スライド+結合のロジック(行/列を寄せて隣接同値を1回だけ結合)。
- 操作: チルトでスライド(水平に戻してから次の傾け)。A=リトライ、B=音。
- 描画: オフスクリーン
Canvasにタイルを描き、移動を補間してちらつき無しのスライドアニメ→一括転送。数字は桁数でフォント切替、4桁は 1K/2K 表記。 - 難易度: 盤が埋まり動かせなくなると終了。
Pong — games/pong
- 状態: 上=CPU / 下=自機パドル、ボール。
- 操作: チルトでパドル左右(加速度に比例・上限あり)。B=音。先に5点で勝敗。
- 描画: コートは静的、ボールとパドルだけ部分再描画(パドルは移動時のみ旧位置消去)。
- AI/難易度: CPU はボールを追うが速度上限で倒せる。パドル端で当てると横方向に変化(english)。
Dinosaur — games/dinosaur
- 状態: 自機(恐竜)と右から流れるサボテン列。簡単な重力ジャンプ(速度+重力)。
- 操作: A=ジャンプ(接地時のみ)。B=音。
- 描画: 走路バンドとスコアバーをそれぞれ
Canvasに描き一括転送(ちらつき無しスクロール)。 - 当たり判定/難易度: AABB。スコアで徐々に加速、サボテン間隔はランダム。
Tetris — games/tetris
- 状態: 10×20 盤(
[20][10]uint8)、7種テトリミノ。回転は box 内 CW 変換+簡易ウォールキック。 - 操作: チルト左右=移動 / チルト下=ソフトドロップ / A=回転 / B=音。
- 描画: 落下ピースは部分再描画、ライン消去時のみ盤面再描画。盤面の枠線・NEXT 表示・各ブロックの縁取り。
- 音: 移動/回転/ライン消去の操作音。開始時に テトリスのテーマ(Korobeiniki) を1回再生(A でスキップ可、B でミュート可)。
- 難易度: 消去ライン数でスコア(100/300/500/800)、ライン数でレベルアップし落下加速。
Invaders — games/invaders
- 状態: 5×4 編隊(生存フラグ配列)、自機、自弾(複数)、爆弾。編隊は左右移動+端で降下。
- 操作: チルトで自機移動 / A=発射(タップ1発・長押しで連射モード ON/OFF)/ B=音。
- 描画: 移動物体のみ部分再描画、編隊は移動/降下ステップ時のみ再描画。3行のステータスバー(スコア/サウンド/連射)。
- 難易度: 全滅で次ウェーブ(加速・少し下から)。編隊が自機の高さまで降下 or 被弾で終了。連射は間隔360ms・同時弾4に調整し簡単になりすぎないように。
共通のライフサイクル
すべてのゲームの Run は概ね次の形:
go
func Run(con *m5stickc.Console, imu *m5stickc.IMU) {
// 表示・ボタン・ブザーを con から取得(IMU 必須ゲームは nil チェック)
seed, exit := title(...) // A タップ=開始 / A 長押し=メニューへ / B=音
if exit { return }
rng := rand.New(rand.NewSource(seed))
for {
if !play(...) { // play は gameOver の結果(リトライ/メニュー)を返す
return // A 長押し=メニューへ戻る
}
}
}title / gameOver の待ちとサウンド切替は pkg/m5stickc の WaitStart / WaitRetryOrExit に集約されている(アーキテクチャ参照)。