ゲーム概要
- 元ネタ: 「農家はReplaceされました()」
- コードで農業を自動化するゲーム
- 本作はローグライク要素を追加して戦闘ゲーム化
- ジャンル: コード構築型ローグライク
- ノード(コード片)を並べて「RUN」し、敵と戦闘
- 戦闘→ショップ→報酬を繰り返して3周回ってボス戦後クリア
ゲームの流れ
- マップ選択: 左回り/右回りを選択
- コード構築: ノードを並べてプログラムを作成
- 戦闘実行: RUNボタンで実行、敵にダメージ
- 報酬獲得: 勝利後、ランダムアイテムを獲得
- ショップ: アイテムの交換・強化
- ボス戦: 3周回後に最終ボスと対決
なぜRubyを選んだのか?
1. カッコを使わない文法
n = 3
n.times do
atk()
end→ 一行一行をアイテムとして分割しやすい
2. 実在する言語の方が親しみやすい
- 完全な疑似言語よりも学習コストが低い
- プログラミング経験者にとって理解しやすい
技術スタック
フロントエンド
- Next.js 16 / React 19
- TypeScript (型安全性)
- Tailwind CSS 4 (スタイリング)
- Nanostores (状態管理)
バックエンド
- Drizzle ORM + Postgres (データ永続化)
- NextAuth (GitHub認証)
- Hono (APIルーティング)
トランスパイラの実装
Ruby風コード → JavaScript変換
export const itemDefinitions: Record<string, ItemDefinition> = {
'atk_call': {
label: 'atk()',
generateCode: () => 'await atk();',
executeAction: async (context) => {
const damage = context.player.atk;
context.updateEnemy({ hp: context.enemy.hp - damage });
await context.sleep(500);
},
},
// ...
};トランスパイラを自作した理由
処理ごとに演出を挟むため
- 演出制御:
await sleep(500)でアニメーションを挟める - ゲームロジック: ダメージ計算やログ出力を細かく制御
- バリデーション: 文法エラーを検出
実装: src/lib/transpiler.ts
Reactでゲームを作る難しさ
状態管理がひたすら増える...
- プレイヤーのHP、攻撃力、BP
- 敵のステータス
- アイテムリスト、コードノード
- マップ進行状況、周回数
- ショップの状態、ログ
- モーダルの表示/非表示
useRef、useState、useContext... 管理が大変!
Nanostoreについて
軽量なバンドルサイズのライブラリ
- バンドルサイズ: わずか 334 bytes (gzip)
- フレームワーク非依存: React, Vue, Svelte, Vanilla JS
- TypeScript完全対応
- シンプルなAPI:
atom,map,computed
