--:-- LUA API

リバーシ・マインスイーパー・ブロック崩し

/lua/apps/ の3本 — pico.game のタイルマップ・スプライト・状態・画面ボタンで作るゲーム

ゲームエンジン pico.game の使い方の実例として、リバーシ・マインスイーパー・ブロック崩し(とテトリス)は全部エンジンの上に作ってあります。ウィジェット(Button Label Canvas など)は1つも作らず、game.new が作る Canvas 1枚の中で、画面ボタン・状態・タイルマップ・スプライトだけで組み立てています。

リバーシ(/lua/apps/リバーシ/)

  • 盤面はタイルマップ(tiles.pimg。24x24のタイル4枚: 空のマス・黒石・白石・打てる場所の印)。石を置く・裏返すは map:set() だけ
  • タップは g.touch(キャンバスの中の座標)から (x - 盤面の左) // 24 でマスを求める
  • 流れは g:state の3つ: play(打つ)・pass(置ける場所が無い側を知らせる。タップか1.8秒で続く)・over(結果。タップでもう一度)。ダイアログは使わないので、ゲームの流れが1つのファイルの中で追える
  • 「戻る」「リセット」は g:button。g:pressed("reset") で読む

マインスイーパー(/lua/apps/マインスイーパー/)

  • 盤面はタイルマップ。難易度ごとにマスの大きさが違う(初級20px・中級16px・上級14px)ので、画像も難易度ごとに1枚(tiles20.pimg tiles16.pimg tiles14.pimg)。タイルの値は 1=閉じたマス 2=空き 3〜10=数字1〜8 11=旗 12=地雷。0マスの連鎖で何十マス開いても、map:set() したマスだけが描き直される
  • 難易度を選び直すたびに g:clear() してタイルマップを作り直す
  • 画面は menu(難易度を選ぶ)→ play → done。状態ごとに showButtons{...} で見せる画面ボタンを入れ替える(隠したボタン(b.visible = false)はタッチも受けない)
  • 最初の1手は必ず安全(最初にタップしたマスを避けて地雷を置く)

ブロック崩し(/lua/apps/ブロック崩し/)

  • ブロックはタイルマップ(tiles.pimg。29x14のタイル7枚: 速さの段1〜6と壊せない灰色)。壊すと map:set(c, r, 0)。ボールの周りのマスだけを map:get(c, r) で引いて当たりを調べるので、ブロックが何個あっても重くならない
  • ボール・パドル・アイテムはスプライト。ボールは draw で円を描く。アイテムは vy を持たせるだけでエンジンが落とし、パドルとの重なりは g:collide("paddle", "item", fn) で拾う
  • ボールの位置と速さは自前(cx cy dx dy)。1フレームを6px以下に刻んで壁・ブロック・パドルへ当てる(エンジンの1回の移動だと、速いボールがブロックをすり抜けるため)
  • ステージクリア・ゲームオーバー・全クリアは g:state の枠(draw)で出し、タップかAで進む
  • ステージは lib.lua の STAGES(形・速さの段・壊せない壁を3つの関数で組み合わせ、詰みを機械的に除く)。自動プレイ(右上の「自動」)はバッテリーの消費を測るときの放置プレイ用

共通するコツ

  • 画面ボタンの名前をコントローラーのボタン名にしておくと、g:down / g:pressed が画面とコントローラーを同じ形で読む(テトリスの操作ボタン)
  • スプライトの draw は w x h の外へはみ出させない。pico.fill_circle(x, y, r, c) は直径 2r+1 画素なので、半径4のボールなら枠は 9x9
  • 画面全体を描き直したいとき(状態の切り替え)は g:go() が行う。一部だけなら g:dirty(x, y, w, h)