【GameMaker】変数と定数・データアクセス(with文)の基本

GameMaker

この記事では、GameMakerの変数と定数、オブジェクト間のデータアクセス(with文・インスタンス)についてまとめていきます。

<参考サイト>

GameMaker Manual

変数

GMLの変数は以下四種類。

変数の種類説明とポイント
インスタンス変数・宣言:<変数名>
・オブジェクトインスタンスを介してアクセスできる変数
ローカル変数・宣言:var <変数名>
・特定イベント内でのみ有効な変数。イベント終了時に破棄される
 →使いまわさないような変数はこちらで宣言することでメモリ節約
・宣言時は変数名の先頭に「_」を付けローカル変数であることを示すとベター
・インスタンス変数などと名前が重複した場合は、[self.<変数名>]でアクセス可能
グローバル変数・宣言:global.<変数名>
・ゲーム中どこからでも自由にアクセスできる変数
・アクセス時も[global.<変数名>]の形で記載する
組み込み変数・宣言:無し
・ユーザが宣言するものではなく、GameMakerで用意されている変数
 →マニュアル(F1)等で詳細な仕様や種類を確認、利用する
一言コメント
一言コメント

重要なポイントとして、ローカル変数の「イベント終了時」というのにはステップイベントの各ステップごとの終了も含まれます
→同じステップイベント内でも、一巡後は新規作成となるのため、参照関係には要注意。

定数

定数=初期化された値が決して変化しないデータ形式 で、GMLでユーザが定義できる定数には以下2つがあります。

マクロ

GMLでは最も基本的な定数の形。変数とほぼ同じ扱い方ができますが、「値の変更はできない」ことと、「宣言の仕方(↓)」に違いがあります。

//定数(マクロ)の宣言:#macro <変数名> <値>
#macro TEST_VALUE 100     //100という値を保持する、TEST_VALUEという定数を宣言
#macro TEST_CALC a+b     //計算式を定数として宣言
#macro TEST_RANDOM_COLOUR make_colour_hsv ( irandom (255), 255, 255)    //関数を含む定数

//マクロ計算式を利用
a=5;
b=10;
ans=TEST_CALC;    //ans=15
b=20;
ans=TEST_CALC;    //ans=25

//マクロ関数を呼び出す
my_col = TEST_RANDOM_COLOUR;    //my_col=実行ごとにランダムな色 となる
一言コメント
一言コメント

変数のように、値の初期化に「=」(等号)を使ったり、文末の「;」(セミコロン)を付けたりしないことに注意してください。(つけてしまうと無効な定義になります。)

構成(Config)とマクロの活用

マクロは、コンポーネント*に応じて使い分ける書き方もできます。
コンポーネントを指定する場合は、マクロ名の前に「:」区切りでコンポーネント名を挿入します。

//コンポーネントによるマクロ定義内容の変更:<コンポーネント名>:<マクロ名> <値>
#macro TEST a+b     //デフォルトで適用されるマクロ
#macro com_a:TEST a+10    //コンポーネント[com_a]が選択されている場合に適用されるマクロ
#macro com_b:TEST b+10    //コンポーネント[com_a]が選択されている場合に適用されるマクロ

詳細は以下の記事でまとめてあります。

列挙型 (enum)

列挙型(enum)は、定数をリストで管理するデータ形式で、以下のように宣言します。

//列挙型の宣言
enum <列挙型名>
{
	<定数名①> = <定数の値>,
	<定数名②> = <定数の値>,
	…以下略…
}

ここで重要なポイントとして、

列挙型内の定数に値を設定しなかった場合、デフォルト値として0から始まる値が設定されます。

enum TEST
{
    CONST_A,
    CONST_B,
    CONST_C
}

例の場合、
 CONST_A = 0
 CONST_B = 1
 CONST_C = 2
となります。

最後に、列挙型のポイントをまとめておきます。

列挙型
enum <列挙型名>
{
	<定数名①> = <定数の値>,
	<定数名②> = <定数の値>,
	…以下略…
}
  • 列挙型(enum)は、定数をリストで管理するデータ形式
  • 列挙型内の定数に値を設定しなかった場合、デフォルト値として0から始まる値が設定される
  • Enumの定数値は[int64]として保存される(実数型ではないことに注意)

組み込み定数

GMLに内蔵されている組み込み定数は以下の通りです。(使用頻度の高そうなものから並べています)

定数名概要
true論理型で「真」、値でいうと「1」となる定数*
*ただし、GMLでは 1以上=「真」と認識することに注意
false論理型で「偽」、値でいうと「0」となる定数*
*ただし、GMLでは 0以下=「偽」と認識することに注意
NaN演算結果が数値として認識できないときにコンパイラから返される値
undefined関数が、適切な戻り値を返せないときに代わりに返す定数*
*論理型では「偽」の判定となります。
pointer_null指定されたポインタで示されるものが存在しないことを示す定数*
*論理型では「偽」の判定となります。
pointer_invalidある値がポインタとして有効でないことを示す定数。
infinity無限大を示す定数
pi円周率を示す定数

データ型(一部抜粋)

GMLで使用できるデータ型には以下のようなものがあります。
(よく使うものから重複を除いて一部抜粋。詳細やほかのデータ型は公式docにてご確認ください)

データ型説明
real・実数型:後述の他データ型に該当しない数値データ型
string・文字列型:”…”でくくられた任意のテキストデータ型
bool・論理型:true(真)またはfalse(偽)として認識されるデータ型
array配列型:複数の値を管理するデータ型。
struct構造体:他変数のコレクションを管理するデータ型
     (定数でいう列挙型に近い形式)
functionメソッド変数:メソッド(関数)が割り当てられた変数データ型
int64・64bit整数型

別オブジェクトインスタンスへのデータアクセス

GameMakerであるオブジェクトインスタンスから別のオブジェクトインスタンス内のデータ(変数)へアクセスする方法には、以下のようなものがあります。

A) ドット記法

<対象オブジェクト名>.<変数名>

これはもっとも一般的な別インスタンスの変数アクセスの方法で、対象オブジェクト名と変数名を「.」(ドット)区切りで指定するものです。

この方法の注意点として、
 同名オブジェクトが同ルーム内に複数あると、その内の一つがアクセス対象*になってしまいます。
 *あるいは基準として適用されてしまう

今回は以下のようなルームで、緑色のボックスから赤いボックスx3を対象として操作してみます。

A) 対象オブジェクトを右へ動かす
 …Stepイベントで別オブジェクト(緑色)から赤い箱を動かしてみます。

o_redbox.x += 2;

動作を見ると、X軸について真ん中の赤い箱が基準としてアクセスされ、他二つのオブジェクトもその影響を受けて縦一列に整列してしまっている状況*が確認できます。

一言コメント
一言コメント

*後述のselfキーワードを用いればこの状況は解消できたりしますが、ここでは割愛します。

B) 対象オブジェクトへ自身(緑色)を移動する

x = o_redbox.x;

今回の例では、右側の赤い箱のX軸が対象となり、他の影響は受けていない状況が見て取れます。

このように、複数の同名オブジェクトがルーム内に存在する場合、ドット記法でのアクセスでは意図しない挙動となってしまうケースがあります。

この場合のアクセス対象は不定であり、この問題を解決するのが、次に示すインスタンス名の指定を使う方法です。

B) インスタンス名の指定

ルーム内に複数の同名オブジェクトが存在するような場合は、インスタンス名を用いて一意に対象を識別する必要があります。

インスタンス名とは

インスタンス名は、オブジェクトインスタンスの生成時に自動的に割り当てられる一意な名称です。
ルームに配置している場合は、ルームエディタからその名称を確認できます。↓

これは、あらかじめルームに配置されているインスタンスだけでなく、スクリプト等で生成したオブジェクトインスタンスについても生成時に同様に設定されるため、後述のwith文などを用いると簡単にアクセスすることができます。

実装例:インスタンス名の取得と指定

インスタンス名の取得がオブジェクト間の相互作用には重要であることから、GameMakerでは様々なインスタンス名の取得方法が用意されています。(衝突時や作成時、インスタンス間の距離など)

今回は簡単な例の一つとして、マウスポインタの位置からインスタンス名を取得する例を実装してみます。

今回も以下のようなルームで、緑色のボックスから赤いボックスx3を対象として操作してみます。

緑色の箱オブジェクトのステップイベントに以下のコードを挿入し、実行してみます。

//マウスカーソル位置から赤い箱オブジェクトのインスタンス名を取得
var _instance_name = instance_position(mouse_x, mouse_y, o_redbox);


//インスタンスが存在するか(マウスカーソルの位置に何らかのインスタンスがあるか)を確認  
if instance_exists(_instance_name)
{
    _instance_name.x += 10;
}

赤い箱の上にマウスカーソルを置くとそれぞれ対応するインスタンスのみが右方向へ対象がそれていきます。
また、オブジェクトとして対象となっていない緑色の箱は影響を受けていません。

これが、最も基本的なインスタンス名の取得と、それに基づく動作の例です。

C) with文

with文は、簡単に言うと、
 「with文で括った範囲内の処理文について、ドット記法の前半部分を省略する書き方です。」

ドット記法との比較と併せて、実際の例を見ながら確認してみましょう。

ドット記法:

o_player.x += 10;

with文の利用

with(o_player)
{
    x += 10;
}

上記で行われる処理は、同様の結果となります。
ここでは、with文の構文を確認するために敢えてシンプルな書き方をしました。
この時点では、前項で指摘したようなドット記法の問題は解消できていないことに注意してください。

複数存在する同名オブジェクトのインスタンスから任意のインスタンスへアクセスするには、
前述の例と同様に「一意なインスタンス名」を活用する必要があります。

ドット記法:

var _instance_name = instance_position(mouse_x, mouse_y, o_redbox);
  
if instance_exists(_instance_name)
{
    _instance_name.x += 10;
}

with文の利用

var _instance_name = instance_position(mouse_x, mouse_y, o_redbox);
  
if instance_exists(_instance_name)
{
    with(_instance_name)
    }
        x += 10;
    }
}

補足:インスタンスキーワード

with文などを活用するにあたって重要度の高い、インスタンスキーワードについてもまとめておきます。

キーワード説明
self・現在のコードブロック位置のインスタンスを示す
・with文:withの引数となりうる個々のインスタンスが適用対象となる
・衝突イベント・関数:処理が発生した自分側のインスタンスが対象
other・現在のコードブロックから見て“相手”や”呼び出し元”に当たるインスタンスへアクセス
・with文:with文が記述されたイベントを持つインスタンスを対象としてアクセスする。
・衝突イベント:衝突が起こった際、イベントを持つ側から見て相手のインスタンスが対象
・関数:関数の呼び出し元インスタンスが対象
all・ルームで現在アクティブなすべてのインスタンスへのアクセス
 →一括変更や、検索処理などに活用
noone・対象となるインスタンスが存在しない状況を示すキーワード
 →インスタンス自体の存在確認判定等に使用する
  例) if instance_nearest(x, y, obj_enemy) != noone
参考ページ:公式doc

他インスタンスからのアクセス

GameMaker Manual

インスタンスキーワード

GameMaker Manual

一言コメント
一言コメント

お疲れさまでした。
当記事につきまして、ご意見やご質問、記載内容の不備等がございましたら、是非↓のコメント欄からお気軽にご連絡いただけますと幸いです。

制作作業、一緒に頑張っていきましょう!

ひらまめ(hiramame)

普通の会社員をやりながら個人で2Dのゲームを作っています。
制作作業の中で解説系ブログの情報に助けられた経験より、得た知見や情報をまとめるついでに共有できればと思い、ブログ運営中です。

ひらまめ(hiramame)をフォローする
GameMaker
ひらまめ(hiramame)をフォローする
ひらまめゲーム制作研究室

コメント

タイトルとURLをコピーしました