Sky Invaders|育成型シューティングゲーム 開発記録
ゲーム紹介
Sky Invaders は、敵を倒して獲得したコインで自機を強化しながら進んでいく 育成型縦スクロールシューティングゲーム です。
全12ステージを収録しており、初心者から上級者まで幅広いプレイヤーが楽しめるよう設計しました。
パワーアップショップで自機を育てながら、難易度が上がっていくステージに挑戦してください!
🎮 プレイURL:https://unityroom.com/games/ysrpw_3027035
プレイ時間
全ステージクリアまで約1〜2時間(強化状況・プレイスキルによる)
開発背景・きっかけ
プログラミングのオンラインスクールでの学習で簡単なシューティングゲームを作成しました。
そのゲームをベースに「もっと面白くしたい・クオリティを上げたい」という思いから、11ヶ月をかけて本作を開発しました。
制作の目的
- シューティングゲームの基本要素にとどまらず育成システム・UI演出・サウンドを統合した完成度の高い作品を制作すること
- Wave制・非同期処理・シングルトンなどの実践的な技術を習得すること
- 誰でも楽しめるUX設計を意識し、初心者でも迷わずプレイできる作品を目指すこと
コンセプト
キャッチコピー
「誰でも楽しめる・育てる・勝つ。すべてが揃った縦スクロールシューティング」
3つのコアバリュー
| コアバリュー | 内容 |
|---|---|
| 誰でも楽しめる | 直感的なUI設計・ガイドテキストでシューティング初心者でも迷わずプレイできる |
| 育てる楽しさ | 敵を倒して獲得したコインで自機を強化する育成システムがモチベーションを維持する |
| 見た目のこだわり | 3D自機・アニメーション演出・UIデザインにこだわりプレイするたびに気持ちいい体験を提供する |
使用技術
| 技術 | 用途 |
|---|---|
| Unity 6.0 (6000.0.49f1) | ゲームエンジン |
| C# | スクリプト全般 |
| DOTween | UIアニメーション・演出全般 |
| UniTask | 非同期処理(敵のスポーン・Wave管理) |
| Waveシステム | ステージごとの敵出現管理 |
| キャンセルトークン | 非同期処理の安全なキャンセル |
| シングルトンパターン | サウンド管理・データ管理の一元化 |
| TextMeshPro | UI文字・スプライト埋め込み |
| ScriptableObject | ステージデータの管理 |
| PlayerPrefs | セーブ・ロード機能 |
こだわったポイント
🏠 タイトル画面
パワーアップショップ
タイトル画面からアクセスできるパワーアップショップを実装しました。
- 誰でも直感的にわかりやすいUIボタンを設計・配置
- ボタンを押すと下からひょっこりと出てくるアニメーションを実装(DOTween OutCubic)
- 閉じるボタンを押すと下に戻るアニメーション(DOTween InCubic)
- パワーアップ時に強化された実感が伝わるSEを選定・実装
ガイドテキスト
プレイヤーが迷わないようにガイドテキストを実装しました。
- パワーアップショップはステージ3クリアまで開放されない仕様(パワーバランス調整のための意図的な設計)
- ショップ未開放時:開放条件をガイドテキストで案内
- ショップ開放後:各強化項目の説明テキストを表示
- 全ステージクリア後:プレイヤーへの称賛メッセージを3種類ランダムで表示
3D自機アニメーション
タイトル画面の自機を3Dモデルで作成しDOTweenで軌道アニメーションを実装しました。
- 奥へ進んで弧を描きながら戻ってくる軌道をCatmullRomパスで実装
- UIと3Dモデルを共存させるためカメラのRender ModeをScreen Space - Cameraに設定
🗺️ ステージ選択画面
ステージボタン押下後のポップアップ
ステージボタンを押した際にそのままステージに遷移するのではなく、スコアに対するコイン報酬を事前に確認できるポップアップを実装しました。
- TextMeshProのSpriteAsset機能を活用してコイン画像をテキスト内に埋め込み
- 獲得済みの星は黄色・未獲得は黒で表示
ステージクリア後の演出
ステージクリア後に以下の3つの演出を連続して実装しました。
① 星の獲得アニメーション
獲得した星を1つずつ順番に光らせるアニメーションを実装しました。
② コイン飛翔アニメーション
獲得コインがステージボタンからトータルコイン表示へ吸い寄せられるように飛んでいき、ジャラジャラと増えるカウントアップ演出を実装しました。
③ 鍵が開くアニメーション
ステージ解放時に鍵が揺れながら開く演出を実装しました。
⚔️ 各ステージ画面
背景の多重スクロール
背景を3層構造にしそれぞれ異なる速度でスクロールさせることでプレイヤーが前進しているような臨場感を演出しました。
スコア表示演出
- 敵を倒した際に獲得スコアがひょっこりと上に表示
- トータルスコアは獲得スコアを50分割してキューに入れることでジャラジャラと増えていく演出を実装
インゲームメニュー
戦闘中に別のステージへ戻りたい場合やパワーアップし忘れた場合に対応するためメニューボタンを各ステージに配置しました。
- メニューボタン押下でTime.timeScale = 0によりゲームを一時停止
- ステージ選択へ戻るボタンには誤操作防止のための確認ポップアップを実装
👾 敵の実装
4種類の敵を実装しScriptableObjectとWaveシステムで管理しました。
| 種類 | 特徴 |
|---|---|
| 突進型(EnemyA) | まっすぐ突進してくる敵 |
| 射撃型(EnemyB) | ゆっくり進みながら弾を発射する敵 |
| 連射型(EnemyC) | 左右に移動しながら3発連続で弾を発射する敵 |
| ボス(EnemyBoss) | 左右に移動しながら弾を発射し体力減少でパワーアップする敵 |
苦労した点と解決策
1. 非同期処理とシーン遷移の競合(幽霊プログラム問題)
課題
ステージクリア時にシーンを切り替えても裏で動いていた敵のスポーン処理(UniTask)が止まらず次のシーンのオブジェクトを操作しようとしてMissingReferenceExceptionが発生しました。
解決策
CancellationTokenを自身で管理しオブジェクト破棄時(OnDestroy)に全ての非同期タスクを確実にキャンセルする仕組みを構築しました。
void OnDestroy()
{
if (cancelToken != null)
{
cancelToken.Cancel();
cancelToken.Dispose();
}
}
学び
「プログラムが動いている時間」と「オブジェクトが存在している時間」のズレを意識した設計の重要性を学びました。
2. メモリ管理と無限ループの回避
課題
スコアを細かく刻んで加算する演出中、計算式の不備(割り切れない数値の扱い)によって無限ループが発生しOutOfMemoryExceptionが発生しました。
解決策
ループによる加算処理を廃止しDOTweenを用いた数値の補間(Toメソッド)に切り替えることでパフォーマンスの劇的な向上と安全性を両立させました。
3. 2.5D的な視覚演出(3Dモデルの導入)
課題
2Dスプライトでは旋回演出時に「ペラペラ感」が出てしまい安っぽく見えてしまう問題がありました。
解決策
自機をOBJ形式の3Dモデルへ置換しました。UIと3Dモデルを同じ画面に映すためにカメラのRender ModeをScreen Space - Cameraに設定しUIの奥行き(Z軸)と3Dモデルの配置をミリ単位で調整しました。
4. 育成システムとセーブデータの連動
課題
ショップで強化したステータスを全12ステージで一貫して反映させる仕組みの構築と、ステージ開始直後にDataManagerがまだ準備できていないタイミングでUIがアクセスしようとする実行順序の問題が発生しました。
解決策
DataManager(シングルトン)を構築しPlayerPrefsを用いてデータの永続化を実現しました。またScript Execution Orderで初期化の優先順位を設定することで解決しました。
public class DataManager : MonoBehaviour
{
public static DataManager instance;
void Awake()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
}
5. UXを高める演出のシーケンス制御
課題
ステージクリア後に「星が出る」→「コインが飛ぶ」→「数字が増える」→「鍵が開く」という連続した演出をユーザーが目で追える速度で実行させることが困難でした。
解決策
UniTask.Delayを駆使し各演出が完了するのを待ってから次の処理へバトンタッチするシーケンス制御を実装しました。
学び
0.1秒単位のウェイトがプレイヤーの「心地よさ」に直結することを実感しました。
6. シーン開始時の即時クリア・ゲームオーバーバグ
課題
シーン開始時に「敵がまだ0体」であることをプログラムが「全滅させた」と勘違いしステージに入った瞬間にリザルト画面に引き戻されるバグが発生しました。
解決策
シーン開始直後の数秒間を「無効時間(セーフティタイマー)」として定義しWaveシステムが完全に起動するまで判定を行わないガードロジックを実装しました。
7. 親子関係とライフサイクル管理
課題
プレイヤーが破壊された際、追従しているオプション機が親を失って画面外へ流れていったり消えない問題が発生しました。
解決策
OnDestroyメソッドを正しく理解し親が消える瞬間に子要素も道連れにする処理と子要素が親の不在を検知して自律的に消えるロジックを追加しました。
ソースコード・企画書
GitHubリポジトリ
主要なスクリプト・仕様書・企画書はGitHubで公開しています。
企画書
ゲームの企画・設計の詳細は以下の企画書にまとめています。
実際に遊べるリンク
🎮 https://unityroom.com/games/ysrpw_3027035
ぜひプレイしてみてください!フィードバックもお待ちしています。





