14 ポイント 投稿者 cybrshin 2026-01-04 | 9件のコメント | WhatsAppで共有

もともとは Claude Code と Cursor を使っていましたが、昨年退職してから11月以降は antigravity に乗り換え、毎日のようにちょっとしたWebサービスのトイプロジェクトを作っていました。そんな中、突然3日前(1/2)にタワーディフェンスゲームを作ってみたくなりました。
もともとWebフロントエンド開発者なので、アプリとして包むのは面倒で、デスクトップブラウザ環境でのみ動作するようにし、Canvasベースの挙動や画像ファイル制作は時間がかかりすぎそうだったので、絵文字を最大限活用しようというアイデアから始めました。

1日で終わらせるつもりでしたが、作っているうちに楽しくなって、あれこれ修正・追加していたら3日もかかってしまいました。

基本的な技術スタックは以下の通りです。

  • Frontend: Next.js 14+ (App Router), TypeScript, HTML5 Canvas
  • Backend: FastAPI, Python 3.9+, Pydantic
  • Database: Supabase (PostgreSQL)
  • Deployment: Vercel

いろいろ修正を重ね、最終的にゲームロジックは次のように決まりました。

1. タワー攻撃力

タワーはマージ(Merge)によってレベルが上がるたびに射程(Range)が10ずつ増加しますが、攻撃力効率は1.8倍に調整されています(バランス調整)。

  • 公式: Damage = floor(BaseDamage * (1.8 ^ (Level - 1)))
    • Lv 1: 10
    • Lv 2: 18
    • Lv 3: 32
    • Lv 4: 57

2. 敵の出現パターン(Wave Logic)

単調さをなくすため、さまざまなウェーブパターンが適用されます。

  • 通常ウェーブ(Horde Mix): 現在ティアの敵(70%)と前ティアの敵(30%)が混ざって出現します。
  • ボスウェーブ(Every 6th): ボスはその時代の最強の敵1体が出現し、周囲を取り巻きが護衛します。
    • ボスウェーブの敵数: Wave / 6(ウェーブ6で1体、ウェーブ12で2体...)

4. ゴールド報酬(Active)

敵を倒したりウェーブをクリアしたりするとゴールドを獲得します。

ps. モバイル環境はあまり考慮していません。タッチイベントは追加しましたが、FoldやPadではうまく動くものの、小さい画面についてはあまり考慮していません〜

ps. 改善点やバグはコメントで教えていただければ、時間があるときに随時反映します。

https://tower.dsp.ai.kr/

9件のコメント

 
wancomplete 2026-01-07

私も最近ゲームを作っていて https://verse8.io を使ってみたのですが、画像や2Dスプライトアニメーションまで直接作ってくれるので、アセット作業に時間を使わずゲームロジックにだけ集中できました。しかもプラットフォーム上でそのままデプロイまでできるので、別途ホスティングを気にする必要もなく本当に便利でした。

 
huiya 2026-01-06

面白いですね。絵文字が積極的に使われているのがとても新鮮に感じます。
私がタワーディフェンスゲームをあまりやったことがないので、これが的外れな意見かもしれませんが、ウェーブ時間と準備時間が分かれていないため、ウェーブが来ている最中でもタワーの位置を変えられるようになっているのが違和感があります。
極端に言えば、位置をずっと変え続けながら常に攻撃できてしまうので、射程が無意味に感じられます。

 
cybrshin 2026-01-06

楽しんでいただけてありがとうございます。
私も作りながら、位置を移動できるのは違和感があると感じていたのですが、それがこのゲームの長所であり、動的でコントロールできる要素にもなり得ると思えたので、そのままにしておきました。
実際、早く移動させようとすると、タワーをマージしないと本当に大変なんです。
移動に対するペナルティを追加で設けるかどうかなど、ゲームバランスは今後も考え続けるポイントだと思います。

 
huiya 2026-01-07

あっ、すでにすべてご考慮されていたんですね。私の考えが浅かったです。

 
cybrshin 2026-01-07

いいえ。ご意見ありがとうございます。

 
waylake 2026-01-04

こんにちは、楽しくプレイしました。セキュリティ関連のフィードバックをお送りします。

  • 現在、HMACシークレット(署名用キー)がフロントエンドに露出しています
    • フロント側から goldwavelivestowers を直接変更できます

Vercel と Supabase の料金プランの問題につながる可能性があるため、お知らせします。

const state = {  
  towers: [],    
  gold: 9999,  
  wave: 1,       
  lives: 1       
};  
  
const state_raw = JSON.stringify(state);  
const user_id = "11111";  
const secret = "11111";  
  
(async () => {  
  const key = await crypto.subtle.importKey(  
    "raw",  
    new TextEncoder().encode(secret),  
    { name: "HMAC", hash: "SHA-256" },  
    false,  
    ["sign"]  
  );  
  const signatureBuffer = await crypto.subtle.sign(  
    "HMAC",  
    key,  
    new TextEncoder().encode(state_raw)  
  );  
  const signature = Array.from(new Uint8Array(signatureBuffer))  
    .map(b => b.toString(16).padStart(2, "0")).join("");  
    
  fetch("https://tower.dsp.ai.kr/api/sync";, {  
    method: "POST",  
    headers: {  
      "Content-Type": "application/json",  
      "Accept": "*/*"  
    },  
    body: JSON.stringify({  
      user_id,  
      state_raw,  
      signature  
    })  
  })  
  .then(res => res.text())  
  .then(console.log)  
  .catch(console.error);  
})();  
  
 
cybrshin 2026-01-04

あっ、ありがとうございます〜

 
roxie 2026-02-27

いや、ありえないんだけど……700ウェーブですって…………???

 
cybrshin 2026-02-28

可能です(笑)