Processingでなんかつくろう
はじめに
ProcessingとかJavaとかオブジェクト指向はよくわからんけど、とりあえずなんか動くゲーム作ってプログラミングに触れたいってコース。
まずはクラスなんか作らずに、動くものを目指す
簡単なSTG(シューティングゲーム)を作る。
画面~自機
とりあえず自機をポン置きしてみよう
使う関数はsizeとtriangle
それぞれ setup()とdraw()に書こう。
trigangleは3頂点の座標をうつだけなので、適当に。
void settings() {
size(600 , 600);
}
void draw(){
triangle(300,300,250,400,350,400);
}
おけた。
今度はこれを動かす。
動かすには、trigangleの座標を動かす必要がある。
実行中に数字打ち直すわけにいかんので、これらを変数で置き直す
プレイヤーのx、y座標なので安直にpx,pyとした
draw関数内に書くと毎回宣言し直されて位置変わらないので注意!
int px = 300;
int py = 300;
void draw(){
triangle(px,py,px-50,py+100,px+50,py+100);
px += 2;
py += 2;
}
しかし、このように画面が更新されず軌跡が残り続けるので、毎回画面を真っ更にする必要がある。
background関数で画面を一気に色つけれるので、200とか入れて灰色にしよう。
この関数はこれからtriangleとか描写系関数よりも先に実行される必要がある(じゃないと塗りつぶされちゃう)
void draw(){
background(200);
triangle( 略
##操作可能にしよう
次にキーボードによる操作を可能にしてゲームっぽくする
キーボードが押されたら、keyPressed()て関数が実行されるので、これを記述する。
void keyPressed() {
if(keyCode==LEFT){
px-=10;
}else if(keyCode==RIGHT){
px+=10;
}else if(keyCode==UP){
py-=10;
}else if(keyCode==DOWN){
py+=10;
}
}
void draw(){
background(200);
triangle(px,py,px-50,py+100,px+50,py+100);
}
ここで、どのキーが押されたか判定は、変数keyCodeを見る。LEFT,RIGHT等は既に変数として用意されているので利用。
押されたキーに対応するよう座標を+-で調整しよう。
ここで座標軸の向きに注意!x→、y↓の向きで正
px+=2を消すのをお忘れなく
弾を撃とう
シューティングゲームなので、発砲したい。
まずは弾丸を用意しよう。これも同じように変数で用意する。Tamaなのでtx,tyとした。
とりあえず四角形(rect)でおく
int px = 300; // Player
int py = 300;
int tx = 300; // Tama
int ty = 300;
void keyPressed() {省略}
void draw(){
background(200);
triangle(px,py,px-50,py+100,px+50,py+100); //Player
rect(tx,ty,10,10); // Tama
ty -= 2 ;
}
弾のy座標が2づつ減ってくので、上にうちあがっていく
このままでは上に一生上がり続けるだけなので、発射ボタンを押したら自機から発射されるようにしたい。
→ボタンおしたら自機の座標に弾を移動。弾は上に上がり続ける。また押されたらまた移動・・・
これでいけそう。
int tx = 0; // Tama
int ty = 0;
void keyPressed() {
if(keyCode==LEFT){
px-=10;
}else if(keyCode==RIGHT){
px+=10;
}else if(keyCode==UP){
py-=10;
}else if(keyCode==DOWN){
py+=10;
}
if(key==' '){ // space!!!!!!
tx=px;
ty=py;
}
}
void draw(){略}
弾の宣言を0,0スタートにして、撃つまで出現しないように。
射撃をSpaceキーにしたが、矢印キーと違う条件式なのでこれも注意。
的を表示し、当たり判定をつける
的(敵)を表示する。なんとなく円で表示することとし、とりあえず適当においてみよう
座標は(100,100)、直径は90とする。
void draw(){
background(200);
triangle(px,py,px-50,py+100,px+50,py+100); //Player
rect(tx,ty,10,10); // Tama
ty -= 2 ; //ここまで同じ
ellipse(100,100,90,90);
}
もちろん弾は通過する。以下で的の座標を利用するので、これも変数でおいてしまおう。
変数名は、ボール1つめってことでb1x,b1yとした。
略
int b1x=100;
int b1y=100;
略
void draw(){
略
ty -= 2 ; //ここまで同じ
ellipse(b1x,b1y,90,90);
}
今度は当たり判定を考えるが、"当たった"と判定する関数は用意されていないので、条件式を考える必要がある。
このゲーム、やっているのは指定した座標に図形を設置しているだけなので、すべて座標で計算すればよさそう。
→当たる=座標が重なる、ということなので、これをif文で書く。
当たったら的の座標を(1000,1000)とかに飛ばしておけば見えなくなるのでとりあえずOK!
void draw(){
略
ellipse(b1x,b1y,90,90);
if(tx > b1x-45 && tx < b1x+45 && ty > b1y-45 && ty < b1y+45) {
b1x = 1000;
b1y = 1000;
}
当たり判定を図解↓
とりあえずこれでクソゲー完成。
コードをまとめておく
void setup() {
size(600, 600);
}
int px = 300; //Player
int py = 300;
int tx = 0; // Tama
int ty = 0;
int b1x=100; // Ball 1
int b1y=100;
void keyPressed() {
if (keyCode==LEFT) { //Move
px-=10;
} else if (keyCode==RIGHT) {
px+=10;
} else if (keyCode==UP) {
py-=10;
} else if (keyCode==DOWN) {
py+=10;
}
if (key==' ') { // Space key
tx=px;
ty=py;
}
}
void draw() {
background(200);
triangle(px, py, px-50, py+100, px+50, py+100); //Player
rect(tx, ty, 10, 10); // Tama
ty -= 2 ;
ellipse(b1x, b1y, 90, 90);
if (tx>(b1x-45) && tx<b1x+45 && ty>b1y-45 && ty<b1y+45) { // Hit judge
b1x = 1000; // Out of Range
b1y = 1000;
}
}
色をつけよう
モノクロは味気ないので、色を付ける。
インベーダーっぽく背景は適当に紺色、自機好きな色(ピンク)にしよう
的は赤、弾は黄色とかにしてみる。
背景はbacground(R,G,B);
で色付け。
他の図形はfill(R,G,B)
で色付けできる。
ちなみに、標準IDEを使ってる場合、適当にfill(0,0,0)
とか打って、上のメニューからスケッチ→Tweak
で実行すると色がビジュアル的に変更できる。
関係部以外省略
void draw() {
background(0, 0, 50);
fill(246,118,255);
triangle(px, py, px-50, py+100, px+50, py+100); //Player
fill(255,255,0);
rect(tx, ty, 10, 10); // Tama
fill(229,10,98);
ellipse(b1x, b1y, 90, 90);
}
色をセットするとこうなる。
そこそこですね。
量産
的が1つなのは味気ないので、3つくらい設置しよう。
同じように、b2x,b2y b3x,b3yとする。
本当はオブジェクト指向に則ってクラスを使うべきだが、簡単に済ませるため割愛。2部でやる
int b1x=100; // Ball 1
int b1y=100;
int b2x=200; // Ball 2
int b2y=150;
int b3x=300; // Ball 3
int b3y=100;
略
void draw(){
略
fill(229,10,98);
ellipse(b1x, b1y, 90, 90);
fill(200,10,0);
ellipse(b2x, b2y, 90, 90);
fill(100,10,200);
ellipse(b3x, b3y, 90, 90);
if (tx>(b1x-45) && tx<b1x+45 && ty>b1y-45 && ty<b1y+45) { // Hit judge
b1x = 1000; // Out of Range Tama 1
b1y = 1000;
}
if (tx>(b2x-45) && tx<b2x+45 && ty>b2y-45 && ty<b2y+45) { // Hit judge
b2x = 1000; //Tama2
b2y = 1000;
}
if (tx>(b3x-45) && tx<b3x+45 && ty>b3y-45 && ty<b3y+45) { // Hit judge
b1x = 1000; //Tama3
b1y = 1000;
}
}
END表示したい
END表示したい
的を3つ消したらENDて表示させたいですね。
これには、残りの的の数を記憶する変数を用意して、0になったらEND表示させましょう。
各当たり判定の処理に残り数を減らすコードも必要
int Nokori = 3
略
void draw(){
略
if(当たり判定
b1x =1000;
b1y =1000;
Nokori-- ; //残り数減らす
}
下2つも同じように
if(Nokori == 0){
fill(255,255,255); //好きな色で
textSize(100); //お好み
text("END",300,300); //座標300,300にEND表示
}
これで一応ENDが出るが、真ん中から左づめで文字表示されててダサい。座標をずらしてもいいけど、ここは中央揃いで表示させる
一回の実行でいいのでセットアップに書く
void setup(){
size(600,600);
textAlign(CENTER);
}
きれい?
秒数表示
せっかくなので、タイムアタック出来るようにする。
時間を測る関数に、millis()
というのがあるのでこれを使う。これはプログラム開始時からこの処理が実行されたタイミングまでの時間を返す。
例えば、int m = millis();
と書いて、これが1.5秒後に実行されたとすると、mには
1500が入る、というわけである。
次に、時間を表示したいなら、
int time = millis() / 1000 ;
text(time,50,500);
をdraw()の中に書けば毎回timeが更新されるので、現在の秒数が表示される。0.x秒数で表示したいなら100で割ればいい。少数で表示するならintをfloatにすればOK
今回はint time = millis() / 100 ;
としよう
というわけでdraw関数中に書けば
略
void draw(){
略
int time = millis() / 100 ;
fill(253, 8, 146);
textSize(30);
text(time, 50, 550);
}
このように時間表示が可能となる。
なお、カウントアップは止まらない。
END時にタイムも表示
単に、if(Nokori == 0)
の中に、text(m,300,400)
と書けばよさそうに見えるが、それだと「終了した時のタイム」ではなく「現在のタイム」が表示される。(つまりカウントアップしたまま)
これでは困るので、的が3つ消えた時点でタイムを取得して、ENDと共に表示すればOKというわけだ。
この「的が3つ消えた時点でタイムを取得」の処理が難しいが、今回は残り的数を少し工夫して対応する。
具体的には、
的が1〜3こ→何もしない
的が0こ→END表示
だったのを、
的が1〜3こ→何もしない
的が0こ→タイム取得 & 的の数を-1に
的が-1こ→END表示
とする。的が-1個というのが意味不明だが、0になったら自動的に-1になるので0みたいなものである。
これをif文で書くと、
int endTime = 0 ;
略
void draw()
略
if(Nokori == 0){
endTime = millis() /100 ;
Nokori = -1 ;
}else if(Nokori == -1){ //ここの処理は前のと同じ
fill(0,0,0)
textSize(30)
text("END",300,300);
text(endTime,300,400);
}
とすれば良い。
右下のタイマーはもう必要ないので消したい。
つまり、残り的数が1~3のときに表示してればいいので、elseにすれば解決。
if (Nokori == 0) {
endTime = millis() /100 ;
Nokori = -1 ;
} else if (Nokori == -1) {
fill(50, 50, 250);
textSize(100);
text("END", 300, 300);
text(endTime, 300, 400);
}else{
int time = millis() / 100 ;
fill(253, 8, 146);
textSize(30);
text(time, 50, 550);
}
ランダム
的の位置をランダムにする。
ランダムの関数はrandom(LOW,HIGH)
またはrandom(HIGH)
。これは中に1つ数字書くと0~その数字までの乱数、2つ書くとLOW~HIGHまでの乱数が帰ってくる。
返り値はfloatなのだが、座標は整数のため(int)(random~)で囲って整数に変える(ダウンキャスト)
int b1x = (int)( random(600) );
int b1y = (int)( random(400) );
int b2x=(int)( random(600) );
int b2y=(int)( random(400) );
int b3x=(int)( random(600) );
int b3y=(int)( random(400) );
おじゃまバー
弾を消し去るおじゃまバーを実装したい。
細い長方形を移動させて、当たったら、弾を画面外に飛ばせばOKかな
int lx=(int)( random(500) );
void draw(){
略(ellipseの次とか)
fill(206,255,34);
rect(lx,250,100,10);
lx += 3 ;
略
}
ああどこへ行ってしまう
困るので、壁で反射してもらう。反射については、移動スピードを逆向きにすればよい。
移動スピードをlspeedと置き、反射するタイミングで-1を掛ける。
int lx=(int)( random(500) );
int ly = 250 ;
int lspeed = 3 ;
void draw(){
略(ellipseの次とか)
fill(206,255,34);
rect(lx,ly,100,10);
lx += lspeed ;
if(lx <0 || lx >500){ // 反射
lspeed *= -1 ;
}
略
}
当たったときに、弾を消失させたいのでこれもifで
if(tx > lx && tx < lx + 100 && ty > ly && ty < ly+10){
tx = 1400; // かぶらなければどこでも
ty = 1000;
}
移動範囲制限をつける
このままでは敵にアタックして弾が打ててしまうので、画面下の方だけ移動できるようにしたい。
これもif文で処理する。
void draw()中に
if (px <= 0) {
px = 0;
} else if (px >= 600) {
px = 600;
}
if (py <= 400) {
py = 400;
} else if (py >= 540) {
py = 540;
}
##とりあえずここまで。