ChatGPTにclusterのスクリプトを書いてもらう方法
はじめに
やっほ〜、さなだよ.
2022年の10月、clusterではスクリプトを使ったギミックが実装された.
CCKで複雑なロジックを簡単に書けるようになったり、位置や速度に関わるギミックの幅が広がった. その影響は半年経った今でも測りきれず、模索開拓が捗るばかり.
特にワールドクラフトでのアイテム制作は大きな影響を受けた. それまでただアイテムを配置することしかできなかったものが、スクリプトの実装によって、動くアイテムやトリガーを使ったアイテムを作ることができるようになった. 実装から1週間後に行われたGAMEJAMではそれを活かしてダイナミックなアスレチックやシューティングゲームも制作された.
GAMEJAM 2022 in autumn 準大賞
ひょろも さん作 「3つのはかりごとアスレチック」
スクリプトを全面に活かしたアスレチックで、動く歯車に消える床…さまざまなギミックを超えてゴールを目指すワールド.
設置されているタイマーを使えば、クリアタイムを「測る」こともできる
GAMEJAM 2022 in autumn ??? 賞
さな 作 「Aim Ring!」
私は私で、どうせならワールドクラフトで今までとは全く違うゲームを作ってみようと思い、簡単なシューティングゲームに挑戦した.
ワールドクラフトにおけるプログラミングのハードル
そんなこんなで制作の幅が大きく広がったワールドクラフトなのだけど、そこでのスクリプトの扱いは結構曲者かもしれない. というのも、Unityの導入だのCCKのロジックだの複雑なことをせずに簡単に創作ができるのがワールドクラフトの第一の強みだと思う. それに対して、スクリプトでギミックを作るのは、UnityでCCKを使ってギミックを作るより難しい気がする.
正直、ワールドクラフトでシューティングゲームを作ってみた第一の感想は「UnityとCCKで作った方が絶対簡単だしもっと面白いものが作れる」というものだ.
ChatGPTがすごい
ところで、最近は自然言語処理AIの発展が目覚ましい. 2022年の12月頃にOpenAI社が公開した「ChatGPT」は、人間らしい会話や文章の要約、はてはプログラミングまでこなすことができる.
そのあまりの「知能」の高さに、機械的な単純作業だけでなく多くの知的生産がAIに代替されうると話題である.
…それなら、clusterのスクリプト書いて貰うこともできるんじゃない?
そう思い至ったのが今回の試みである.
(と言いつつ実際はW@さんの試みにインスパイアされたところが大きい)
ChatGPTにclusterのスクリプトを書いてもらう
clusterで使われるスクリプトについて
clusterでスクリプトアイテムを動かすためのコードは、Javascriptというプログラミング言語をベースにしている. そしてChatGPTはJavascriptのプログラミングもきっちりマスターしている.
ただ「clusterのスクリプトアイテムを動かすためのコードをjavascriptで書いて」と単純にお願いしてもまともに動くコードを返してはくれない. cluster javascriptには、アイテムをUseしたときに動くようなclusterのギミックシステムに合わせた独自の機能が追加されており、また逆に制約もある.
そして現状、ChatGPTも流石にcluster javascriptの独自仕様までは学習していない. そのため、その辺の文法はきっちり教えてあげる必要がある.
プロンプト
cluster javascriptの文法をある程度まとめて記載し、欲しいアイテムの要件と一緒に提示したプロンプトが以下のものである.
あなたはプロのプログラマーです
cluster javascriptという、cluster内でアイテムを操作するための言語を用いてプログラミングしてください
##要求するアイテム
x軸方向に周期5秒振幅5mで振動するアイテム
##cluster javascriptの仕様
#イベント関数
cluster javascriptでは、処理を実行するタイミング別に関数が分かれています
以下のイベント関数のみ使用できます
$.onUpdate(deltaTime => {
//ここに毎フレーム行われる処理を記述
});
$.onGrab(isGrab => {
if(isGrab){
//ここにアイテムを持ったときに行われる処理
}else{
//ここにアイテムを放したときに行われる処理
}
});
$.onUse(isDown => {
if(isDown){
//ここにアイテムをUseしたときに行われる処理
}
$.onInteract(() => {
//ここにアイテムにInteractしたときに行われる処理
});
$.onRide(isGetOn => {
if(isGetOn){
//ここにアイテムに乗ったときに行われる処理
}else{
//ここにアイテムから降りたときに行われる処理
}
});
#ステート変数
cluster javascriptではグローバル変数を用いることができず、代わりにステート変数を使います
ステート変数には、boolean, integer, float, Vector3を代入することができます
ステート変数はonUpdate関数の中で初期値を宣言する必要があります
例えば、乗っている間の時間を計測するアイテムのスクリプトは以下のようになります
$.onUpdate(deltaTime => {
if (!$.state.initialized) {
$.state.initialized = true;
$.state.riding = false;
$.state.time = 0;
}
if ($.state.riding){
$.state.time += deltaTime;
}
});
$.onRide(isGetOn => {
if(isGetOn){
$.state.riding = true;
$.state.time = 0;
}else{
$.state.riding = false;
}
});
#3次元ベクトルの操作
let a = new Vector3(0,0,0);
a = a.clone().add(b); //ベクトルaにベクトルbを加える
a = a.clone().sub(b); //ベクトルaからベクトルbを引く
a = a.clone().multiply(b); //ベクトルaにベクトルbをかける
a = a.clone().divide(b); //ベクトルaをベクトルbで割る
a = a.clone().length() //ベクトルaの長さをcに代入
a = a.clone().addScalar(b); //ベクトルaの各要素にスカラーbを加える
a = a.clone().subScalar(b); //ベクトルaの各要素からスカラーbを引く
a = a.clone().multiplyScalar(b); //ベクトルaの各要素にスカラーbをかける
a = a.clone().divideScalar(b); //ベクトルaの各要素をスカラーbで割る
a = new Vector3(a.x, a.y+1, a.z); //ベクトルaの一部の要素の操作
#アイテムの位置・回転の操作
アイテムのxyz座標をVector3で取得
let ownposi = $.getPosition();
アイテムを(0,0,0)に移動
$.setPosition(new Vector3(0,0,0));
アイテムのオイラー角をVector3で取得
let ownrot = $.getRotation().createEulerAngles();
アイテムをオイラー角(0,0,0)となるように回転
$.setRotation(new Quaternion().setFromEulerAngles(new Vector3(0,0,0)));
#注意
a.y += 1というようにベクトルの要素を直接操作する代わりに、a = new Vector3(a.x+1, a.y, a.z)というようにベクトルを再度生成してください
a.clone().add(b)というようにベクトルの演算だけを行う代わりに、a = a.clone().add(b)というように演算結果を明確に変数に代入してください
a.clone().add(b)というようにベクトルの演算だけを行う代わりに、a = a.clone().add(b)というように演算結果を明確に変数に代入してください
出力結果
このプロンプトをChatGPTに入力すると、以下の返答が得られた.
ご丁寧にコードの中身の解説までしてくれている.
ではこれは本当にclusterの中でまともに動くコードなのか.
試してみよう.
実行結果
Cubeがきちんと5秒かけて振幅5mの振動をするように動いた.
考察
ChatGPTにcluster javascriptの独自仕様を教えることで、Cubeを指定した条件で振動させるコードを書いてもらうことができた.
##要求するアイテム の部分を書き換え他の動き方を指定することも可能だ.
ただ、提示したプロンプトはまだ完全ではない.
まず、cluster javascriptの全ての機能・制約を網羅しているわけではない. これは全ての機能を盛り込もうと指示を長くしすぎると返答が悪くなるためだ.
このプロンプトで教えていることは
・onUpdate, onInteract, onGrab, onUse, onRideのトリガー
・ステート変数の使い方(値を記憶する方法)
・アイテム自身の移動・回転のさせ方
に限定される.
$.subNodeを使った子オブジェクトの操作などは教えていないことに注意してほしい.
また、javascriptに搭載されているがclusterでは使えない関数や、教えたものに似ているがcluster内では使えない関数を交えたコードを返すことがある.
$.getVelocity()とか…確かに$.getPosition()や$.getRotation()があるのだからありそうではある.
他にも、文法的な誤りはないが単純にコードの設計をミスして、無限の彼方へ飛んでいってしまうアイテムを生むこともある.
ただ、何度か返答を再生成してもらうと、どこかで動くコードを出してくれるのでプロンプト次第でこのあたりの制約は解消できそうである. 教える範囲の制約も、より効率の良い文字数の少ないプロンプトや教える範囲を分けて段階的に文法を教えることができれば解消できそうである.
また、私はWeb上で無料で使えるGPT-3.5版で試してみたのだが、有料のGPT-4版でどのような結果になるのかも気になるところ.
ChatGPTにclusterのスクリプトを書いてもらう方法
ChatGPTにclusterのスクリプトを書いてもらう方法をまとめると以下のようになる.
上述のプロンプトの ##要求するアイテム の部分を欲しいアイテムの要件に書き換える.
書き換えたプロンプトをChatGPTに入力する.
返されたスクリプトをcluster内のスクリプトアイテムに入力する. この際、アイテムが無限の彼方へ飛んでいく可能性もあるため、正常な動作を確認するまでは必ずテスト用の使い捨てのワールドを使って欲しい.
アイテムが思ったように動かなかった場合、ChatGPTの返答部分にある Regenerate response を押して再度スクリプトを生成してもらう. そして3の手順を繰り返す. (まあわざわざ試さなくても、公開されているサンプルスクリプトと比べておかしいと分かれば再生成してもらえばいい)
正常な動作を確認したら、本番用のワールドにスクリプトアイテムを設置する
繰り返しになるが提示したプロンプトもここでまとめた手法も完璧ではない.
色々なアイテム, プロンプト, 実行手法を試すことで新たな発見があると思う.
追記
より良いプロンプトを模索していく記事を用意しました.
良さげなのを見つけ次第掲載していきます.
宣伝
新作ワールド「CubeEx」を公開しました
こちらUnity制作の、スクリプトを活かした完全オートエイム・ステータス操作自在の対戦ゲームになっています. 友達を誘ってぜひ遊んでみてね.
おまけ
Github Copilot
要件をもとに0からスクリプトを組んでくれるChatGPTを紹介したが、実はプログラミングを補助してくれるAIは他にもある. Github Copilot という、ChatGPTを開発するOpenAIがGithubと協力して作ったコード提案ツールだ.
この画像は左右に動くアイテムを作るコードを途中まで入力したもの. そして、Github Copilotはその流れから続くコードを予測し、(左右ではなく前後だが)動くアイテムを作るコードを提案してくれている.
面白いのは、私はこの Github Copilot に対しcluster javascript の文法を全く教えていない. 恐らく使っているエディタに入っている他のファイルからスクリプトを読み取り、自動で cluster javascript の独自仕様を学んでいる.
ChatGPTに懇切丁寧に文法を教えずとも、公開されているスクリプトアイテムのサンプルコードをエディタに入れるだけで良い感じに必要なコードを提案してくれるかもしれない.
スクリプトを0から作るツールとしての可能性は未開拓だが、少なくとも補助ツールとしては有用であることを、CubExの開発の中で実感している.
Github Copilot は月10ドル、60日の無料トライアルで提供されている(学生や一部の開発者は無料). ぜひお試しあれ.
この記事が気に入ったらサポートをしてみませんか?