本記事について
ChatGPT APIを利用してコードを生成し、それを動的に実行することでtoioを動かした記事
chatgptで動的にコード実行する参考にはなるかもしれない。
成果物1 toioを1台動かす。Simulation
プロンプト
cube1: patrol random 3 points once
生成されたコードを表示(折りたたみ)
function routine()
cubeCommand:ShowMessage('Starting patrol')
-- Define 3 random points
local points = {}
for i=1,3 do
local x = math.random(100, 400)
local y = math.random(100, 400)
table.insert(points, {x=x, y=y})
end
-- Move to each point and wait for 1 second
for i, point in ipairs(points) do
coroutine1 = startCoroutine(cubeCommand:Navi2TargetCoroutine('cube1', point.x, point.y))
coroutine.yield(coroutine1)
coroutine.yield(CS.UnityEngine.WaitForSeconds(1))
end
cubeCommand:ShowMessage('Patrol finished')
end
成果物2 toioを2台で相撲してみる。Real
相撲をしてください。
配置はNavi, 突撃するときはMoveを1s使ってください。
勝敗はどちらかが勝つように決めてください。
負けた方は四隅のどこかに飛ばされてください。
## Cube1
技: フェイント
少し前に進み、すぐ後ろに下がる
## Cube2
技: spin
cube2がspinすると半径50以内にいる相手は吹き飛んで負けます。
## 相撲の流れ
1. スタートポジションにつく。 cube1がtop側 y300、cube2がbottom側でy200
2. 対峙する (cube1はdeg -90、cube2はdeg 90) Use Rotate2DegCoroutine
3. 0.5秒待つ
4. 「はっけよーい」のメッセージ
5. 0.5秒待つ
6. のこった!のメッセージ
7. それぞれのCubeが正面に向かって突撃する Use 「cubeCommand:Move」両方ともspeed 70(not minus)
8. 0.2秒待つ
9. 後ろに下がる
10. 0.2秒待つ
11. それぞれ技を出してください。
12. 0.2秒待つ
13. どちらかが負けて吹き飛ばされてください。
14. 0.1秒待つ
15. 負けた方がspinしてください。
16. 勝敗宣言をしてください
突撃にはMoveを使用してください。突撃でNavi2Targetは使用しないでください。
生成されたコードを表示(折りたたみ)
function routine()
-- スタートポジションにつく
coroutine1 = startCoroutine(cubeCommand:Navi2TargetCoroutine('cube1', 250, 300))
coroutine2 = startCoroutine(cubeCommand:Navi2TargetCoroutine('cube2', 250, 200))
coroutine.yield(coroutine1)
coroutine.yield(coroutine2)
coroutine.yield(CS.UnityEngine.WaitForSeconds(0.5))
-- はっけよーい
cubeCommand:ShowMessage('はっけよーい')
coroutine.yield(CS.UnityEngine.WaitForSeconds(0.5))
-- のこった!
cubeCommand:ShowMessage('のこった!')
coroutine.yield(CS.UnityEngine.WaitForSeconds(0.5))
-- 突撃
coroutine1 = startCoroutine(cubeCommand:Move('cube1', 100, 100, 1000))
coroutine2 = startCoroutine(cubeCommand:Move('cube2', -100, -100, 1000))
coroutine.yield(coroutine1)
coroutine.yield(coroutine2)
-- 技を出す
coroutine1 = startCoroutine(faint, 'cube1')
coroutine2 = startCoroutine(spin, 'cube2')
coroutine.yield(coroutine1)
coroutine.yield(coroutine2)
-- 勝敗宣言
if cubeCommand:GetCubePosY('cube1') > cubeCommand:GetCubePosY('cube2') then
cubeCommand:ShowMessage('cube1の勝ち!')
coroutine.yield(startCoroutine(cubeCommand:Navi2TargetCoroutine('cube2', 50, 50)))
else
cubeCommand:ShowMessage('cube2の勝ち!')
coroutine.yield(startCoroutine(cubeCommand:Navi2TargetCoroutine('cube1', 450, 450)))
end
end
function faint(id)
-- フェイント
coroutine.yield(CS.UnityEngine.WaitForSeconds(0.1))
coroutine1 = startCoroutine(cubeCommand:Move(id, 100, 100, 500))
coroutine.yield(coroutine1)
coroutine.yield(CS.UnityEngine.WaitForSeconds(0.1))
coroutine2 = startCoroutine(cubeCommand:Move(id, -100, -100, 500))
coroutine.yield(coroutine2)
end
function spin(id)
-- spin
coroutine.yield(CS.UnityEngine.WaitForSeconds(0.1))
coroutine1 = startCoroutine(cubeCommand:Move(id, 60, -60, 200))
coroutine.yield(coroutine1)
coroutine.yield(CS.UnityEngine.WaitForSeconds(0.1))
coroutine2 = startCoroutine(cubeCommand:Move(id, -60, 60, 200))
coroutine.yield(coroutine2)
coroutine.yield(CS.UnityEngine.WaitForSeconds(0.1))
coroutine3 = startCoroutine(cubeCommand:Move(id, 60, -60, 200))
coroutine.yield(coroutine3)
-- 判定
if math.sqrt((cubeCommand:GetCubePosX('cube1') - cubeCommand:GetCubePosX('cube2'))^2 + (cubeCommand:GetCubePosY('cube1') - cubeCommand:GetCubePosY('cube2'))^2) < 50 then
cubeCommand:ShowMessage(id .. 'の勝ち!')
if id == 'cube1' then
coroutine.yield(startCoroutine(cubeCommand:Navi2TargetCoroutine('cube2', 50, 50)))
else
coroutine.yield(startCoroutine(cubeCommand:Navi2TargetCoroutine('cube1', 450, 450)))
end
end
end
リポジトリ
クライアント
サーバー
仕組み
unity側のロジックは以下
サーバーのロジックは以下みればだいたい書いてある。
知見
コード以外のものを含めてくる問題
=> 「```」で囲まれたコードブロックとってくることで対処
chatgptが生成するluaのバージョンが低く、廃止されているメソッドを生成してしまう。(math.atan2)
=> 幸い置換(math.atan2 => math.atan)でなんとかなった。
while trueで無限ループしたり、実行するとフリーズするやばいコードを作ってくる時がある。
=> while true禁止を指示しても使うため防ぐのなかなか厳しい。
同期的に呼ぶ関数を非同期に呼ぼうとする。
=> 非同期な呼び方をしても大丈夫なように同期メソッドを作る。
非同期な並列処理も自動生成できるけど精度かなり落ちる
=> 複数台動かすといった処理の生成が向いてない。
chatgptが生成するコードは単語のイメージに強く依存する。
toioは専用のマットの上だと自分の位置の絶対座標が取得できる。
で、その絶対座標は左上原点のため「topに行くほどYの値が小さくなる」
「top」という単語には正のイメージがあるらしく、
そのままこの座標を使うと、「go left top」でleft bottomに進むコードが
生成されがちになる。
そのため、左下原点の位置をもらうのが有効
// NOTE: 左上原点の座標系だとchatgptの精度落ちるため左下原点の座標系での点をもらう。
double ReversePosY(double y)
{
return 500 - y;
}
関連
xLua の使い方