Created: 2025/01/07
本記事は、Unity初心者が「片隅アイロニー」というゲームを作り上げるまでの過程を記したドキュメンタリーです。
今回は企画が生まれてからタイトルシーンができるまでを記事にしました。
筆者がUnity6で作っている、
です。
ようは、
ちっちゃい画面サイズで、作業中にアイロニーというキャラクターを育てて
ストーリーを進める2Dゲームですね。
作業に最適化されたゲームメカニズムと、PCゲームの特性を活かしたストーリーがウリです。
もっと詳しく知りたい方は企画書をご覧ください。
https://drive.google.com/file/d/1Hj4OS8XJ9xzO1r0hk3mcNwvKAsXpaQr-/view?usp=drive_link
「片隅アイロニー」が生まれたのは2024年7月中旬の木曜日、電子情報工学概論の講義を受けているときのことです。
インターネットのあれこれをぼけーっと学びながら、わたしは思いました。
ねむい。
せめて何か、パソコンのすみっこで面白映像とかながれていればなぁ…と。
ひらめきました。パソコンの片隅で遊べるゲームを。
作業中にプレイして、退屈を紛らわせることに特化したゲームを。
その後、「片隅」から連想するキーワードを考えていたら、おぼろげながらアイロニーという言葉が浮かんできたんです。
このとき私は言葉の意味を知りません。語感だけで思いつきました。
検索するとアイロニー=皮肉とのこと。
皮肉…片隅…作業中にプレイ…
最初はゲーム画面を小さくして、作業中にプレイをしやすくしよう!
ゲームが進むごとに画面を大きくして、最終的にフルスクリーンにしよう!
ああ、これは皮肉!やればやるほど作業の邪魔になっていく!
となると、キャラクター育成ゲームがふさわしい!キャラの成長につれて画面サイズもデカくしよう!
操作もほとんどないから作業中プレイに適している!
こうして、ながら育成ストーリーゲーム、「片隅アイロニー」が生まれました。
最初はプログラマー志望の子にコードを任せ、PythonのPygameで作ろうとしていましたが一向に進まず。
2024年11月になり、ちょうどUnity6がリリースされたので思い切って切り替え、
Unity6000.0.26f1で本格的に開発を始めました。
このあたりで件のプログラマーと完全に決裂し、一人で進めるように。
今考えても…この縁切りは賢明な判断だと思います。
ちなみになぜUnity6なのかというと、ゲーム起動時のスプレッド画像を変えられるから。
それだけです。新機能はまったく活用してません。
さて、Unityでゲームを作ってみようとやる気になったものの、ツクールとティラノスクリプトしか使ったことがないので
なにをやればいいのかさっぱり分かりません。C言語も分かりません。
なのでChatGPTに聞いてみました。
以下、やり取りを全部テキストにしてるのでめっちゃ長いです。
Q:
unity6で2Dのゲームを制作します。ゲームを起動したらウィンドウモード、画面サイズ480*360ピクセルのtitle_sceneを開き、そのシーン内にはクリックできる162*48ピクセルのボタンを配置します。背景には3枚の差分がある480*360ピクセルの画像を切り替えてアニメーションさせます。ボタンを押したら画面全体を5フレームだけ480*360ピクセルの画像で覆うトランジションを挟んだのち、画面サイズを240*180ピクセルに変更してscene_1へ遷移します。 ここまでの流れを作るにはどのようにすればいいですか?1工程ずつ具体的に教えてください。
A:
Unity6(Unity 2021以降のバージョン)での具体的な手順を、順を追って説明します。
1: プロジェクトの作成
Unity Hubで新規プロジェクトを作成します。プロジェクトタイプは「2D」を選択し、プロジェクト名や保存場所を指定してプロジェクトを作成します。
2: ウィンドウモードと画面サイズの設定
Edit > Project Settingsを開き、Player設定に移動します。
「Resolution and Presentation」セクションで、デフォルトのスクリーンモードをウィンドウモードに変更します。
Default WidthとDefault Heightにそれぞれ「480」と「360」を設定し、ウィンドウサイズを固定します。
3: Title Sceneの作成
File > New Sceneから新しいシーンを作成し、保存時に「title_scene」と命名します。
4: 背景アニメーションの作成
必要な3枚の背景画像(480x360ピクセル)をAssetsフォルダにインポートします。
シーン内にImageコンポーネントを配置し、サイズを「480x360」に設定して、背景画像をスプライトとして適用します。
スクリプトを作成して、背景画像を3枚の画像で切り替えるアニメーションを設定します。
アニメーションをスクリプト内で一定間隔(例:0.5秒毎)でループするように設定します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using UnityEngine;
using UnityEngine.UI;
public class BackgroundAnimation : MonoBehaviour
{
public Sprite[] backgrounds;
public Image backgroundImage;
private int currentImageIndex = 0;
private float timer = 0;
public float interval = 0.5f;
void Update()
{
timer += Time.deltaTime;
if (timer >= interval)
{
timer = 0;
currentImageIndex = (currentImageIndex + 1) % backgrounds.Length;
backgroundImage.sprite = backgrounds[currentImageIndex];
}
}
}
・BackgroundAnimationスクリプトをCanvas内のImageオブジェクトにアタッチし、backgrounds配列にインポートした3枚の背景画像を設定します。
5: クリック可能なボタンの作成
UI > Buttonでボタンを追加し、サイズを「162x48」に設定します。
ボタンのテキストやデザインを必要に応じて変更します。
ボタンがクリックされた際にトランジションが始まるよう、次の手順で設定します。
6: トランジション用の画面覆い画像の設定
480x360ピクセルのトランジション用画像をAssetsフォルダにインポートします。
新たにImageコンポーネントをシーン内に配置し、トランジション用画像をスプライトとして設定します。
トランジションのImageオブジェクトは、初期状態で非表示(enabled = false)にしておきます。
7: トランジションとシーン遷移を管理するスクリプトの作成
ボタンクリック時に5フレームだけ画面を覆った後、画面サイズを変更してscene_1へ遷移するスクリプトを作成します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using System.Collections;
public class TransitionManager : MonoBehaviour
{
public Image transitionImage;
public Button startButton;
void Start()
{
startButton.onClick.AddListener(() => StartCoroutine(TransitionToScene1()));
}
IEnumerator TransitionToScene1()
{
// トランジションを5フレーム表示
transitionImage.enabled = true;
for (int i = 0; i < 5; i++)
{
yield return null;
}
transitionImage.enabled = false;
// 画面サイズ変更
Screen.SetResolution(240, 180, false);
// 次のシーンへ移動
SceneManager.LoadScene("scene_1");
}
}
・TransitionManagerスクリプトをCanvasの任意のオブジェクトにアタッチし、transitionImageフィールドにトランジション用のImageオブジェクト、startButtonフィールドにボタンオブジェクトを指定します。
8: Scene_1の作成
File > New Sceneで新しいシーンを作成し、「scene_1」として保存します。
必要なゲームオブジェクトや背景、キャラクターなどを配置し、scene_1を構築します。
9: テストとデバッグ
最後に、title_sceneからscene_1への遷移がスムーズに行われるかテストします。
うわぁすごい。よくわかりませんがめちゃくちゃ具体的に教えてくれました。
この後、初心者にもわかるように教えてくださいとお願いしたら
もっと丁寧に教えてくれました。
言うとおりにエディタやコードをいじってみますが、当然エラーが出ます。
しかしAI君はエラーの解決方法も丁寧に教えてくれました。
○○ができないエラーがおきました or エラーコードコピペ するだけで。
デバッグに関しては確実にシンギュラリティ起きてます。
なんどもやり取りを繰り返し、背景画像をアニメーションさせるBackgroundAnimation、タイトルシーンを制御するTitleSceneController、シーン遷移の演出を管理するTransitionManagerができました。
↓背景画像を切り替えまくってアニメーションさせています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using UnityEngine;
using UnityEngine.UI;
public class BackgroundAnimation : MonoBehaviour
{
public Sprite[] backgrounds; // ここに3枚の背景画像を登録
public Image backgroundImage;
private int currentImageIndex = 0;
private float timer = 0;
public float interval = 0.5f; // 背景が切り替わる間隔
void Update()
{
timer += Time.deltaTime;
if (timer >= interval)
{
timer = 0;
currentImageIndex = (currentImageIndex + 1) % backgrounds.Length;
backgroundImage.sprite = backgrounds[currentImageIndex];
}
}
}
↓ボタンを押したらセーブデータをロードして、TrantisionManagerを起動しています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class TitleSceneController : MonoBehaviour
{
public TransitionManager transitionManager; // TransitionManager を参照
private void Start()
{
Screen.SetResolution(480, 360, false);
}
public void LoadGame()
{
// トランジションを開始
if (transitionManager != null)
{
transitionManager.StartTransition(); // トランジションをスタート
}
// トランジションの終了後にシーンをロード
StartCoroutine(WaitForTransition());
}
private IEnumerator WaitForTransition()
{
// トランジションが終了するまで待機
yield return new WaitUntil(() => !transitionManager.IsTransitioning);
// ゲームデータをロード
LoadGameData();
// トランジションが終わったらシーンをロード
if (GameManager.Instance.SceneLevel > 0)
{
SceneManager.LoadScene("Scene" + GameManager.Instance.SceneLevel);
}
else
{
Debug.LogWarning("No valid save data found. Starting new game.");
}
}
private void LoadGameData()
{
// セーブデータをロード
SaveManager.Instance.LoadGame();
// ステータスがロードされたかを確認(Debug用)
Debug.Log($"Loaded Game Data: SceneLevel={GameManager.Instance.SceneLevel}, ScenarioLevel={GameManager.Instance.ScenarioLevel}, Exp={GameManager.Instance.Exp}, etc.");
}
}
↓暗転からの一瞬画像をチラ見させる演出を入れ、終わったらセーブデータの変数SceneLevelに応じてシーンを遷移させています。
(画面サイズ変更うんぬんは修正するかもしれない)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class TransitionManager : MonoBehaviour
{
public Image fadeImage; // 暗転用のImage(黒の背景画像)
public Image transitionImage; // トランジション用のImage
private bool isTransitioning = false;
// トランジション中かどうかを外部から確認できるプロパティ
public bool IsTransitioning => isTransitioning;
void Start()
{
// 初期設定
fadeImage.color = new Color(0, 0, 0, 0); // 完全に透明な黒
fadeImage.enabled = true; // fadeImageを有効化
transitionImage.enabled = false; // トランジション用の画像は最初は非表示
}
public GameObject buttonObject; // ボタンのGameObject
public void StartTransition()
{
if (!isTransitioning)
{
isTransitioning = true;
// ボタンを非表示にする
if (buttonObject != null)
{
buttonObject.SetActive(false); // ボタンを無効化
}
StartCoroutine(TransitionSequence());
}
}
private IEnumerator TransitionSequence()
{
// 1. 暗転処理(120フレーム)
for (int i = 0; i <= 120; i++)
{
float alpha = (float)i / 120f; // 0から1へ増加
fadeImage.color = new Color(0, 0, 0, alpha); // 徐々に黒に
yield return null; // 1フレーム待機
}
// 2. トランジション画像の表示(2フレーム)
transitionImage.enabled = true;
fadeImage.enabled = false; // 暗転用の画像を非表示に
yield return new WaitForSeconds(0.5f / 60f); // 2フレーム待機(約0.33秒)
// 3. シーン遷移の準備(画面サイズ変更を遅延)
string sceneName = "scene" + GameManager.Instance.SceneLevel;
SceneManager.LoadScene(sceneName);
// 4. シーンロード後に画面サイズを設定
StartCoroutine(WaitForSceneLoad(sceneName));
}
private IEnumerator WaitForSceneLoad(string sceneName)
{
// シーンが完全にロードされるまで待機
while (!SceneManager.GetSceneByName(sceneName).isLoaded)
{
yield return null;
}
// シーンがロードされた後に画面サイズ変更
switch (sceneName)
{
case "scene1":
Screen.SetResolution(240, 180, false);
break;
case "scene2":
Screen.SetResolution(240, 180, false);
break;
case "scene3":
Screen.SetResolution(320, 240, false);
break;
case "scene4":
Screen.SetResolution(400, 300, false);
break;
case "scene5":
Screen.SetResolution(480, 360, false);
break;
case "scene6":
Screen.SetResolution(480, 360, false);
break;
}
Debug.Log("Screen resolution set for " + sceneName);
}
}
そして出来たタイトルシーンが記事のトップ画像です。ちゃんと背景画像はアニメーションして、はじめるボタンを押すとScene1に遷移してくれます。
この3つのスクリプトを含むタイトルシーンの処理、なんと2日で出来ました。
ChatGPTのエンジニア力はすごいです。シンギュラリティを実感しましたね。
ときどき間違いを起こすので注意は必要ですが、使いこなせればとても便利な代物だと感じました。
今回の記事はここまでとさせていただきます。
次回があればScene1のはしりと、中ボスクラスのスクリプト、会話システムを司るConversationControllerのことを書きます。