ChatGPTの指示通りUnityゲームを作ってみる
最近ではChatGPTを始め様々な大規模言語モデルの対話型AIが公開されていますね。
そこで今回はChatGPTの指示に従ってゲームを作ってみる実験をしてみます。
ChatGPTに最初に伝えているのは以下の通りです。
そしたら次のステップを示してください。
画像等の素材は基本使いません
必要となった場合「**何々の画像をいくつ用意してください**」と言った指示をしてください
Unityのゲームの場合、ゲームオブジェクトの配置場所(position)やスケールなども指示してください
コンポーネントのパラメータなども必要に応じて「何々のパラメータを◎◎にしてください」と言った具体的な指示もしてください
果たしてAIといっしょにどんなゲームが作れるのか。
興味津々です。
開始のプロンプトを実行
早速やってみます。
まず以下のプロンプトを入力しました。
ではUnityで簡単なゲームを作るのでお願いします。
どんなゲームにするのかもすべてあなたが考えて指示を出してください。
唯一プロジェクト名だけは英語でお願いします。
了解しました。Unityで簡単なゲームを一緒に作っていきましょう。まず、ゲームのコンセプトを考えます。プロジェクト名は英語で設定しますが、ゲームの内容は以下の通りです:
ゲームのタイトル: “Maze Runner”
ジャンル: パズル / アドベンチャー
ゲームの目的: プレイヤーは複雑な迷路を探索し、制限時間内に出口を見つける必要があります。
操作方法: キーボードまたはマウスでプレイヤーを操作します。
特徴: レベルごとに迷路の複雑さが増していきます。プレイヤーは特定のアイテムを集めながら、迷路を解き明かす必要があります。
Unityを開き、「New Project」を選択します。
プロジェクト名を「Maze Runner」と入力します。
プロジェクトのテンプレートは「3D」を選択します。
プロジェクトの作成場所を選択し、「Create」をクリックします。
これで初期セットアップが完了しました。「次お願いします」とお伝えください、次に進むための指示をお出しします。
Maze Runnerですか。
全世界で1000万本ダウンロード間違いなし。
面白すぎて鼻血を出して卒倒しそうなゲームタイトルですね。
さすがChatGPTです。最先端だわー
とりあえず言われたとおりにプロジェクトを作りました。
これからChatGPTと僕の二人の共同制作が始まります。
シーンの構築
プロジェクトが出来ましたので次の指示をChatGPTに出してもらいました。
次は、迷路の基本的なゲームオブジェクトを作成し、シーンを構築していきます。
「Hierarchy」ウィンドウで右クリックし、「3D Object」->「Plane」を選択して、地面を作成します。Positionを(0, 0, 0)、Scaleを(10, 1, 10)に設定します。
再び「Hierarchy」ウィンドウで右クリックし、「3D Object」->「Cube」を選択して壁を作成します。このCubeを使って迷路の壁を構築します。PositionとScaleは壁のサイズや位置に応じて調整してください。
Cubeを複製(Ctrl + D)して、迷路の形を作ります。複数のCubeを組み合わせて迷路の道と壁を形成します。
「Hierarchy」ウィンドウで右クリックし、「3D Object」->「Sphere」を選択して、プレイヤーを表す球を作成します。Positionを迷路のスタート位置に合わせ、Scaleは(1, 1, 1)に設定します。
Sphereに「Rigidbody」コンポーネントを追加します。これにより、物理演算がSphereに適用されます。
「Main Camera」の位置と向きを調整して、迷路全体が見えるように設定します。カメラを斜め上から迷路を見下ろすような位置がおすすめです。
これで基本的なシーン構築は完了しました。ゲームオブジェクトが配置され、プレイヤーと迷路が設定されました。次に、プレイヤーを動かすためのスクリプトを作成し、ゲームの基本的な動作を実装します。「次お願いします」と伝えていただければ、次のステップに進みます。
更に詳しく聞く
一度に色々言ってきました。
しかしCubeの大きさや色、またカメラの具体的な角度などもふわっとしていたのでここでツッコミを入れます。
次に進めません。なぜならあなたの指示が明確ではありません。
Cubeのサイズやポジション、色なども指示してください。カメラの向きなどもちゃんと指示してください。
一度にシーンの構築を説明するのでも良いですが、順番に区切っていってください。
了解しました。より具体的な指示で、ステップごとにシーン構築を進めていきます。
「Hierarchy」ウィンドウで右クリックし、「3D Object」->「Plane」を選択して地面を作成します。
Position: (0, 0, 0)
Scale: (10, 1, 10)
Color: デフォルトの灰色
壁用の「Cube」を作成します(「Hierarchy」で右クリック ->「3D Object」->「Cube」)。
最初の壁のPosition: (0, 0.5, 0)
Scale: (1, 1, 1)(これは壁1つの基本サイズです。迷路に応じてサイズは調整します)
Color: 任意の色を選択(例:灰色)
このCubeを複製して(Ctrl + D)、迷路の道と壁を形成します。各CubeのPositionとScaleは迷路の設計に応じて調整してください。
プレイヤーを表す「Sphere」を作成します(「Hierarchy」で右クリック ->「3D Object」->「Sphere」)。
Position: 迷路のスタート位置に合わせます(例: (2, 0.5, 2))
Scale: (1, 1, 1)
Color: 任意の色を選択(例:青色)
Sphereに「Rigidbody」コンポーネントを追加します。
「Main Camera」を選択し、カメラの位置と向きを調整します。
Position: 迷路を見下ろす形に設定します(例:(10, 20, 10))
Rotation: カメラを迷路中心に向けます(例:(45, -45, 0))
これで詳細なシーンの構築が完了しました。各オブジェクトの位置や色など、細かい指示を行いました。次にプレイヤーの動きを制御するスクリプトを作成し、ゲームの基本的なインタラクションを実装します。次のステップに進む準備ができたら、また教えてください。
マテリアルの作り方も聞く
多少良くなったのですが色の指定方法などの説明が抜け落ちているのでそこを指摘します。
まだだめです。色の設定の方法を説明していません。
失礼しました。Unityでゲームオブジェクトの色を設定する方法について具体的に説明します。
ゲームオブジェクトに色を適用するには、まずマテリアルを作成する必要があります。
「Project」タブで右クリックし、「Create」->「Material」を選択します。
新しく作成されたマテリアルに名前を付けます(例: WallMaterial, FloorMaterial, PlayerMaterial)。
マテリアルを選択した状態で、「Inspector」タブに表示される「Albedo」の色をクリックして、好みの色を選択します。
色を設定したマテリアルを、色を変更したいゲームオブジェクトにドラッグ&ドロップします。
壁用のマテリアル(WallMaterial)を作成し、「Albedo」で灰色を選択します。壁(Cube)を選択し、ProjectタブからWallMaterialを壁のInspectorウィンドウにあるマテリアルスロットにドラッグ&ドロップします。
同様の手順で、地面(Plane)やプレイヤー(Sphere)にもそれぞれ色を設定できます。例えば、地面は緑色、プレイヤーは青色に設定することができます。
これでゲームオブジェクトの色設定方法が明確になりました。次のステップに進む準備ができたら教えてください。
とりあえずMaterialをそれぞれ作ってオブジェクトにアタッチしました。
カメラのポジションについても聞く
その後MainCameraのポジションを先程の例に合わせて変更したところなにも映らなくなったので伝えてみます。
カメラの位置や角度が適切でないため、期待したシーンが映らなくなってしまったようですね。カメラの位置と角度を調整して、迷路がしっかりと画面に映るようにしましょう。
カメラの位置は、迷路全体が画面に収まるように調整する必要があります。まずはカメラを上に移動させ、迷路全体が映るようにします。
Position: (10, 30, 10) に変更してみましょう(迷路のサイズに応じてさらに調整が必要かもしれません)。
カメラの角度も迷路が中心に来るように調整します。カメラが迷路の中心を向くようにRotationを調整してください。
Rotation: (60, -45, 0) に変更してみましょう(こちらも迷路の配置に応じて微調整が必要です)。
カメラを調整した後は、Unityエディタの「Game」タブを見て、カメラビューが適切かどうか確認します。迷路全体がうまく映っているかをチェックしてください。
カメラの位置や角度は、迷路のサイズや形状によって最適な値が異なります。Gameビューを確認しながら、迷路全体が適切に映るように細かく調整してください。
これらのステップでカメラを調整し、迷路が正しく画面に映るように設定してください。設定が完了したら、シーンが期待通りに表示されているかを確認し、次のステップに進む準備が整います。何か他にも不明点があれば、遠慮なく質問してください。
ということで位置などに関しては自分で調整した方が良さそうだったので一旦真上から撮影するように調整しました。
この辺りは完全にChatGPTの指示通りにするよりかは柔軟に自分で調整した方が良さそうですね。
迷路の作り方についても聞く
これだけだと迷路は出来てませんのでそこも聞いてみましょう。
とりあえずカメラは配置しました。ただまだ迷路は作っていません。Cubeを作っただけです。
具体的な迷路の作り方をお願いします
迷路を作成するために、Cubeオブジェクトを使用して壁を形成する方法を詳しく説明します。
迷路は手作業で一つ一つ壁を配置する方法と、スクリプトを使用して自動生成する方法がありますが、ここでは初心者にもわかりやすい手作業による方法を紹介します。
まず、シーンにCubeを追加し、これを迷路の壁の一部とします。このCubeを複製して、迷路の道と壁を形成します。
CubeのScaleを調整して壁の厚さや高さを設定します。例えば、Scaleを(X: 1, Y: 2, Z: 1)にすると、通常の壁のサイズになります。
CubeのPositionを調整して、迷路内での正確な位置に設置します。迷路の設計に応じて、XとZの値を変更してください。
まず、迷路の外周を作成します。四方の壁を配置して、迷路の枠を作ります。
次に、内部の壁を配置していきます。迷路の道を決めながら、Cubeを複製し、移動させて壁を形成します。
迷路には入口と出口が必要です。適切な場所に入口と出口を設定してください。これは単に壁を一部設置しないことで作成できます。
迷路の道が狭すぎたり、通り抜けられない部分がないか確認します。
プレイヤーが迷路を解きやすいよう、適切な難易度に調整します。必要に応じて壁の位置を微調整してください。
迷路が完成したら、実際にプレイヤーオブジェクトを動かして、迷路を通過できるかテストプレイします。
入口から出口までのルートがしっかりと存在し、迷路として機能するか確認してください。
この手順を踏むことで、手作業による迷路の作成ができます。迷路のデザインは自由にアレンジ可能ですが、プレイヤーが楽しめるように、適度な難易度と変化に富んだ設計を心がけましょう。迷路の作成が完了したら、次のステップに進んでください。
最後の方にテストプレイって言われましたが、まだプレイヤーオブジェクトを動かすとか実装してないんですけどね。。
PlayerのPositionを手動で動かしてちゃんと通れるかどうかってことですかね?
とりあえずChatGPTの言う通りに手作業でCubeを配置していくことにしましょうか。
ちまちまとCubeを置いていきます。
さて迷路が出来ましたので、次のステップを聞いてみましょう。
プレイヤーを動かすスクリプト
いよいよプレイヤーを動かすスクリプトを準備してくれましたよ。
素晴らしいです!迷路が完成したので、次はプレイヤーが迷路内を移動できるようにするスクリプトを作成しましょう。
プレイヤーを操作する簡単なスクリプトをC#で作成して、Sphereオブジェクト(プレイヤー)にアタッチします。
Unityエディタで「Project」タブを開き、「Create」→「C# Script」を選択し、新しいスクリプトに「PlayerController」という名前を付けます。
作成したスクリプトをダブルクリックして、コードエディタ(例: Visual Studio)で開きます。
PlayerController スクリプトに以下のコードを追加します。これは簡単な移動制御のためのコードです。
※枠外に記述します。
このスクリプトは、キーボードの入力に応じてプレイヤー(Sphere)を移動させます。speed 変数で移動速度を調整できます。
Unityエディタに戻り、「Hierarchy」からプレイヤーを表すSphereオブジェクトを選択します。
「Inspector」パネルで「Add Component」ボタンをクリックし、作成した「PlayerController」スクリプトを検索してアタッチします。
Unityエディタで「Play」ボタンを押してゲームを実行し、キーボードの矢印キーまたはWASDキーでプレイヤーを操作し、迷路内を移動できるかテストします。
プレイヤーの操作性が確認できたら、ゲームの基本的な動作は完成です。次に、迷路のゴール設定やタイマーの追加、レベルデザインなど、ゲームにさらなる要素を追加していくことができます。どのように進めるか、または他に質問があればお知らせください。
以下がChatGPTの考えてくれたコードです。
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float speed = 5.0f;
void Update()
{
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);
transform.Translate(movement * speed * Time.deltaTime, Space.World);
}
}
では実際に動かしてみたいと思います。
ちゃんとPlayer(緑のやつ)は動いていますね。
壁も貫通しません。ただ壁に当たったとにバウンドしますね。
とりあえず動かせたので次のステップを聞いてみます。
ゴールの設定
続いてChatGPTはゴールを設定しようと提案してくれました。
プレイヤーは動きました。
次のステップをお願いします
プレイヤーが動いたとのことで、素晴らしい進捗です!次はゲームにゴールを設定し、プレイヤーがゴールに到達した際の処理を追加しましょう。
「Hierarchy」で右クリックし、「3D Object」->「Cube」を選択して、ゴールを表すオブジェクトを作成します。
ゴールオブジェクトにわかりやすい名前を付け、例えば「Goal」とします。
ゴールオブジェクトを迷路の出口に配置し、サイズや色を調整して目立たせます。
新しいC#スクリプトを作成し、「GoalController」という名前を付けます。
GoalController スクリプトを編集し、以下のように記述します。
※枠外に記述します。
このスクリプトは、プレイヤーがゴールに触れた時にメッセージを表示し、後にゲームの終了や次のレベルへの遷移の処理を追加するための基盤となります。
GoalController スクリプトをゴールオブジェクトにアタッチします。
プレイヤーオブジェクトを選択し、「Tag」を「Player」と設定します(新しいタグが必要な場合は、「Add Tag…」で追加してから設定)。
再びゲームを実行し、プレイヤーを操作してゴールに到達させます。コンソールウィンドウにメッセージが表示されることを確認します。
これでゲームにゴールが設定され、プレイヤーがゴールに到達した際の基本的な処理が実装されました。次に、ゲームのフィードバックを改善するためのUIの追加や、さらなるゲームプレイ要素の導入などを行うことができます。次のステップに進む準備ができたら、またお知らせください。
ChatGPTが考えてくれたGoalControllerはこちらです。
using UnityEngine;
public class GoalController : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
Debug.Log("Congratulations! You've reached the goal!");
// ここにゲーム終了または次のレベルへの遷移の処理を追加
}
}
}
ではChatGPTが言う通りゴールを設定していきましょう。
Playerのタグも言われた通り設定しました。
ChatGPTが言う通り設定したので実行してみましょう。
ゴールに接触してもログが出ませんね。
原因はわかっているのですが、ここはあえてChatGPTに聞いてみましょう。
ゴールのデバッグ
こんなふうに聞いてみました。
プレイヤーがゴールに接触してもログが出ません。
何が原因だとあなたはお考えですか?
するといくつかの可能性を示してくれましたね。
プレイヤーがゴールに接触してもログが出力されない問題は、いくつかの原因が考えられます。以下のチェックリストを参考に、問題の解決に役立ててください。
プレイヤーオブジェクトに「Player」タグが正しく設定されていることを確認してください。スクリプトは「Player」タグのオブジェクトとの接触を検出するようになっています。
プレイヤーとゴールオブジェクトの両方にコライダーが適切に設定されていることを確認してください。また、プレイヤーにはRigidbodyコンポーネントが追加されている必要があります。
ゴールオブジェクトのコライダーについて、Is Triggerオプションが有効になっているか確認してください。OnTriggerEnterメソッドは、Is Triggerが有効なコライダーでのみ機能します。
GoalControllerスクリプトにタイプミスやその他のエラーがないか再度確認してください。
Unityのコンソールウィンドウにエラーメッセージが表示されていないか確認してください。エラーがある場合は、それが原因でスクリプトが正しく実行されていない可能性があります。
スクリプト内でDebug.Logを使用して、ゴールに到達した際だけでなく、プレイヤーが特定のエリアに入った時にもログを出力するようにすることで、問題の切り分けができます。
これらのポイントを一つずつ確認していき、問題の原因を特定してください。それでも問題が解決しない場合は、さらに詳細な情報を元に調査が必要になるかもしれません。
この中に答えはありました。
そうです、ゴールにIs Triggerの設定がないためです。
嫌味っぽく聞いてみました。
あなたはIsTriggerを設定しろと先ほど私に伝えましたか?
申し訳ありません、その部分について明確に指示を出していませんでした。
ゴールオブジェクトのコライダーに対してIs Triggerオプションを有効にする必要があります。
これにより、プレイヤーがゴールオブジェクトに触れた際にイベントをトリガーできるようになります。
ちゃんと素直に謝ってくれました。
こちらこそ嫌味っぽく言ってごめんなさいという気持ちになりました。
ではちゃんとIs Triggerにチェックを入れてゴール時にログが出るか確認してみましょう。
無事にゴールしたらログが出ましたね!
では次のステップに進んでみましょう。
タイマーとスコアのUIを追加
次にChatGPTが提案してくれたのはタイマーとスコアでした。
素晴らしいです!プレイヤーがゴールに正常に到達できるようになったので、次にゲームにタイマーやスコア表示を追加して、プレイヤーにフィードバックを提供しましょう。
Unityの「Hierarchy」ビューで右クリックし、「UI」→「Canvas」を選択して新しいキャンバスを作成します。
同様にして「UI」→「Text」を選択し、Canvas内にテキストオブジェクトを作成します。このテキストはタイマー表示に使用します。
必要であれば、スコア表示用にもう一つテキストオブジェクトを追加します。
新しいC#スクリプトを作成し、「Timer」という名前を付けます。
Timerスクリプトを編集して、以下のようなタイマー機能を実装します。
※枠外にコードを記述します
Timerスクリプトを任意のゲームオブジェクトにアタッチします(例えば、新しく作成したCanvas)。
スクリプトのtimerTextフィールドに、タイマー表示用のテキストオブジェクトをドラッグ&ドロップして関連付けます。
ゴールに到達したときにタイマーを停止するように、GoalControllerスクリプトにタイマー停止のロジックを追加します。例えば、TimerコンポーネントのStopTimerメソッドを呼び出します。
これでゲームにタイマーが追加され、プレイヤーがゴールに到達するまでの時間を測定できるようになりました。プレイヤーにはゲームの進行状況が視覚的にフィードバックされるため、より没入感のあるゲーム体験が提供できます。次のステップに進む準備ができたら、またお知らせください。
だそうです。頼もしいですね。
ChatGPTが提案してくれたコードです。
using UnityEngine;
using UnityEngine.UI;
public class Timer : MonoBehaviour
{
public Text timerText;
private float startTime;
private bool isRunning = true;
void Start()
{
startTime = Time.time;
}
void Update()
{
if (isRunning)
{
float t = Time.time - startTime;
string minutes = ((int) t / 60).ToString();
string seconds = (t % 60).ToString("f2");
timerText.text = minutes + ":" + seconds;
}
}
public void StopTimer()
{
isRunning = false;
}
}
ふむふむ、では言われたとおりにやっていきましょう。
Textの位置や文字の大きさなどは特に指定なかったのでこちらで適当に調整することにします。
ただ一点、ゲームの終了時にタイマーを停止というところで具体的な指示がなかったのでそこはツッコんでみましょう。
タイマー停止スクリプト
ゲームの終了時にタイマーを停止と言いましたが、具体的なソースコードを示してませんよ。
失礼しました。ゴールに到達したときにタイマーを停止させる具体的な実装方法を示します。
ここでは、GoalController スクリプトにタイマーを停止させる処理を追加することで、プレイヤーがゴールに到達した際にタイマーが停止するようにします。
まず、Timerスクリプトに公開メソッドを追加してタイマーを停止できるようにし、その後GoalControllerスクリプトからそのメソッドを呼び出すことでタイマーを停止します。
Timer修正
using UnityEngine;
using UnityEngine.UI;
public class Timer : MonoBehaviour
{
public Text timerText;
private float startTime;
private bool isRunning = true;
void Start()
{
startTime = Time.time;
}
void Update()
{
if (isRunning)
{
float t = Time.time - startTime;
string minutes = ((int)t / 60).ToString();
string seconds = (t % 60).ToString("f2");
timerText.text = minutes + ":" + seconds;
}
}
// タイマーを停止するための公開メソッド
public void StopTimer()
{
isRunning = false;
}
}
GoalController 修正
GoalControllerスクリプト内でTimerスクリプトのStopTimerメソッドを呼び出してタイマーを停止させます。
これを行うには、まずTimerスクリプトがアタッチされているオブジェクトを参照する必要があります。
using UnityEngine;
public class GoalController : MonoBehaviour
{
public Timer timer; // Inspectorからアクセスできるように公開
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
Debug.Log("Congratulations! You've reached the goal!");
timer.StopTimer(); // タイマーを停止する
}
}
}
Unityエディタ内でGoalControllerスクリプトがアタッチされているオブジェクトのInspectorビューから、Timerフィールドにタイマー機能がアタッチされているオブジェクトをドラッグ&ドロップして設定します。
これで、プレイヤーがゴールに到達した際にタイマーが停止するようになります。
言われた通り直していきますよ。
それでは実際にプレイしてみましょう。
ゴールしたら無事にタイマーは止まってくれました。
スタート画面とゲームオーバー画面の追加
徐々にゲームらしくなってきましたね。
次の指示を仰ぎましょう。
出来ました。次のステップお願いします。
素晴らしいです!次のステップでは、ゲームにスタート画面とゲームオーバー画面を追加し、プレイヤーにより良い体験を提供します。
Canvas内に新しいテキストオブジェクトを作成し、「Game Title」などのゲーム名を表示します。
「Play」ボタンを作成します。ボタンは「UI」->「Button」で追加できます。このボタンをクリックするとゲームが開始されるように設定します。
ボタンのクリックイベントに反応してゲームを開始するスクリプトを作成し、ボタンにアタッチします。
※枠外のコードを記述します
ゲームオーバー画面も新しいCanvasとして作成し、ゲームオーバーのテキストとリトライボタンを含めます。
リトライボタンを押すと、ゲームが再スタートするようにします。これは上記のスタート画面のスクリプトを再利用するか、同様の機能を持つ新しいスクリプトを作成して実装できます。
ゲームのスタート画面が最初に表示され、プレイヤーが「Play」ボタンを押すとゲームシーンがロードされるようにします。
プレイヤーがゲームオーバーになった場合(例えば、タイマーがゼロになる、特定の条件を満たすなど)、ゲームオーバー画面に遷移します。
ゲームオーバー画面からは、リトライまたはメインメニューに戻るオプションをプレイヤーに提供します。
これらのステップにより、ゲームには明確な開始と終了のフローが設定され、プレイヤーはゲームを再開したり、新しい試行を開始したりすることが容易になります。
これらの画面は、ゲームのプロフェッショナルな見た目とフィーリングを強化する重要な要素です。次のステップに進む準備ができたらお知らせください。
using UnityEngine;
using UnityEngine.SceneManagement;
public class StartGame : MonoBehaviour
{
public void LoadGame()
{
SceneManager.LoadScene("GameScene"); // ゲームシーンをロード
}
}
ふむふむ。では言われた通りに作ってみましょう。
と思ったのですが、シーンに関しては特に何も言われてなかったのでこんな質問をします。
スタート画面とゲーム画面を追加するとのことですが、それはそれぞれのシーンを追加するということですか?
またゲームのシーン名は「GameScene」と指定されていませんでしたが、それに変更すればいいですか?
はい、スタート画面とゲームオーバー画面を追加する場合、それぞれ異なるシーンを作成すると管理がしやすくなります。
Unityでは、ゲームの各部分(例えば、メインメニュー、ゲーム本編、ゲームオーバー画面)を別々のシーンとして扱うことで、ゲームの構造を明確にし、各部分を個別に編集できるようになります。
Unityエディタの上部メニューから「File」->「New Scene」を選択し、新しいシーンを作成します。
この新しいシーンにスタート画面のUI要素(ゲームタイトル、プレイボタンなど)を追加します。
シーンを「StartScene」として保存します。
既に作成しているゲームのシーンがある場合、そのシーン名が「GameScene」でないなら、シーン名を変更するか、コード内のシーン名を既存のものに合わせます。
シーンを開き、「File」->「Save As」を選択して「GameScene」として保存するか、またはスクリプト内のシーン名を既存のシーン名に変更します。
ゲームオーバー画面のシーン作成:
同様に、ゲームオーバー画面用の新しいシーンを作成し、「GameOverScene」として保存することも考えられます。
スタート画面からゲーム画面への遷移は、プレイボタンにアタッチされたスクリプトでSceneManager.LoadScene(“GameScene”)を呼び出すことで実現します。
ゲームオーバー時の遷移も同様に、条件を満たした時点でSceneManager.LoadScene(“GameOverScene”)などを呼び出します。
シーン名やシーン構成はプロジェクトによって変わるため、既存の構成に合わせて適宜調整してください。シーン間の遷移やシーンの構成を適切に管理することで、ゲームのフローがスムーズになり、プレイヤー体験が向上します。次のステップに進む準備が整いましたら、またお知らせください。
今回はシーンの説明漏れの事は謝ってきませんでした(ちっ)。
しかしChatGPTの回答にはスルーできない落ち度がありましたのでツッコミを入れておきます。
シーンを登録する
あなたはシーンの登録に関して一つ重要な事を忘れていませんか?
はい、おっしゃる通りです。
シーンをプロジェクトに追加して使用するためには、シーンをビルド設定に登録する必要があります。
これを行わないと、SceneManager.LoadScene を使用しても、シーン間の遷移がうまく機能しません。
この重要なステップを追加しましょう。
Unityエディタで「File」->「Build Settings…」を開きます。
開いたウィンドウ内で、「Scenes In Build」セクションがあります。ここにゲーム内で使用する全てのシーン(スタート画面、ゲーム本編、ゲームオーバー画面など)を追加する必要があります。
「Add Open Scenes」をクリックして、現在開いているシーンをリストに追加します。他のシーンも同様に、一つずつ開いて「Add Open Scenes」をクリックすることでリストに追加できます。
ビルド設定内でシーンの順番を変更することができます。シーンはリスト内で上から順に0から始まるインデックスが割り当てられます。通常、スタート画面が最初に来るように設定します。
すべてのシーンを追加し、順番を設定したら、「Build Settings」ウィンドウを閉じます。これで設定はプロジェクトに保存されます。
これで、ゲーム内のシーンがすべてビルド設定に登録され、シーン間の遷移が正しく機能するようになります。これはゲーム開発において非常に重要なステップなので、忘れずに行うようにしてください。次のステップへ進む準備が整いましたら、またお知らせください。
非常に重要なステップと言いながらお前が忘れてるだろ。と思いつつ、ちゃんとシーンを登録しておきます。
さてそれではスタートシーンからゲームを始めてみましょう!
無事にゲームは始まりました!
何の説明もなく唐突に始まるところがいい感じです。さすがMaze Runner。
ゲームオーバーの処理
ではゲームオーバーの処理に関して具体的に聞いてみましょう。
スタートの実装はできました。次はゲームオーバーです。
どうなればゲームオーバーになるか考えてください
素晴らしい進捗です!ゲームオーバーの条件はゲームのジャンルや目的によって異なりますが、「Maze Runner」という迷路ゲームにおいては、以下のような条件をゲームオーバーのトリガーとすることが考えられます。
プレイヤーが迷路を解くために与えられた時間が尽きた場合。
タイマーがゼロに達した時点でゲームオーバーとします。
迷路内に危険な障害物や敵キャラクターを配置し、これらにプレイヤーが接触した場合にゲームオーバーにします。
例えば、迷路内に設置されたパズルや特定のアイテムを集める必要があり、それが完了できなかった場合にゲームオーバーとする。
Timerスクリプト内でタイマーがゼロになった時にゲームオーバーのロジックを実行します。
例えば、ゲームオーバーシーンへ遷移する、ゲームオーバーUIを表示するなどです。
障害物や敵にColliderとRigidbody(もしくはRigidbody2D)を設定し、プレイヤーと接触した際にゲームオーバーの処理を行います。
これらの実装を通じて、プレイヤーに緊張感を持続させ、ゲームの挑戦性を高めることができます。ゲームオーバーの条件とそのロジックを実装し、テストしてみてください。次のステップに進む準備ができたらお知らせください。
ゲームオーバーの条件は僕に委ねられました。
タイムアウトの実装
ではタイマーと敵とか壁にぶつかったらゲームオーバーにしましょう。
タイマーの方から実装していきたいです
承知しました。タイマーがゼロに達した場合にゲームオーバーとなる機能を実装しましょう。まずは、Timerスクリプトを修正して、タイマーが0になったときにゲームオーバーシーンに遷移するようにします。
以下のコードはTimerスクリプトに追加または修正する部分です。タイマーが0以下になったときにゲームオーバーシーンをロードする処理をUpdateメソッド内に追加します。
※枠外にコードを記述します。
このスクリプトは、タイマーが0以下になった瞬間にゲームオーバーシーンに遷移します。timeLimitはインスペクタから調整可能で、ゲームの難易度に応じて設定できます。
ゲームオーバーシーンは予め作成し、ビルド設定に追加しておく必要があります。シーン名はプロジェクトに合わせて”GameOverScene”を適切なものに変更してください。
次に、プレイヤーが敵や壁にぶつかった場合のゲームオーバー処理を実装します。準備ができたら教えてください。
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement; // シーン管理を使用するために必要
public class Timer : MonoBehaviour
{
public Text timerText;
private float startTime;
private bool isRunning = true;
public float timeLimit = 60; // タイマーの制限時間を設定
void Start()
{
startTime = Time.time;
}
void Update()
{
if (isRunning)
{
float timeLeft = timeLimit - (Time.time - startTime);
if (timeLeft <= 0)
{
isRunning = false;
timeLeft = 0;
SceneManager.LoadScene("GameOverScene"); // タイマーが0になったらゲームオーバーシーンをロード
}
string minutes = ((int)timeLeft / 60).ToString();
string seconds = (timeLeft % 60).ToString("f2");
timerText.text = minutes + ":" + seconds;
}
}
public void StopTimer()
{
isRunning = false;
}
では実際に動かしてみます。ちょっと60秒は長いので2秒にしときましょう。
GameOverシーンはまだ何も作っていないのですが、ちゃんとシーン遷移しています。
接触によるゲームオーバー
いよいよChatGPTと僕の共同制作「Maze Runner」の完成が見えてきました。
タイムアウトの処理は出来ました。次は敵とか壁にぶつかったらゲームオーバーにしたいです。
プレイヤーが敵や壁にぶつかった際にゲームオーバーとなる処理を実装しましょう。
この処理はプレイヤーのオブジェクトにアタッチされる新しいスクリプト、または既存のプレイヤー制御スクリプトに追加することで実現できます。
プレイヤーに新しいスクリプトを作成し、PlayerCollisionという名前を付けます(または既存のプレイヤー制御スクリプトに追加します)。
以下のコードをPlayerCollisionスクリプトに追加します。
このコードはプレイヤーが特定のタグ(例えば"Enemy"や"Obstacle")を持つオブジェクトに触れた時にゲームオーバーシーンに遷移させます。
※枠外にコードを記述します。
敵と壁(障害物)に"Enemy"や"Obstacle"のタグを設定します。
Unityエディタで敵や壁のオブジェクトを選択し、Inspectorビューの「Tag」ドロップダウンから新しいタグを追加し、適用します。
PlayerCollisionスクリプトをプレイヤーオブジェクトにアタッチします。
これで、プレイヤーが敵や壁にぶつかった時にゲームオーバーシーンに遷移する処理が追加されました。
ゲーム内で適切にタグが設定されていることを確認し、テストプレイを行って動作を確認してください。次のステップに進む準備ができたらお知らせください。
using UnityEngine;
using UnityEngine.SceneManagement;
public class PlayerCollision : MonoBehaviour
{
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Enemy") || collision.gameObject.CompareTag("Obstacle"))
{
SceneManager.LoadScene("GameOverScene"); // ゲームオーバーシーンに遷移
}
}
}
言われた通りPlayerContorllerを修正し、壁にタグを付けて実験してみます。
敵はまだいませんがEnemyというタグも作っておきましょう。エラーになっちゃうので。
では実行してみます。
壁に当たると即死です。Maze Runner恐るべしと言ったところでしょうか。
敵を作る
今度は敵キャラを作ってもらいます。
壁に触れたらゲームオーバーになりました。
しかしまだ敵がいません。
敵を作ってください
キャラクターを追加することでゲームにさらなる挑戦とバリエーションを加えることができます。
簡単な敵キャラクターを作成し、プレイヤーが接触するとゲームオーバーになるように設定しましょう。
Unityエディタの「Hierarchy」ビューで右クリックし、「3D Object」->「Sphere」を選択して敵のオブジェクトを作成します。
Sphereを使って簡単な敵キャラクターを作りますが、任意の3Dモデルを使用しても構いません。
敵オブジェクトにわかりやすい名前を付けます(例: "Enemy")。
敵オブジェクトを選択し、「Tag」ドロップダウンメニューから「Add Tag...」を選択し、新しいタグを作成します(例: "Enemy")。
再度敵オブジェクトを選択し、新しく作成した「Enemy」タグを適用します。
敵に簡単な動きを追加するために、新しいC#スクリプト(例: "EnemyMovement")を作成し、次のような簡単な動きを実装できます。
※枠外にコードを記述します
このスクリプトは敵を一定方向に動かします。必要に応じて、動きをカスタマイズしてください。
作成した「EnemyMovement」スクリプトを敵オブジェクトにアタッチします。
敵オブジェクトにRigidbodyコンポーネントを追加します(衝突検出のため)。Use Gravityをオフにし、必要に応じて他の設定を調整します。
これで敵キャラクターの基本的な設定が完了しました。ゲーム内で敵とプレイヤーが接触した際にゲームオーバーになるように、既に設定した衝突検出のロジックが機能するはずです。ゲームを実行して敵の動作と衝突時の挙動をテストしてください。次のステップに進む準備が整いましたら、またお知らせください。
using UnityEngine;
public class EnemyMovement : MonoBehaviour
{
public float speed = 5.0f;
public Vector3 moveDirection = new Vector3(0, 0, 1);
void Update()
{
transform.position += moveDirection * speed * Time.deltaTime;
}
}
では敵キャラをガシガシ作っていきます。
とりあえず6体敵を作りました。
一直線に進む恐ろしい敵です。
実行するとこんな感じ。
Maze Runnerを行く手を阻止してきますが、ちょっと動きもほしいですよね。
敵キャラの動きを考えさせる
敵キャラは無事に出来ましたが一直線にしか動きません。
動きにバリエーションを付けてください。
敵キャラクターの動きにバリエーションをつけることで、ゲームの難易度と面白さを向上させることができます。
ここでは、敵キャラクターがランダムな方向に動くようにスクリプトを改良しましょう。
また、一定の時間ごとに方向転換する機能を追加します。
以下のEnemyMovementスクリプトを修正または置き換えて、敵がランダムな方向に動くようにします。
また、一定のインターバルで方向を変更する機能を追加します。
※枠外にコードを記述します
このスクリプトでは、ChangeDirectionメソッドが一定の間隔(changeInterval)で呼び出され、敵キャラクターの移動方向をランダムに変更します。
Random.Rangeを使用してランダムな角度を生成し、その角度を基に新しい移動方向を計算しています。
敵キャラクターが壁や障害物に衝突した場合にどう振る舞うかも重要です。
必要に応じて、衝突検出を追加して敵が壁にぶつかったときに方向を変えるなどの処理を実装するとより自然な動きになります。
この改良により、敵キャラクターの動きがより予測不可能で、ゲームプレイがよりエキサイティングになるはずです。ゲーム内で敵の新しい動きをテストし、期待通りの挙動をしているか確認してください。次のステップに進む準備ができたら教えてください。
using UnityEngine;
public class EnemyMovement : MonoBehaviour
{
public float speed = 5.0f;
private Vector3 moveDirection;
public float changeInterval = 2.0f;
private float timer;
void Start()
{
ChangeDirection();
}
void Update()
{
timer += Time.deltaTime;
if (timer > changeInterval)
{
ChangeDirection();
timer = 0;
}
transform.position += moveDirection * speed * Time.deltaTime;
}
void ChangeDirection()
{
float randomAngle = Random.Range(0, 360);
moveDirection = new Vector3(Mathf.Cos(randomAngle * Mathf.Deg2Rad), 0, Mathf.Sin(randomAngle * Mathf.Deg2Rad));
}
}
実行してみると敵キャラが宙を飛んでいくという、ChatGPTが言う通りエキサイティングなゲームになりました。
この事をChatGPTにきいてみましょう。
確かにエキサイティングになってきました。
なんと敵が宙を舞い始めました。
あなたはこれを意図して居たのですか?
敵キャラクターが宙を舞ってしまうのは意図した動作ではありません。
この問題は、おそらく敵キャラクターの物理挙動や移動ロジックに起因していると思われます。
Unityでキャラクターが地面から離れてしまうのを防ぐために、いくつかの対策を講じる必要があります。
敵キャラクターに追加されたRigidbodyコンポーネントの設定を確認します。
Use Gravityが有効になっていることを確認し、ConstraintsセクションでFreeze Position Yを有効にすることで、Y軸方向の動きを制限し、敵が上下に移動するのを防ぎます。
敵キャラクターの移動ロジックでY軸の値が変化していないことを確認します。
EnemyMovementスクリプトでは、moveDirectionのY成分を0に設定して、敵が水平方向のみに移動するようにしてください。
コードでは既にY成分を0に設定していますので、敵キャラクターが上下に動くことはないはずです。
敵キャラクターが地形や床と正しく衝突しているか確認します。
地形にもコライダーが設定されていることを確認し、敵キャラクターと地形が物理的に正しくインタラクションしていることを保証します。
これらの対策を行うことで、敵キャラクターが意図せずに宙に浮く問題を解決できるはずです。修正後、ゲームをプレイして敵キャラクターの挙動を再度確認し、問題が解消されているかを確かめてください。次のステップに進む準備ができたら、またお知らせください。
言われた通りRigidbodyの設定を行ったら敵キャラは宙を舞うことはなくなりました。
せっかくなので敵キャラが壁にぶつかったときの方向転換も考えてもらいましょう。
おかげさまで敵は宙を舞わなくなりました。
次に敵キャラが壁にぶつかったら方向転換するようにしてください。
敵キャラクターが壁にぶつかった際に方向を転換する機能を実装することで、より自然な動きを再現できます。
ここでは、EnemyMovementスクリプトを修正して、壁にぶつかったときにランダムな新しい方向に向かせる処理を追加します。
以下のコードは、EnemyMovementスクリプトに衝突検出と方向転換のロジックを追加する方法を示しています。
※枠外にコードを記述します
OnCollisionEnter メソッドを使用して、敵キャラクターが壁("Wall"タグが付けられたオブジェクト)に衝突したときにChangeDirectionメソッドを呼び出して、新しいランダムな方向に転換します。
このためには、壁のオブジェクトに"Wall"タグを割り当てておく必要があります。
これで、敵キャラクターが壁にぶつかると新しい方向に転換するようになります。ゲーム内でこの新しい挙動をテストし、期待通りに機能するか確認してください。さらに進める準備ができたら、次のステップに進んでください。
ChatGPTはWallと言っていますがここは先程作ったタグ「Obstacle」にしときましょう。
using UnityEngine;
public class EnemyMovement : MonoBehaviour
{
public float speed = 5.0f;
private Vector3 moveDirection;
public float changeInterval = 2.0f;
private float timer;
void Start()
{
ChangeDirection();
}
void Update()
{
timer += Time.deltaTime;
if (timer > changeInterval)
{
ChangeDirection();
timer = 0;
}
transform.position += moveDirection * speed * Time.deltaTime;
}
void ChangeDirection()
{
float randomAngle = Random.Range(0, 360);
moveDirection = new Vector3(Mathf.Cos(randomAngle * Mathf.Deg2Rad), 0, Mathf.Sin(randomAngle * Mathf.Deg2Rad));
}
// 新しいメソッド: 壁にぶつかった時の方向転換
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Obstacle"))
{
ChangeDirection();
}
}
}
実際にプレイしてみると急に難易度が上がった気がします。
仕上げにゲームクリアの処理を考えてもらいましょう。
ゲームクリアしたときの処理
では最後にゲームクリア時の処理を考えてください
ゲームクリア時の処理を設計することで、プレイヤーに達成感を与えることができます。
ゲームクリアの条件は通常、ゲームの目的に応じて決定されますが、ここでは「Maze Runner」のゲームでプレイヤーがゴールに到達したときをゲームクリアの条件としましょう。
以下に、ゲームクリア時の基本的な処理をいくつか示します。
ゲームクリアを示す専用のシーンを作成します。
このシーンには、「Congratulations!」や「Game Clear!」などのテキストが表示されるほか、スコアやクリアタイムを表示することもできます。
シーン内には、メインメニューに戻るボタンや次のレベルへ進むボタンを配置することが考えられます。
GoalController スクリプト内で、プレイヤーがゴールに到達した際にゲームクリアシーンをロードする処理を追加します。
※枠外にコードを記述します
新しく作成したゲームクリアシーンをUnityのビルド設定に追加します。
ゲームクリア時には、達成感を演出するためのアニメーションやサウンドエフェクトを追加することが効果的です。
例えば、ファンファーレのサウンドを再生したり、画面に花火のアニメーションを表示するなどが考えられます。
これらの処理を実装することで、プレイヤーがゲームのゴールに到達した際の達成感を高め、ゲーム体験を向上させることができます。
ゲームクリア時の処理を実装してテストし、すべてが期待通りに機能するかを確認してください。
ゲーム開発の最終段階に達したら、さらなる質問や次のステップに進む準備ができているか教えてください。
ということですのでサクッとGameClearSceneとスクリプトを記述していきましょう。
なんかChatGPT、コード端折り始めましたね。
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
Debug.Log("Game Clear!");
// タイマー停止
timer.StopTimer();
// ゲームクリアシーンへの遷移
SceneManager.LoadScene("GameClearScene");
}
}
とりあえずちゃんとゲームクリアシーンに飛ぶかどうかのチェックをしたいのでクリア画面を適当に作っておきます。
ゲームオーバーシーンも合わせて作っておきましょう。
一旦壁と敵のタグを外しておきます。
そうしないと難しくて即ゲームオーバーになってしまうので。
無事にゲームクリアの実装も出来ました。
まだChatGPTは作る気満々ですが、会話が長くなりレスポンスが悪くなってきたのでこれでMaze Runnerは完成としておきます。
ChatGPTの今後のプラン
一応ChatGPTにこのあと何を作る予定だったのかを聞いてみました。
これでMazeRunnerは完成としてもいいと思います。
ちなみにあなたは今後どのようなステップを考えていたのですか?
参考までに聞かせてください。
「Maze Runner」が完成したとのこと、おめでとうございます!
この段階からさらにゲームを拡張していく場合、以下のようなステップを考えていました。
プレイヤーに継続的な挑戦を提供するために、さまざまなレイアウトや難易度を持つ追加のレベルを設計します。
レベルごとに異なるテーマやメカニズムを導入することで、ゲームプレイにバリエーションを持たせます。
プレイヤーが収集または利用できる様々なパワーアップやアイテムを追加します。
これにより、ゲームプレイの戦略性が増し、プレイヤーのエンゲージメントが向上します。
敵キャラクターに複雑な動きや行動パターンを追加し、AIを強化します。
また、プレイヤーに対してもより高度な操作や戦略が求められるようにします。
オンラインまたはローカルのマルチプレイヤー機能を追加し、友達と一緒にプレイできるようにします。
ゲームのビジュアルとオーディオをさらにブラッシュアップします。
キャラクターや環境の詳細なモデリング、アニメーションの改善、音楽と効果音のクオリティ向上などが含まれます。
ゲームのUI/UXを洗練させ、プレイヤーにより直感的で魅力的なインターフェースを提供します。
ゲームのパフォーマンスを最適化し、さまざまなプラットフォームやデバイスでのテストを行い、幅広いユーザーに最高の体験を提供します。
これらのステップは、ゲームをさらに深化させ、プレイヤーに長期間楽しんでもらうためのものです。すでに完成したと感じているなら、これらのアイデアは将来のアップデートや新しいプロジェクトへの参考にしていただければと思います。もし新たなゲーム開発や拡張についてさらに話し合いたい場合は、いつでもお知らせください。
想像以上にしっかりと先の事まで考えていてくれたのですね。
MyGPTsの調整なども含めて3時間ちょいでしたが、ChatGPTの言う通りにゲームを作ってみました。
本当は具体的に座標なども指定してほしかったのですが、そこは自分で調整する必要がありましたね。
ただゲームのアイデアから実装、そして今後の展望なども考えてくれていたのでChatGPTはゲーム開発にかなり役に立つと感じました。
あと説明が一つ一つ長いので、その辺りはMyGPTSの「Instructions」で設定しておいても良いかなと。
ともあれ、僕とChatGPTの処女作は「Maze Runner」でした。
また別のゲームを作るときは記事にしたいと思います。
関連記事
最後までご覧頂いてありがとうございました。