オレンジブログ

オレンジブログ

自作ゲームについてとか色々

【GM:S 1.4】Surfaceで明かりを表現する【アイワナ制作】

こんにちは。この前アイワナをリリースしたオレンジです。

今回はそのアイワナでも使われている「光源」の実装方法について紹介していきたいと思います。

f:id:orangeLily:20200824154700p:plain

私の作ったアイワナについては、過去記事をどうぞ

orangelily.hatenablog.com

光源とは

光源、つまり光の発する点の事ですね。

ゲームとかだと、ライトとか炎の明かり等に使われているシーンが多いと思います。

イワナのような2Dアクションだと、自分の周りだけ明るくて他が暗い、みたいなステージがありますよね。

これをGameMakerで再現するなら

f:id:orangeLily:20201031192147p:plain:h200

こんな感じの真ん中が透明で周りが黒い画像を準備して、それを光源の中心に置く...

みたいな方法をしてた方もいるかもしれません。(他にも多数方法はありますが)

でもこれ、ちょっと汎用性低いんですよね。

明かりをいくつも動かしたりすると周りの黒い部分が邪魔になったり、色の違う明かりを作る度に画像を準備したり...etc

そこで、Surface機能を使って明かりを再現しよう!と言うのが今回の記事です!

※記事タイトルの通り、GameMaker : Studio専用です。

GameMaker8.0や8.1Lite版では動かせません。

実装方法

Sprite

まずは明かりの画像を準備しましょう。

f:id:orangeLily:20201031193130p:plain:h300

今回はこの画像を使います。使いたい明かりによって色々作ってみたり、フリーの素材を使ってみるのが良いでしょう。

この画像でSpriteを作ります。名前は適当に「spr_light」とかにしておきます。
オフセットをcenterに設定し、閉じます。

f:id:orangeLily:20201031193218p:plain:h300

Script

次は光源の描画更新の処理を行うScriptを1つ作ります。この処理は何度か呼び出すことになるので、Scriptにまとめておくと便利です・

名前を「light_update_process」と言う名前で新規Scirptを作成し、以下のコードを書きます。

///light_update_process(light_surface)
//引数で受け取ったサーフェスを代入
now_surface = argument0;
//対象を現在のサーフェスに変更
surface_set_target(now_surface);
//サーフェスの描画処理
draw_clear(c_black);
draw_sprite_ext(sprite_index, image_index, sprite_width / 2, sprite_height / 2, image_xscale, image_yscale, image_angle, c_white, 1);   
//対象をリセット
surface_reset_target();


このような感じになればOKです。
f:id:orangeLily:20201031235239p:plain:h300

Object

次に明かりオブジェクトを作りましょう。名前を「obj_light」とし、Spriteに先ほど作成した「spr_light」を設定します。
そして、Visibleのチェックを外します(ここ忘れがち)

f:id:orangeLily:20201031235516p:plain

そしたらobj_lightにCreateイベントを作って、そこにコードを追加します。

///CreateEvent

//サイズ変更、数字は自由に
image_xscale = 3;
image_yscale = 3;

//光源用のサーフェス生成
light_surface = surface_create(sprite_width, sprite_height);
//更新処理を一回入れる
light_update_process(light_surface);

上記のコードを入力したら閉じます。

次にlight全体をコントロールするオブジェクト「obj_light_controller」を作ります。

Sprite画像は設定しなくて大丈夫です。もし設定したい場合はゲーム画面に映らないようにVisibleのチェックを外しておきましょう。

今作ったobj_light_controllerのCreateイベントに下記のコードを書きます。

///CreateEvent

//全体を描画するサーフェス生成
controller_surface = surface_create(room_width, room_height);

次はStepイベントにこちらのコードを記述します。

///StepEvent

//対象を全体のサーフェスに
surface_set_target(controller_surface);
//画面全体を黒に
draw_clear(c_black);
//ブレンドモードを加算に変更
draw_set_blend_mode(bm_add);
//光源の更新処理
with (obj_light) {
  draw_surface_ext(light_surface, x - sprite_width / 2, y - sprite_height / 2, 1, 1, 0, image_blend, 1);
}
//ブレンドモードをノーマルに
draw_set_blend_mode(bm_normal);
//対象をリセット
surface_reset_target();

次にEndStepイベントにこちらのコードを記述してください。

///EndStepEvent

//光源のEndStep更新処理
with (obj_light)
{
  light_update_process(light_surface);
}

最後にDrawEndイベントに以下のコードを書いたら終わりです。

///DrawEndEvent

//拡張ブレンドモード設定
//詳しくはこちらのURLで
//https://docs.yoyogames.com/source/dadiospice/002_reference/drawing/colour%20and%20blending/draw_set_blend_mode_ext.html
draw_set_blend_mode_ext(bm_dest_color, bm_zero);
draw_surface_ext(controller_surface, 0, 0, 1, 1, 0, c_white, 1);
draw_set_blend_mode(bm_normal);

準備はこれくらいで大丈夫です。イベント数が以下の画像と同じになっていればOKです。

f:id:orangeLily:20201101000627p:plain

コードの処理については、コメントを確認してください

Room

それでは実際にroomを作って試してみましょう。

roomの設定は適当で良いですが、サイズを大きくしすぎないようにするのと、分かりやすいように背景色は青とかにします。

roomを作ったらそこに「obj_light_controller」を置いて、明かりを起きたいところに「obj_light」を置きましょう。

私はこんな感じのルームを作りました。

f:id:orangeLily:20201101001210p:plain:h300

これで起動してみると...。

f:id:orangeLily:20201101001240p:plain:h300

画面上部が明るくなっていて、他が暗くなっていますね!これで成功です!!

イワナのステージに適用させてみよう

さて、これだけでもアイワナのステージに「obj_light_controller」と「obj_light」を置けば光源を実装することができます。

置くだけでもいいですが、せっかくですし動かしたいですよね。

そこで、「obj_light」にマウスに追従してくる機能を実装してみましょう。

obj_lightのStepEventに以下の記述をしてみましょう。

///StepEvent

//座標をマウスに合わせる
x = mouse_x;
y = mouse_y;

これをアイワナのルームに配置して実行してみると。
f:id:orangeLily:20201101003111g:plain:h400

良い感じにマップを照らせるようになりましたね!

その他の実装

その他にも、いくつか機能を紹介しておきます。

光源の色の変え方

光源の色の変え方ですが、例えばobj_lightのCreateイベントか生成時に

image_blend = make_color_rgb(255,150,150);

と記述してあげると、赤色に変わります。

f:id:orangeLily:20201101013137p:plain:h300

その他の色に変えたいときは、rgbの数値を変えてみましょう!

全体を覆う色の変え方

全体を覆う色ですが、今は黒になっているので明かりが届いていない部分は真っ暗になっていますね。
実はこれの色も変えることができます。この色を変えることでよりステージに特徴を持たすことができます。

変え方ですが、obj_light_controllerのStepイベントの

//画面全体を黒に
draw_clear(c_black);

のc_blackの部分を

//画面全体を赤に
draw_clear(make_color_rgb(255,0,0));

とすると、画面全体を赤くすることができます。

f:id:orangeLily:20201101012426p:plain:h300

色の部分をランダムな数値を扱えば、毎回ランダムな色に変化してくれます。

だいたいこんなところでしょうか。

この機能自体はそこまで処理が重くありませんが、一度に大量の光を動かしたり、めちゃくちゃ大きな明かりを動かそうとすると処理が重くなります。

そこだけは気をつけて使いましょう!!

以上の部分で今回の実装は終わりです。

実装お疲れ様でした!!