見出し画像

Claude-3.5-Sonnet vs GPT4o ゲーム開発にはどちらがより向いているのか


はじめに

はじめまして、AKです。
私は普段、日々の日記やAIを用いたポケモン開発などに焦点を当ててブログを書いています。
最近は3か月チャレンジと題し、「ポケモン風ゲームを3か月で作成する」に挑戦しています。ゲームエンジンはGodotです。
使用したことのないゲームエンジンでは相当厳しい(というかほぼ不可能)のため、ここで生成AIを全力投入します。ほぼ0知識のGodot独自で使用する言語、GDScriptやノードといわれる概念をチュートリアルやAIを活用して勉強しています。
コードの切り貼りでのゲーム作りもよいですが、私は何か自分に残したいと思い、ゲーム開発の学習を含めてAIでどこまでいけるのかを見たかったのでこのような形で進めています。
前置きは長かったですが、次に実験内容について共有します。

※進捗はまだまだです。
簡単なバトルであれば開始できるようになったというところです。
ポケモン模倣ゲーム制作 #Godot #勉強 #devlog (youtube.com)


実験開始

私の質問は2つです。

1.  ポケモンをgodotで開発したいです。主人公が草むらなどのエリアに入ると野生ポケモンが出現しますが、これをgodotで開発するためにはどのような設計が良いでしょうか。可能な限り詳細に、実際のポケモンがどうかを熟考して具体的に教えてください。コーディングは不要です。

2.では、簡単なところから実装していきます。具体的なコードも含めて提示してください。

以下はそれぞれの回答です。

「ポケモンをgodotで開発したいです。主人公が草むらなどのエリアに入ると野生ポケモンが出現しますが、これをgodotで開発するためにはどのような設計が良いでしょうか。可能な限り詳細に、実際のポケモンがどうかを熟考して具体的に教えてください。コーディングは不要です。」

Claude-3.5-Sonnet「ポケモンのような遭遇システムをGodotで開発するための設計案を詳細に説明します:1. マップシステム - TileMapノードを使用して、草むら、道路、建物などの異なる地形タイプを作成 - 各タイルに「エンカウント率」のプロパティを設定(例:草むらは10%、道路は0%)2. プレイヤーキャラクター - KinematicBody2Dを使用してプレイヤーを作成 - 移動システムを実装(上下左右の移動) - 現在位置を常に追跡し、どのタイル上にいるかを把握3. エンカウントシステム - プレイヤーが移動するたびに、現在のタイルのエンカウント率をチェック - 乱数生成器を使用して、エンカウントが発生するかどうかを決定 - エンカウントが発生した場合、バトルシーンに遷移4. ポケモンデータベース - JSON or CSV形式でポケモンのデータを保存(名前、タイプ、能力値など) - 各エリアに出現するポケモンのリストと出現確率を定義5. バトル開始システム - エンカウントが決定したら、現在のエリアに基づいて出現するポケモンをランダムに選択 - ポケモンのレベルを決定(プレイヤーのレベルに基づいて調整) - バトルシーンを準備し、選択されたポケモンのデータを渡す6. トランジション効果 - シェーダーを使用して、フィールドからバトルへの移行効果を作成 - 画面をフェードアウトし、バトル画面にフェードイン7. バトルシステム - 別のシーンとして実装 - ターンベースの戦闘システムを構築 - プレイヤーのポケモンと野生ポケモンの情報を表示 - 攻撃、アイテム使用、逃走などのオプションを提供8. サウンドシステム - エンカウント時の効果音を実装 - バトル開始時のBGM切り替えを実装9. セーブシステム - プレイヤーの現在位置、所持ポケモン、アイテムなどをセーブ - エンカウント直前の状態を一時的に保存し、バトル後に復元10. パフォーマンス最適化 - エンカウントチェックを毎フレームではなく、一定間隔で行う - 画面外のエリアはエンカウントチェックを行わない11. デバッグモード - エンカウント率を調整できるデバッグメニューを実装 - 特定のポケモンを強制的に出現させる機能を追加この設計は、実際のポケモンゲームの仕組みを考慮しつつ、Godotエンジンの特性を活かした実装方法を提案しています。実際の開発では、これらの要素を段階的に実装し、テストを重ねながら調整していくことが重要です。」

claude

GPT4o「ポケモン風のゲームをGodotで開発する際に、主人公が草むらに入ると野生ポケモンが出現するシステムを設計する方法について説明します。以下に、設計の具体的な手順を示します。

### 1. エリアの設計
#### マップとエリアの設定
1. **タイルマップ**: マップ全体をタイルマップとして作成します。草むらやその他のエリアは異なるタイルで表現します。
2. **エリアの識別**: 各タイルにはエリアの種類(草むら、道路、洞窟など)を識別するための属性を設定します。例えば、タイルにはカスタムデータとして「is_grass: true」といった情報を含めます。

### 2. 主人公の移動とエリア検出
#### プレイヤーキャラクターの設定
1. **プレイヤーキャラクター**: プレイヤーキャラクターをKinematicBody2D(または3D)として設定し、移動スクリプトを追加します。
2. **エリア検出**: プレイヤーキャラクターにRayCast2Dを追加し、足元のタイルの種類を常に検出するようにします。RayCast2Dの衝突検出を使って、現在のタイルが草むらかどうかを確認します。

### 3. 野生ポケモンの出現ロジック
#### 確率的な出現
1. **出現判定**: プレイヤーが草むらのタイル上にいる間、一定の確率で野生ポケモンが出現するように設定します。例えば、毎フレームごとにランダムな数値を生成し、一定の閾値を超えた場合に出現イベントを発生させます。
2. **タイマーの使用**: 出現頻度を制御するためにタイマーを使用し、タイマーが一定時間経過するごとに出現判定を行います。

### 4. 野生ポケモンの出現イベント
#### イベントのトリガーとバトルシーン
1. **イベントのトリガー**: 出現判定が成功した場合、野生ポケモン出現イベントをトリガーします。このイベントは、バトルシーンに遷移するためのトリガーとして機能します。
2. **バトルシーン**: バトルシーンを別途用意し、トリガーが発生した際に現在のシーンをバトルシーンに切り替えます。バトルシーンでは、ランダムに選ばれた野生ポケモンとの戦闘を開始します。

### 5. ポケモンデータの管理
#### ポケモンのデータ構造
1. **データベース**: すべてのポケモンのデータ(名前、ステータス、技など)を管理するためのデータベースを作成します。これはJSONファイルやカスタムリソースとして保存します。
2. **ランダム選択**: 野生ポケモン出現時には、草むらで出現する可能性のあるポケモンのリストからランダムに選択します。

### まとめ
以上のステップを踏むことで、Godotでポケモン風のゲームを開発し、主人公が草むらに入ると野生ポケモンが出現するシステムを実装することができます。それぞれのステップは詳細に分解されており、それに従うことで具体的な実装が可能となります。各要素の実際のコーディングはGodotのGDScriptを用いて行うことになりますが、設計の概念をしっかり理解することが重要です。」

GPT4o

「では、簡単なところから実装していきます。具体的なコードも含めて提示してください。」
Claude-3.5-Sonnet「はい、それでは簡単なところから実装を始めましょう。まずは基本的なマップシステムとプレイヤーの移動、そして簡単なエンカウントシステムを実装します。

1. マップシステム (Map.tscn)

```gdscript
extends Node2D

# TileMapノードを追加し、草むらと道路のタイルを設定します
onready var tilemap = $TileMap

# タイルの種類に応じたエンカウント率を定義
var encounter_rates = {
0: 0, # 道路
1: 10, # 草むら
}

func _ready():
# マップの初期化処理(必要に応じて)
pass

func get_encounter_rate(pos):
var tile = tilemap.get_cellv(tilemap.world_to_map(pos))
return encounter_rates.get(tile, 0)
```

2. プレイヤーキャラクター (Player.tscn)

```gdscript
extends KinematicBody2D

export var speed = 200

var velocity = Vector2.ZERO

func _physics_process(delta):
var input_vector = Vector2.ZERO
input_vector.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
input_vector.y = Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
input_vector = input_vector.normalized()

if input_vector != Vector2.ZERO:
velocity = input_vector * speed
else:
velocity = Vector2.ZERO

move_and_slide(velocity)
```

3. メインゲームシーン (Main.tscn)

```gdscript
extends Node2D

onready var player = $Player
onready var map = $Map

var steps_since_last_encounter = 0
var steps_per_encounter_check = 5

func _physics_process(delta):
if player.velocity != Vector2.ZERO:
steps_since_last_encounter += 1

if steps_since_last_encounter >= steps_per_encounter_check:
check_for_encounter()
steps_since_last_encounter = 0

func check_for_encounter():
var encounter_rate = map.get_encounter_rate(player.global_position)
if randf() * 100 < encounter_rate:
start_battle()

func start_battle():
print("野生のポケモンが現れた!")
# ここでバトルシーンに遷移する処理を追加
```

4. プロジェクト設定

プロジェクト設定で、入力マップに "ui_up", "ui_down", "ui_left", "ui_right" を設定してください。

5. シーンの構成

- Main.tscn
- Map (Map.tscnをインスタンス化)
- Player (Player.tscnをインスタンス化)

この基本的な実装では、以下の機能が含まれています:

- TileMapを使用した簡単なマップシステム
- プレイヤーの基本的な移動システム
- タイルの種類に応じたエンカウント率の設定
- 一定歩数ごとのエンカウントチェック

次のステップとしては、以下の機能を追加することができます:

1. ポケモンのデータベースの作成
2. バトルシーンの実装
3. トランジション効果の追加
4. サウンドシステムの実装

これらの基本的な要素を実装した後、段階的に機能を追加していくことで、より本格的なポケモン風ゲームを開発することができます。」

claude

GPT4o「もちろんです。まずは、Godotで主人公が草むらに入った際に野生ポケモンが出現する簡単なシステムを実装してみましょう。以下に、基本的なステップと具体的なコードを提示します。

### ステップ1: プロジェクトのセットアップ

1. **Godotプロジェクトの作成**:
- Godotを起動し、新しいプロジェクトを作成します。

2. **シーンの設定**:
- 新しい2Dシーンを作成し、これを`Main.tscn`として保存します。

### ステップ2: タイルマップの作成

1. **タイルセットの設定**:
- タイルセットを作成し、草むらタイルを含めます(例: `grass_tile`)。
- タイルセットのエディタで、草むらタイルにカスタムデータを設定します(例: `is_grass: true`)。

2. **タイルマップの配置**:
- シーンに`TileMap`ノードを追加し、先ほど作成したタイルセットを設定します。
- マップ上に草むらタイルを配置します。

### ステップ3: プレイヤーの設定

1. **プレイヤーノードの作成**:
- `KinematicBody2D`ノードをシーンに追加し、`Player`と名前を付けます。
- `Player`ノードに`Sprite`と`CollisionShape2D`を追加します。`Sprite`にはプレイヤーの画像を設定します。

2. **プレイヤーのスクリプト**:
- `Player`ノードに新しいスクリプトを追加します(`Player.gd`)。

```gdscript
extends KinematicBody2D

export var speed = 200

func _process(delta):
var velocity = Vector2()

if Input.is_action_pressed("ui_right"):
velocity.x += 1
if Input.is_action_pressed("ui_left"):
velocity.x -= 1
if Input.is_action_pressed("ui_down"):
velocity.y += 1
if Input.is_action_pressed("ui_up"):
velocity.y -= 1

velocity = velocity.normalized() * speed
move_and_slide(velocity)
```

### ステップ4: エリア検出と野生ポケモンの出現

1. **RayCast2Dの追加**:
- `Player`ノードに`RayCast2D`を追加し、足元に向けて設置します。

2. **出現判定のスクリプト**:
- `Player`ノードのスクリプト(`Player.gd`)に以下のコードを追加して、草むらタイル上にいるかどうかを検出します。

```gdscript
extends KinematicBody2D

export var speed = 200
onready var ray_cast = $RayCast2D
var grass_probability = 0.1 # 野生ポケモン出現確率

func _process(delta):
var velocity = Vector2()

if Input.is_action_pressed("ui_right"):
velocity.x += 1
if Input.is_action_pressed("ui_left"):
velocity.x -= 1
if Input.is_action_pressed("ui_down"):
velocity.y += 1
if Input.is_action_pressed("ui_up"):
velocity.y -= 1

velocity = velocity.normalized() * speed
move_and_slide(velocity)

# 出現判定
if ray_cast.is_colliding():
var collider = ray_cast.get_collider()
if collider is TileMap:
var tile_map = collider as TileMap
var cell = tile_map.world_to_map(ray_cast.get_collision_point())
var tile_data = tile_map.get_cell_data(cell)

if tile_data and tile_data.has("is_grass") and tile_data["is_grass"]:
if randi() % 100 < grass_probability * 100:
print("野生ポケモンが出現した!")
```

### ステップ5: シーンの接続

1. **シーンの保存**:
- すべての変更を保存し、`Main.tscn`シーンを実行時のメインシーンに設定します。

2. **インプットマッピング**:
- プロジェクトの設定でインプットマッピングを設定し、`ui_right`, `ui_left`, `ui_down`, `ui_up`に対応するキーを割り当てます。

### まとめ」

GPT4o


※確認したかった2つの質問はここまでですが、興味本位でもう一つ質問してみました。

「func start_battle():を実装してみてください。」
Claude-3.5-Sonnet「もちろんです。`start_battle()` 関数を実装して、簡単なバトルシーンへの遷移を行いましょう。まず、バトルシーンを作成し、そこへの遷移を実装します。

1. まず、新しいシーン "Battle.tscn" を作成します。

2. Battle.tscn (バトルシーン)

```gdscript
extends Node2D

func _ready():
print("バトルが開始されました!")
# ここにバトル開始時の初期化処理を追加

func _on_ExitButton_pressed():
# バトル終了時、メインシーンに戻る
get_tree().change_scene("res://Main.tscn")

# バトルシーンにボタンを追加し、以下のシグナルを接続
# func _on_ExitButton_pressed() と接続してください
```

3. Main.tscn のスクリプトを以下のように更新します:

```gdscript
extends Node2D

onready var player = $Player
onready var map = $Map

var steps_since_last_encounter = 0
var steps_per_encounter_check = 5

# トランジション用のColorRectを追加
onready var transition_rect = $TransitionRect
var is_transitioning = false

func _ready():
transition_rect.color = Color(0, 0, 0, 0) # 初期状態は透明

func _physics_process(delta):
if is_transitioning:
return

if player.velocity != Vector2.ZERO:
steps_since_last_encounter += 1

if steps_since_last_encounter >= steps_per_encounter_check:
check_for_encounter()
steps_since_last_encounter = 0

func check_for_encounter():
var encounter_rate = map.get_encounter_rate(player.global_position)
if randf() * 100 < encounter_rate:
start_battle()


func start_battle():
print("野生のポケモンが現れた!")
is_transitioning = true

# フェードアウトのトランジション
var tween = get_tree().create_tween()
tween.tween_property(transition_rect, "color", Color(0, 0, 0, 1), 0.5)
tween.tween_callback(self, "change_to_battle_scene")

func change_to_battle_scene():
# バトルシーンに遷移
get_tree().change_scene("res://Battle.tscn")


# Main.tscnにColorRectノードを追加し、TransitionRectという名前を付けてください
# ColorRectは画面全体を覆うように設定し、Z-Indexを最も高く設定してください
```

4. プロジェクト設定

プロジェクト設定で、自動ロードのタブに新しいシングルトンスクリプト "GameState" を追加します。

5. GameState.gd (新しいスクリプト)

```gdscript
extends Node

var player_position = Vector2.ZERO

func save_player_position(pos):
player_position = pos

func get_player_position():
return player_position
```

6. Main.tscn のスクリプトに以下を追加:

```gdscript
func start_battle():
print("野生のポケモンが現れた!")
is_transitioning = true

# プレイヤーの位置を保存
GameState.save_player_position(player.global_position)

# フェードアウトのトランジション
var tween = get_tree().create_tween()
tween.tween_property(transition_rect, "color", Color(0, 0, 0, 1), 0.5)
tween.tween_callback(self, "change_to_battle_scene")

func _ready():
transition_rect.color = Color(0, 0, 0, 0) # 初期状態は透明

# バトルから戻ってきた場合、プレイヤーの位置を復元
if GameState.player_position != Vector2.ZERO:
player.global_position = GameState.player_position
GameState.player_position = Vector2.ZERO # リセット
```

この実装により、以下の機能が追加されます:

1. エンカウント時にバトルシーンへの遷移
2. シーン遷移時のフェードエフェクト
3. バトル終了後にメインシーンに戻る機能
4. プレイヤーの位置の保存と復元

これにより、基本的なバトルシーンへの遷移とメインシーンへの復帰が実現されます。次のステップとしては、実際のバトルシステムの実装や、より詳細なポケモンデータの管理などが考えられます。」

claude

本当にざっと見たかんじ、多少のエラーはあれど大まかな筋はあっていて、かつ簡潔に知りたい情報をコンパクトに表示してくれるClaude-3.5-Sonnetに軍配が上がるような気がします。
特に、「では、簡単なところから実装していきます。具体的なコードも含めて提示してください。」の回答に大きく差が出ています。
GPT4oは確かに簡単なところから具体的なコードをつらつらと書いてくれてはいますが、とはいえ長いです。この質問の後、回答が途切れていたのでcontinueを繰り返しましたが、一向に戦闘の出現率やバトルシーンの切り替えを教えてくれず、精度もどんどん落ちていました。

私の質問が悪いというのもあると思うのですが、より欲しい情報を制度の悪い質問でも渡してくれたのは(生産性が良いのは)Claude-3.5-Sonnetdでした。

後、Claude-3.5-Sonnetのおもしろい個所として太字のfunc check_for_encounter():部分で、しっかりと草むらで出現するポケモンの確率や、バトルシーンを呼び出す際にキャラクターの現在地を取得する、少し細かめの設計まで意識していました。※キャラクターの現在地を取得については私も漏れてました、、

ついで、GPT4oはすぐにコードを書こうとしますが(悪いことではないのですが。)、Claudeは簡潔に文字で最初に教えてくれる傾向も個人的には設計がまとまるので使用しやすいです。

感想

すごい。正直GPT4oを上回っている可能性はあると思います。
私としてはこれが本当に上回っているのか、今後も引き続き調査します。
いよいよ、「ポケモン作って」で全てを作ってくれる未来も近いのかもしれません。。

ご高覧ありがとうございました。


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

#AIとやってみた

28,811件

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