
AIと作る「ブロック自動配置の重なり防止システム」

前回は、ローグライクなテニスゲームを目標に、AIと一緒にブロック自動配置システムを作った。
今回は、ブロックが重なったり、画面外に配置されるのを修正する。
アドバイザーのAIはCopilotさん
ブロックの重なり防止
ブロックが重なったり画面外に出たりしていたので、まずは重ならないようにする方法を聞いた。
ブロックが重ったら再設定しなおすようにしたい
了解しました!Y方向がランダムで、ブロックが重ならないように配置するための方法をご紹介します。ブロックが重ならないかを確認し、重なっている場合は再設定するようにします。
このコードでは、is_overlappingという関数を使って新しいY位置が既存のブロックと重なっていないかを確認します。重なっている場合は新しいY位置をランダムに再設定し、重ならない位置が見つかるまで繰り返します。
Create Event
// 変数の定義
var grid_size = 10;
var blocks_per_side = argument0; // ブロックの個数を引数で指定
var x_range = argument1; // X方向の範囲を引数で指定
var center_x = room_width / 2;
var offset_x;
var random_y;
var y_positions = []; // 生成されたY位置を保持する配列
function is_overlapping(new_y) {
for (var i = 0; i < array_length(y_positions); i++) {
if (abs(_new_x - x_positions[i]) < obj_block.sprite_width && abs(_new_y - y_positions[i]) < obj_block.sprite_height) {
return true; // 重なっている場合
}
}
return false; // 重ならない場合
}
// 左右対称にブロックを生成(X方向は指定された範囲内、Y方向はランダム)
for (var i = 0; i < blocks_per_side; i++) {
offset_x = (i + 1) * (x_range / blocks_per_side); // 範囲に基づいてオフセットを計算
repeat {
random_y = random(room_height);
} until (!is_overlapping(random_y)); // 重ならないY位置が見つかるまで繰り返す
y_positions[i] = random_y; // 新しいY位置を配列に追加
// 左側のブロック
instance_create_layer(center_x - offset_x, random_y, "Instances", obj_block);
// 右側のブロック
instance_create_layer(center_x + offset_x, random_y, "Instances", obj_block);
}
言われた通りにコードを記述。
だが、新しい関数やvarのせいで、修正に鬼のように時間がかかるとは、この時点では思っていなかった。( ;∀;)
問題が続々登場
①array_lengthは、varで設定したら使えなかったので、varを外した。
array_lengthは、配列の長さを取得するためのGame関数。
配列に含まれている要素の数を返す。
y_positions = [1,2,3,4,5]; という配列があったとしたら、
array_length(y_positions); は5個になるということ。
しかし、Copilotさんの言う通り、varでy_positionsを設定するとエラー。
varの使い方がが分かっていない俺のせいだが、凄い嫌いになった。
varを絶対使わなければ動かない所だけvarにして他は普通の定義に戻す。
今は動けばいい。
②repeat, until , while, go , forが動いたり動かなかったり
知らん構文は、ことごとくAIの言う通りには動かない。。。
今回は前から知ってるforとwhileを使ってなんとか動かした。
③function+何かで混乱
これもたぶん、分かったら楽になるんだろうな。
function is_overlappingで重なっているかどうかを判定するとのこと。
④Y方向だけしか重なりチェックしていないのに気づかなかった
もう聞くのも面倒なので、自力でxもyもチェックするように修正。
ブロックのスプライトの大きさでチェックするように修正。
⑤Y座標が画面に出てしまうので補正する
画面外に出ないように補正するようにCopilotさんに聞いたら、画面外に出た時に、画面端ギリギリの値を突っ込んでしまえという風に言われ、スゲーと思った。1回その座標で確定してしまえば、次からの重なりチェックでそこがはじけるわけね。やるね、Copilotさん。
Copilotさんに動作確認してバグ修正する機能欲しい
結局、テスト用のワークスペースを作って、そこで地道に1個づつ動作確認しながら構造を理解するというので時間をかなり消費した。だるー。
ということで、ブロックの自動配置がなんとか完成。

本当は、ボールの通路を何か所か開けるとか、巻き込みダメージ与えられるようにある程度固めるとかの仕様追加は必要だが、そこは、次回、「BlockTennis」とガッチャンコしてから調整しよう。
今日もありがとう。Copilotさん。
もっと勉強しないと、動かなかった時に全然わからん。
Copilotさんの方でコードの実装確認してから教えてくれればいいのに。
しかし、この自動生成システムは小さな一歩だけが、たぶん、スゲーの作れるわ。ヤベーな俺。
自動生成の移り変わり



ブロック配置の重なり防止サンプルプログラム
obj_generate の Create Event(作成)
/// @description 説明をここに挿入
// このエディターでコードを作成することができます
// 重なりを判定する関数
grid_size_x = 20;
grid_size_y = 10;
blocks_per_side = 10;
x_range = 60;
center_x = room_width / 2;
x_positions = []; // 既存のブロックのx座標
y_positions = []; // 既存のブロックのY座標
var _new_x; // 新しいブロックのx座標
var _new_y; // 新しいブロックのY座標
randomize();
// 重なりを判定する関数
function is_overlapping(_new_x, _new_y) {
for (i = 0; i < array_length(x_positions); i++) {
if (abs(_new_x - x_positions[i]) < grid_size_x && abs(_new_y - y_positions[i]) < grid_size_x) {
return true; // 重なっている場合
}
} return false;// 重ならない場合
}
for (i = 0; i < blocks_per_side; i++)
{
_new_x = irandom(x_range/grid_size_x) * grid_size_x;
_new_y = irandom(room_height/grid_size_y) * grid_size_y;
// ブロックが重ならなくなるまでやりなおす。
while (is_overlapping(_new_x, _new_y))
{
_new_x = irandom(x_range/grid_size_x) * grid_size_x;
_new_y = irandom(room_height/grid_size_y) * grid_size_y;
}
// 画面外に出てしまった場合の再設定
if (_new_y < 10) _new_y = 10;
if (_new_y > room_height - 10) _new_y = room_height - 10;
x_positions[i] = _new_x;
y_positions[i] = _new_y;
// 左側のブロック
instance_create_layer(center_x - _new_x - grid_size_y, _new_y, "Instances", obj_block);
// 右側のブロック
instance_create_layer(center_x + _new_x + grid_size_y, _new_y, "Instances", obj_block);
}
if (is_overlapping(_new_x, _new_y)) {
show_debug_message("新しいブロックは既存のブロックと重なります");
}
else { show_debug_message("新しいブロックは既存のブロックと重なりません");
}
たったこれだけなのに、凄い時間かかったよ。( ;∀;)
それにしても、Copilotさんから長い記事は読まれないと言われたのに、コードつけると4300文字ぐらいになっちゃうな。コードだけで2300文字。
しばらく、コードなしで行くか。