こんばんは。kenoです。
今回はビジュアルプログラミングのProcessingにおけるdisposeについて話したいと思います。
ちょっと必要になって調べたんですが、disposeに関する情報が少なすぎないですか。
あんまりProcessingだと使われないんですかね。
まあ、とりあえずいってみよう!
今回使用しているバージョンは「Processing 4.4.4」です。
主題:disposeとは
Processingにおいて、とかくゲームを作ったりするときはこんな感じでプログラム作ったりしますよね。
void setup(){
size(300,400);
}
void draw(){
background(0,0,0);
PlayerInput();
UpdateGame();
GenerateOutput();
}
void PlayerInput(){
//...
}
void UpdateGame(){
//...
}
void GenerateOutput(){
//...
}
最初の一回だけsetup関数が呼び出され、毎フレームdraw関数が呼び出されるといった感じ。
dispose関数は、これらの関数と同じでprocessing側で定義された関数のうちの一つです。
効果は「最後の1回だけ呼び出される関数」です。
例えば、processingの実行画面を×ボタンで閉じるときとか、なにがしかのエラーで画面が閉じるときとか。
そんなときに1回だけ呼び出される関数になります。
言うなればsetupの逆ということですね。
プログラムの一番最後に呼び出されるので、ゲームの情報を保存する際やプログラム内で展開したメモリの情報を片付けるときなどに使用します。
一つ具体例を見てみましょう。
void setup(){
size(300,400);
}
void draw(){
background(0,0,0);
}
void dispose(){
println("goodbye");
}
これをProcessingのエディタに張り付けて実行してみます。
実行したときはただの黒い画面が出てくると思いますが、×ボタンをおして閉じてみると...
画面下部のコンソール画面に「goodbye」と表示されているのがわかるでしょうか。
これはつまり、プログラムのプロセスが終了する直前にprintlnが実行されたということを示しています。
おわかりいただけたでしょうか。
副題:disposeを使って簡易なゲームを作ってみる
僕はゲームを作るのが好きなので、disposeをゲームに応用してみましょう。
processingには標準でテキストファイルを作成したりロードしたりする機能があります。これを併用して面白いことができそうじゃないですか?
英語で「dispose」とは「処分する」という意味があるらしいです。
ではそれにちなんで、「ゴミを処分する」ゲームを作ってみましょう。
まず1段階目。
ゴミが散らばっていて、マウスカーソルでそれを集めるというゲームを作りました。
- class garbage{ //四角いゴミのクラス
- int x;
- int y;
- int w;
- color col;
- boolean isTrashed;
- garbage(int _x,int _y,int _w,color _col){
- x=_x;
- y=_y;
- w=_w;
- col=_col;
- isTrashed=false;
- }
- //ゴミを表示する
- void drawGarbage(){
- if(!isTrashed){
- noFill();
- stroke(col);
- rect(x,y,w,w);
- noStroke();
- }
- }
- }
- ArrayList<garbage> list;
- int num=30;
- void setup(){
- size(300,400);
- rectMode(CENTER);
- //ゴミの配列
- list = new ArrayList<garbage>();
- for(int i=0;i<num;i++){
- garbage g = new garbage(
- (int)random(0,300),(int)random(200,400),(int)random(10,50),
- color(random(255),random(255),random(255)));
- list.add(g);
- }
- }
- void draw(){
- background(0,0,0);
- //ゴミを集める場所を表示
- fill(255,255,255);
- noStroke();
- rect(150,50,300,100);
- //すべてのゴミに対して
- for(int i=0;i<num;i++){
- //もしもマウスとゴミがかぶさってたら
- if(isOverlap2(list.get(i).x,list.get(i).y,list.get(i).w)&&mouseY>40){
- //マウスにくっつくようにする
- if(list.get(i).y>50){
- list.get(i).x=mouseX;
- list.get(i).y=mouseY;
- }
- }
- list.get(i).drawGarbage();
- }
- }
- //マウス座標がいずれかのゴミのなかに入ったら、ゴミを集める
- boolean isOverlap(int x,int y,int w){
- return x<mouseX && mouseX < x+w && y < mouseY && mouseY < y+w;
- }
- //rectMode(Center)バージョン
- boolean isOverlap2(int x,int y,int w){
- return x-w/2<mouseX && mouseX < x+w/2 && y-w/2 < mouseY && mouseY < y+w/2;
- }
- void dispose(){
- println("goodbye");
- }


こんな感じになってます。
マウスカーソルで四角いゴミを集めて、上の白いゾーンに持っていくと捨てられる(という想定)です。
では2段階目、ファイルの入出力を使ってデータを保持できるようにしてみます。
- class garbage{ //四角いゴミのクラス
- int x;
- int y;
- int w;
- color col;
- boolean isTrashed;
- garbage(int _x,int _y,int _w,color _col){
- x=_x;
- y=_y;
- w=_w;
- col=_col;
- isTrashed=false;
- }
- //ゴミを表示する
- void drawGarbage(){
- if(!isTrashed){
- noFill();
- stroke(col);
- rect(x,y,w,w);
- noStroke();
- }
- }
- //データを保存するための関数
- String GetDataString(){
- return x+","+y+","+w+","+col;
- }
- }
- ArrayList<garbage> list;
- int num=30;
- void setup(){
- size(300,400);
- rectMode(CENTER);
- //ゴミの配列
- list = new ArrayList<garbage>();
- //データをロードする
- list.clear();
- String lines = loadStrings("data.txt");
- if(lines == null){
- //data.txtがなければゴミの生成をする
- for(int i=0;i<num;i++){
- garbage g = new garbage(
- (int)random(0,300),(int)random(200,400),(int)random(10,50),
- color(random(255),random(255),random(255)));
- list.add(g);
- }
- }
- else
- {
- //ロードした各行において
- for (String line : lines) {
- //例: "50,50,30" -> ["50", "50", "30"]
- //データをばらしてそれぞれ使用する
- String parts = split(line, ',');
- int x = Integer.parseInt(parts[0].trim());
- int y = Integer.parseInt(parts[1].trim());
- int w = Integer.parseInt(parts[2].trim());
- int col = Integer.parseInt(parts[3].trim());
- list.add(new garbage(x,y,w,col));
- }
- }
- }
- void draw(){
- background(0,0,0);
- //ゴミを集める場所を表示
- fill(255,255,255);
- noStroke();
- rect(150,50,300,100);
- //すべてのゴミに対して
- for(int i=0;i<num;i++){
- //もしもマウスとゴミがかぶさってたら
- if(isOverlap2(list.get(i).x,list.get(i).y,list.get(i).w)&&mouseY>40){
- //マウスにくっつくようにする
- if(list.get(i).y>50){
- list.get(i).x=mouseX;
- list.get(i).y=mouseY;
- }
- }
- list.get(i).drawGarbage();
- }
- }
- //マウス座標がいずれかのゴミのなかに入ったら、ゴミを集める
- boolean isOverlap(int x,int y,int w){
- return x<mouseX && mouseX < x+w && y < mouseY && mouseY < y+w;
- }
- //rectMode(Center)バージョン
- boolean isOverlap2(int x,int y,int w){
- return x-w/2<mouseX && mouseX < x+w/2 && y-w/2 < mouseY && mouseY < y+w/2;
- }
- void dispose(){
- //終了時にデータをCSV形式で保存する
- String lines = new String[list.size()];
- for(int i=0;i<list.size();i++){
- lines[i] = list.get(i).GetDataString();
- }
- saveStrings("data.txt",lines);
- }
ここではdispose関数でデータを保存して、setup関数でデータをロードしています。
最後、3段階目では、ゲーム中に白いゾーンに入れたごみを処分しましょう。
- class garbage{ //四角いゴミのクラス
- int x;
- int y;
- int w;
- color col;
- boolean isTrashed;
- garbage(int _x,int _y,int _w,color _col,boolean b){
- x=_x;
- y=_y;
- w=_w;
- col=_col;
- isTrashed=b;
- }
- //ゴミを表示する
- void drawGarbage(){
- if(!isTrashed){
- noFill();
- stroke(col);
- rect(x,y,w,w);
- noStroke();
- }
- }
- //データを保存するための関数
- String GetDataString(){
- //もしisTrashedがtrueなら1, falseなら0
- int i=isTrashed?1:0;
- return x+","+y+","+w+","+col+","+i;
- }
- }
- ArrayList<garbage> list;
- int num=30;
- void setup(){
- size(300,400);
- rectMode(CENTER);
- //ゴミの配列
- list = new ArrayList<garbage>();
- //データをロードする
- list.clear();
- String lines = loadStrings("data.txt");
- if(lines == null){
- //data.txtがなければゴミの生成をする
- for(int i=0;i<num;i++){
- garbage g = new garbage(
- (int)random(0,300),(int)random(200,400),(int)random(10,50),
- color(random(255),random(255),random(255)),false);
- list.add(g);
- }
- }
- else
- {
- //ロードした各行において
- for (String line : lines) {
- //例: "50,50,30" -> ["50", "50", "30"]
- //データをばらしてそれぞれ使用する
- String parts = split(line, ',');
- int x = Integer.parseInt(parts[0].trim());
- int y = Integer.parseInt(parts[1].trim());
- int w = Integer.parseInt(parts[2].trim());
- int col = Integer.parseInt(parts[3].trim());
- //もし最後の数字が1ならtrue, 0ならfalseにする
- boolean b=Integer.parseInt(parts[4].trim())==1?true:false;
- list.add(new garbage(x,y,w,col,b));
- }
- }
- }
- void draw(){
- background(0,0,0);
- //ゴミを集める場所を表示
- fill(255,255,255);
- noStroke();
- rect(150,50,300,100);
- //すべてのゴミに対して
- for(int i=0;i<num;i++){
- //もしもマウスとゴミがかぶさってたら
- if(isOverlap2(list.get(i).x,list.get(i).y,list.get(i).w)&&mouseY>40){
- //マウスにくっつくようにする
- if(list.get(i).y>50){
- list.get(i).x=mouseX;
- list.get(i).y=mouseY;
- }
- }
- //処分対象でなかったら表示する
- if(!list.get(i).isTrashed){
- list.get(i).drawGarbage();
- }
- }
- }
- //マウス座標がいずれかのゴミのなかに入ったら、ゴミを集める
- boolean isOverlap(int x,int y,int w){
- return x<mouseX && mouseX < x+w && y < mouseY && mouseY < y+w;
- }
- //rectMode(Center)バージョン
- boolean isOverlap2(int x,int y,int w){
- return x-w/2<mouseX && mouseX < x+w/2 && y-w/2 < mouseY && mouseY < y+w/2;
- }
- void dispose(){
- //終了時にデータをCSV形式で保存する
- String lines = new String[list.size()];
- for(int i=0;i<list.size();i++){
- //yが50より小さかったら処分対象です。
- if(list.get(i).y<50)list.get(i).isTrashed=true;
- lines[i] = list.get(i).GetDataString();
- }
- saveStrings("data.txt",lines);
- }
はい。これで完成です!
まず最初にランダムでゴミが生成されます。
マウスカーソルでゴミをあつめて白いゾーンに持っていきます。
動かなくなる地点まで上の白いゾーンにゴミを持っていったのちに×ボタンを押します。
そしてもう一度起動すると、白いゾーンに持っていったゴミはみんな消えています!
正確には表示されていないということですね。
面白い~。
もしここまでお付き合いいただいて、うまく動かないな...と思った方は、一度data.txtを探し出して消去してもらうとうまくいくかなと思います。
おしまいに
今回はProcessingのdispose関数について少しだけしゃべらせていただきました。
disposeの具体例としてゲームのほうも楽しんでいただければ幸いです。
それでは!
kenoでした。