キンドル出版で作成する「ご利用前に必ずお読みください・免責事項」の項目の書き方とテンプレート
きたたく
きたたくブログ
本記事では、ChatGPT o3-mini-highが生成したコードを実際に実行してAIのプログラミング能力を検証します。
あなたはUnityのプロフェッショナルなゲーム開発者です。C#を使用して、シンプルな生態系シミュレーションを作成してください。ゲームは以下の要件を満たす必要があります。
このプロジェクトは異なるAIモデルで比較するため、以下の点に注意すること:
完全なUnity C#コードを出力してください。
このコードを基に、開発者が簡単にシミュレーションを実行できるようにしてください。
以下は、Unity上で動作するシンプルな生態系シミュレーションのサンプルコードです。
以下のコードは、Animal.cs(エージェント=動物)、Food.cs(食料)、GameManager.cs(シミュレーション全体の管理)の3つのスクリプトで構成されています。
また、シミュレーションをより面白くするためのユニークな要素として…
などを実装しています。
以下に各スクリプトのコードと、Unity上でのセットアップ手順を示します。
using UnityEngine;
using UnityEngine.AI;
public class Animal : MonoBehaviour
{
[Header("Energy Settings")]
public float energy = 100f;
public float energyConsumptionRate = 2f; // 単位:秒間のエネルギー消費量
public float energyGainFromFood = 30f;
public float reproductionThreshold = 150f; // このエネルギー以上で繁殖
[Header("Movement Settings")]
public float detectionRadius = 10f; // 食料検知範囲
public float wanderRadius = 20f; // ランダム移動の範囲
private NavMeshAgent agent;
private GameManager gameManager;
void Start()
{
// NavMeshAgent コンポーネントを取得
agent = GetComponent<NavMeshAgent>();
// GameManager はシーン内に1つだけ存在する前提
gameManager = GameObject.FindObjectOfType<GameManager>();
// 初回はランダムな目的地へ移動
ChooseRandomDestination();
}
void Update()
{
// 毎フレーム、エネルギーを消費する(Time.deltaTime により秒単位の消費)
energy -= energyConsumptionRate * Time.deltaTime;
if (energy <= 0f)
{
Die();
return;
}
// 周囲にある食料を検知
Food targetFood = FindClosestFood();
if (targetFood != null)
{
// 食料が見つかった場合、その位置へ向かう
agent.SetDestination(targetFood.transform.position);
}
else
{
// 目的地に到着していれば、新たなランダムな目的地を選択
if (!agent.pathPending && agent.remainingDistance < 0.5f)
{
ChooseRandomDestination();
}
}
// 繁殖判定:エネルギーが閾値を超えたら繁殖
if (energy >= reproductionThreshold)
{
Reproduce();
}
// エネルギー量に応じた色の更新(低エネルギー=赤、高エネルギー=緑)
UpdateColor();
}
/// <summary>
/// 周囲のコライダーから Food コンポーネントを持つ最も近い食料を探す
/// </summary>
/// <returns>見つかった食料(なければ null)</returns>
Food FindClosestFood()
{
Collider[] hits = Physics.OverlapSphere(transform.position, detectionRadius);
Food closestFood = null;
float minDist = Mathf.Infinity;
foreach (Collider hit in hits)
{
Food food = hit.GetComponent<Food>();
if (food != null)
{
float dist = Vector3.Distance(transform.position, food.transform.position);
if (dist < minDist)
{
minDist = dist;
closestFood = food;
}
}
}
return closestFood;
}
/// <summary>
/// ランダムな目的地を選び、NavMeshAgent にセットする
/// </summary>
void ChooseRandomDestination()
{
Vector3 randomDirection = Random.insideUnitSphere * wanderRadius;
randomDirection += transform.position;
NavMeshHit hit;
if (NavMesh.SamplePosition(randomDirection, out hit, wanderRadius, NavMesh.AllAreas))
{
agent.SetDestination(hit.position);
}
}
/// <summary>
/// 繁殖処理:GameManager を通じて新たな個体をスポーンし、エネルギーを半分に分割する
/// </summary>
void Reproduce()
{
if (gameManager != null)
{
// 親の周囲に少し離れた位置へ新しい個体を生成
Vector3 spawnPos = transform.position + Random.insideUnitSphere * 2f;
spawnPos.y = transform.position.y;
gameManager.SpawnAnimal(spawnPos);
energy /= 2f;
}
}
/// <summary>
/// エネルギーが0以下になった場合の死亡処理
/// </summary>
void Die()
{
Destroy(gameObject);
}
/// <summary>
/// エネルギー量に応じてマテリアルの色を変化させる
/// </summary>
void UpdateColor()
{
Renderer rend = GetComponent<Renderer>();
if (rend != null)
{
// energy が 0 なら赤、繁殖閾値なら緑とする補間(0~reproductionThreshold)
float t = Mathf.InverseLerp(0, reproductionThreshold, energy);
rend.material.color = Color.Lerp(Color.red, Color.green, t);
}
}
/// <summary>
/// 衝突判定:食料に接触した場合、食べる
/// ※ 食料オブジェクトには Collider(Is Triggerにチェック)を設定してください
/// </summary>
/// <param name="other">接触したコライダー</param>
private void OnTriggerEnter(Collider other)
{
Food food = other.GetComponent<Food>();
if (food != null)
{
energy += energyGainFromFood;
food.Consume();
}
}
}
using UnityEngine;
public class Food : MonoBehaviour
{
[Header("Floating Animation (Optional)")]
public float floatSpeed = 0.5f;
public float floatAmplitude = 0.5f;
private Vector3 startPosition;
void Start()
{
startPosition = transform.position;
}
void Update()
{
// 食料がふわふわ浮くようなアニメーション(上下運動)
transform.position = startPosition + new Vector3(0, Mathf.Sin(Time.time * floatSpeed) * floatAmplitude, 0);
}
/// <summary>
/// エージェントに食べられた時に呼ばれる処理
/// </summary>
public void Consume()
{
Destroy(gameObject);
}
}using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
[Header("Prefab Settings")]
public GameObject animalPrefab;
public GameObject foodPrefab;
[Header("Initial Spawn Counts")]
public int initialAnimalCount = 10;
public int initialFoodCount = 20;
[Header("Field Settings")]
public Vector2 fieldSize = new Vector2(50, 50); // X-Z平面上のフィールドサイズ
[Header("Food Spawn Settings")]
public float foodSpawnInterval = 5f;
public int foodSpawnCount = 5;
[Header("UI (任意)")]
public Text animalCountText;
public Text foodCountText;
// 状況表示用(例:豊作シーズン中、シミュレーション終了など)
public Text simulationStatusText;
void Start()
{
// 初期の動物を生成
for (int i = 0; i < initialAnimalCount; i++)
{
Vector3 pos = GetRandomPosition();
SpawnAnimal(pos);
}
// 初期の食料を生成
for (int i = 0; i < initialFoodCount; i++)
{
SpawnFood(GetRandomPosition());
}
// 食料を定期的にスポーンするコルーチンを開始
StartCoroutine(SpawnFoodRoutine());
// さらに、一定間隔で「豊作シーズン」が発生するコルーチンを開始(ユニークな要素)
StartCoroutine(SeasonalEventRoutine());
}
void Update()
{
// UI のカウンター更新
UpdateUI();
// 全エージェントが死亡したらシミュレーション終了
if (GameObject.FindObjectsOfType<Animal>().Length == 0)
{
if (simulationStatusText != null)
{
simulationStatusText.text = "シミュレーション終了:すべての動物が死にました。";
}
StopAllCoroutines(); // 食料スポーンなどのコルーチンを停止
}
}
/// <summary>
/// ランダムな位置を返す(フィールド内)
/// </summary>
/// <returns>ランダムな Vector3</returns>
Vector3 GetRandomPosition()
{
float x = Random.Range(-fieldSize.x / 2f, fieldSize.x / 2f);
float z = Random.Range(-fieldSize.y / 2f, fieldSize.y / 2f);
return new Vector3(x, 0, z);
}
/// <summary>
/// 外部から呼ばれる動物の生成処理
/// </summary>
/// <param name="position">生成位置</param>
public void SpawnAnimal(Vector3 position)
{
Instantiate(animalPrefab, position, Quaternion.identity);
}
/// <summary>
/// 外部から呼ばれる食料の生成処理
/// </summary>
/// <param name="position">生成位置</param>
public void SpawnFood(Vector3 position)
{
Instantiate(foodPrefab, position, Quaternion.identity);
}
/// <summary>
/// 定期的に食料を生成するコルーチン
/// </summary>
IEnumerator SpawnFoodRoutine()
{
while (true)
{
yield return new WaitForSeconds(foodSpawnInterval);
for (int i = 0; i < foodSpawnCount; i++)
{
SpawnFood(GetRandomPosition());
}
}
}
/// <summary>
/// ユニークな要素:一定間隔で「豊作シーズン」を発生させ、一定期間食料のスポーンレートをアップさせる
/// </summary>
IEnumerator SeasonalEventRoutine()
{
while (true)
{
// 30秒ごとに豊作シーズン発生
yield return new WaitForSeconds(30f);
// 現在のスポーン設定をバックアップ
int originalFoodSpawnCount = foodSpawnCount;
float originalFoodSpawnInterval = foodSpawnInterval;
// 豊作シーズン:食料生成数を2倍、スポーン間隔を半分に
foodSpawnCount *= 2;
foodSpawnInterval /= 2f;
if (simulationStatusText != null)
{
simulationStatusText.text = "★ 豊作シーズン ★";
}
// 豊作シーズンは10秒間持続
yield return new WaitForSeconds(10f);
// 設定を元に戻す
foodSpawnCount = originalFoodSpawnCount;
foodSpawnInterval = originalFoodSpawnInterval;
if (simulationStatusText != null)
{
simulationStatusText.text = "";
}
}
}
/// <summary>
/// UI のカウンター(動物数、食料数)の更新
/// </summary>
void UpdateUI()
{
if (animalCountText != null)
{
animalCountText.text = "動物数: " + GameObject.FindObjectsOfType<Animal>().Length;
}
if (foodCountText != null)
{
foodCountText.text = "食料数: " + GameObject.FindObjectsOfType<Food>().Length;
}
}
}
このコードとセットアップ手順をもとに、開発者は簡単にシミュレーションを実行でき、AIの動きやエコシステムのバランス、シーズンイベントなどを比較・検証することが可能です。必要に応じてパラメータ(エネルギー消費率、繁殖閾値、スポーンレートなど)を調整して、より細かいシミュレーション挙動を実現してください。