オレンジブログ

オレンジブログ

GameMakerのちょっとしたTipsとか

【GMS2】functionの基本的な使い方


はじめに

ゲーム開発において 関数(function)は欠かせない機能 です。
特にコードの再利用性を高めたり、
処理を整理するうえで重要な役割を果たします。

しかしGMLの関数は他の言語とは異なる点が多く、独自の仕様を持っています
そのため、ちょっとわかりにくいなーと思う方もいると思います。

そこで今回は GMLの関数に関する基礎的な内容 についてまとめようと思います。


関数とは?

関数(function)とは 「ある値を受け取って処理を行い、結果を返す仕組み」 です。
中学生の数学で習った y = x + 2 という関数と同じように、
プログラムでも 関数は入力(引数)を受け取り、処理をして出力(戻り値)を返す 役割を持ちます。

例えば、数学の関数で

y = x + 2

という式があったとすると、
x に 3 を入れると y は 5 になります。
また、x に 8 を入れると y は 10 になりますね。
このように、xに値を代入すると、決まったパターンで値を返す(今回はプラス2される)
ような処理を関数といいます。


同じように、GMLの関数でも以下のように書くことができます。

/**
 * @function AddTwo
 * @description 指定した数に 2 を加える関数
 * @param {Real} _x - 入力値(数学の関数だとxを指す)
 * @returns {Real} - _x に 2 を加えた値(数学の関数だとyを表す)
 */
function AddTwo(_x) {
    return _x + 2;
}

// 関数の実行
show_debug_message(AddTwo(3)); // 出力: 5
show_debug_message(AddTwo(8)); // 出力: 10

このように、関数を使うことで処理をまとめ、同一の処理を再利用しやすくする ことができます。


関数の作成

基本はscriptファイルに宣言します。
アセットブラウザーで右クリックをしてScriptを選択しましょう。

Scriptsフォルダに作るのがオススメです

こんな感じの画面になればOK
script名は用途に分けて自由に決めてください。

関数は主に以下の2つの形式で定義できます。


スクリプト関数(推奨)

function showLog() {
    show_debug_message("Hello, Wolrd!");
}

この形式はグローバルスコープに登録され、スクリプト関数として扱われます。
基本はこの形式で宣言しましょう。

  • 呼び出し方 関数は基本 関数名() という形式で呼び出します。
// Hello, World! と出力される
showLog();

メソッド変数

showLog = function()
{
    show_debug_message("Hello, Wolrd!");
}

この書き方でも宣言できますが、
この形式はメソッド変数となり、関数として認識されません。
使用する際は global.showLog() のように global を付ける必要があります。

global.showLog();

わざわざこのように宣言する必要は無いので、あまり使うケースはないでしょう。


ローカル変数の宣言

関数内でローカル変数の宣言が行えます。

function move(){
    // ローカル変数で_spdと_dirを宣言
    var _spd = 10;
    var _dir = 20;
    
    speed = _spd;
    direction = dir;
}
// speedとdirectionに値をセットさせて移動させる
move();

ローカル変数はスコープを抜けると破棄されるため、
外部から参照することはできません。

move();
// _spdが存在しなくてエラーになる
speed = _spd;

▶︎GML特有の挙動について(折りたたみ)

GMLのグローバル関数の特異な挙動

一般的なプログラミング言語では
グローバル関数はどのオブジェクトにも属さず、インスタンス変数にアクセスできません

C++ のグローバル関数の例

// C++ のグローバル関数
void IncreaseValue() {
    // x という変数が存在しないため、エラー
    x += 2;
}

このようにC++ では グローバル関数がインスタンスの変数にアクセスすることはできません

しかし、GMLではグローバル関数が self(現在のインスタンス)の変数にアクセスできます

GML のグローバル関数の例

/**
 * @function IncreaseX
 * @description インスタンス変数 x を 2 増やす
 */
function IncreaseX() {
    x += 2; // 現在のインスタンスの x にアクセスできる
}

この関数をオブジェクト内で呼び出すと、そのオブジェクトの x が増加します。

IncreaseX(); // 現在のオブジェクトの x が 2 増加する

なぜこの違いが生じるのか?

GMLのグローバル関数は現在の self に影響を受ける という仕様を持っています。

  • C++ のグローバル関数selfthis を持たず、どのインスタンスにも依存しない
  • GML のグローバル関数暗黙的に self を参照し、インスタンスの変数にアクセスできる

このためGMLでは グローバル関数を実行すると、
その関数を呼び出したオブジェクトの変数を操作することが可能
になっています。

これはだいぶ特殊な仕様で、他の言語を触れてからGMLを触る方や、
逆にGMLを使ってから他の言語を使う方は気をつけてください。


引数の扱い

関数には引数を指定でき、ローカル変数として利用可能です。
数学の関数だとxだった部分ですね。
呼び出し元によって異なる値を代入できるのが引数の最大の強みです。

function move(spd, dir)
{
    speed = spd;
    direction = dir;
}
// 現在の座標からマウスまでの角度を取得
var _mouse_dir = point_direction(x, y, mouse_x, mouse_y);
// 移動値と角度を指定してmove関数を呼び出し
move(4, _mouse_dir);

戻り値のある関数

関数は return を使って値を返せます。
y = x + 2y だった部分ですね。

/**
 * @function sqr_calc
 * @description 指定した値の二乗を計算する。ただし、数値でない場合は 0 を返す。
 * @param {Real} _val - 二乗する値
 * @returns {Real} - 計算結果(数値でない場合は 0)
 */
function sqr_calc(_val) {
    // 数値じゃないので0を返す
    if (!is_real(_val)) {
        return 0;
    }
    return _val * _val;
}
// 5を2乗しか結果を_resultに代入
var _result = sqr_calc(5);
 // _result = 25
show_debug_message(string(_result));

シンプルな機能に見えてかなり使い勝手がいいので積極的に使っていきましょう


オブジェクトインスタンス内での function の定義と使い方

GameMakerではScriptファイルだけでなく、
オブジェクトのイベント内で function を定義できます。
Createイベントで定義することで、そのオブジェクトインスタンス全てのイベントで呼び出すことが可能です。


関数の定義方法

// オブジェクトのCreateイベント内
Move = function(_dx, _dy) {
    x += _dx;
    y += _dy;
};

// 関数の実行(どのイベントでもOK)
Move(10, 5);

もしくは

// オブジェクトのCreateイベント内
function Move(_dx, _dy) {
    x += _dx;
    y += _dy;
}

// 関数の実行
Move(10, 5);

外部からの関数呼び出し

// インスタンス名を指定して関数を呼び出す
objPlayer.Move(20, 5);

// with構文を使用して関数を呼び出す
with(objPlayer) {
    Move(15, 10);
}

インスタンスIDを取得して関数を呼び出す

// 新しいインスタンスを作成し、そのIDを取得
var _player = instance_create_layer(x, y, objPlayer, layer);

// IDを使って関数を呼び出す
_player.Move(5, 5);

// with構文を使って関数を呼び出す
with (_player) {
    Move(10, 10);
}

まとめ

今回はGMLにおける関数の基本的な使い方 をまとめました。

関数の宣言から呼び出し方、引数や戻り値について書きました。
ただ、最初はうまく使いこなせないと思います。結構複雑な機能ですし...。 関数を使いこなすためには、実際に コードを書いて試しながら慣れることが重要 です。

まずはこの記事の内容を活用しながら、GMLの関数を実際に使ってみましょう!