GameMaker 日本語掲示板

スクリプトに引数として配列を渡した時の挙動について

4 コメント
views
16 フォロー

https://www.wikihouse.com/GameMaker/index.php?%C7%DB%CE%F3%A4%CB%A4%C4%A4%A4%A4%C6#a74251b1
上記wikiの"より高度な配列の機能"の箇所で、

"配列はスクリプトに渡す際に、参照を渡すのではなくコピーしたものを渡していることに注意が必要です。つまり、引数として渡した配列の中身を変更した場合は、戻り値としてその配列を返す必要があります。"

とありますが、現バージョン(v2.3.1.409)ではスクリプト内で配列の値に変更をかけると、戻り値を返していないにも関わらず呼び出し元の配列の値が書き換わってしまいます。
これは仕様なのでしょうか?

サクレ
作成: 2020/12/25 (金) 22:47:32
通報 ...
1
ディーン 2020/12/26 (土) 03:15:09

2.3から仕様が変わったのかと思って簡単に調べました。

IDE:2.3.1.542
Rutime:2.3.1.409
Windows

var _arr1 = [1, 0, 0];
var _arr2 = _arr1;

_arr2[1] = 1;

show_debug_message(string(_arr1));
show_debug_message(string(_arr2));

結果

[ 1,0,0 ]
[ 1,1,0 ]

もし参照になっている場合、_arr2の要素に更新をかけると参照されている_arr1も更新されます。
結果としては元々の仕様通り、配列は値渡し(コピー)になってました。

2
サクレ 2020/12/26 (土) 17:43:36 >> 1

返信、検証ありがとうございます。

どうも1,2次元配列と3次元配列でスクリプトでの扱いに違いがあるみたいで、そこでつまづいています。
3次元配列を使ってこのようなコードを書いてみたのですが、

//オブジェクト Createイベント
for(i=2; i>-1; i--){
	for(var j=2; j>-1; j--){
		for(var l=2; l>-1; l--){
			_firld[i][j][l] = 0;
		}
	}
}
Scr_Return_Array(_firld);
//スクリプト
function Scr_Return_Array(_a){
	 _a[0][0][0]=123;
}

このように書くとオブジェクトの_firld配列は変更されないはずなのですが、実際には_firld[0][0][0]に123が書き込まれてしまいます。
2次元配列でほぼ同じコードとスクリプトを書くと元の配列に変更は加えられませんでした。
3次元配列をスクリプトに参照ではなく値渡しする方法がわからず困っています。解決法を教えていただければ幸いです。

3
SUPPY 2020/12/27 (日) 21:15:31 修正

3次元配列ちょこちょこいじってみました。
配列をコピーした場合でも同様の配列を参照してしまうみたいです。
なので、

// [引数]3次元配列(コピー元)
function array_copy3d(_a){
	var _b = array_create(0);	// コピー先

	var _length1 = array_length(_a);
	for(var i=0; i<_length1; i++){
		var _length2 = array_length(_a[i]);
		_b[i] = array_create(_length2)
		array_copy(_b[i], 0, _a[i], 0, _length2);
	}
}

このように配列の2次元目をコピーすると別の配列として参照できました。
(3次元目をコピーしてもいけますが、記述が長くなるので2次元目にしました)

コピー先をいじった後、元に返すのは、

	// _aコピー元	_bコピー先
	var _length1 = array_length(_a);
	array_copy(_a, 0, _b, 0, _length1);

	// 戻り値があるなら
	return _b;

でいけます。

GMSで3次元配列を扱うのはリスキーに思われるので、1次元配列の中に2次元配列を格納する
という手法も1つの策かと思われます。
参考になれば幸いです。

4
サクレ 2020/12/27 (日) 22:31:46 >> 3

おおお、これで何とかなりそうです。ありがとうございます!!
3次元配列が単純にコピーできないのは不具合なのかな・・・。