[Sample]タピオカショット
物理演算エンジンFisicaを使い、グラスにタピオカを入れるゲームを作ります。水色のエリアでドラッグすると、その方向にタピオカが飛んでいきます。残り時間が0になると、「GAME OVER」とグラスに入っている個数が表示されます。
Fisicaのセットアップ
こちらのページを参考に、Fisicaのセットアップを行います。この段階ではまだ黒い枠が表示されるだけです。
import fisica.*;//ライブラリのインポート
FWorld world;//物理演算を司るオブジェクト
void setup() {
size(1000, 1000);
Fisica.init(this);//ライブラリを初期化
world = new FWorld();//世界を司るオブジェクトを生成
world.setEdges();//ウィンドウの端に壁を作る
}
void draw() {
background(255);
world.step();//物理演算を進める
world.draw();//オブジェクトを描画
}
タピオカの画像を取り込む
Processingのメニューの[スケッチ] > [ファイルを追加...]から、tapioca_black.pngを選択する。スケッチフォルダの中にdataフォルダが作られ、その中に画像ファイルがコピーされる。スケッチフォルダは、Processingのメニューの[スケッチ] > [スケッチフォルダを開く]で確認できる。
マウスでクリックしたところにタピオカを落とす
import fisica.*;//ライブラリのインポート
FWorld world;//物理演算を司るオブジェクト
PImage tapiocaImage;//タピオカの画像
float tapiocaSize;//タピオカの大きさ
void setup() {
size(1000, 1000);
Fisica.init(this);//ライブラリを初期化
world = new FWorld();//世界を司るオブジェクトを生成
world.setEdges();//ウィンドウの端に壁を作る
tapiocaSize = 50;//タピオカの大きさ
tapiocaImage = loadImage("tapioca_black.png");//タピオカの画像
tapiocaImage.resize(int(tapiocaSize), int(tapiocaSize));//画像サイズを円にあわせる
}
void draw() {
background(255);
world.step();//物理演算を進める
world.draw();//オブジェクトを描画
}
void mouseReleased() {
FCircle circle = new FCircle( tapiocaSize );//タピオカの大きさの円を作る
circle.setPosition(mouseX, mouseY);//マウスの位置に移動
circle.attachImage(tapiocaImage);//円に画像を貼り付ける。
world.add(circle);//物理演算に円を登録する
}
ドラッグしてタピオカを飛ばす
マウスのボタンを押した場所と離した場所を比較して、その方向の力を物体に加える。
import fisica.*;//ライブラリのインポート
FWorld world;//物理演算を司るオブジェクト
PImage tapiocaImage;//タピオカの画像
float tapiocaSize;//タピオカの大きさ
PVector pressPos;//マウスをクリックした位置
boolean isDrag;//ドラッグ中のフラグ
void setup() {
size(1000, 1000);
Fisica.init(this);//ライブラリを初期化
world = new FWorld();//世界を司るオブジェクトを生成
world.setEdges();//ウィンドウの端に壁を作る
tapiocaSize = 50;//タピオカの大きさ
tapiocaImage = loadImage("tapioca_black.png");//タピオカの画像
tapiocaImage.resize(int(tapiocaSize), int(tapiocaSize));//画像サイズを円にあわせる
isDrag = false;
}
void draw() {
background(255);
world.step();//物理演算を進める
world.draw();//オブジェクトを描画
if ( isDrag ) {//ドラッグ中ならば、
stroke( 255, 127, 0 );
strokeWeight(2);
line( pressPos.x, pressPos.y, mouseX, mouseY );
image( tapiocaImage, mouseX-tapiocaSize/2, mouseY-tapiocaSize/2, tapiocaSize, tapiocaSize );
}
}
void mousePressed() {
isDrag = true;
pressPos = new PVector( mouseX, mouseY );
}
void mouseReleased() {
isDrag = false;
FCircle circle = new FCircle( tapiocaSize );//タピオカの大きさの円を作る
circle.setPosition(mouseX, mouseY);//マウスの位置に移動
circle.attachImage(tapiocaImage);//円に画像を貼り付ける。
circle.addForce( (pressPos.x - mouseX )*3000, (pressPos.y - mouseY)*3000 );//クリックした位置と、現在のマウスの位置を比較して、物体に力を加える
world.add(circle);//物理演算に円を登録する
}
グラスを表示する
グラスの画像(glassware05.png)をスケッチに取り込む。
グラスの画像を読み込み背景に表示します。この段階では、画像として表示されるだけなので当たり判定はありません。
import fisica.*;//ライブラリのインポート
FWorld world;//物理演算を司るオブジェクト
PImage tapiocaImage;//タピオカの画像
float tapiocaSize;//タピオカの大きさ
PVector pressPos;//マウスをクリックした位置
boolean isDrag;//ドラッグ中のフラグ
PImage glassImage;//グラスの画像
void setup() {
size(1000, 1000);
Fisica.init(this);//ライブラリを初期化
world = new FWorld();//世界を司るオブジェクトを生成
world.setEdges();//ウィンドウの端に壁を作る
tapiocaSize = 50;//タピオカの大きさ
tapiocaImage = loadImage("tapioca_black.png");//タピオカの画像
tapiocaImage.resize(int(tapiocaSize), int(tapiocaSize));//画像サイズを円にあわせる
isDrag = false;
glassImage = loadImage("glassware05.png");//グラスの画像
}
void draw() {
background(255);
image( glassImage, 344, 500, 172*2, 250*2 );//背景画像を表示
world.step();//物理演算を進める
world.draw();//オブジェクトを描画
if ( isDrag ) {//ドラッグ中ならば、
stroke( 255, 127, 0 );
strokeWeight(2);
line( pressPos.x, pressPos.y, mouseX, mouseY );
image( tapiocaImage, mouseX-tapiocaSize/2, mouseY-tapiocaSize/2, tapiocaSize, tapiocaSize );
}
}
void mousePressed() {
isDrag = true;
pressPos = new PVector( mouseX, mouseY );
}
void mouseReleased() {
isDrag = false;
FCircle circle = new FCircle( tapiocaSize );//タピオカの大きさの円を作る
circle.setPosition(mouseX, mouseY);//マウスの位置に移動
circle.attachImage(tapiocaImage);//円に画像を貼り付ける。
circle.addForce( (pressPos.x - mouseX )*3000, (pressPos.y - mouseY)*3000 );//クリックした位置と、現在のマウスの位置を比較して、物体に力を加える
world.add(circle);//物理演算に円を登録する
}
グラスの当たり判定を加える
グラスの当たり判定を指定します。vertex( x, y );で指定した図形を作り、固定する設定を行います。
次の2行のコメントアウトを外すと、表示されなくなり、当たり判定だけが残ります。
glassBody.setNoFill();//塗りを非表示
glassBody.setNoStroke();//線を非表示
import fisica.*;//ライブラリのインポート
FWorld world;//物理演算を司るオブジェクト
PImage tapiocaImage;//タピオカの画像
float tapiocaSize;//タピオカの大きさ
PVector pressPos;//マウスをクリックした位置
boolean isDrag;//ドラッグ中のフラグ
PImage glassImage;//グラスの画像
void setup() {
size(1000, 1000);
Fisica.init(this);//ライブラリを初期化
world = new FWorld();//世界を司るオブジェクトを生成
world.setEdges();//ウィンドウの端に壁を作る
tapiocaSize = 50;//タピオカの大きさ
tapiocaImage = loadImage("tapioca_black.png");//タピオカの画像
tapiocaImage.resize(int(tapiocaSize), int(tapiocaSize));//画像サイズを円にあわせる
isDrag = false;
glassImage = loadImage("glassware05.png");//グラスの画像
FPoly glassBody = new FPoly();//グラスの形状
glassBody.vertex(380, 560);
glassBody.vertex(400, 910);
glassBody.vertex(630, 910);
glassBody.vertex(650, 560);
glassBody.vertex(640, 560);
glassBody.vertex(620, 900);
glassBody.vertex(410, 900);
glassBody.vertex(390, 560);
glassBody.setStatic(true);//固定する
//glassBody.setNoFill();//塗りを非表示
//glassBody.setNoStroke();//線を非表示
world.add(glassBody);//ワールドに追加
}
void draw() {
background(255);
image( glassImage, 344, 500, 172*2, 250*2 );//背景画像を表示
world.step();//物理演算を進める
world.draw();//オブジェクトを描画
if ( isDrag ) {//ドラッグ中ならば、
stroke( 255, 127, 0 );
strokeWeight(2);
line( pressPos.x, pressPos.y, mouseX, mouseY );
image( tapiocaImage, mouseX-tapiocaSize/2, mouseY-tapiocaSize/2, tapiocaSize, tapiocaSize );
}
}
void mousePressed() {
isDrag = true;
pressPos = new PVector( mouseX, mouseY );
}
void mouseReleased() {
isDrag = false;
FCircle circle = new FCircle( tapiocaSize );//タピオカの大きさの円を作る
circle.setPosition(mouseX, mouseY);//マウスの位置に移動
circle.attachImage(tapiocaImage);//円に画像を貼り付ける。
circle.addForce( (pressPos.x - mouseX )*3000, (pressPos.y - mouseY)*3000 );//クリックした位置と、現在のマウスの位置を比較して、物体に力を加える
world.add(circle);//物理演算に円を登録する
}
制限時間を設ける
制限時間を設けて、0になったらGAME OVERと表示します。
import fisica.*;//ライブラリのインポート
FWorld world;//物理演算を司るオブジェクト
PImage tapiocaImage;//タピオカの画像
float tapiocaSize;//タピオカの大きさ
PVector pressPos;//マウスをクリックした位置
boolean isDrag;//ドラッグ中のフラグ
PImage glassImage;//グラスの画像
int limitTime;//制限時間
int startTime;//開始時間
boolean isOver;//ゲームオーバーしているかどうか
void setup() {
size(1000, 1000);
Fisica.init(this);//ライブラリを初期化
world = new FWorld();//世界を司るオブジェクトを生成
world.setEdges();//ウィンドウの端に壁を作る
tapiocaSize = 50;//タピオカの大きさ
tapiocaImage = loadImage("tapioca_black.png");//タピオカの画像
tapiocaImage.resize(int(tapiocaSize), int(tapiocaSize));//画像サイズを円にあわせる
isDrag = false;
glassImage = loadImage("glassware05.png");//グラスの画像
FPoly glassBody = new FPoly();//グラスの形状
glassBody.vertex(380, 560);
glassBody.vertex(400, 910);
glassBody.vertex(630, 910);
glassBody.vertex(650, 560);
glassBody.vertex(640, 560);
glassBody.vertex(620, 900);
glassBody.vertex(410, 900);
glassBody.vertex(390, 560);
glassBody.setStatic(true);//固定する
glassBody.setNoFill();//塗りを非表示
glassBody.setNoStroke();//線を非表示
world.add(glassBody);//ワールドに追加
limitTime = 30000;//制限時間
startTime = millis();//開始時間
}
void draw() {
if ( isOver == false ) {
background(255);
image( glassImage, 344, 500, 172*2, 250*2 );//背景画像を表示
world.step();//物理演算を進める
world.draw();//オブジェクトを描画
if ( isDrag ) {//ドラッグ中ならば、
stroke( 255, 127, 0 );
strokeWeight(2);
line( pressPos.x, pressPos.y, mouseX, mouseY );
image( tapiocaImage, mouseX-tapiocaSize/2, mouseY-tapiocaSize/2, tapiocaSize, tapiocaSize );
}
int durationTime = millis() - startTime;//開始時間から現在時間を引いて、経過時間を求める
int remainingTime = limitTime - durationTime;//制限時間から経過時間を引いて、残り時間を求める
fill(0);
textAlign(CENTER);
textSize( 50 );
text( remainingTime/1000, width/2, 100 );//タピオカの残り数を表示
if ( remainingTime <= 0 ) {//残り時間が0以下になったら、
gameOver();//ゲームオーバーの処理
}
}
}
void mousePressed() {
isDrag = true;
pressPos = new PVector( mouseX, mouseY );
}
void mouseReleased() {
isDrag = false;
FCircle circle = new FCircle( tapiocaSize );//タピオカの大きさの円を作る
circle.setPosition(mouseX, mouseY);//マウスの位置に移動
circle.attachImage(tapiocaImage);//円に画像を貼り付ける。
circle.addForce( (pressPos.x - mouseX )*3000, (pressPos.y - mouseY)*3000 );//クリックした位置と、現在のマウスの位置を比較して、物体に力を加える
world.add(circle);//物理演算に円を登録する
}
void gameOver() {
isOver = true;
fill(255, 0, 0);
textAlign(CENTER);
textSize( 100 );
text("GAME OVER", width/2, height/2 );//ゲームオーバーの表示
}
グラスに入った個数を数える
制限時間になったときに、グラスに入っている個数を数えて表示します。
ArrayList bodys = world.getBodies();
この行で、worldに登録されているオブジェクトの配列(ArrayList)を取得します。
for ( Object object : bodys ) { }
for文をこのように書くとArrayListに含まれる項目がobjectとして取り出され、すべてのオブジェクトに操作を行うことができます。
if ( x>400 && x<640 && y>560 && y<900 ) {//グラスの範囲内ならば、
count++;//カウントを1増やす
}
とりだしたオブジェクトの座標が、グラスの範囲内ならカウントを1増やします。すべてをチェックすると入っている個数がわかります。
import fisica.*;//ライブラリのインポート
FWorld world;//物理演算を司るオブジェクト
PImage tapiocaImage;//タピオカの画像
float tapiocaSize;//タピオカの大きさ
PVector pressPos;//マウスをクリックした位置
boolean isDrag;//ドラッグ中のフラグ
PImage glassImage;//グラスの画像
int limitTime;//制限時間
int startTime;//開始時間
boolean isOver;//ゲームオーバーしているかどうか
void setup() {
size(1000, 1000);
Fisica.init(this);//ライブラリを初期化
world = new FWorld();//世界を司るオブジェクトを生成
world.setEdges();//ウィンドウの端に壁を作る
tapiocaSize = 50;//タピオカの大きさ
tapiocaImage = loadImage("tapioca_black.png");//タピオカの画像
tapiocaImage.resize(int(tapiocaSize), int(tapiocaSize));//画像サイズを円にあわせる
isDrag = false;
glassImage = loadImage("glassware05.png");//グラスの画像
FPoly glassBody = new FPoly();//グラスの形状
glassBody.vertex(380, 560);
glassBody.vertex(400, 910);
glassBody.vertex(630, 910);
glassBody.vertex(650, 560);
glassBody.vertex(640, 560);
glassBody.vertex(620, 900);
glassBody.vertex(410, 900);
glassBody.vertex(390, 560);
glassBody.setStatic(true);//固定する
glassBody.setNoFill();//塗りを非表示
glassBody.setNoStroke();//線を非表示
world.add(glassBody);//ワールドに追加
limitTime = 30000;//制限時間
startTime = millis();//開始時間
}
void draw() {
if ( isOver == false ) {
background(255);
image( glassImage, 344, 500, 172*2, 250*2 );//背景画像を表示
world.step();//物理演算を進める
world.draw();//オブジェクトを描画
if ( isDrag ) {//ドラッグ中ならば、
stroke( 255, 127, 0 );
strokeWeight(2);
line( pressPos.x, pressPos.y, mouseX, mouseY );
image( tapiocaImage, mouseX-tapiocaSize/2, mouseY-tapiocaSize/2, tapiocaSize, tapiocaSize );
}
int durationTime = millis() - startTime;//開始時間から現在時間を引いて、経過時間を求める
int remainingTime = limitTime - durationTime;//制限時間から経過時間を引いて、残り時間を求める
fill(0);
textAlign(CENTER);
textSize( 50 );
text( remainingTime/1000, width/2, 100 );//タピオカの残り数を表示
if ( remainingTime <= 0 ) {//残り時間が0以下になったら、
gameOver();//ゲームオーバーの処理
}
}
}
void mousePressed() {
isDrag = true;
pressPos = new PVector( mouseX, mouseY );
}
void mouseReleased() {
isDrag = false;
FCircle circle = new FCircle( tapiocaSize );//タピオカの大きさの円を作る
circle.setPosition(mouseX, mouseY);//マウスの位置に移動
circle.attachImage(tapiocaImage);//円に画像を貼り付ける。
circle.addForce( (pressPos.x - mouseX )*3000, (pressPos.y - mouseY)*3000 );//クリックした位置と、現在のマウスの位置を比較して、物体に力を加える
world.add(circle);//物理演算に円を登録する
}
void gameOver() {
isOver = true;
fill(255, 0, 0);
textAlign(CENTER);
textSize( 100 );
text("GAME OVER", width/2, height/2 );//ゲームオーバーの表示
textSize( 100 );
text( countInside(), width/2, height/2+100 );//グラスに入っているタピオカの数を表示
}
int countInside() {
ArrayList bodys = world.getBodies();//すべての物理オブジェクトを取り出す
int count = 0;
for ( Object object : bodys ) {
FBody body = (FBody)object;
float x = body.getX();//位置を取り出す
float y = body.getY();
if ( x>400 && x<640 && y>560 && y<900 ) {//グラスの範囲内ならば、
count++;//カウントを1増やす
}
}
return count;//グラス範囲内の数を返す
}
操作できる範囲を制限する
ゲーム性を加えるため、画面の下半分だけ操作できるように制限します。
import fisica.*;//ライブラリのインポート
FWorld world;//物理演算を司るオブジェクト
PImage tapiocaImage;//タピオカの画像
float tapiocaSize;//タピオカの大きさ
PVector pressPos;//マウスをクリックした位置
boolean isDrag;//ドラッグ中のフラグ
PImage glassImage;//グラスの画像
int limitTime;//制限時間
int startTime;//開始時間
boolean isOver;//ゲームオーバーしているかどうか
int operationalHeight;//タピオカを作れる範囲
void setup() {
size(1000, 1000);
Fisica.init(this);//ライブラリを初期化
world = new FWorld();//世界を司るオブジェクトを生成
world.setEdges();//ウィンドウの端に壁を作る
tapiocaSize = 50;//タピオカの大きさ
tapiocaImage = loadImage("tapioca_black.png");//タピオカの画像
tapiocaImage.resize(int(tapiocaSize), int(tapiocaSize));//画像サイズを円にあわせる
isDrag = false;
glassImage = loadImage("glassware05.png");//グラスの画像
FPoly glassBody = new FPoly();//グラスの形状
glassBody.vertex(380, 560);
glassBody.vertex(400, 910);
glassBody.vertex(630, 910);
glassBody.vertex(650, 560);
glassBody.vertex(640, 560);
glassBody.vertex(620, 900);
glassBody.vertex(410, 900);
glassBody.vertex(390, 560);
glassBody.setStatic(true);//固定する
glassBody.setNoFill();//塗りを非表示
glassBody.setNoStroke();//線を非表示
world.add(glassBody);//ワールドに追加
limitTime = 30000;//制限時間
startTime = millis();//開始時間
operationalHeight = 600;//タピオカを作れる高さ
}
void draw() {
if ( isOver == false ) {
background(255);
noStroke();
fill( 216, 255, 236 );
rect( 0, operationalHeight, width, height-operationalHeight );//操作できるエリアを塗りつぶす
image( glassImage, 344, 500, 172*2, 250*2 );//背景画像を表示
world.step();//物理演算を進める
world.draw();//オブジェクトを描画
if ( isDrag ) {//ドラッグ中ならば、
stroke( 255, 127, 0 );
strokeWeight(2);
line( pressPos.x, pressPos.y, mouseX, mouseY );
image( tapiocaImage, mouseX-tapiocaSize/2, mouseY-tapiocaSize/2, tapiocaSize, tapiocaSize );
}
int durationTime = millis() - startTime;//開始時間から現在時間を引いて、経過時間を求める
int remainingTime = limitTime - durationTime;//制限時間から経過時間を引いて、残り時間を求める
fill(0);
textAlign(CENTER);
textSize( 50 );
text( remainingTime/1000, width/2, 100 );//タピオカの残り数を表示
if ( remainingTime <= 0 ) {//残り時間が0以下になったら、
gameOver();//ゲームオーバーの処理
}
}
}
void mousePressed() {
if ( mouseY > operationalHeight) {
isDrag = true;
pressPos = new PVector( mouseX, mouseY );
}
}
void mouseReleased() {
if ( isDrag ) {
isDrag = false;
FCircle circle = new FCircle( tapiocaSize );//タピオカの大きさの円を作る
circle.setPosition(mouseX, mouseY);//マウスの位置に移動
circle.attachImage(tapiocaImage);//円に画像を貼り付ける。
circle.addForce( (pressPos.x - mouseX )*3000, (pressPos.y - mouseY)*3000 );//クリックした位置と、現在のマウスの位置を比較して、物体に力を加える
world.add(circle);//物理演算に円を登録する
}
}
void gameOver() {
isOver = true;
fill(255, 0, 0);
textAlign(CENTER);
textSize( 100 );
text("GAME OVER", width/2, height/2 );//ゲームオーバーの表示
textSize( 100 );
text( countInside(), width/2, height/2+100 );//グラスに入っているタピオカの数を表示
}
int countInside() {
ArrayList bodys = world.getBodies();//すべての物理オブジェクトを取り出す
int count = 0;
for ( Object object : bodys ) {
FBody body = (FBody)object;
float x = body.getX();//位置を取り出す
float y = body.getY();
if ( x>400 && x<640 && y>560 && y<900 ) {//グラスの範囲内ならば、
count++;//カウントを1増やす
}
}
return count;//グラス範囲内の数を返す
}
0 notes