
今回はProcessingでドロップザナンバーゲームにチャレンジしてみます!
こんにちは。コメ吉です。
最近暑い日が続きますね。コメ吉はクーラーの効いた部屋からなかなか出られません(笑)
本日はProcessingを使ったゲーム作成にチャレンジしてみたいと思います。
具体的には、数字が書かれたブロックが落ちてくるゲームをProcessingで作ってみました。
ブロックが落ちてくる時の、動作の実装方法、数字が加算されるコーディングなどについて書いています。
長男に教えてもらいながら、少し形になりましたので、以下コード含め共有させて頂きますので、ご参考になれば幸いです。
Processingでドロップザナンバーゲームにチャレンジ!? コードを詳しくチェックしてみた!
Processingの概要
過去の記事に Processingの導入、基本的な操作に関しては記載していますので、Processingに触れたことがない、という方は以下ご参照頂けますと幸いです。
>プログラミングでデザインに挑戦!? 初心者でも取り組みやすいProcessingを体験!https://comekichi.com/2022/09/24/プログラミングでデザインに挑戦?%E3%80%80初心者でも/
今回作成できるゲームの概要
まずはどんなゲームなのか、以下イメージ動画になります。
数字が書いてあるブロックを積み上げるゲームですね。
同じ数字のブロックを置いた場合、元々あったブロックに新しく置いたブロックが吸収されて、その際に、新しく置いたブロックの数字が加算されるタイプのゲームになります。
今回のプログラミングの前提になる情報として、「Processingのブロック崩しゲーム」については以下の記事でまとめていますので、ご興味があればご覧下さい。「配列」と呼ばれる手法について記載しています。
>Processing ゲーム作りに挑戦!ブロック崩しゲームで遊んでみた!https://comekichi.com/2023/04/09/processing-ゲーム作りに挑戦!ブロック崩しゲームで遊ん/
プログラミングのポイント
以下、ポイントと思われることを書いていきますね。
どうやってブロックが積みあがるようにさせる?
今回はドロップ・ナンバーゲームに似たゲームを作成していきますが、最初に悩んだのは落ちてきたブロックをどのように積みあがっていくようにさせるか、ということです。
落ちてきた四角形をそのまま積み上げさせるのは難しそうなので、「落ちてくる四角形」と「積みあがるように表示される四角形」別々に設置することにしました。
また、以前ブロック崩しゲームを書いたときに「配列」と呼ばれる手法で作成しましたが、その時の「配列」も応用して作ってみました。今回は「yList」と「xList」、「Mane」という配列が大事な役割を果たしています。
「xList,yList」という配列は「もし四角形が落ちてきたらこの位置に四角形を配置する」というもので、落ちてくる四角形がこの配列に登録されている座標と一致すればそこに新しく四角形が描画されます。
続いてManeという配列(名前の由来は英語の“管理”という意味のManageに由来しています)ですがこれはどの位置に四角形を表示させるかを管理させるための配列で
先ほど説明したように落ちてくる四角形がxList[i] とyList[i]に一致すればMane[i]が”IESとなり、新しい四角形が表示され、積みあがっていくように表示されるのです。
このアプローチをコードに表すと以下のようになります。
if (dropPOS==720&&Xpos==xList[i]&&dropPOS==yList[i]) {
Mane[i]="IES";
dropActive="n";
}
if (Xpos==xList[i]&&dropPOS==yList[i]&&Mane[i+1]=="IES"&&Mane[i]=="Nothing") {
Mane[i]="IES";
No[i]=uesuuti;
dropActive="n";
uesuuti = (int)random(1, 9);//ランダム数値を生成
}
ちなみに配列dropActiveというものがありますが、これはユーザーが四角形を落とすボタン(ここではsキー)を連打して四角形が重なるくらいに大量に落とされ、複数の四角形が同じ場所に積もってエラーにならないようにするためのもので、四角形が落ちている間は”y”となり、四角形がこれ以上落ちないようにさせます。
そして新しく四角形が描画されればdropActiveの中身は“n”となりいつでも四角形を落としていいようにスタンバイ状態になります。
ランダムに数値を生成
今回のゲームは数字が書かれたキューブが落ちてくるようなゲームですが、これの数値はどのようにして作られるのでしょうか?これには「乱数」というものが関係してます。
乱数はその名の通り、コンピューターが数値をランダムに生成するものです。ナンバーザドロップゲームでは、ゲームが始まった直後と毎回四角形が一つ積もったときに生成されます。
今回のゲームのように1~9までの数値を生成する方法は以下のようになります。
(int)random(1, 9);
補足ですが、randomの前に(int)という文字を打ち込んでいるのは「整数だけしか数字を生成しないで~」といった感じと思ってもらえて大丈夫です。ちなみにここを(String)にすると小数点も生成されます。
しかし乱数では生成した数値を入れる場所がないとその数値は利用できないようになっています(これの数値を入れる場所のことをを引数といいますが数じゃないです。
は覚えておくと役に立つかもしれません)。そこで今回のゲームでは、uesuutiという引数を」用意して代入させることで、違う数値を表示させるようにセットさせているのです。そして四角形が降り積もったときに配列Noにuesuutiにある数値を代入させ各々の四角形に表示させるになるのです。
数値が同じときには四角形がドッキングする
今回最も苦労したのは「縦か横もしくはその両方の積もった四角形の数値が同じならくっついて一つになる」部分のコーディングです。
これには最初どのように本物のナンバーザドロップゲームのように四角形同士がくっつくアニメーションを作るか等色々考えましたが、最も簡単な方法で考え、四角形が瞬間的にくっつくようにさせました。
また、「下の数値が同じ」「右の数値」「左の数値」「左右の数値」「左右下」というようにパターン別に分けて数値が同じかどうかも判定させるのも難しかったですが、何とか苦労の末できました。
コードの内訳は以下のようになります。
if (Mane[i]=="IES"&&Mane[i+1]=="Nothing"&&yList[i]<720) {
No[i+1]=No[i];
delay(100);
Mane[i+1]="IES";
No[i]=0;
Mane[i]="Nothing";
score=score+No[i];
}
if (dropPOS==720&&Xpos==xList[i]&&dropPOS==yList[i]) {
Mane[i]="IES";
dropActive="n";
}
if (i>10&&i<41) {
if (Mane[i]=="IES"&&No[i+1]==No[i]&&No[i+10]==No[i]&&No[i-10]==No[i]) {
No[i]=No[i]*4;
Mane[i+10]="Nothing";
Mane[i+1]="Nothing";
Mane[i-10]="Nothing";
}
if (Mane[i]=="IES"&&No[i+10]==No[i]&&No[i-10]==No[i]) {
No[i]=No[i]*3;
Mane[i+10]="Nothing";
Mane[i-10]="Nothing";
score=score+No[i];
}
}
if (i>10) {
if (Mane[i]=="IES"&&No[i-10]==No[i]&&No[i+1]==No[i]) {
No[i]=No[i]*3;
Mane[i-10]="Nothing";
Mane[i+1]="Nothing";
score=score+No[i];
}
if (Mane[i]=="IES"&&No[i-10]==No[i]&&xList[i]==dropRectPos) {
No[i]=No[i-10]+No[i];
Mane[i-10]="Nothing";
score=score+No[i];
}
}
if (10<i&&i<41) {
if (Mane[i]=="IES"&&No[i+10]==No[i]&&No[i-10]==No[i]) {
No[i]=No[i]*3;
No[i+1]=0;
No[i-1]=0;
Mane[i+10]="Nothing";
Mane[i-10]="Nothing";
score=score+No[i];
}
}
if (i<41) {
if (Mane[i]=="IES"&&No[i+1]==No[i]&&No[i+10]==No[i]) {
No[i]=No[i]*3;
Mane[i+10]="Nothing";
Mane[i+1]="Nothing";
score=score+No[i];
}
if (Mane[i]=="IES"&&No[i+10]==No[i]&&xList[i]==dropRectPos) {
No[i]=No[i+10]+No[i];
Mane[i+10]="Nothing";
score=score+No[i];
}
}
if (Mane[i]=="IES"&&No[i+1]==No[i]&&xList[i]==dropRectPos) {
No[i]=No[i+1]+No[i];
Mane[i+1]="Nothing";
score=score+No[i];
}
if (Mane[i]=="Nothing"&&No[i]>0) {
No[i]=0;
}
四角形が底面にあるときとそうでないときの場合にも分けました。
子の四角形のくっつく時の一連の流れとしては、
(1)左右もしくは下の四角形の数値が一致→(2)相手の四角形の数値を自分のほうに加算→(3)相手の四角形の数値を0にし、Mane[i]も0にして四角形を非表示
同じ数値の四角形がある場合は、(1)→(2)相手の四角形に自分の数値を加算→自分の四角形の数値を0にし、Mane[i]も0にして四角形を非表示
となります。
終わりに
今回は「ナンバーザドロップの」基本的なコーディングを説明させていただきました。しかし多少の不具合、例えば四角形の数値が左右一致しても合わさらない時がたまにある等、一部不具合がありますので、その点だけご了承ください。
コード全体
これまでご説明してきたコード全体を以下に記載しますので、ご参考になれば幸いです。
動作の不具合などは今後も改善いきたいと思います。
float[] xList =new float[51];
float[] yList =new float[51];
int[] No =new int[51];
String[] Mane =new String[51];
int UE =1;
int dropPOS=0;
String dropActive ="n";
int z =0;
int c =0;
int uesuuti=0;
int mojidrop;
int Xpos;
int[] Rcolor =new int[51];
int[] Gcolor =new int[51];
int[] Bcolor =new int[51];
//float moveRectx = 2000;
//float moveRecty = 2000;
String gameActive="Notstart";
//PFont myFont = loadFont("BradleyHandITC-48.vlw");
int score=0;
int dropRectPos;
void setup() {
//textFont(myFont);
size(400, 800);
Mane[50]="IES";
for (int i=0; i<50; i++) {
yList[i]=80*z;
xList[i]=80*c;
Mane[i]="Nothing";
z +=1;
println(i, xList[i], yList[i]);
if (z>9) {
z=0;
c +=1;
}
}
uesuuti = (int)random(1, 6);
println(uesuuti);
}
void draw() {
//println(Xpos);
background(0);
if (gameActive=="Notstart"&&mouseX>=110&&mouseX<=110+200&&mouseY>=400&&mouseY<=400+89) {
rect(110, 400, 200, 89);
fill(200, 10, 55);
fill(255, 222, 255);
}
if (gameActive=="Notstart") {
textSize(24);
rect(110, 400, 200, 89);
fill(200, 10, 55);
text("Drop de number", 130, 445);
fill(255, 255, 255);
textSize(50);
text("Tap here to start", 100, 55);
}
if (gameActive=="start") {
text("Score"+score, 40, 40);
for (int i=0; i<50; i++) {
if (score%500==0) {
int s = second();
if (s<3) {
text (score, 400, 400);
fill(0, 0, 255);
}
if (s==3) {
s=0;
}
}
Rcolor[i]=10*No[i];
Gcolor[i]=2*No[i];
Bcolor[i]=255-2*No[i];
if (Mane[i]=="IES"&&Mane[i+1]=="Nothing"&&yList[i]<720) {
No[i+1]=No[i];
delay(100);
Mane[i+1]="IES";
No[i]=0;
Mane[i]="Nothing";
score=score+No[i];
}
if (dropPOS==720&&Xpos==xList[i]&&dropPOS==yList[i]) {
Mane[i]="IES";
dropActive="n";
}
if (i>10&&i<41) {
if (Mane[i]=="IES"&&No[i+1]==No[i]&&No[i+10]==No[i]&&No[i-10]==No[i]) {
No[i]=No[i]*4;
Mane[i+10]="Nothing";
Mane[i+1]="Nothing";
Mane[i-10]="Nothing";
}
if (Mane[i]=="IES"&&No[i+10]==No[i]&&No[i-10]==No[i]) {
No[i]=No[i]*3;
Mane[i+10]="Nothing";
Mane[i-10]="Nothing";
score=score+No[i];
}
}
if (i>10) {
if (Mane[i]=="IES"&&No[i-10]==No[i]&&No[i+1]==No[i]) {
No[i]=No[i]*3;
Mane[i-10]="Nothing";
Mane[i+1]="Nothing";
score=score+No[i];
}
if (Mane[i]=="IES"&&No[i-10]==No[i]&&xList[i]==dropRectPos) {
No[i]=No[i-10]+No[i];
Mane[i-10]="Nothing";
score=score+No[i];
}
}
if (10<i&&i<41) {
if (Mane[i]=="IES"&&No[i+10]==No[i]&&No[i-10]==No[i]) {
No[i]=No[i]*3;
No[i+1]=0;
No[i-1]=0;
Mane[i+10]="Nothing";
Mane[i-10]="Nothing";
score=score+No[i];
}
}
if (i<41) {
if (Mane[i]=="IES"&&No[i+1]==No[i]&&No[i+10]==No[i]) {
No[i]=No[i]*3;
Mane[i+10]="Nothing";
Mane[i+1]="Nothing";
score=score+No[i];
}
if (Mane[i]=="IES"&&No[i+10]==No[i]&&xList[i]==dropRectPos) {
No[i]=No[i+10]+No[i];
Mane[i+10]="Nothing";
score=score+No[i];
}
}
if (Mane[i]=="IES"&&No[i+1]==No[i]&&xList[i]==dropRectPos) {
No[i]=No[i+1]+No[i];
Mane[i+1]="Nothing";
score=score+No[i];
}
if (Mane[i]=="Nothing"&&No[i]>0) {
No[i]=0;
}
if (Xpos==xList[i]&&dropPOS==yList[i]&&Mane[i+1]=="IES"&&Mane[i]=="Nothing") {
Mane[i]="IES";
No[i]=uesuuti;
dropActive="n";
uesuuti = (int)random(1, 9);
}
if (Xpos==xList[i]&&dropPOS==yList[i]&&dropPOS==720) {
No[i]=uesuuti;
dropActive="n";
//uesuuti = (int)random(1,6);
}
if (Mane[i]=="IES") {
rect(xList[i], yList[i], 80, 80);
fill(222, 244, 255);
}
if (No[i]==0) {
} else {
text(No[i], xList[i]+20, yList[i]+60);//各々のサイコロに表す文字
textSize(35);
fill(222, 244, 255);
}
fill(Rcolor[i], Bcolor[i], Gcolor[i]);
}
Xpos=80*UE;
rect(80*UE, 0, 80, 80);//上の四角形
rect(Xpos, dropPOS, 80, 80);//落ちる四角形そのもの
fill(255, 255, 255);
text(uesuuti, 80*UE+20, mojidrop+50);//落ちる四角形についてくる文字
fill(255, 255, 255);
textSize(35);
text(uesuuti, 80*UE+20, 60);//上だけで操作する文字
textSize(35);
fill(255, 255, 255);
if (key=='s') {
mojidrop=dropPOS+=10;
if (dropActive =="y") {
dropPOS +=10;
//println(dropPOS);
}
}
if (dropPOS+80>800) {
dropActive ="n";
}
if (dropActive=="n") {
dropPOS=0;
}
}
}
void keyPressed() {
if (gameActive=="start") {
if (dropActive=="n") {
if (key =='d') {
if (UE<4) {
UE +=1;
}
}
if (key=='a') {
if (UE>0) {
UE -=1;
}
}
}
if (key=='s') {
dropRectPos=80*UE;
dropActive ="y";
//uesuuti = (int)random(1,200);
}
}
}
void mousePressed() {
if (gameActive=="Notstart"&&mouseX>=110&&mouseX<=110+200&&mouseY>=400&&mouseY<=400+89) {
fill(255, 202, 255);
gameActive="start";
}
}
最後までお読み頂きありがとうございました。
以下、コメ吉の記事になりますので、ご興味があればご覧下さい。
>>プログラミング 就職サポートをしてくれる!? ITエンジア志望必見のスクールのご紹介!https://comekichi.com/2023/04/02/プログラミング-就職サポートをしてくれる!?-it/



コメント