• 検索結果がありません。

p5.js p5.js p5.js Tetris Tetris

N/A
N/A
Protected

Academic year: 2021

シェア "p5.js p5.js p5.js Tetris Tetris"

Copied!
189
0
0

読み込み中.... (全文を見る)

全文

(1)

平成

28

年度

数学講究録

題目

p5.jsによるテトリスプログラム

ProcessingによるShooting Gameの作成

ProcessingのOthelloのプログラム作成

指導教員

冨田 耕史

120429030

熊澤 龍佑

130440071

堀部 達也

130440087

矢野 稜也

130440058

城  裕太

130440076

丸山 慎椰

130440090

山本 幸司

提出日

平成

29

1

30

差替日

平成

29

3

6

(2)

p5.js

によるテトリスプログラム

120429030

熊澤龍佑

130440071

堀部達也

130440087

矢野稜也

2017

3

4

目次

1 p5.jsとは 2 1.1 p5.js . . . 2 2 Tetrisの説明 2 2.1 Tetrisの歴史 . . . 2 2.2 ルール . . . 3 2.3 作成動機 . . . 3 3 Tetrisプログラムの説明 3 3.1 プログラムの使い方 . . . 3 3.2 p5.js内で使える関数の説明 . . . 4 3.3 Tetrisプログラムの流れ . . . 5 3.4 Tetrisプログラムの説明 . . . 6 4 問題点の整理 13 4.1 実際にプログラムを制作,実行しての問題点 . . . 13 4.2 今後の課題 . . . 14 5 まとめ 15 5.1 全体を通してのまとめ . . . 15

(3)

6 プログラムソースコード 15 6.1 test.html . . . 15 6.2 map1.js . . . 17 6.3 Tetorimino.js . . . 33

1

p5.js

とは

1.1

p5.js

p5.js はProcessingと同様の命令を使うことのできる, グラフィックスや音声, ゲーム などが作りやすくなっているJavaScriptのためのライブラリである. 内部で Canvasや WebAudioなど, 最近のMTML5の技術を用いている.ライブラリとは,ある特定の機能 を持ったプログラムを,他のプログラムから呼び出して利用できるように部分化し, その ようなプログラム部品を集めて1つのファイルに収納したものである.つまり,すでに出 来上がっているプログラムで利用可能な機能のことをさす. Processingはプログラムを教 える道具として,また視覚的なプログラムを書く道具としても, これからますます多方面 において活用できるものだと考えられる([1]参照). p5.js, Processingを学び, 容易にグラフィックが表現できることが実感できた. それに より, C 言語よりプログラム数も少なくよりシンプルにできると考えた. このことから, p5.jsを用いて数学的な概念を使うゲームを実際に制作し, 動作させたいと考えた.

2

Tetris

の説明

2.1

Tetris

の歴史

テトリスはロシアの科学者アクセイ・パジトノフのよって開発されたゲームである.当 初は学習用のソフトウエアとして開発された. テトリスは1984年に開発されて以降,様々 なゲームメーカーによって開発され,非常に多くのプラットフォームで発売され現在に 至っている. テトリスはシンプルなルールからなるが,次々と行を消していく爽快感から 多くのユーザーに長年支持されている.また,様々な国のゲーム会社にライセンス提供が 行われていることもテトリスが全世界でプレイされている要因となっている.テトリスは 世界でも有名な歴史のあるパズルゲームといえる([2]参照).

(4)

2.2

ルール

テトリスはテトリミノと呼ばれる7つのピースからなる. これらはすべて4つのブロッ クの組み合わせで作られている. 7つのテトリミノは下図のようになる. 左から順番に, O-テトリミノ, I-テトリミノ, T-テトリミノ, S-テトリミノ, Z-テトリミノ, L-テトリミノ, J-テトリミノ という. また,ゲームに必要なは操作は4つで, 「ブロックを 右に動かす」, 「ブロックを左に動かす」, 「ブロックを下に落とす」, 「ブロックを回転 させる」という単純な操作方法である. テトリスのルールは, 「一列ブロックが揃えば,ブロックを消す」, という非常に簡単なも のである. テトリスでは消した段数によって,「1段消し…シングル」, 「2段消し…ダブ ル」, 「3段消し…トリプル」, 「4段消し…テトリス」という名前で呼ばれる. 4つのブロックの組合せでブロックピースが構成される為, 4段消しのテトリスが最も高 得点となる([2]参照).

2.3

作成動機

テトリスを作ろうと決めた動機は, よくパズルゲームで見ること, また大多数の人が一 度は遊んだことがあるが, 動作する仕組みやプログラムの内容について知らず, プログラ ム方法について興味が湧いてきたからである. この身近なゲームを実際に自分たちの手で 一から作ってみたいと考えた.

3

Tetris

プログラムの説明

3.1

プログラムの使い方

次に(1)から(14)の説明をする.

(1) test.html, map1.js, Tetorimino.jsの3つのファイルを1つのフォルダに入れる. (2) test.htmlファイルをchromiumウェブブラウザ上で開く.

(3) で図1が表示されるので右クリックを押す.

(5)

する. この操作方法でテトリスをする. ゲームオーバーになると図2が表示される.

3.2

p5.js

内で使える関数の説明

createCanvas(x,y)の説明 引数x, y で縦(x),(y)の画面の幅を決める. background(x)の説明 引数xで背景の色を決める. 0(黒) 204(白)の間の値に設定する. frameRate(x)の説明 引数xで, 1秒間にx回draw関数をループさせるか設定する. fill(x,y,z)の説明 引数x(), y(), z(青)の配合で, 文字や図形の色を設定する. textSize(x)の説明 引数xで, 文字の大きさを決める. textの説明

(6)

text(" ")の " " 内に打った文字が表示される.

3.3

Tetris

プログラムの流れ

まずsetup関数による変数の宣言の初期化((1)から(8))をする. その後draw関数に よる繰り返し((9)から(14))よりなる. var m,t,b=0,c=0,k=0,x=4,y=0,r,q,g=0,w=0; //(1) //m:map1のインスタンス //t:tetoriminoのインスタンス //b:どのテトリミノを生成するのかの判断をする変数 //c:回転を判断する変数 //k:ミノを消す際,何段目を消したかを判断する変数 //x:落下させているミノの場所を判断する変数 //y:落下させているミノの場所を判断する変数 //r:map1にミノを書き込む際に用いる変数 //g:ゲームをスタートする際にスタートするかどうかを反する変数 //w:ゲームを終了する際に終了するかどうかを判断する変数 function setup(){ createCanvas(251,501); //キャンバスの大きさを指定 //(2) m=new Map1(10,20); //Map1の宣言と初期化 /*(3) t=new Tetorimino();  //Tetoriminoの宣言と初期化 */ m.init(); //init関数を呼び出す //(4) background(204); //背景を指定する /*(5) frameRate(7); //速度の指定 */ textFont("Source Code Pro"); //ゲーム開始画面を出す //(6)

fill(0,0,255); /*(7) textSize(35); */ text("GAME START",25,200); /*(8) fill(0); textSize(16); text("クリックしてください",80,240); */

(7)

}

function draw(){ if(g==1){

if(y==0) m.clear(); //clearの関数を呼び出し揃っている行を消す //(10) t.initMino(); //initMinoの関数を呼び出す //(11) t.down(); //downの関数を呼び出す //(12) m.display(); //diplayの関数を呼び出し //(13) if(w==1){noLoop(); //ゲームを終了させ終了画面を出す //(14) fill(255,0,0); background(204); textSize(35); text("GAME OVER",25,200); } } if(mouseIsPressed) g=1; //クリックしてゲームをはじめる }

3.4

Tetris

プログラムの説明

(1) 各変数の初期化. setup関数 (2) createCanvasでキャンバスの大きさを設定する (3) map1.js,Tetorimino.jsの宣言と初期化. (4) map1.js内のinit関数を使ってテトリスの各マスに0を設定する. (5) background,frameRateで背景の色とプログラミングの更新速度を決める. (6) textFontで文字を出すための関数を宣言する. (7) fill, textSizeで文字の色と大きさを設定する. (8) textでゲーム開始画面を表示する. draw関数 (9) g = 1(クリックすると, g=1 となる)なら, 次にいく. (10) y = 0(落ちているテトリミノが止まったら)なら, clear関数を呼び出す.

(8)

(11) initMino関数を呼び出す. (12) down関数を呼び出す. (13) display関数を呼び出す. (14) down関数がw = 1を返してきたら画面にゲームオーバーの文字を出しクリックし たらまたゲームを再スタートさせる. clear関数の説明 clear関数は変数i, j, gを使って次の1から5の処理をする. iはマップの列を指定する変数, j はマップの行を指定する変数,qはマップの 1行 が埋まっているか確認する変数である. 1. j を19から0までループ(することで全行見ることができる)する. 2. qの初期化. 3. iを0から10までループ(することで全列見ることができる)する. 4. そのマスがミノで埋まっていたらqにプラス1する. 5. q が 10 なら(その行が全列ミノで埋まっていたら) その行のミノを消し, change関数を呼び出して, j をプラス1する. 実際のclear関数のソースコードは次のようになっている. this.clear=function(){ //1段揃っているかを判断し揃っていれば消す関数 for(j=19;j>=0;j--){ //1段目から20段目まで調べる q=0; for(i=0;i<10;i++){ if(this.map1[i][j]!=0) q++; //1段すべてが揃っているかを調べる } if(q==10) { for(i=0;i<10;i++){ //揃っていたら消す this.map1[i][j]=0; //消したところに0を代入し上から一段づつ下ろしていく this.change(j); j++; }

(9)

} } }; change関数の説明 change関数は変数i, kを使って次の1, 2の処理をする. iは横1列揃っているかどうかを調べる変数, kはミノを消す際,何段目を消したか を判断する変数である. 1. 消した行から一番上の行までループさせる. 2. iを0から10までループさせて1マスずつ下に落とす. 実際のchange関数のソースコードは次のようになっている. this.change=function(k){ //消した時に1段づつ下ろしていく関数 for(k;k>0;k--){ //消した段から1段づつ上のやつを下ろしていく for(i=0;i<10;i++){ this.map1[i][k]=this.map1[i][k-1]; } } }; initMino関数の説明 initMino関数は変数b, c, d, x, yを使って次の1から3の処理をする. bはランダムに1から7までの整数を与える変数, cは回転を判断する変数, xy は落下させているミノの場所を判断する変数である. 1. y = 0なら, bの値(ミノの種類)をランダム(1から7)に決める. 2. ’t’が押されたらcをプラスしてそれを4で割ったあまりを出して(そうする ことで0から3の値が出て, テトリミノが回転してできる4つのパターンが表 せる. )次に続く. 3. b = 2(iテトリミノ),b = 6(sテトリミノ), b = 7(zテトリミノ)なら, 回転して できる形の種類はそれぞれ2種類なのでc = 0, c = 2の時とc = 1, c = 3のと きで場合分けして, b = 3(tテトリミノ), b = 4(lテトリミノ), b = 5(jテトリ

(10)

ミノ)なら, 回転してできる種類はそれぞれ4種類なのでc = 0, c = 1, c = 2, c = 3の4種類に場合分けして, それぞれ回転して形を変えた先が空白かどう か調べて, 空白なら回転する前のテトリミノを消しておく. 回転できないと判 定した場合はdに値を入れそれに対応してcの値をもとの値に戻す. 実際のinitMino関数のソースコードは次のようになっている. this.initMino=function(){ if(y==0){ b=int(random(1,8)); //ランダムに1から7を決め,その値によりミノを決める } if(keyIsPressed){ if(key==’t’){ //tボタンを押してミノを回転させる c++; c=c%4; if(b==2){ //ミノの種類(iミノ)の判定 if((c==0)||(c==2)){ if((m.get(x,y+1)==0)&&(m.get(x,y+2)==0)){ //i1ミノ,i3ミノが回転できるか調べる if(m.get(x,y+3)==0){ t.i1_del(x,y); //できると判定したらi1ミノ,i3ミノを消す } else this.d=1; //できないと判定したらd=1をかえす } else this.d=1; }

(11)

if((c==1)||(c==3)){ if((m.get(x+1,y)==0)&&(m.get(x+2,y)==0)){ //l0ミノ,l2ミノが回転できるか調べる if(m.get(x+3,y)==0){ t.i0_del(x,y); //できると判定したらi0ミノ,i2ミノを消す } else this.d=2; //できないと判定したらd=2をかえす } else this.d=2; } if(this.d==1){ c=1; //回転できないと判断したためcを元の値に戻す this.d=0; } if(this.d==2){ c=0; this.d=0; } } 以下省略 down関数の説明 down関数は変数b, w, x, yを使って次の1から5の処理をする. bはどのテトリミノを生成するのかの判断をする変数, wはゲームを終了する際に 終了するかどうかを判断する変数, xyは落下させているミノの場所を判断する 変数である. 1. b = 1 7の判定をする. b = 1 (oテトリミノ)以外の場合, c = 0からc = 3 の 判定もする. 2. 画面の一番上にテトリミノが出せるスペースがあるか調べる. 3. スペースがなければw = 1(ゲームオーバー)を返す. 4. スペースがあれば次にしたに落とせるかどうか調べ1段下に落とす.

(12)

5. 落とすスペースがなければy = 0, x = 4を返し新しいテトリミノを出す準備 をする. 実際のdown関数のソースコードは次のようになっている. this.down=function(){ //ミノを落とす関数 if(b==1){ if(y==0){ if((m.get(x,y)==0)&&(m.get(x+1,y)==0) //初めにo0ミノが出せるか調べる &&(m.get(x,y+1)==0)&&(m.get(x+1,y+1)==0) &&(m.get(x,y+2)==0)&&(m.get(x+1,y+2)==0)){ this.o0_del(x,y+1); y++; } else w=1; //出せなければ終了させる } else if(m.o0_serch(x,y)==1){ //下に落とせる場合は1つ下に落とす y++; t.o0_down(x,y); } else y=0,x=4; //下に落とせない場合は新しいミノを落とす } 以下省略 display関数の説明 display関数は変数i, jを使って1の処理をする. iはマップ上の行を表す変数, j マップ上の列を表すは変数である. 1. マップの全マスを調べその中の値に対応した色のテトリミノを表示する. 実際のdisplay関数のソースコードは次のようになっている. this.display=function(){ //表示する関数 for(i=0;i<this.map1.length;i++){ //mapの値から表示する色を決める

(13)

for(j=0;j<this.map1[i].length;j++){

if(this.map1[i][j]==1) fill(82,162,197); else if (this.map1[i][j]==2) fill(255,255,0); else if (this.map1[i][j]==3) fill(196,0,204); else if (this.map1[i][j]==4) fill(15,82,188); else if (this.map1[i][j]==5) fill(255,183,76); else if (this.map1[i][j]==6) fill(0,255,65); else if (this.map1[i][j]==7) fill(204,0,0); else fill(255);

rect(i*25,j*25,25,25); }

} };

(14)

4

問題点の整理

4.1

実際にプログラムを制作

,

実行しての問題点

上図のようにブロックを横からいれこむ際, 端のブロックが消えてしまう現象が起きた. o0-down関数とsearch関数により, 横移動した後下にブロックがある場合は上のブロッ クを消さないという変更を加えようとしたが, 改善できなかった. ただ, 他のテトリミノ の場合はエラーが出なかったので, 他のテトリミノとo-テトリミノとの違いは回転がある かないかという違いがあるので, そこが理解できれば改善の余地があると考えた. またテ トリミノを動かす際の命令が場合分けされプログラムが長くなってしまっている. これ は, テトリミノ自体をオブジェクト指向で作り, メソッドとしてテトリミノ自体に落下や 横移動, 回転を持たせるプログラムにすべきであった. さらに, p5.jsを用いてプログラム を実際に制作して, if文の数を増やしていくと上手く動かなくなるエラーが多発すること がわかった. これは, if文の中にifを用いるのではなく,論理演算子&&を利用することに より改善できた. 改善前のプログラム

(15)

this.t_serch=function(i,j){ if((this.map1[i][j+1]==0)&&(this.map1[i+1][j+1]==0)){ if(this.map1[i+2][j+1]==0){ s=1; } } else s=0; return s; }; 改善後のプログラム this.t0_serch=function(i,j){ //t0ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j+1]==0)&&(this.map1[i+1][j+1]==0)&& (this.map1[i+2][j+1]==0)){ s=1; //下に落ちることができるときは1を返し, できないときは0を返す } else s=0; return s; };

4.2

今後の課題

今回はできなかったが, テトリミノを落とす時の消し方を, 横移動した際, 下に落とすこ とができない場合にdown関数の中身を場合分けすれば, 今回製作したプログラムのまま でも修繕可能だと考えた. もうひとつの課題として, 各メソッド毎に細かくオブジェクト 指向を導入して, テトリミノ自体をオブジェクトで作り, テトリミノ自体をプロパティと して, 下に落とす作業や左右の移動, 回転をテトリミノ自体のメソッドとすることでより 短いプログラムコードでプログラムを作成することができる. さらに, 1つ1つの指示を 細かく出していると, プログラムが複雑になってしまう. 複雑なプログラムは変更する際 に難しく, エラーが発生しやすくなるので, オブジェクト指向を使用することにより, プロ

(16)

グラムを簡潔にしエラーを抑えること, プログラムの作成自体もよりスムーズに進めるこ とができると考えた.

5

まとめ

5.1

全体を通してのまとめ

今回実際にテトリスのプログラムを作成してみて, 当初考えていたよりもずっと難しく, また時間もかかるものであった. テトリミノを管理し,その情報を画面に表示する事が当 初の予定どうりに進まず苦労した.それを改善する為に, プログラムの上手く動作しない 箇所の場合分けなど試行錯誤を繰り返した. 結果として, 場合分けなどプログラムの長さ は増えたが, 想定どうりの動きのゲームが完成した.

6

プログラムソースコード

6.1

test.html

<!doctype html> <html> <head> <meta charset="utf-8"> <script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script> <script src="Tetorimino.js"></script> <script src="map1.js"></script> <title> test </title>

</head> <body> <script> var m,t,b=0,c=0,k=0,x=4,y=0,r,q,g=0,w=0; //m:map1のインスタンス //t:tetoriminoのインスタンス //b:どのテトリミノを生成するのかの判断をする変数 //c:回転を判断する変数 //k:ミノを消す際,何段目を消したかを判断する関数

(17)

//x:落下させているミノの場所を判断する変数 //y:落下させているミノの場所を判断する変数 //r:map1にミノを書き込む際に用いる変数 //g:ゲームをスタートする際にスタートするかどうかを反する関数 //w:ゲームを終了する際に終了するかどうかを判断する関数 function setup(){ createCanvas(251,501); //キャンバスの大きさを指定

m=new Map1(10,20); //Map1の宣言と初期化

t=new Tetorimino();  //Tetoriminoの宣言と初期化

m.init(); //init関数を呼び出す

background(204); //背景を指定する

frameRate(7); //速度の指定

textFont("Source Code Pro"); //ゲーム開始画面を出す

fill(0,0,255); textSize(35); text("GAME START",25,200); fill(0); textSize(16); text("クリックしてください",80,240); } function draw(){ if(g==1){

if(y==0) m.clear(); //clearの関数を呼び出し揃っている行を消す

t.initMino(); //initMinoの関数を呼び出す t.down(); //downの関数を呼び出す m.display(); //diplayの関数を呼び出し表示す if(w==1){ noLoop(); //ゲームを終了させ終了画面を出す fill(255,0,0); background(204); textSize(35); text("GAME OVER",25,200);

(18)

} } if(mouseIsPressed) g=1; //クリックしてゲームをはじめる } </script> </body> </html>

6.2

map1.js

function Map1(m,n){ this.map1=new Array(m); //m個の配列を与える this.p=0; this.init=function(){ for(i=0;i<this.map1.length;i++){ //i=0からm個まで繰り返す this.map1[i]=new Array(n); //m個の配列がn個づつ配列を与える } for(i=0;i<m;i++){ //すべての配列に0を代入する for(j=0;j<n;j++){ this.map1[i][j]=0; } } }; this.set=function(a,b,r){ //引数からmapに値を代入する関数 if (r==0) this.map1[a][b]=0; else if(r==1) this.map1[a][b]=1; else if(r==2) this.map1[a][b]=2; else if(r==3) this.map1[a][b]=3; else if(r==4) this.map1[a][b]=4;

(19)

else if(r==5) this.map1[a][b]=5; else if(r==6) this.map1[a][b]=6; else if(r==7) this.map1[a][b]=7; }; this.get=function(a,b){ //引数により指定したところが0かそうでないのかを判定する関数 if(this.map1[a][b]!=0){ return 1; } else return 0; }; this.o0_serch=function(i,j){ //o0ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j+1]==0)&&(this.map1[i+1][j+1]==0)){ return 1; //下に落ちることができるときは1を返し,できないときは0を返す } else return 0; }; this.i0_serch=function(i,j){ //i0ミノの時に下に落ちることができるかを判定する関数 if(this.map1[i][j+3]==0){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.i1_serch=function(i,j){

(20)

//i1ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j]==0)&&(this.map1[i+1][j]==0)&& (this.map1[i+2][j]==0) &&(this.map1[i+3][j]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.t0_serch=function(i,j){ //t0ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j+1]==0)&&(this.map1[i+1][j+1]==0)&& (this.map1[i+2][j+1]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.t1_serch=function(i,j){ //t1ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j+2]==0)&&(this.map1[i+1][j+1]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.t2_serch=function(i,j){

(21)

//t2ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j]==0)&&(this.map1[i+1][j+1]==0)&& (this.map1[i+2][j]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.t3_serch=function(i,j){ //t3ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j+1]==0)&&(this.map1[i+1][j+2]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.l0_serch=function(i,j){ //l0ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j+2]==0)&&(this.map1[i+1][j+2]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.l1_serch=function(i,j){ //l1ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j+1]==0)&&(this.map1[i+1][j]==0)&&

(22)

(this.map1[i+2][j]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.l2_serch=function(i,j){ //l2ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j+1]==0)&&(this.map1[i+1][j+3]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.l3_serch=function(i,j){ //l3ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j+1]==0)&&(this.map1[i+1][j+1]==0)&& (this.map1[i+2][j+1]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.j0_serch=function(i,j){ //j0ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j+2]==0)&&(this.map1[i+1][j+2]==0)){ s=1;

(23)

//下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.j1_serch=function(i,j){ //j1ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j+1]==0)&&(this.map1[i+1][j+1]==0)&& (this.map1[i+2][j+1]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.j2_serch=function(i,j){ //j2ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j+2]==0)&&(this.map1[i+1][j]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.j3_serch=function(i,j){ //j3ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j]==0)&&(this.map1[i+1][j]==0)&& (this.map1[i+2][j+1]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す

(24)

} else s=0; return s; }; this.s0_serch=function(i,j){ //s0ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j+1]==0)&&(this.map1[i+1][j+2]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.s1_serch=function(i,j){ //s1ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j+1]==0)&&(this.map1[i+1][j+1]==0)&& (this.map1[i+2][j]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.z0_serch=function(i,j){ //z0ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j+2]==0)&&(this.map1[i+1][j+1]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0;

(25)

return s; }; this.z1_serch=function(i,j){ //z1ミノの時に下に落ちることができるかを判定する関数 if((this.map1[i][j]==0)&&(this.map1[i+1][j+1]==0)&& (this.map1[i+2][j+1]==0)){ s=1; //下に落ちることができるときは1を返し,できないときは0を返す } else s=0; return s; }; this.right=function(x,y){ //右に動かす関数 if(b==1){ //元あったものを消し,動かしたものを表示する t.o0_del(x-1,y); t.o0_set(x,y); } if((b==2)&&(c==0)){ t.i0_del(x-1,y); t.i0_set(x,y); } if((b==2)&&(c==1)){ t.i1_del(x-1,y); t.i1_set(x,y); } if((b==3)&&(c==0)){ t.t0_del(x-1,y); t.t0_set(x,y); } if((b==3)&&(c==2)){ t.t2_del(x-1,y);

(26)

t.t2_set(x,y); } if((b==3)&&(c==3)){ t.t3_del(x-1,y); t.t3_set(x,y); } if((b==4)&&(c==1)){ t.l1_del(x-1,y); t.l1_set(x,y); } if((b==4)&&(c==3)){ t.l3_del(x-1,y); t.l3_set(x,y); } if((b==5)&&(c==1)){ t.j1_del(x-1,y); t.j1_set(x,y); } if((b==5)&&(c==3)){ t.j3_del(x-1,y); t.j3_set(x,y); } if((b==6)&&(c==1)){ t.s1_del(x-1,y); t.s1_set(x,y); } if((b==7)&&(c==1)){ t.z1_del(x-1,y); t.z1_set(x,y); } if((b==3)&&(c==1)){ t.t1_del(x-1,y); t.t1_set(x,y);

(27)

} if((b==4)&&(c==0)){ t.l0_del(x-1,y); t.l0_set(x,y); } if((b==4)&&(c==2)){ t.l2_del(x-1,y); t.l2_set(x,y); } if((b==5)&&(c==0)){ t.j0_del(x-1,y); t.j0_set(x,y); } if((b==5)&&(c==2)){ t.j2_del(x-1,y); t.j2_set(x,y); } if((b==6)&&(c==0)){ t.s0_del(x-1,y); t.s0_set(x,y); } if((b==7)&&(c==0)){ t.z0_del(x-1,y); t.z0_set(x,y); } }; this.r0serch=function(x,y){ //oミノの時に右に動くことができるかを判定する関数 this.p=0; //動かせることが出来れば1を返す if((this.get(x+2,y-1)==0)&& (this.get(x+2,y)==0)) this.p++;

(28)

return this.p; }; this.r1serch=function(x,y){ //縦に1段のミノの時に右に動くことができるかを判定する関数 this.p=0; //動かせることが出来れば1を返す if (this.get(x+4,y-1)==0) this.p++; return this.p; }; this.r2serch=function(x,y){ //縦に2段のミノの時に右に動くことができるかを判定する関数 this.p=0; //動かせることが出来れば2を返す if(((this.get(x,y-1)==1)&&(this.get(x+1,y-1)==0))|| ((this.get(x+1,y-1)==1)&&(this.get(x+2,y-1)==0))||((this.get(x+2,y-1)==1) &&(this.get(x+3,y-1)==0))) this.p++; if(((this.get(x,y)==1)&&(this.get(x+1,y)==0))||((this.get(x+1,y)==1) &&(this.get(x+2,y)==0))||((this.get(x+2,y)==1) &&(this.get(x+3,y)==0))) this.p++; return this.p; }; this.r3serch=function(x,y){ //縦に3段のミノの時に右に動くことができるかを判定する関数 this.p=0; //動かせることが出来れば3を返す if(((this.get(x,y-1)==1)&&(this.get(x+1,y-1)==0))|| ((this.get(x+1,y-1)==1)&&(this.get(x+2,y-1)==0))) this.p++; if(((this.get(x,y)==1)&&(this.get(x+1,y)==0))|| ((this.get(x+1,y)==1)&&(this.get(x+2,y)==0))) this.p++; if(((this.get(x,y+1)==1)&&(this.get(x+1,y+1)==0))|| ((this.get(x+1,y+1)==1)&&(this.get(x+2,y+1)==0))) this.p++; return this.p;

(29)

}; this.r4serch=function(x,y){ //縦に4段のミノの時に右に動くことができるかを判定する関数 this.p=0; //動かせることが出来れば1を返す if((this.get(x+1,y-1)==0)&&(this.get(x+1,y)==0)&& (this.get(x+1,y+1)==0)&&(this.get(x+1,y+2)==0))this.p++; return this.p; }; this.left=function(x,y){ //左に動かす関数 if(b==1){ //元あったものを消し,動かしたものを表示する t.o0_del(x+1,y); t.o0_set(x,y); } if((b==2)&&(c==0)){ t.i0_del(x+1,y); t.i0_set(x,y); } if((b==2)&&(c==1)){ t.i1_del(x+1,y); t.i1_set(x,y); } if((b==3)&&(c==0)){ t.t0_del(x+1,y); t.t0_set(x,y); } if((b==3)&&(c==2)){ t.t2_del(x+1,y); t.t2_set(x,y); } if((b==3)&&(c==3)){ t.t3_del(x+1,y);

(30)

t.t3_set(x,y); } if((b==4)&&(c==1)){ t.l1_del(x+1,y); t.l1_set(x,y); } if((b==4)&&(c==3)){ t.l3_del(x+1,y); t.l3_set(x,y); } if((b==5)&&(c==1)){ t.j1_del(x+1,y); t.j1_set(x,y); } if((b==5)&&(c==3)){ t.j3_del(x+1,y); t.j3_set(x,y); } if((b==6)&&(c==1)){ t.s1_del(x+1,y); t.s1_set(x,y); } if((b==7)&&(c==1)){ t.z1_del(x+1,y); t.z1_set(x,y); } if((b==3)&&(c==1)){ t.t1_del(x+1,y); t.t1_set(x,y); } if((b==4)&&(c==0)){ t.l0_del(x+1,y);

(31)

t.l0_set(x,y); } if((b==4)&&(c==2)){ t.l2_del(x+1,y); t.l2_set(x,y); } if((b==5)&&(c==0)){ t.j0_del(x+1,y); t.j0_set(x,y); } if((b==5)&&(c==2)){ t.j2_del(x+1,y); t.j2_set(x,y); } if((b==6)&&(c==0)){ t.s0_del(x+1,y); t.s0_set(x,y); } if((b==7)&&(c==0)){ t.z0_del(x+1,y); t.z0_set(x,y); } }; this.l0serch=function(x,y){ //oミノの時に左に動くことができるかを判定する関数 this.p=0; //動かせることが出来れば1を返す if((this.get(x-1,y-1)==0)&&(this.get(x-1,y)==0)) this.p++; return this.p; }; this.l1serch=function(x,y){

(32)

//縦に1段のミノの時に左に動くことができるかを判定する関数 this.p=0; //動かせることが出来れば1を返す if (this.get(x-1,y-1)==0) this.p++; return this.p; }; this.l2serch=function(x,y){ //縦に2段のミノの時に左に動くことができるかを判定する関数 this.p=0; //動かせることが出来れば2を返す if(((this.get(x,y-1)==1)&&(this.get(x-1,y-1)==0))|| ((this.get(x+1,y-1)==1)&&(this.get(x,y-1)==0))|| ((this.get(x+2,y-1)==1)&&(this.get(x+1,y-1)==0))) this.p++; if(((this.get(x,y)==1)&&(this.get(x-1,y)==0))|| ((this.get(x+1,y)==1)&&(this.get(x,y)==0))|| ((this.get(x+2,y)==1)&&(this.get(x+1,y)==0))) this.p++; return this.p; }; this.l3serch=function(x,y){ //縦に3段のミノの時に左に動くことができるかを判定する関数 this.p=0; //動かせることが出来れば3を返す if(((this.get(x,y-1)==1)&&(this.get(x-1,y-1)==0))|| ((this.get(x+1,y-1)==1)&&(this.get(x,y-1)==0))) this.p++; if(((this.get(x,y)==1)&&(this.get(x-1,y)==0))|| ((this.get(x+1,y)==1)&&(this.get(x,y)==0))) this.p++; if(((this.get(x,y+1)==1)&&(this.get(x-1,y+1)==0))|| ((this.get(x+1,y+1)==1)&&(this.get(x,y+1)==0))) this.p++; return this.p; }; this.l4serch=function(x,y){ //縦に4段のミノの時に左に動くことができるかを判定する関数

(33)

this.p=0; //動かせることが出来れば1を返す if((this.get(x-1,y-1)==0)&&(this.get(x-1,y)==0) &&(this.get(x-1,y+1)==0)&&(this.get(x-1,y+2)==0))this.p++; return this.p; }; this.display=function(){ //表示する関数 for(i=0;i<this.map1.length;i++){ //mapの値から表示する色を決める for(j=0;j<this.map1[i].length;j++){ if(this.map1[i][j]==1) fill(82,162,197);

else if (this.map1[i][j]==2) fill(255,255,0); else if (this.map1[i][j]==3) fill(196,0,204); else if (this.map1[i][j]==4) fill(15,82,188); else if (this.map1[i][j]==5) fill(255,183,76); else if (this.map1[i][j]==6) fill(0,255,65); else if (this.map1[i][j]==7) fill(204,0,0); else fill(255); rect(i*25,j*25,25,25); } } }; this.clear=function(){ //1段揃っているかを判断し揃っていれば消す関数 for(j=19;j>=0;j--){ //1段目から20段目まで調べる q=0; for(i=0;i<10;i++){ if(this.map1[i][j]!=0) q++; //1段すべてが揃っているかを調べる } if(q==10) {

(34)

for(i=0;i<10;i++){ //揃っていたら消す this.map1[i][j]=0; //消したところに0を代入し上から一段づつ下ろしていく this.change(j); j++; } } } }; this.change=function(k){ //消した時に1段づつ下ろしていく関数 for(k;k>0;k--){//消した段から1段づつ上のやつを下ろしていく for(i=0;i<10;i++){ this.map1[i][k]=this.map1[i][k-1]; } } }; }

6.3

Tetorimino.js

function Tetorimino(){ this.t; this.d; this.o0_down=function(x,y){ //o0ミノを落とす関数 this.o0_del(x,y-1); this.o0_set(x,y); }; this.i0_down=function(x,y){ //i0ミノを落とす関数

(35)

this.i0_del(x,y-1); this.i0_set(x,y); }; this.i1_down=function(x,y){ //i1ミノを落とす関数 this.i1_del(x,y-1); this.i1_set(x,y); }; this.t0_down=function(x,y){ //t0ミノを落とす関数 this.t0_del(x,y-1); this.t0_set(x,y); }; this.t1_down=function(x,y){ //t1ミノを落とす関数 this.t1_del(x,y-1); this.t1_set(x,y); }; this.t2_down=function(x,y){ //t2ミノを落とす関数 this.t2_del(x,y-1); this.t2_set(x,y); }; this.t3_down=function(x,y){ //t3ミノを落とす関数 this.t3_del(x,y-1); this.t3_set(x,y); }; this.l0_down=function(x,y){ //l0ミノを落とす関数 this.l0_del(x,y-1); this.l0_set(x,y); }; this.l1_down=function(x,y){ //l1ミノを落とす関数 this.l1_del(x,y-1); this.l1_set(x,y); }; this.l2_down=function(x,y){ //l2ミノを落とす関数 this.l2_del(x,y-1);

(36)

this.l2_set(x,y); }; this.l3_down=function(x,y){ //l3ミノを落とす関数 this.l3_del(x,y-1); this.l3_set(x,y); }; this.j0_down=function(x,y){ //j0ミノを落とす関数 this.j0_del(x,y-1); this.j0_set(x,y); }; this.j1_down=function(x,y){ //j1ミノを落とす関数 this.j1_del(x,y-1); this.j1_set(x,y); }; this.j2_down=function(x,y){ //j2ミノを落とす関数 this.j2_del(x,y-1); this.j2_set(x,y); }; this.j3_down=function(x,y){ //j3ミノを落とす関数 this.j3_del(x,y-1); this.j3_set(x,y); }; this.s0_down=function(x,y){ //s0ミノを落とす関数 this.s0_del(x,y-1); this.s0_set(x,y); }; this.s1_down=function(x,y){ //s1ミノを落とす関数 this.s1_del(x,y-1); this.s1_set(x,y); }; this.z0_down=function(x,y){ //z0ミノを落とす関数 this.z0_del(x,y-1); this.z0_set(x,y);

(37)

}; this.z1_down=function(x,y){ //z1ミノを落とす関数 this.z1_del(x,y-1); this.z1_set(x,y); }; this.o0_del=function(x,y){ //o0ミノを消す関数 m.set(x,y-1,0); m.set(x+1,y-1,0); m.set(x,y,0); m.set(x+1,y,0); }; this.i0_del=function(x,y){ //i0ミノを消す関数 m.set(x,y-1,0); m.set(x,y,0); m.set(x,y+1,0); m.set(x,y+2,0) }; this.i1_del=function(x,y){ //i1ミノを消す関数 m.set(x,y-1,0); m.set(x+1,y-1,0); m.set(x+2,y-1,0); m.set(x+3,y-1,0); }; this.t0_del=function(x,y){ //t0ミノを消す関数 m.set(x+1,y-1,0); m.set(x,y,0); m.set(x+1,y,0); m.set(x+2,y,0); }; this.t1_del=function(x,y){ //t1ミノを消す関数 m.set(x,y-1,0); m.set(x,y,0); m.set(x+1,y,0);

(38)

m.set(x,y+1,0); }; this.t2_del=function(x,y){ //t2ミノを消す関数 m.set(x,y-1,0); m.set(x+1,y-1,0); m.set(x+2,y-1,0); m.set(x+1,y,0); }; this.t3_del=function(x,y){ //t3ミノを消す関数 m.set(x+1,y-1,0); m.set(x,y,0); m.set(x+1,y,0); m.set(x+1,y+1,0); }; this.l0_del=function(x,y){ //l0ミノを消す関数 m.set(x,y-1,0); m.set(x,y,0); m.set(x,y+1,0); m.set(x+1,y+1,0); }; this.l1_del=function(x,y){ //l1ミノを消す関数 m.set(x,y-1,0); m.set(x+1,y-1,0); m.set(x+2,y-1,0); m.set(x,y,0); }; this.l2_del=function(x,y){ //l2ミノを消す関数 m.set(x,y,0); m.set(x+1,y,0); m.set(x+1,y+1,0); m.set(x+1,y+2,0); }; this.l3_del=function(x,y){ //l3ミノを消す関数

(39)

m.set(x+2,y-1,0); m.set(x,y,0); m.set(x+1,y,0); m.set(x+2,y,0); }; this.j0_del=function(x,y){ //j0ミノを消す関数 m.set(x+1,y-1,0); m.set(x+1,y,0); m.set(x,y+1,0); m.set(x+1,y+1,0); }; this.j1_del=function(x,y){ //j1ミノを消す関数 m.set(x,y-1,0); m.set(x,y,0); m.set(x+1,y,0); m.set(x+2,y,0); }; this.j2_del=function(x,y){ //j2ミノを消す関数 m.set(x,y-1,0); m.set(x+1,y-1,0); m.set(x,y,0); m.set(x,y+1,0); }; this.j3_del=function(x,y){ //j3ミノを消す関数 m.set(x,y-1,0); m.set(x+1,y-1,0); m.set(x+2,y-1,0); m.set(x+2,y,0); }; this.s0_del=function(x,y){ //s0ミノを消す関数 m.set(x,y-1,0); m.set(x,y,0); m.set(x+1,y,0);

(40)

m.set(x+1,y+1,0); }; this.s1_del=function(x,y){ //s1ミノを消す関数 m.set(x+1,y-1,0); m.set(x+2,y-1,0); m.set(x,y,0); m.set(x+1,y,0); }; this.z0_del=function(x,y){ //z0ミノを消す関数 m.set(x+1,y-1,0); m.set(x,y,0); m.set(x+1,y,0); m.set(x,y+1,0); }; this.z1_del=function(x,y){ //z1ミノを消す関数 m.set(x,y-1,0); m.set(x+1,y-1,0); m.set(x+1,y,0); m.set(x+2,y,0); }; this.initMino=function(){ if(y==0){ b=int(random(1,8)); //ランダムに1から7を決め,その値によりミノを決める } if(keyIsPressed){ if(key==’t’){ //tボタンを押してミノを回転させる c++; c=c%4; if(b==2){ //ミノの種類(iミノ)の判定

(41)

if((c==0)||(c==2)){ if((m.get(x,y+1)==0)&&(m.get(x,y+2)==0)){ //i1ミノ,i3ミノが回転できるか調べる if(m.get(x,y+3)==0){ t.i1_del(x,y); //できると判定したらi1ミノ,i3ミノを消す } else this.d=1; //できないと判定したらd=1をかえす } else this.d=1; } if((c==1)||(c==3)){ if((m.get(x+1,y)==0)&&(m.get(x+2,y)==0)){ //l0ミノ,l2ミノが回転できるか調べる if(m.get(x+3,y)==0){ t.i0_del(x,y); //できると判定したらi0ミノ,i2ミノを消す } else this.d=2; //できないと判定したらd=2をかえす } else this.d=2; } if(this.d==1){ c=1; //回転できないと判断したためcを元の値に戻す this.d=0; } if(this.d==2){ c=0; this.d=0; } } if(b==3){ //ミノの種類(tミノ)の判定 if(c==0){

(42)

if((m.get(x,y+1)==0)&&(m.get(x+2,y+1)==0)){ //t3ミノが回転できるか調べる t.t3_del(x,y); //できると判定したらt3ミノを消す } else this.d=1; //できないと判定したらd=1をかえす } if(c==1){ if((m.get(x,y+1)==0)&&(m.get(x,y+2)==0)){ //t0ミノが回転できるか調べる if(m.get(x+1,y+1)==0){ t.t0_del(x,y); //できると判定したらt0ミノを消す } else this.d=2; //できないと判定したらd=2をかえす } else this.d=2; } if(c==2){ if((m.get(x+2,y)==0)&&(m.get(x+1,y+1)==0)){ //t1ミノが回転できるか調べる t.t1_del(x,y); //できると判定したらt1ミノを消す } else this.d=3; //できないと判定したらd=3をかえす } if(c==3){ if((m.get(x,y+1)==0)&&(m.get(x+1,y+2)==0)){ //t2ミノが回転できるか調べる if(m.get(x+1,y+1)==0){ t.t2_del(x,y); //できると判定したらt2ミノを消す } else this.d=4; //できないと判定したらd=4をかえす } else this.d=4; }

(43)

if(this.d==1){ c=3; //回転できないと判断したためcを元の値に戻す this.d=0; } if(this.d==2){ c=0; this.d=0; } if(this.d==3){ c=1; this.d=0; } if(this.d==4){ c=2; this.d=0; } } if(b==4){ //ミノの種類(lミノ)の判定 if(c==0){ if((m.get(x,y+1)==0)&&(m.get(x,y+2)==0)){ //l3ミノが回転できるか調べる if(m.get(x+1,y+2)==0){ t.l3_del(x,y); //できると判定したらl3ミノを消す } else this.d=1; //できないと判定したらd=1をかえす } else this.d=1; } if(c==1){ if((m.get(x+1,y)==0)&&(m.get(x+2,y)==0)){ //l0ミノが回転できるか調べる t.l0_del(x,y); //できると判定したらl0ミノを消す }

(44)

else this.d=2; //できないと判定したらd=2をかえす } if(c==2){ if((m.get(x+1,y)==0)&&(m.get(x+1,y+1)==0)){ //l1ミノが回転できるか調べる if(m.get(x+1,y+2)==0){ t.l1_del(x,y); //できると判定したらl1ミノを消す } else this.d=3; //できないと判定したらd=3をかえす } else this.d=3; } if(c==3){ if((m.get(x+2,y)==0)&&(m.get(x,y+1)==0)){ //l2ミノが回転できるか調べる if(m.get(x+2,y+1)==0){ t.l2_del(x,y);//できると判定したらl2ミノを消す } else this.d=4; //できないと判定したらd=4をかえす } else this.d=4; } if(this.d==1){ c=3; //回転できないと判断したためcを元の値に戻す this.d=0; } if(this.d==2){ c=0; this.d=0; } if(this.d==3){ c=1; this.d=0;

(45)

} if(this.d==4){ c=2; this.d=0; } } if(b==5){ //ミノの種類(jミノ)の判定 if(c==0){ if((m.get(x+1,y)==0)&&(m.get(x+1,y+1)==0)){ //j3ミノが回転できるか調べる if((m.get(x,y+2)==0)&&(m.get(x+1,y+2)==0)){ t.j3_del(x,y); //できると判定したらj3ミノを消す } else this.d=1; //できないと判定したらd=1をかえす } else this.d=1; } if(c==1){ if((m.get(x,y)==0)&&(m.get(x+2,y+1)==0)){ //j0ミノが回転できるか調べる t.j0_del(x,y); //できると判定したらj0ミノを消す } else this.d=2; //できないと判定したらd=2をかえす } if(c==2){ if((m.get(x,y+1)==0)&&(m.get(x,y+2)==0)){ //j1ミノが回転できるか調べる t.j1_del(x,y); //できると判定したらj1ミノを消す } else this.d=3; //できないと判定したらd=3をかえす } if(c==3){ if((m.get(x+1,y)==0)&&(m.get(x+2,y)==0)){

(46)

//j2ミノが回転できるか調べる if(m.get(x+2,y+1)==0){ t.j2_del(x,y); //できると判定したらj2ミノを消す } else this.d=4; //できないと判定したらd=4をかえす } else this.d=4; } if(this.d==1){ c=3; //回転できないと判断したためcを元の値に戻す this.d=0; } if(this.d==2){ c=0; this.d=0; } if(this.d==3){ c=1; this.d=0; } if(this.d==4){ c=2; this.d=0; } } if(b==6){ //ミノの種類(sミノ)の判定 if((c==0)||(c==2)){ if((m.get(x,y+1)==0)&&(m.get(x+1,y+1)==0)){ //s1ミノ,s3ミノが回転できるか調べる if(m.get(x+1,y+2)==0){ t.s1_del(x,y); //できると判定したらs1ミノ,s3ミノを消す }

(47)

else this.d=1; //できないと判定したらd=1をかえす } else this.d=1; } if((c==1)||(c==3)){ if((m.get(x+2,y)==0)&&(m.get(x,y+1)==0)){ //s0ミノ,s2ミノが回転できるか調べる t.s0_del(x,y); //できると判定したらs0ミノ,s2ミノを消す } else this.d=2; //できないと判定したらd=2をかえす } if(this.d==1){ c=1; //回転できないと判断したためcを元の値に戻す this.d=0; } if(this.d==2){ c=0; this.d=0; } } if(b==7){ //ミノの種類(zミノ)の判定 if((c==0)||(c==2)){ if((m.get(x,y+1)==0)&&(m.get(x+1,y+1)==0)){ //z1ミノ,z3ミノが回転できるか調べる if(m.get(x,y+2)==0){ t.z1_del(x,y); //できると判定したらz1ミノ,z3ミノを消す } else this.d=1; //できないと判定したらd=1をかえす } else this.d=1; }

(48)

if((c==1)||(c==3)){ if((m.get(x+1,y+1)==0)&&(m.get(x+2,y+1)==0)){ //z0ミノ,z2ミノが回転できるか調べる t.z0_del(x,y); //できると判定したらz0ミノ,z2ミノを消す } else this.d=2; //できないと判定したらd=2をかえす } if(this.d==1){ c=1; //回転できないと判断したためcを元の値に戻す this.d=0; } if(this.d==2){ c=0; this.d=0; } } } } if(keyIsPressed){ if(keyCode == RIGHT_ARROW){ //右を押した時に右に動かす if((b==1)&&(x<8)&&(m.r0serch(x,y)==1)&&(y>1)){//制御をかける x++;y--; //ブロックと回転しているかどうかで場合分けする m.right(x,y+1); } if((b==2)&&(c==0)&&(x<9)&&(m.r4serch(x,y)==1)&&(y>1)){ x++;y--; m.right(x,y+1); y++; } if((b==2)&&(c==1)&&(x<6)&&(m.r1serch(x,y)==1)&&(y>1)){ x++;y--; m.right(x,y+1); y++; }

(49)

if(((b==3)&&((c==0)||(c==2)))&&(x<7)&& (m.r2serch(x,y)==2)&&(y>1)){ x++;y--; m.right(x,y+1);y++; } if(((b==4)&&((c==1)||(c==3)))&&(x<7)&& (m.r2serch(x,y)==2)&&(y>1)){ x++;y--; m.right(x,y+1); y++; } if(((b==5)&&((c==1)||(c==3)))&&(x<7)&& (m.r2serch(x,y)==2)&&(y>1)){ x++;y--; m.right(x,y+1); y++; } if((((b==6)||(b==7))&&(c==1))&&(x<7)&& (m.r2serch(x,y)==2)&&(y>1)){ x++;y--; m.right(x,y+1); y++; } if(((b==3)&&((c==1)||(c==3)))&&(x<8)&& (m.r3serch(x,y)==3)&&(y>1)){ x++;y--; m.right(x,y+1);y++; } if((((b==4)||(b==5))&&(c==0))&&(x<8)&& (m.r3serch(x,y)==3)&&(y>1)){ x++;y--; m.right(x,y+1); y++; } if((b==4)&&(c==2)&&(x<8)&&(m.r3serch(x,y+1)==3)&&(y>1)){ x++;y--; m.right(x,y+1); y++;

(50)

} if((b==5)&&(c==2)&&(x<8)&&(m.r3serch(x,y)==3)&&(y>1)){ x++;y--; m.right(x,y+1); y++; } if(((b==6)&&(c==0))&&(x<8)&&(m.r3serch(x,y)==3)&&(y>1)){ x++;y--; m.right(x,y+1); y++; } if(((b==7)&&(c==0))&&(x<8)&&(m.r3serch(x,y)==3)&&(y>1)){ x++;y--; m.right(x,y+1); y++; } } } if(keyIsPressed){ if(keyCode ==LEFT_ARROW){ //左を押した時に左に動かす if((b==1)&&(x>0)&&(m.l0serch(x,y)==1)&&(y>1)){//制御をかける x--;y--; //ブロックと回転しているかどうかで場合分けする m.left(x,y+1); } if((b==2)&&(c==0)&&(x>0)&&(m.l4serch(x,y)==1)&&(y>1)){ x--;y--; m.left(x,y+1); y++; } if((b==2)&&(c==1)&&(x>0)&&(m.l1serch(x,y)==1)&&(y>1)){ x--;y--; m.left(x,y+1); y++; } if(((b==3)&&((c==0)||(c==2)))&&(x>0)&& (m.l2serch(x,y)==2)&&(y>1)){ x--;y--;

(51)

m.left(x,y+1); y++; } if(((b==4)&&((c==1)||(c==3)))&&(x>0)&& (m.l2serch(x,y)==2)&&(y>1)){ x--;y--; m.left(x,y+1); y++; } if(((b==5)&&((c==1)||(c==3)))&&(x>0)&& (m.l2serch(x,y)==2)&&(y>1)){ x--;y--; m.left(x,y+1); y++; } if((((b==6)||(b==7))&&(c==1))&&(x>0)&& (m.l2serch(x,y)==2)&&(y>1)){ x--;y--; m.left(x,y+1); y++; } if(((b==3)&&((c==1)||(c==3)))&&(x>0)&& (m.l3serch(x,y)==3)&&(y>1)){ x--;y--; m.left(x,y+1); y++; } if((((b==4)||(b==5))&&(c==0))&& (x>0)&&(m.l3serch(x,y)==3)&&(y>1)){ x--;y--; m.left(x,y+1); y++; } if((b==4)&&(c==2)&&(x>0)&&(m.l3serch(x,y+1)==3)&&(y>1)){ x--;y--; m.left(x,y+1); y++; } if((b==5)&&(c==2)&&(x>0)&&(m.l3serch(x,y)==3)&&(y>1)){ x--;y--;

(52)

m.left(x,y+1); y++; } if(((b==6)&&(c==0))&&(x>0)&&(m.l3serch(x,y)==3)&&(y>1)){ x--;y--; m.left(x,y+1); y++; } if(((b==7)&&(c==0))&&(x>0)&&(m.l3serch(x,y)==3)&&(y>1)){ x--;y--; m.left(x,y+1); y++; } } } }; this.down=function(){ //ミノを落とす関数 if(b==1){ if(y==0){ if((m.get(x,y)==0)&&(m.get(x+1,y)==0) //初めにo0ミノが出せるか調べる &&(m.get(x,y+1)==0)&&(m.get(x+1,y+1)==0) &&(m.get(x,y+2)==0)&&(m.get(x+1,y+2)==0)){ this.o0_del(x,y+1); y++; } else w=1; //出せなければ終了させる } else if(m.o0_serch(x,y)==1){//下に落とせる場合は1つ下に落とす y++; t.o0_down(x,y); } else y=0,x=4; //下に落とせない場合は新しいミノを落とす } if(b==2){

(53)

if(y==0){ if((m.get(x,y)==0)&&(m.get(x,y+1)==0) //初めにi0ミノが出せるか調べる &&(m.get(x,y+2)==0)&&(m.get(x,y+3)==0) &&(m.get(x,y+4)==0)){ this.i0_del(x,y+1); y++; } else w=1; //出せなければ終了させる } else if((c==0)||(c==2)){ //iミノの状態を場合分けし下に落とせる場合は1つ下に落とす if(m.i0_serch(x,y)==1){ y++; t.i0_down(x,y); } else y=0,x=4,c=0;//下に落とせない場合は新しいミノを落とす } else if((c==1)||(c==3)){ if(m.i1_serch(x,y)==1){ y++; t.i1_down(x,y); } else y=0,x=4,c=0; } } if(b==3){ if(y==0){ if((m.get(x,y)==0)&&(m.get(x+1,y)==0) //初めにt0ミノが出せるか調べる &&(m.get(x+2,y)==0)&&(m.get(x,y+1)==0) &&(m.get(x+1,y+1)==0)&&(m.get(x+2,y+1)==0) &&(m.get(x,y+2)==0)&&(m.get(x+1,y+2)==0) &&(m.get(x+2,y+2)==0)){

(54)

this.t0_del(x,y+1); y++; } else w=1; //出せなければ終了させる } else if(c==0){ //tミノの状態を場合分けし下に落とせる場合は1つ下に落とす if(m.t0_serch(x,y)==1){ y++; t.t0_down(x,y); } else{ y=0,x=4,c=0; //下に落とせない場合は新しいミノを落とす } } else if(c==1){ if(m.t1_serch(x,y)==1){ y++; t.t1_down(x,y); } else{ y=0,x=4,c=0; } } else if(c==2){ if(m.t2_serch(x,y)==1){ y++; t.t2_down(x,y); } else{ y=0,x=4,c=0; } } else if(c==3){

(55)

if(m.t3_serch(x,y)==1){ y++; t.t3_down(x,y); } else{ y=0,x=4,c=0; } } } if(b==4){ if(y==0){ if((m.get(x,y)==0)&&(m.get(x+1,y)==0) //初めにl0ミノが出せるか調べる &&(m.get(x,y+1)==0)&&(m.get(x+1,y+1)==0) &&(m.get(x,y+2)==0)&&(m.get(x+1,y+2)==0) &&(m.get(x,y+3)==0)&&(m.get(x+1,y+3)==0)){ this.l0_del(x,y+1); y++; } else w=1; //出せなければ終了させる } else if(c==0){ //lミノの状態を場合分けし下に落とせる場合は1つ下に落とす if(m.l0_serch(x,y)==1){ y++; t.l0_down(x,y); } else{ y=0,x=4,c=0; //下に落とせない場合は新しいミノを落とす } } else if(c==1){ if(m.l1_serch(x,y)==1){

(56)

y++; t.l1_down(x,y); } else{ y=0,x=4,c=0; } } else if(c==2){ if(m.l2_serch(x,y)==1){ y++; t.l2_down(x,y); } else{ y=0,x=4,c=0; } } else if(c==3){ if(m.l3_serch(x,y)==1){ y++; t.l3_down(x,y); } else{ y=0,x=4,c=0; } } } if(b==5){ if(y==0){ if((m.get(x,y)==0)&&(m.get(x+1,y)==0) //初めにj0ミノが出せるか調べる &&(m.get(x,y+1)==0)&&(m.get(x+1,y+1)==0) &&(m.get(x,y+2)==0)&&(m.get(x+1,y+2)==0) &&(m.get(x,y+3)==0)&&(m.get(x+1,y+3)==0)){

(57)

this.j0_del(x,y+1); y++; } else w=1; //出せなければ終了させる } else if(c==0){ //jミノの状態を場合分けし下に落とせる場合は1つ下に落とす if(m.j0_serch(x,y)==1){ y++; t.j0_down(x,y); } else{ y=0,x=4,c=0; //下に落とせない場合は新しいミノを落とす } } else if(c==1){ if(m.j1_serch(x,y)==1){ y++; t.j1_down(x,y); } else{ y=0,x=4,c=0; } } else if(c==2){ if(m.j2_serch(x,y)==1){ y++; t.j2_down(x,y); } else{ y=0,x=4,c=0; } } else if(c==3){

(58)

if(m.j3_serch(x,y)==1){ y++; t.j3_down(x,y); } else{ y=0,x=4,c=0; } } } if(b==6){ if(y==0){ if((m.get(x,y)==0)&&(m.get(x+1,y)==0) //初めにs0ミノが出せるか調べる &&(m.get(x,y+1)==0)&&(m.get(x+1,y+1)==0) &&(m.get(x,y+2)==0)&&(m.get(x+1,y+2)==0) &&(m.get(x,y+3)==0)){ this.s0_del(x,y+1); y++; } else w=1; //出せなければ終了させる } else if((c==0)||(c==2)){ if(m.s0_serch(x,y)==1){ //sミノの状態を場合分けし下に落とせる場合は1つ下に落とす y++; t.s0_down(x,y); } else{ y=0,x=4,c=0; //下に落とせない場合は新しいミノを落とす } } else if((c==1)||(c==3)){ if(m.s1_serch(x,y)==1){

(59)

y++; t.s1_down(x,y); } else{ y=0,x=4,c=0; } } } if(b==7){ if(y==0){ if((m.get(x,y)==0)&&(m.get(x+1,y)==0) //初めにz0ミノが出せるか調べる &&(m.get(x,y+1)==0)&&(m.get(x+1,y+1)==0) &&(m.get(x,y+2)==0)&&(m.get(x+1,y+2)==0) &&(m.get(x,y+3)==0)){ this.z0_del(x,y+1); y++; } else w=1; //出せなければ終了させる } else if((c==0)||(c==2)){ if(m.z0_serch(x,y)==1){ //zミノの状態を場合分けし下に落とせる場合は1つ下に落とす y++; t.z0_down(x,y); } else{ y=0,x=4,c=0; //下に落とせない場合は新しいミノを落とす } } else if((c==1)||(c==3)){ if(m.z1_serch(x,y)==1){ y++;

(60)

t.z1_down(x,y); } else{ y=0,x=4,c=0; } } } }; this.o0_set=function(x,t){ //o0ミノをセットする関数 m.set(x,y-1,b); m.set(x+1,y-1,b); m.set(x,y,b); m.set(x+1,y,b); }; this.i0_set=function(x,y){ //i0ミノをセットする関数 m.set(x,y-1,b); m.set(x,y,b); m.set(x,y+1,b); m.set(x,y+2,b); }; this.i1_set=function(x,y){ //i1ミノをセットする関数 m.set(x,y-1,b); m.set(x+1,y-1,b); m.set(x+2,y-1,b); m.set(x+3,y-1,b); }; this.t0_set=function(x,y){ //t0ミノをセットする関数 m.set(x+1,y-1,b); m.set(x,y,b); m.set(x+1,y,b); m.set(x+2,y,b); }; this.t1_set=function(x,y){ //t1ミノをセットする関数

(61)

m.set(x,y-1,b); m.set(x,y,b); m.set(x+1,y,b); m.set(x,y+1,b); }; this.t2_set=function(x,y){ //t2ミノをセットする関数 m.set(x,y-1,b); m.set(x+1,y-1,b); m.set(x+2,y-1,b); m.set(x+1,y,b); }; this.t3_set=function(x,y){ //t3ミノをセットする関数 m.set(x+1,y-1,b); m.set(x,y,b); m.set(x+1,y,b); m.set(x+1,y+1,b); }; this.l0_set=function(x,y){ //l0ミノをセットする関数 m.set(x,y-1,b); m.set(x,y,b); m.set(x,y+1,b); m.set(x+1,y+1,b); }; this.l1_set=function(x,y){ //l1ミノをセットする関数 m.set(x,y-1,b); m.set(x+1,y-1,b); m.set(x+2,y-1,b); m.set(x,y,b); }; this.l2_set=function(x,y){ //l2ミノをセットする関数 m.set(x,y,b); m.set(x+1,y,b); m.set(x+1,y+1,b);

(62)

m.set(x+1,y+2,b); }; this.l3_set=function(x,y){ //l3ミノをセットする関数 m.set(x+2,y-1,b); m.set(x,y,b); m.set(x+1,y,b); m.set(x+2,y,b); }; this.j0_set=function(x,y){ //j0ミノをセットする関数 m.set(x+1,y-1,b); m.set(x+1,y,b); m.set(x,y+1,b); m.set(x+1,y+1,b); }; this.j1_set=function(x,y){ //j1ミノをセットする関数 m.set(x,y-1,b); m.set(x,y,b); m.set(x+1,y,b); m.set(x+2,y,b); }; this.j2_set=function(x,y){ //j2ミノをセットする関数 m.set(x,y-1,b); m.set(x+1,y-1,b); m.set(x,y,b); m.set(x,y+1,b); }; this.j3_set=function(x,y){ //j3ミノをセットする関数 m.set(x,y-1,b); m.set(x+1,y-1,b); m.set(x+2,y-1,b); m.set(x+2,y,b); }; this.s0_set=function(x,y){ //s0ミノをセットする関数

(63)

m.set(x,y-1,b); m.set(x,y,b); m.set(x+1,y,b); m.set(x+1,y+1,b); }; this.s1_set=function(x,y){ //s1ミノをセットする関数 m.set(x+1,y-1,b); m.set(x+2,y-1,b); m.set(x,y,b); m.set(x+1,y,b); }; this.z0_set=function(x,y){ //z0ミノをセットする関数 m.set(x+1,y-1,b); m.set(x,y,b); m.set(x+1,y,b); m.set(x,y+1,b); }; this.z1_set=function(x,y){ //z1ミノをセットする関数 m.set(x,y-1,b); m.set(x+1,y-1,b); m.set(x+1,y,b); m.set(x+2,y,b); }; } このプログラムは, 次の環境にて動作確認を行なった.

HP Workstaion Z600 (Memory 4GB, CPU Xeon 2.67GHz ) OS: VineLinux 6.1

Web Browser : Firefox version 33.0 p5.js: version0.5.2

(64)

参考文献

[1] L.McCarthy, C.Reas,and B.Fry,Getting Started with p5.js,Maker Media books (2015)

(65)

Processing

による

Shooting Game

の作成

130440058

 城 裕太

2017

3

4

目次

1 はじめに 2 1.1 Shooting Gameについて . . . 2 1.2 作成理由 . . . 3 1.3 操作説明 . . . 3 2 プログラムについて 5 2.1 移動方法 . . . 5 2.2 Processingの角度処理. . . 7 2.3 N -way弾の処理 . . . 8 2.4 弾に当たっているかの判定 . . . 11 2.5 弾に当たった時の処理 . . . 13 2.6 リトライ時の処理 . . . 14 2.7 継承クラスの利用 . . . 15 2.8 ステージの進行方法 . . . 16 2.9 各クラスの説明 . . . 17 3 問題点,今後の課題 18 3.1 問題点 . . . 18 3.2 今後の課題 . . . 21 4 まとめ 23 4.1 まとめ . . . 23

(66)

4.2 感想 . . . 23 5 ソースコード 24 5.1 Shooting(メイン) . . . 24 5.2 Bossクラス . . . 40 5.3 Enemyクラス . . . 46 5.4 Stageクラス . . . 48 5.5 Tama set1クラス . . . 57 5.6 Tama set2クラス . . . 58 5.7 Tama typeクラス . . . 59 5.8 color . . . 60 5.9 Boss1クラス . . . 61 5.10 Boss2クラス . . . 62 5.11 Boss3クラス . . . 63 5.12 Boss4クラス . . . 65 5.13 Boss5クラス . . . 67 5.14 Boss6クラス . . . 71 5.15 Stage1 Enemy . . . 75 5.16 Stage2 Enemy . . . 79 5.17 Stage3 Enemy . . . 85 5.18 Stage4 Enemy . . . 87 5.19 Stage5 Enemy . . . 91 5.20 Stage6 Enemy . . . 94

1

はじめに

1.1

Shooting Game

について

シューティングゲームは, 弾丸やレーザーなどを用いて敵を倒していくゲームの総称で あり, STGやSHTなどと略される.   シューティングゲームの歴史は古く, 1962年にマサチューセッツ工科大学の学生, ス ティーブ・ラッセルを中心に作成された, 『スペースウォー!』が世界初のシューティン グゲームとされている([2]参照). 1978年にタイトーにより発売された『スペースイン ベーダー』は, 当時の日本で社会現象を起こす最初のテレビゲームとなり, この作品に追

(67)

随して, 多数のヒットゲームが登場した. 1980年代にはシューティングゲームは最盛期を 迎え, システム, グラフィックなど各ゲーム会社が工夫を施していき, 独自の進化を遂げて いった. ところが, 1990年代に入ると, ロールプレイングゲームや, 対戦型格闘ゲームの 台頭により, シューティングゲームは次第に衰退していった. しかし,今もなお一部では根 強い人気があり, フリーゲームや同人作品で活発に創作が行われている.   シューティングゲームは主に2Dシューティング, 3Dシューティング,ガンシューティ ングなどに分類される. 2Dシューティングは, 名前の通り2次元的視点でプレイするもの である. 3Dシューティングは3Dポリゴンなどを使用するもので, 兵士や戦闘機などを用 いて, 3Dマップを自由に移動して戦うFPS(First-person shooter), TPS(Third-Person Shooter)といったゲームが主流である. ガンシューティグは光線銃を模したコントロー ラー装置を使って遊ぶタイプのゲームである([3]参照).

  今回私がProcessingを用いて作成したShooting Gameは, 2Dシューティングに分類 される,弾幕シューティングゲームである. 弾幕シューティングゲームは,シューティング ゲームの中でも,「打つ」爽快感より「避ける」爽快感を追求したものであり,敵弾が大量 に発射されることが特徴である([4]参照).

1.2

作成理由

Processingで弾幕シューティングゲームを作ろうと考えた理由は, 元々私が弾幕シュー ティングが好きであったこともあるが, 去年の春休みに暇つぶし程度に東方弾幕風([5] 参照)という弾幕シューティングゲームを作成するフリーソフトを使用して弾幕シュー ティングゲームを作ってみたことがきっかけである. 作成したところ, 色々調整しながら 弾幕を作っていく楽しさや, シューティングゲームの奥深さなどがわかり, もっと高度な シューティングゲームを作りたいと考えた. しかし, そのフリーソフトで使用されている プログラム言語が私には少し難しく, 私にも馴染みのあるJava言語で作れないかと考え た結果, 動的プログラミングに特化したProcessingを用いてシューティングゲームのシ ステムから作ってみようと考えたからである.

1.3

操作説明

以下は作成したゲームの操作説明である. ○ゲーム説明

(68)

敵の弾を避けつつ自機のビームを動く敵に当てていくゲームである. 全6ステージを制覇するとクリアとなる. 敵の弾に当たると自機の残機が1ずつ減り, 残機がなくなるとゲームオーバーとなる (残 機がマイナスになるとゲームオーバー). 残機の数は画面左側に丸印●で表示される. 初期残機は10で, ステージを1つクリアするごとに残機は1ずつ増える. 各ステージにおいて,ステージをある程度進めると,強力なボスが出現する. 各ステージは ボスを倒すとステージクリアとなる. ○操作説明 自機の操作は, キーボードの矢印キー, Shiftキー及びマウスを使って行う. 各キーの機能割り当ては, 次のようになっている.   キー:上移動   キー:下移動 →  キー:右移動 ←  キー:左移動 Shift:押しっぱなしで低速モード マウス:ステージ選択等 ○移動モードの紹介 自機の移動には2つのモードが用意されており, それぞれ次のような特徴がある. 通常モード(青色ビーム): ビーム威力は高いが精密な動きができない. ダメージを与えたいときや大きく移動したいときに有効. 低速モード(赤色ビーム): ビーム威力は低いが精密な避けができる. 敵の弾が密集していて、精密に避けたいときに有効. ○クリアへのアドバイス 敵の弾は弾ごとに当たり判定が決まっている. 弾に少しふれるだけであれば, 残機

(69)

が減らないこともある. 自機めがけて飛んでくる弾に対してはあまり大きく動かず, 少しずつ動くことで簡 単に避けることができる. 自機が壁際に追い詰められそうになったら逆に大きく動くことで, 弾と弾の隙間を 広くして反対側へ切り替えすとよい. 避けるのに夢中でボスの位置が分からないときは, 画面下部のエネミーマーカーを 見てボスの位置を把握するとよい.

2

プログラムについて

2.1

移動方法

まず, Processingで自機を移動させる方法を考えた. 最初は条件文を使ってif( キーが 押されている場合), if( キーが押されている場合), ・・・のように区切って移動を定義 しようとしたが, その方法だと動きが滑らかにならず, キーの同時押しなどにも対応しな かった. そこで, 色々と方法を模索し, 2進数にキーの状態の情報を詰め込み, それを読み 込んで移動させるという方法を取ることとした([6]参照). int keyMove=0; void keyPressed(){ if (key == CODED){ switch(keyCode){ case UP: keyMove|=0x1;//0001との論理和 break; case DOWN: keyMove|=0x2;//0010との論理和 break; case LEFT: keyMove|=0x4;//0100との論理和 break;

(70)

case RIGHT: keyMove|=0x8;//1000との論理和 break; } } } void keyReleased() { if (key == CODED) { switch(keyCode) { case UP: keyMove&=~0x1;//0001との排他的論理和 break; case DOWN: keyMove&=~0x2;//0010との排他的論理和 break; case LEFT: keyMove&=~0x4;//0100との排他的論理和 break; case RIGHT: keyMove&=~0x8;//1000との排他的論理和 break; } } } if((keyMove&0x1)!=0)Y-=speed;//上が押されているとき if((keyMove&0x2)!=0)Y+=speed;//下が押されているとき if((keyMove&0x4)!=0)X-=speed;//左が押されているとき if((keyMove&0x8)!=0)X+=speed;//右が押されているとき まず, 初期値0のkeyMoveという2進数の変数を作り, 図1のように, それぞれ1の位が 上, 2の位が下, 4の位が左, 8の位が右と対応していることとする.

(71)

図1  その状態で上キーが押されたとき, keyMoveと0001とのビットごとの論理和をとった ものをkeyMove に代入する. すると, 上キーの情報が格納されている部分には1が格納 される. その状態で下キーが押されると, 今度はkeyMoveと0010とのビットごとの論理 和をとってkeyMoveは0011となる.この状態は上キーと下キーが同時に押されている状 態である. 同様に左の場合は0100とのビットごとの論理和, 右の場合は1000とのビット ごとの論理和をとる.  キーが離された場合には, ビットごとの排他的論理和をとる. 例えば, keyMove=0011 であるときに上キーが離されると, keyMoveと0001のビットごとの排他的論理和を取り, keyMoveは0010となる. 見事に上キーの情報が格納されている部分には0が格納され, 上キーは押されていないと判断することができる. 同様に下の場合は0010, 左の場合は 0100, 右の場合は1000との排他的論理和をそれぞれとる.  最後にkeyMoveと0001,0010,0100,1000とのビットごとの論理積をとり, それぞれ上, 下, 左, 右キーが押されているか判定し, 押されている場合は, その方向へ動くという処理 をしている.  keyStatも同様の仕組みでShiftキーが押されている状況を格納している.

2.2

Processing

の角度処理

Processingは, y軸が画面の下方向に向かって伸びている関係上, 角度は図2のように x軸方向が0で時計回りの方向が正の方向となる. これは, Processingでプログラミング をする際に気をつけなければならない点の1つだが, 角度が大切な要素であるシューティ ングゲームにおいては, 大変重要な問題である. シューティングゲームのプログラムでこ の角度処理によって悩まされた部分がいくつかあった. その 1つがz angle()という関 数を作っていた場面であった.

(72)

図2

\end{figure}

float z_angle(float Ex,float Ey){ float angle; angle=atan((Y-Ey)/(X-Ex)); if(X-Ex<0)angle=PI+angle; return angle; }  この関数は,指定された地点から自機の地点への角度を返すという関数である. 2地点か ら角度を出すのでarctanを利用し, angle=atan((Y-Ey)/(X-Ex));としたが, これでは 自機が左側にいる場合にうまくいかなかった. なぜうまくいかないのかと考えた結果, 普 通のxy-平面で考えていたからだと気づいた. 前述の通りProcessingでは, y 軸の方向が 画面下方向なので,不具合がおきたと考えられる. そこで, if(X-Ex<0)angle=PI+angle; の命令を追加することで正常に機能するようになった.

2.3

N -way

弾の処理

弾幕シューティングゲームにはN -way弾という主要な弾がある. それは, ある角度(多 くの場合は自機への角度)を中心としてN 個の弾を扇形状に発射するというものである. 自機への角度へ向けた(以下, 自機狙いという)N -way弾は, N が偶数であるか奇数であ

(73)

るかによって避け方が大きく変わる. N が奇数の場合, 中心の弾が自分の方向に向かって くるので, 避けなければ必ず当たってしまう.それに対しN が偶数の場合, 自機に対して 右方向, 左方向に弾が分かれるので,逆に,動かなければ弾が当たることはない. 図3 N が奇数の場合 4 N が偶数の場合 奇数の場合と偶数の場合で描画が大きく異なるので, プログラムも偶数の場合と奇数の 場合で分けて考える必要があった.

void N_way(float x,float y,float speed,int span,int N,float angle, float anglespan,Tama_set2 Tama,Tama_type TamaT,color c){ //(発射位置X,発射位置Y,スピード,弾と弾のフレーム数,way数,角度, // 弾と弾の間の角度,Tama_setクラス(弾の座標を格納),Tama_typeクラス(弾の形, 大きさ),色) if(Tama.flag==true){ if(Tama.time%span==0){//Sspanにひとつ弾を打つ Tama.Tspeed[Tama.n]=speed; for(int k=1;k<N+1;k++){ Tama.Tx[Tama.n][k]=x; Tama.Ty[Tama.n][k]=y;

参照

関連したドキュメント

c加振振動数を変化させた実験 地震動の振動数の変化が,ろ過水濁度上昇に与え る影響を明らかにするため,入力加速度 150gal,継 続時間

このように,フラッシュマーケティングのためのサイトを運営するパブ

本体背面の拡張 スロッ トカバーを外してください。任意の拡張 スロット

必要に応じて、「タイムゾーンの設定(p5)」「McAfee Endpoint Security

ZoomのHP https://zoom.us にアクセスし、画面右上の「サインアップは無料です」をクリッ

回転に対応したアプリを表示中に本機の向きを変えると、 が表 示されます。 をタップすると、縦画面/横画面に切り替わりま

づくる溶岩を丸石谷を越えて尾添尾根の方へ 延長した場合,尾添尾根の噴出物より約250

パキロビッドパックを処方入力の上、 F8特殊指示 →「(治)」 の列に 「1:する」 を入力して F9更新 を押下してください。.. 備考欄に「治」と登録されます。