GameMakerでAIと一緒に作る「卓球」
前回はAIと一緒にブラウザで動く「卓球」を作ってみた。
ダメもとでAIにGameMakerでプログラムできるか聞いてみたら、できるというので、今回は、以前に自力で作った「卓球」を目標に、AIと一緒に、GameMakerで「卓球」を作ってみる。
自力で作った「卓球」
AIはCopilotさん
GamaMakerで「卓球」を作る
早速、お願いしてみる。
スプライトの作成
以前、自力で作ったボール、パドル、背景を用意。
スプライトを右クリックすると、メニューの中に「既存の物を追加」と出てくるので、そこから追加ができる。
ない場合は、Copilotの言う通りの長方形と円をツールを使って描けばOK。
オブジェクトの作成
プレイヤーオブジェクトのコード(obj_player)
Create Event(作成)
// Create Event
x = 20;
y = room_height / 2 - sprite_height / 2;
Step Event(ステップ)
// Step Event
if (keyboard_check(vk_up)) {
y -= 5;
}
if (keyboard_check(vk_down)) {
y += 5;
}
y = clamp(y, 0, room_height - sprite_height);
コンピュータオブジェクトのコード(obj_computer)
Create Event(作成)
// Create Event
x = room_width - 30;
y = room_height / 2 - sprite_height / 2;
Step Event(ステップ)
// Step Event
if (obj_ball.y < y + sprite_height / 2) {
y -= 5;
} else if (obj_ball.y > y + sprite_height / 2) {
y += 5;
}
y = clamp(y, 0, room_height - sprite_height);
ボールオブジェクトのコード(obj_ball)
Create Event(作成)
// Create Event
x = room_width / 2;
y = room_height / 2;
speed = 5;
direction = choose(0, 180); // 左右どちらかに発射
Step Event(ステップ)
// Step Event
x += lengthdir_x(speed, direction);
y += lengthdir_y(speed, direction);
// 壁の反射
if (y <= 0 || y >= room_height) {
direction = 360 - direction;
}
// プレイヤーとの衝突
if (place_meeting(x, y, obj_player)) {
direction = 180 - direction + irandom_range(-10, 10);
speed *= 1.1;
}
// コンピュータとの衝突
if (place_meeting(x, y, obj_computer)) {
direction = 180 - direction + irandom_range(-10, 10);
speed *= 1.1;
}
// スコア更新
if (x <= 0) {
obj_computer.score += 1;
game_restart();
} else if (x >= room_width) {
obj_player.score += 1;
game_restart();
}
スコア表示のためのコード(Draw GUI Event)
draw_text(50, 50, string(obj_player.score));
draw_text(room_width - 50, 50, string(obj_computer.score));
ルームの設定
ここで、スコアの描画にエラーが発生した。
このエラーについて、Copilotに直してもらおうとして何回か修正願いを出したが、改善しないので、今までのようにobj_controlを作って解決した。
コントロールオブジェクトのコード(obj_control)
Create Event(作成)
// Creat Event
obj_computer.score = 0;
obj_player.score = 0;
Draw Event(描画)
// Draw Event
draw_text(100, 20, string(obj_player.score));
draw_text(room_width - 100, 20, string(obj_computer.score));
これで起動すると、スコア表示が変わらなかった。
obj_ball内の「// スコア更新」の所が、game_restart()で毎回リセットされるので、ここを変更。
obj_ballのstep eventのスコア更新を以下に変更
// スコア更新
if (x <= 0) {
obj_computer.score += 1;
x = xstart; // x初期位置
y = ystart; // y初期位置
speed = 3; // スピードを初期値に戻す
} else if (x >= room_width) {
obj_player.score += 1;
x = xstart;
y = ystart;
speed = 3; // スピードを初期値に戻す
}
実行すると以下になった
AIと一緒に仕様を追加
ここから少し調整を入れる
勝利とサーブ権の追加
ここから、前回のブラウザ版でも行った修正をお願いしてみる。
むむむ。Copilotさん!?
前のエラーが出たスコアの所も含めて、全部コードを出してくるよ。
AIのコードを修正する
スコアだけでなく、色んな不具合が出たので自力で修正した。
AIと一緒に作った卓球の最終形
結果、以下のようになった。
GameMakerの最新コードは未対応?
Copilotも俺もGameMakerの理解が不十分なので、それぞれのやりたいことが嚙み合わなかったみたい。
こっちは、日本語にローカライズされ、新機能に対応したGameMakerを使っているが、copilotは古いのしか対応してなさそう。
最新のGameMakerには「コリジョン」や「境界線」や「キーを押した時」など色んなイベントがあるのだが、copilotはステップイベントの中で全部やろうとするので、不具合が起きても、俺が理解できない
今回は、自力でコードを書いていたので直すことができた。
コードを全然触ったことなければ、GameMakerで作るのは、おススメできないかな。
UnityやHTML、JAVAとかの方が、AIにコード書いてもらいやすいかもしれない。他の言語も今後は試してみよう。
AIはサンプルプログラムやアドバイスには使えるかも?
1から自分で調べて自力でコードを書くよりは楽。
サンプルコードをもらって、それを元に、自分でコードを書く形で、しばらくやってみようと思う。まさに、共同作業だ。
AIの使い方①:AIに解説してもらう
サンプルプログラムの内容を解説してもらう。
説明は丁寧で、コードを書いていれば理解できる。
// Reset ball function
function reset_ball(losing_side) {
gameStarted = false;
launchingPlayer = losing_side;
x = room_width / 2;
y = room_height / 2;
speed = 5;
}
// スコア更新
if (x <= 0) { // プレイヤーがボールをロスト
obj_computer.score += 1;
if (obj_computer.score >= 5) {
show_message("Computer Wins!");
game_restart();
} else {
reset_ball(obj_computer); // コンピュータが次にボールを発射
}
} else if (x >= room_width) { // コンピュータがボールをロスト
obj_player.score += 1;
if (obj_player.score >= 5) {
show_message("Player Wins!");
game_restart();
} else {
reset_ball(obj_player); // プレイヤーが次にボールを発射
}
}
if (!gameStarted) {
if (launchingPlayer == obj_player) {
x = obj_player.x + obj_player.sprite_width;
y = obj_player.y + obj_player.sprite_height / 2;
} else if (launchingPlayer == obj_computer) {
x = obj_computer.x - sprite_width;
y = obj_computer.y + obj_computer.sprite_height / 2;
}
if (mouse_check_button_pressed(mb_left)) {
gameStarted = true;
if (launchingPlayer == obj_player) {
direction = 0; // 右に発射
} else {
direction = 180; // 左に発射
}
}
}
最終的なコードのサンプル
以下、今回作ったコードのサンプル。
コントロールオブジェクトのコード(obj_control)
Create Event(作成)
// Creat Event
obj_computer.score = 0;
obj_player.score = 0;
Draw Event(描画)
// Draw Event
draw_text(100, 20, string(obj_player.score));
draw_text(room_width - 100, 20, string(obj_computer.score));
プレイヤーオブジェクトのコード(obj_player)
Create Event(作成)
// Create Event
image_blend = c_aqua; // プレイヤーのパドルの色を水色に指定
x = xstart; // xスタート位置をルームに設定した場所に指定
y = ystart; // yスタート位置をルームに設定した場所に指定
spd = 7; // 移動スピード
Step Event(ステップ)
// Step Event
if (keyboard_check(vk_up)) { // 上矢印で上に移動
y -= spd;
}
if (keyboard_check(vk_down)) { // 下矢印で下に移動
y += spd;
}
y = clamp(y + speed, sprite_height /2, room_height - sprite_height /2); // めり込み対策を中心点からに変更
コンピュータオブジェクトのコード(obj_computer)
Create Event(作成)
// Create Event
image_blend = c_red; // CPUのパドルカラーを赤に
// Create Event
x = xstart; // ルームに置いた位置を初期位置に設定
y = ystart; // ルームに置いた位置を初期位置に設定
spd = 5; // 移動スピード
Step Event(ステップ)
// Step Event
if (obj_ball.start_game == true) // ボールがリリースされると移動を開始
{
if (obj_ball.y < y - sprite_height / 4) { // ボールの位置が上の時は上に移動
y -= spd;
} else if (obj_ball.y > y + sprite_height / 4) { // ボールの位置が下の時は下に移動
y += spd;
} else speed = 0; // ボールに追いついたら止まる
y = clamp(y + speed, sprite_height /2, room_height - sprite_height /2); // 画面外対策
}
ボールオブジェクトのコード(obj_ball)
Create Event(作成)
// Create Event
spd = 3; // ボールの初期スピード
a_spd = 0.3; // パドルに当たった時の加速度
speed = spd;
randomize(); // 完全ランダム
// 最初にボールを発射するプレイヤーを抽選
if (irandom(1) = 0) launch_player = obj_player;
else launch_player = obj_computer;
start_game = false; // ゲーム開始しているか?
// Reset ball function ボールをロストした時の設定
function reset_ball(_losing_side) {
start_game = false;
launch_player = _losing_side;
speed = spd;
}
// Game restart function ゲームのリスタート設定
function game_restart() {
instance_destroy(); // すべてのインスタンスを削除して再生成
room_restart(); // ルームを再起動
}
Step Event (ステップ)
// Step Event
// ロストした方からスタート
if (start_game == false) {
if (launch_player == obj_player) {
x = obj_player.x + obj_player.sprite_width + 10;
y = obj_player.y ;
} else if (launch_player == obj_computer) {
x = obj_computer.x - obj_computer.sprite_width - 10;
y = obj_computer.y;
}
} else {
x += lengthdir_x(speed, direction);
y += lengthdir_y(speed, direction);
// 壁の反射
if (bbox_bottom > room_height or 0 > bbox_top)
{
vspeed = -vspeed; // 壁に当たったら縦方向の速度を反転
y = clamp(y, sprite_yoffset, room_height-sprite_yoffset); // 潜らない対策の中心点補正
}
// スコア更新
if (x <= 0) {
obj_computer.score += 1; // プレイヤーが後逸したらCPUに得点追加
if (obj_computer.score >= 5) {
show_message("Computer Wins!"); // 5点取ったらメッセージを表示してリスタート
game_restart();
} else {
reset_ball(obj_player); // プレイヤーにサーブ権
}
} else if (x >= room_width) {
obj_player.score += 1; // CPUが後逸したらプレイヤーに得点追加
if (obj_player.score >= 5) {
show_message("Player Wins!"); // 5点取ったらメッセージを表示してリスタート
game_restart();
} else {
reset_ball(obj_computer); // コンピューターにサーブ権
}
}
}
press key space event(キープレス・スペース)
if (start_game == false){
start_game = true;
if (launch_player == obj_player) {
direction = 0; // 右に発射
} else {
direction = 180; // 左に発射
}
}
Collision Event(obj_computer)
direction = point_direction (other.x, other.y, x, y); // 中心点同士を結ぶ方向に反射
speed += a_spd; // 加速
Collision Event(obj_player)
direction = point_direction (other.x, other.y, x, y); // 中心点同士を結ぶ方向に反射
speed += a_spd; // 加速