見出し画像

[Unity] Claude3にローグライクを作らせようとした話。#2


今回は以前の続きからClaude3にローグライクに必須の
状態異常、インベントリ、スキル、魔法攻撃、アイテムデータ、さらにショップ機能や実績機能のコードを書かせてみようと思います。

以前の記事では、Claude3がターン制バトルや敵のAIなどのコードを書いてくれました。(コードが動くかは別問題)

今回はローグライクゲームの醍醐味である
状態異常や魔法などの特殊攻撃、階層の生成
さらには、インベントリや実績 ショップ
などを作ってもらいます!

以前の記事で、Claude3に具体的なローグライクの開発手順やゲームシステムを資料として入れてるので、こんな感じの質問でも分かってくれるはず!

実装が完了したStepの続きから順番にローグライクをコードやオブジェクトを作成せよ。作成するオブジェクト、スクリプトを明記して、作成すること

さあ続きを書いてくれ!
(相変わらずこの質問の日本語が変だな)

分かりました。これまでに実装したステップに続いて、開発手順に沿ってローグライクゲームの作成を進めていきます。必要となるオブジェクトやスクリプトを明記しながら進めていきます。

**Step 8. データファイル**

- キャラクターのステータスデータを格納するJSONファイルを作成します。

**Resources**
- CharacterStats.json

- メッセージデータを格納するJSONファイルを作成します。

**Resources**
- MessageData.json

- データファイルの読み込みスクリプトを作成します。

**スクリプト**
- DataManager.cs

**Step 9. アイテム**

- アイテムのスプライトを作成/インポートします。

**Sprites**
- HealingPotionSprite.png
- WeaponSprite.png

- アイテムのプレハブを作成します。

**Prefabs**
- HealingPotion.prefab
- Weapon.prefab

- アイテムデータを格納するJSONファイルを作成します。

**Resources**
- ItemData.json

- アイテム管理スクリプトを作成します。

**スクリプト**
- ItemManager.cs

- インベントリUIを作成します。

**UI要素**
- InventoryCanvas
- InventorySlots

- インベントリ管理スクリプトを作成します。

**スクリプト**
- InventoryManager.cs

**Step 10. 魔法と特殊攻撃**

- 魔法や特殊攻撃のデータを格納するJSONファイルを作成します。

**Resources**
- MagicData.json

- 魔法や特殊攻撃の効果を処理するスクリプトを作成します。

**スクリプト**
- MagicEffectManager.cs

- 状態異常の種類を定義する列挙型を作成します。

**スクリプト**
- StatusEffects.cs

- 状態異常の効果を処理するスクリプトを作成します。

**スクリプト**
- StatusEffectManager.cs

**Step 11. シンプルなゲームでテストプレイ**

- このステップではコード変更はありませんが、作成したシステムをテストプレイし、問題点を改善します。

**Step 12. 階の生成と移動**

- 階段のスプライトを作成/インポートします。

**Sprites**
- StairsSprite.png

- 階段のプレハブを作成します。

**Prefabs**
- Stairs.prefab

- プロシージャル生成でマップを作成するスクリプトを作成します。

**スクリプト**
- DungeonGenerator.cs

- 階層の管理スクリプトを作成します。

**スクリプト**
- LevelManager.cs

これまでのステップで必要となるオブジェクトとスクリプトを作成しました。今後のステップでさらにオブジェクトやスクリプトを追加していきます。開発手順に沿って順次実装を進めていきましょう。

おお!すごい!
さぁスクリプトを見せてくれ!

作成したスクリプトやファイルを具体的に記述せよ

はい、作成したスクリプトやファイルの具体的な内容を記述します。

**DataManager.cs**
```csharp
using UnityEngine;

public class DataManager : MonoBehaviour
{
    public TextAsset characterStatsData;
    public TextAsset messageData;

    private void Start()
    {
        LoadData();
    }

    private void LoadData()
    {
        // Load character stats data from JSON
        CharacterStats[] stats = JsonUtility.FromJson<CharacterStats[]>(characterStatsData.text);

        // Load message data from JSON
        MessageData[] messages = JsonUtility.FromJson<MessageData[]>(messageData.text);

        // Process loaded data
        ProcessCharacterStats(stats);
        ProcessMessageData(messages);
    }

    private void ProcessCharacterStats(CharacterStats[] stats)
    {
        // Assign loaded stats to characters in the game
    }

    private void ProcessMessageData(MessageData[] messages)
    {
        // Assign loaded messages to message manager
    }
}
```

**CharacterStats.json**
```json
[
  {
    "name": "Player",
    "maxHealth": 100,
    "attack": 10,
    "defense": 5
  },
  {
    "name": "Goblin",
    "maxHealth": 50,
    "attack": 8,
    "defense": 3
  }
]
```

**MessageData.json**
```json
[
  {
    "id": 1,
    "message": "You found a healing potion."
  },
  {
    "id": 2,
    "message": "The goblin attacks you!"
  }
]
```

**ItemManager.cs**
```csharp
using UnityEngine;

public class ItemManager : MonoBehaviour
{
    public TextAsset itemData;

    private void Start()
    {
        LoadItemData();
    }

    private void LoadItemData()
    {
        // Load item data from JSON
        ItemData[] items = JsonUtility.FromJson<ItemData[]>(itemData.text);

        // Process loaded item data
        ProcessItemData(items);
    }

    private void ProcessItemData(ItemData[] items)
    {
        // Instantiate item prefabs based on loaded data
        foreach (ItemData item in items)
        {
            GameObject itemObj = Instantiate(Resources.Load<GameObject>($"Prefabs/Items/{item.prefabName}"), item.position, Quaternion.identity);
            itemObj.GetComponent<ItemProperties>().SetProperties(item);
        }
    }
}
```

**ItemData.json**
```json
[
  {
    "name": "Healing Potion",
    "prefabName": "HealingPotion",
    "healAmount": 20,
    "position": {
      "x": 2,
      "y": 3,
      "z": 0
    }
  },
  {
    "name": "Sword",
    "prefabName": "Weapon",
    "attackBonus": 5,
    "position": {
      "x": 5,
      "y": 1,
      "z": 0
    }
  }
]
```

**InventoryManager.cs**
```csharp
using UnityEngine;
using UnityEngine.UI;

public class InventoryManager : MonoBehaviour
{
    public GameObject slotPrefab;
    public Transform slotsParent;

    private ItemProperties[] inventoryItems = new ItemProperties[8];
    private GameObject[] slotObjects = new GameObject[8];

    private void Start()
    {
        CreateSlots();
    }

    private void CreateSlots()
    {
        for (int i = 0; i < inventoryItems.Length; i++)
        {
            GameObject slotObj = Instantiate(slotPrefab, slotsParent);
            slotObjects[i] = slotObj;
            slotObj.GetComponent<Image>().sprite = null;
        }
    }

    public void AddItem(ItemProperties item)
    {
        for (int i = 0; i < inventoryItems.Length; i++)
        {
            if (inventoryItems[i] == null)
            {
                inventoryItems[i] = item;
                slotObjects[i].GetComponent<Image>().sprite = item.sprite;
                return;
            }
        }
    }
}
```

**MagicEffectManager.cs**
```csharp
using UnityEngine;

public class MagicEffectManager : MonoBehaviour
{
    public TextAsset magicData;

    private void Start()
    {
        LoadMagicData();
    }

    private void LoadMagicData()
    {
        // Load magic data from JSON
        MagicData[] magicEffects = JsonUtility.FromJson<MagicData[]>(magicData.text);

        // Process loaded magic data
        ProcessMagicData(magicEffects);
    }

    private void ProcessMagicData(MagicData[] magicEffects)
    {
        // Assign magic effects to appropriate game objects or systems
    }
}
```

**MagicData.json**
```json
[
  {
    "name": "Fireball",
    "damage": 30,
    "range": 5
  },
  {
    "name": "Heal",
    "healAmount": 50,
    "targetSelf": true
  }
]
```

**StatusEffects.cs**
```csharp
public enum StatusEffectType
{
    None,
    Poison,
    Stun,
    Burn
}
```

**StatusEffectManager.cs**
```csharp
using UnityEngine;

public class StatusEffectManager : MonoBehaviour
{
    public void ApplyStatusEffect(StatusEffectType effect, CharacterStats target, int duration)
    {
        switch (effect)
        {
            case StatusEffectType.Poison:
                ApplyPoisonEffect(target, duration);
                break;
            case StatusEffectType.Stun:
                ApplyStunEffect(target, duration);
                break;
            case StatusEffectType.Burn:
                ApplyBurnEffect(target, duration);
                break;
        }
    }

    private void ApplyPoisonEffect(CharacterStats target, int duration)
    {
        // Apply poison effect to target for specified duration
    }

    private void ApplyStunEffect(CharacterStats target, int duration)
    {
        // Apply stun effect to target for specified duration
    }

    private void ApplyBurnEffect(CharacterStats target, int duration)
    {
        // Apply burn effect to target for specified duration
    }
}
```

**DungeonGenerator.cs**
```csharp
using UnityEngine;
using UnityEngine.Tilemaps;

public class DungeonGenerator : MonoBehaviour
{
    public Tilemap dungeon;
    public Tile floorTile;
    public Tile wallTile;

    private void Start()
    {
        GenerateDungeon();
    }

    private void GenerateDungeon()
    {
        // Generate a random dungeon layout using procedural generation algorithms
        for (int y = 0; y < 20; y++)
        {
            for (int x = 0; x < 20; x++)
            {
                Tile tile = Random.value < 0.3f ? wallTile : floorTile;
                dungeon.SetTile(new Vector3Int(x, y, 0), tile);
            }
        }
    }
}
```

**LevelManager.cs**
```csharp
using UnityEngine;

public class LevelManager : MonoBehaviour
{
    public int currentLevel = 1;
    public Transform playerSpawnPoint;

    private void Start()
    {
        SpawnPlayer();
    }

    private void SpawnPlayer()
    {
        Instantiate(Resources.Load<GameObject>("Prefabs/Player"), playerSpawnPoint.position, Quaternion.identity);
    }

    public void LoadNextLevel()
    {
        currentLevel++;
        // Load next level dungeon layout

あれ?なんか途中で止まったな。
一度に生成できる文字数の限界がきたのかな?
続きを書いてくれ!

LevelManagerから続きを記述せよ

using UnityEngine;
using UnityEngine.SceneManagement;

public class LevelManager : MonoBehaviour
{
    public int currentLevel = 1;
    public Transform playerSpawnPoint;

    private void Start()
    {
        SpawnPlayer();
    }

    private void SpawnPlayer()
    {
        Instantiate(Resources.Load<GameObject>("Prefabs/Player"), playerSpawnPoint.position, Quaternion.identity);
    }

    public void LoadNextLevel()
    {
        currentLevel++;

        // Unload current level
        SceneManager.UnloadSceneAsync(SceneManager.GetActiveScene());

        // Load next level
        SceneManager.LoadSceneAsync($"Level{currentLevel}", LoadSceneMode.Additive);
    }

    public void ReloadCurrentLevel()
    {
        // Unload current level
        SceneManager.UnloadSceneAsync(SceneManager.GetActiveScene());

        // Reload current level
        SceneManager.LoadSceneAsync($"Level{currentLevel}", LoadSceneMode.Additive);
    }

    private void OnLevelCompleted()
    {
        // Level completed logic, such as spawning stairs or opening the exit
        // ...

        // Spawn stairs or exit prefab
        GameObject stairsPrefab = Resources.Load<GameObject>("Prefabs/Stairs");
        Instantiate(stairsPrefab, playerSpawnPoint.position, Quaternion.identity);
    }
}

この実装では、以下の機能が追加されています。

LoadNextLevelメソッドでは、現在のレベルをアンロードし、次のレベルをロードしています。レベルごとにシーンを分割しており、SceneManager.LoadSceneAsyncを使ってシーンをロードしています。
ReloadCurrentLevelメソッドでは、現在のレベルをリロードしています。これは、プレイヤーが死亡した場合などに使用できます。
OnLevelCompletedメソッドは、レベルをクリアした際の処理を行うためのメソッドです。ここでは、階段やレベル出口のプレハブをインスタンス化しています。このメソッドは、特定のイベントやトリガーによって呼び出されることを想定しています。
レベルごとにシーンを分割しているため、レベルデータは各シーンに含まれていることを想定しています。シーンには、ダンジョンのレイアウト、敵の配置、アイテムの配置などのデータが含まれています。
プレイヤーのスポーン位置は、レベルマネージャーに設定されたスポーンポイントを使用しています。

この実装では、レベルの管理とロード、プレイヤーのスポーン位置の設定、レベルクリア時の処理を行っています。実際のゲームでは、さらにレベルデータの読み込みや、レベル間での状態の保存と復元などの処理が必要になる可能性があります。

相変わらずたまに不自然なコードがあるけど

まぁパッと見た感じは良さそうなだな!(適当)

さあ続きを書いてくれ!

Your message will exceed the length limit for this chat. Try shortening your message or starting a new conversation. Or consider upgrading to Claude Pro.

え?なんか赤文字で変な文章出てきた!
助けてGoogle翻訳!

このチャットのメッセージの長さ制限を超えています。メッセージを短くするか、新しい会話を開始してください。または、Claude Pro へのアップグレードを検討してください。

なるほど、つまりチャットの長さに制限があったのかな?
まぁ新しいチャットでもう一度始めてみるか。

でも前の続きから書かせるためにはどうすれば良いんだ?

とりあえずこのチャットログを全部コピーして、
新しいチャットのはじめに資料として貼り付けるか。

(やってる事は、ただ1番上から1番下までチャットをコピーして、新しいチャットの1番初めに貼り付けてるだけ)


これが前のチャットのログである。チャットの限界を超えたため新たにこちらでローグライクの開発を始める。
前のチャットのログをよく読み、実装済みのStepの次から記述せよ

さぁ前のチャットの引き続きはできるのか?

分かりました。前のチャットログを確認し、実装済みのステップから続けて開発を進めていきます。
前のチャットログによると、最後に実装したのはStep 12でした。
Step 13. 経験値とスキル
次は経験値の獲得とレベルアップのシステム、およびプレイヤーのスキルを実装していきます。
必要となるオブジェクトやスクリプトは以下の通りです。
スクリプト

ExperienceManager.cs
SkillManager.cs

ExperienceManager.csでは、以下の機能を実装します。

敵を倒した際の経験値の獲得処理
必要経験値の設定と、レベルアップ条件のチェック
レベルアップ時のステータス上昇処理




```csharp
using UnityEngine;

public class ExperienceManager : MonoBehaviour
{
    public int currentExperience;
    public int experienceToNextLevel = 100;

    public int playerLevel = 1;

    private CharacterStats playerStats;

    private void Start()
    {
        playerStats = GameObject.FindGameObjectWithTag("Player").GetComponent<CharacterStats>();
    }

    public void GainExperience(int experience)
    {
        currentExperience += experience;
        CheckForLevelUp();
    }

    private void CheckForLevelUp()
    {
        if (currentExperience >= experienceToNextLevel)
        {
            LevelUp();
        }
    }

    private void LevelUp()
    {
        playerLevel++;
        currentExperience -= experienceToNextLevel;
        experienceToNextLevel = Mathf.Max(experienceToNextLevel + 50, experienceToNextLevel * 1.2f);

        playerStats.maxHealth += 10;
        playerStats.attack += 2;
        playerStats.defense += 1;

        // Display level up message
        MessageManager.Instance.AddMessage($"You leveled up to level {playerLevel}!");
    }
}
```

SkillManager.csでは、プレイヤーの特殊攻撃やスキルを管理します。スキルのデータはJSONファイルから読み込むことができます。

```csharp
using UnityEngine;

public class SkillManager : MonoBehaviour
{
    public TextAsset skillData;

    private SkillData[] playerSkills;

    private void Start()
    {
        LoadSkillData();
    }

    private void LoadSkillData()
    {
        playerSkills = JsonUtility.FromJson<SkillData[]>(skillData.text);
    }

    public void UseSkill(int skillIndex, CharacterStats targetStats)
    {
        SkillData skill = playerSkills[skillIndex];

        switch (skill.skillType)
        {
            case SkillType.Damage:
                DamageTarget(targetStats, skill.damageAmount);
                break;
            case SkillType.Heal:
                HealTarget(targetStats, skill.healAmount);
                break;
            // Add more skill types as needed
        }
    }

    private void DamageTarget(CharacterStats targetStats, int damageAmount)
    {
        targetStats.currentHealth -= damageAmount;
        // Display damage message
    }

    private void HealTarget(CharacterStats targetStats, int healAmount)
    {
        targetStats.currentHealth = Mathf.Min(targetStats.currentHealth + healAmount, targetStats.maxHealth);
        // Display heal message
    }
}
```

続いて、Step 14に移ります。

なんかスゲェ!(語彙力ゼロ)
まぁコードはちゃんと合っていそうかな?(適当)

続いて、Step 14に移ります。

雑になる質問
それでもちゃんと答えてくれるClaude3。

はい、Step 14を実装していきましょう。 Step 14. その他の機能 ここでは、ゲームに追加の要素を実装します。ショップ、クエスト、実績など、ゲームの魅力をさらに高める機能を追加できます。また、総プレイ時間や倒した敵の種類など、プレイヤーの統計データを記録する機能も実装できます。 必要となるオブジェクトやスクリプトは以下の通りです。 Prefabs - ShopKeeper.prefab Scripts - ShopManager.cs - QuestManager.cs - AchievementManager.cs - StatisticsManager.cs ShopManager.csでは、ショップの機能を実装します。プレイヤーはここでアイテムを購入したり、所持品を売却したりできます。



```csharp
using UnityEngine;

public class ShopManager : MonoBehaviour
{
    public ItemData[] stockedItems;

    private InventoryManager playerInventory;

    private void Start()
    {
        playerInventory = GameObject.FindGameObjectWithTag("Player").GetComponent<InventoryManager>();
    }

    public void BuyItem(int itemIndex)
    {
        ItemData itemToBuy = stockedItems[itemIndex];

        if (playerInventory.CanAddItem(itemToBuy.item))
        {
            playerInventory.AddItem(itemToBuy.item);
            // Deduct gold from player
        }
        else
        {
            // Display "Inventory full" message
        }
    }

    public void SellItem(ItemProperties itemToSell)
    {
        playerInventory.RemoveItem(itemToSell);
        // Add gold to player
    }
}
```

QuestManager.csでは、クエストの管理を行います。クエストの目標や報酬などのデータは外部ファイルから読み込むことができます。

```csharp
using UnityEngine;

public class QuestManager : MonoBehaviour
{
    public TextAsset questData;

    private QuestData[] quests;

    private void Start()
    {
        LoadQuestData();
    }

    private void LoadQuestData()
    {
        quests = JsonUtility.FromJson<QuestData[]>(questData.text);
    }

    public void StartQuest(int questIndex)
    {
        QuestData quest = quests[questIndex];
        // Display quest objectives
        // Register quest callbacks
    }

    public void CompleteQuest(int questIndex)
    {
        QuestData quest = quests[questIndex];
        // Grant quest rewards
        // Display completion message
    }
}
```

AchievementManager.csでは、実績の管理を行います。実績の条件と報酬などのデータは外部ファイルから読み込むことができます。

```csharp
using UnityEngine;

public class AchievementManager : MonoBehaviour
{
    public TextAsset achievementData;

    private AchievementData[] achievements;

    private void Start()
    {
        LoadAchievementData();
    }

    private void LoadAchievementData()
    {
        achievements = JsonUtility.FromJson<AchievementData[]>(achievementData.text);
    }

    public void UnlockAchievement(int achievementIndex)
    {
        AchievementData achievement = achievements[achievementIndex];
        // Grant achievement rewards
        // Display unlock message
    }
}
```

StatisticsManager.csでは、プレイヤーの統計データを記録します。

```csharp
using UnityEngine;

public class StatisticsManager : MonoBehaviour
{
    public float totalPlayTime;
    public int enemiesKilled;
    public int bosseDefeated;

    private void Update()
    {
        totalPlayTime += Time.deltaTime;
    }

    public void RegisterEnemyKill(EnemyType enemyType)
    {
        enemiesKilled++;
        if (enemyType == EnemyType.Boss)
        {
            bossesDefeated++;
        }
    }
}
```

これらの機能を実装することで、ゲームにさらなる深みと楽しさが加わります。プレイヤーの満足度が高まり、長時間楽しめるゲームになるでしょう。

おお!とうとう実績機能が来た!

どのゲームでもあると嬉しいシステムの実績機能とかショップ機能とかだ!

こういう機能をUnityで作ろうと思っても、あまり情報が無いので良いよね!(コードが動くかは別問題)

まぁひとまず、これでローグライクの大体の機能をClaude3に作らせることが出来ました!

まぁこのままUnityにこのコードをぶち込んでも
ほぼ確実にどっかでエラーが起きそうですが、
そのエラーが発生した場所と、エラーメッセージを
Claude3に貼り付けたら、修正してくれそうですね。

しかし問題はこのコードが実際にUnityで動くのか?
という事です。(多分動かない)
まぁいつかこれらのコードをUnityで実際に動くか検証して記事にしようと思います。

では今回はここまで!

この記事を見た人にオススメの記事



この記事が参加している募集

ゲームの作り方

AIとやってみた

この記事が気に入ったらサポートをしてみませんか?