processingにおけるシーン遷移(画面遷移)を実現する一般的なテクニック
はじめに
ここでは,processingのシーン遷移について解説します.
シーン遷移を知っていれば,様々な方面に活用できます.具体的には,スタート画面,クリア画面,操作説明の画面などを簡単に作ることができます.他にも,ステージクリア制のゲーム制作,アート作品のポートフォリオアプリの制作などにも応用が利きます.
この記事では,まず基本アイデアとして,ステージ遷移の考え方について書きます.
その後,その実装方法を簡略化して3通り述べます.
最後に,単純なゲームを作成してみて,実践的な使い方を解説します.
基本アイデア
まずは概要として,基本アイデアを示します.
まずは,全てのシーンに番号を振ります(頭の中で).例えば,スタートシーンは0
,ゲーム画面は1
にするかー,という感じです.そして,プログラム上で番号を管理する変数を一つ持っておいて,その番号によって実行するプログラムを変えます.例えば,番号を管理する変数が0
なら,スタート画面のプログラムを実行するようにします.このような実装はif文で書けます.
さて,次からは具体的な実装面を見ていきますが,シーンや,それぞれに対応する番号を次のように決めることにします(頭の中で).
まず,シーンはスタート,ゲーム,クリアの3種類を想定します.また,それぞれに対応する番号は0
:スタートシーン,1
:ゲームシーン,2
:クリアシーン だと思うことにします.さらに,シーン遷移するためには,シーン遷移する「きっかけ」が必要です.今回は,スタート→ゲームの遷移は「スタートボタンを押す」,ゲーム→クリアの遷移は「ゲームをクリアする」ことがきっかけになるとします.
実装例
ここからは実装例を書きます.
なお,processingのテンプレである以下の形から付け加えていくことにします.
void setup(){ // 最初の1回だけ実行される } void draw(){ // 何回も実行される }
1. draw()に直書き
一番愚直な方法です.ある意味わかりやすいかもしれません.
int scene = 0; // シーンを指定する番号 void setup(){ } void draw(){ if(scene == 0){ // スタートシーンの処理 if(スタートボタンを押したら) scene = 1; }else if(scene == 1){ // ゲームシーンの処理 if(クリアしたら) scene = 2; }else if(scene == 2){ // クリアシーンの処理 } }
各シーンについて,次のシーンに移れるようにsceneの値を書き換える処理を入れています.
また,この例では,全ての処理をdraw()に直書きします.一見分かりやすそうですが,例えば,ゲームシーンの処理が200行とかになった場合,プログラム上で処理の流れが追いにくくなります.
2. 関数を呼び出す
int scene = 0; // シーンを指定する番号 void setup(){ } void draw(){ if(scene == 0){ start_scene(); }else if(scene == 1){ game_scene(); }else if(scene == 2){ clear_scene(); } } void start_scene(){ // スタートシーンの処理 if(スタートボタンを押したら) scene = 1; } void game_scene(){ // ゲームシーンの処理 if(クリアしたら) scene = 2; } void clear_scene(){ // クリアシーンの処理 }
各シーンでの処理を,関数によって記述しました.ここでは,具体的な処理は全てstart_scene(), game_scene(), clear_scene()に記述します.
この実装で嬉しいことは,各シーンの処理によらず,draw()の中身は変わらないことです.とりあえずdraw()さえ見ればシーンと番号の対応が一目で分かるので,コードの可読性がぐっと上がります.
ちなみに,シーンによらず常に実行したい処理もあるかもしれません.例えば,background()や,BGMに関する処理です.このような時は,もう一つ専用の関数を作って,if文の影響を受けないところで呼び出します.
int scene = 0; void setup(){ } void draw(){ common(); // if文の影響を受けないところで呼ぶ if(scene == 0){ start_scene(); }else if(scene == 1){ game_scene(); }else if(scene == 2){ clear_scene(); } } void common(){ // 共通の処理 } void start_scene(){ // スタートシーンの処理 if(スタートボタンを押したら) scene = 1; } void game_scene(){ // ゲームシーンの処理 if(クリアしたら) scene = 2; } void clear_scene(){ // クリアシーンの処理 }
3. シーンを文字列で指定する
1.および2.では,シーンを番号で指定していました.でもこの方法は,「0番はスタート」という情報を自分が覚えておく必要があります.これでは,より複雑なゲームでは,何番が何のシーンだったかを忘れるかもしれません.「キャラ選択画面は5で,魔法使いの能力確認画面は49で..」みたいなのは,できるだけやりたくないです.
このような時,シーンの指定に文字列を使えば良いかもしれません.例えば,"start"はスタートシーン,"select_character"はキャラ選択画面, "magic_ability"が魔法使いの能力確認画面,みたいな要領です.これだと,非常に直感的に記述できます.
String scene = "start"; // シーンを指定する文字列 void setup(){ } void draw(){ if(scene == "start"){ start_scene(); }else if(scene == "game"){ game_scene(); }else if(scene == "clear"){ clear_scene(); } } void start_scene(){ // スタートシーンの処理 if(スタートボタンを押したら) scene = "game"; } void game_scene(){ // ゲームシーンの処理 if(クリアしたら) scene = "clear"; } void clear_scene(){ // クリアシーンの処理 }
文字列はString型で扱うことができます.数字で指定していた時よりも,少しわかりやすくなった気がしますね.
単純なゲーム制作で理解するシーン遷移
最後に,具体的なサンプルを見て,実践的な感覚を掴みましょう.ここでは,3.の方法を用いて,文字列でシーンを制御します.
ここでは単純な例として,赤い四角をクリックしたらクリアできるようなゲームを考えましょう.
もちろん,スタート画面とクリア画面も作ります.
まずはテンプレです.
void setup(){ size(500, 500); } void draw(){ }
共通部分の追加
まずは共通部分です.今回は,画面更新のたびに画面を塗りつぶすことくらいです.
void setup(){ size(500, 500); } void draw(){ common(); // 呼び出し } // 共通部分 void common(){ background(255); }
スタートシーンの追加
スタートシーンを作ります.これに伴って,シーンを指定する文字列も作成します. この文字列には,最初"start"を代入しているので,最初はスタートシーンが表示されます.
また,何かしらのキーをクリックしたらゲームが始まるようにします.これはvoid keyPressedの中で,sceneの文字列を書き換えれば良いです.
String scene = "start"; void setup(){ size(500, 500); textSize(50); } void draw(){ if(scene == "start") start_scene(); //呼び出し } void common(){ background(255); } // スタートシーンの処理 void start_scene(){ fill(0); text("Start", width/5, height/2); text("Press any key", width/5, height/2+60); } void mousePressed(){ // ゲームシーンへ遷移 if(scene == "start") scene = "game"; }
ゲームシーンの追加
次にゲームシーンを作成します.
ゲームの内容的には,赤い四角が描画できて,クリックしたらシーン遷移すれば良いです.
String scene = "start"; void setup(){ size(500, 500); textSize(50); } void draw(){ common(); if(scene == "start") start_scene(); else if(scene == "game") game_scene(); } void common(){ background(255); } void start_scene(){ fill(0); text("Start", width/5, height/2); text("Press any key", width/5, height/2+60); } // ゲームシーンの処理 void game_scene(){ fill(255,0,0); rect(30, 50, 70, 90); } void mousePressed(){ if(scene == "start")scene = "game"; else if(scene == "game"){ // クリックできたらクリア画面に遷移 if(get(mouseX,mouseY) == color(255,0,0)){ scene = "clear"; } } }
get(x,y)は点(x,y)の色を取得する関数で,get(mouseX, mouseY)でマウス座標の色を取得できます.color(255,0,0)は赤色を表します.
クリアシーンの追加
最後にクリア画面を追加します.ここでは単純に,Clearの文字を出すことにします.
String scene = "start"; void setup(){ size(500, 500); textSize(50); } void draw(){ common(); if(scene == "start") start_scene(); else if(scene == "game") game_scene(); else if(scene == "clear") clear_scene(); // 呼び出し } void common(){ background(255); } void start_scene(){ fill(0); text("Start", width/5, height/2); text("Please click", width/5, height/2+60); } void game_scene(){ fill(255,0,0); rect(30, 50, 70, 90); } // クリアシーンの処理 void clear_scene(){ fill(0); text("Clear", width/5, height/2); } void mousePressed(){ if(scene == "start")scene = "game"; else if(scene == "game"){ if(get(mouseX,mouseY) == color(255,0,0)){ scene = "clear"; } } }
このようにして,スタートシーン→ゲームシーン→クリアシーンの遷移を実装できました.
おわりに
今回は,processingにおけるシーン遷移について説明し,具体的なサンプルと共に使い方を説明しました.いろいろなシーンで使えるので,ぜひ使ってみてください.
以上です.ありがとうございました.