for Proce55ing
RallX - Source code
(C) Kenta Cho(ABA."Saba")
RallX.java
/**
* Rallx.<br>
* 迷路脱出ゲームレーダー付き<br><br>
*
* Copyright 2004 Kenta Cho. All rights reserved.
*
* @p5 description
* -車をマウスで操作して、全ての旗を回収、迷路の中央の出口に向かってください。
* -Control a car with your mouse, get all flags and go to the exit at the center of the maze.
* -赤い岩にぶつかると車を失います。
* -Avoid red square shaped rocks. You lose a car when you crash into a rock.
* -マウスボタンを押しっぱなしでレーダーを見られます。迷路全体を見渡すことができますが、岩は表示されません。
* -Hold a mouse button to see the radar screen. You can see the entire maze but rocks are not shown on the radar.
* -画面下にある残り時間がなくなっても車を失います。
* -You also lose a car when a time(displayed at the bottom of screen) runs out.
*/
public class RallX extends BApplet {
/**
* 迷路データ(0-空、1-壁、2-ゴール、3-旗、10〜-岩)
*/
int[][] maze;
/**
* 迷路や出口の大きさ用定数
*/
int MAZE_SIZE = 49, EXIT_SIZE = 7;
/**
* 迷路1ブロックのレーダー上の大きさ
*/
int mazeRectSize;
/**
* 迷路1ブロックのスクロール画面上の大きさ
*/
float mazeWallSize;
/**
* 出口の方向
*/
int exitD;
/**
* スクロール画面内に表示するブロック数
*/
int wallSightRange;
/**
* 自車関連データ
*/
float cx, cy, cd, cmd, cmx, cmy, csp, cmsp;
/**
* 自車のいるブロック位置
*/
int wx, wy;
/**
* レーダー切り替え時カウンタ
*/
int rcnt;
/**
* レーダー切り替え時アルファ値
*/
int ca;
/**
* ラウンドクリア時カウンタ
*/
int ccnt;
/**
* 自車クラッシュ時カウンタ
*/
int dcnt;
/**
* 画面中央に表示するメッセージ
*/
String msg;
/**
* メッセージ用カウンタ
*/
int mcnt;
/**
* パーティクルの最大数
*/
int PARTICLE_NUM = 32;
/**
* パーティクルインスタンスプール
*/
Particle[] particle;
/**
* 岩の最大数
*/
int ROCK_NUM = 50;
/**
* 岩インスタンスプール
*/
Rock[] rock;
/**
* 残りの旗の数
*/
int flagNum;
/**
* ステージ数
*/
int stage;
/**
* スコア
*/
float score;
/**
* 残機数
*/
int left;
/**
* 残り時間
*/
int time;
/**
* ゲーム状態用定数
*/
int TITLE = 0, IN_GAME = 1;
/**
* ゲームの状態(タイトル/ゲーム中)
*/
int state;
/**
* 各面のスタート時の残り時間(30frame * 60sec)
*/
int STAGE_TIME = 1800;
/**
* フォントデータ
*/
BFont font;
/**
* BGMデータ
*/
BSound bgm;
/**
* SEデータ
*/
BSound flagSe, crashSe, clearSe;
/**
* 初期化(フォント、サウンド読み込み、インスタンス生成)
*/
void setup() {
size(300, 300);
framerate(30);
smooth();
cursor();
ellipseMode(CENTER_DIAMETER);
font = loadFont("OCR-A.vlw.gz");
textFont(font);
bgm = loadSound("bgm.wav");
flagSe = loadSound("flag.wav");
crashSe = loadSound("crash.wav");
clearSe = loadSound("clear.wav");
mazeRectSize = width / MAZE_SIZE;
maze = new int[MAZE_SIZE][MAZE_SIZE];
mazeWallSize = 40;
wallSightRange = (int) (width / mazeWallSize) / 2 + 2;
particle = new Particle[PARTICLE_NUM];
for (int i = 0; i < particle.length; i++)
particle[i] = new Particle();
rock = new Rock[ROCK_NUM];
for (int i = 0; i < rock.length; i++)
rock[i] = new Rock();
startTitle();
}
/**
* タイトル初期化
*/
void startTitle() {
state = TITLE;
stop(bgm);
exitD = 0;
stage = 0;
left = 0;
initStage();
ca = 150;
time = -999;
float d = random(PI * 2);
cmx = sin(d);
cmy = cos(d);
mcnt = 0;
}
/**
* ゲーム開始
*/
void startGame() {
state = IN_GAME;
exitD = 0;
stage = -1;
score = 0;
left = 2;
initStage();
volume(bgm, 1.0f);
jump(bgm, 0);
repeat(bgm);
}
/**
* ステージ生成
*/
void initStage() {
// Init a car potision.
switch (exitD) {
case 0 :
cx = MAZE_SIZE * mazeWallSize / 2;
cy = mazeWallSize * 1.5f;
cd = PI;
break;
case 1 :
cx = MAZE_SIZE * mazeWallSize - mazeWallSize * 1.5f;
cy = MAZE_SIZE * mazeWallSize / 2;
cd = PI / 2 * 3;
break;
case 2 :
cx = MAZE_SIZE * mazeWallSize / 2;
cy = MAZE_SIZE * mazeWallSize - mazeWallSize * 1.5f;
cd = 0;
break;
case 3 :
cx = mazeWallSize * 1.5f;
cy = MAZE_SIZE * mazeWallSize / 2;
cd = PI / 2;
break;
}
cmx = cmy = 0;
csp = 0;
rcnt = 0;
ccnt = -8;
dcnt = 0;
time = STAGE_TIME;
// Set a stage pattern.
stage++;
int rockNum = 0;
switch (stage % 6) {
case 0 :
mazeGrid = 8;
mazePtn = 0;
rockNum = stage * 3;
flagNum = 4;
break;
case 1 :
mazeGrid = 4;
mazePtn = 0;
rockNum = stage - 1;
flagNum = 0;
break;
case 2 :
mazePtn = 1;
rockNum = 10 + stage * 4;
flagNum = 8;
break;
case 3 :
mazeGrid = 6;
mazePtn = 0;
rockNum = stage * 3;
flagNum = 4;
break;
case 4 :
mazeGrid = 3;
mazePtn = 0;
rockNum = stage;
flagNum = 0;
break;
case 5 :
mazeGrid = 6;
mazePtn = 2;
rockNum = 12 + stage * 3;
flagNum = 3;
break;
}
if (rockNum > rock.length)
rockNum = rock.length;
if (stage == 0) {
msg = "Get flags.";
mcnt = 60;
} else if (stage == 2) {
msg = "Avoid rocks.";
mcnt = 60;
} else if (flagNum == 0) {
msg = "Go to the exit.";
mcnt = 60;
} else {
mcnt = 0;
}
// Create a maze and set flags and rocks.
createMaze();
wx = (int) (cx / mazeWallSize);
wy = (int) (cy / mazeWallSize);
maze[wx][wy] = 1;
for (int i = 0; i < flagNum; i++) {
int x, y;
do {
x = (int) random(MAZE_SIZE - 2) + 1;
y = (int) random(MAZE_SIZE - 2) + 1;
} while (maze[x][y] != 0);
maze[x][y] = 3;
}
for (int i = 0; i < rockNum; i++) {
int x = (int) random(MAZE_SIZE - 2) + 1;
int y = (int) random(MAZE_SIZE - 2) + 1;
if (maze[x][y] == 0) {
maze[x][y] = i + 10;
rock[i].ox = random(mazeWallSize / 2) + mazeWallSize / 4;
rock[i].oy = random(mazeWallSize / 2) + mazeWallSize / 4;
rock[i].x = x * mazeWallSize + rock[i].ox;
rock[i].y = y * mazeWallSize + rock[i].oy;
}
}
maze[wx][wy] = 0;
}
/**
* 迷路の壁と壁の間隔
*/
int mazeGrid;
/**
* 迷路パターン(0-通常、1-なにもなし、2-うずまき)
*/
int mazePtn;
/**
* 壁を延ばした地点の数(迷路作成終了判定用)
*/
int pointNum;
/**
* 壁を延ばしている座標
*/
int stx, sty, std;
/**
* 壁を延ばす方向の移動量定数
*/
int[] DMX = { 0, 1, 0, -1 }, DMY = { -1, 0, 1, 0 };
/**
* うずまき型迷路作成用カウンタ
*/
int turnCnt;
/**
* 壁を延ばして迷路作成
*/
void createMaze() {
for (int x = 0; x < MAZE_SIZE; x++)
maze[x][0] = maze[x][MAZE_SIZE - 1] = 1;
for (int y = 1; y < MAZE_SIZE - 1; y++) {
maze[0][y] = maze[MAZE_SIZE - 1][y] = 1;
for (int x = 1; x < MAZE_SIZE - 1; x++)
maze[x][y] = 0;
}
int ep = (MAZE_SIZE - EXIT_SIZE) / 2;
int bn = 0;
switch (mazePtn) {
case 0 :
bn = 100;
pointNum = MAZE_SIZE / mazeGrid;
pointNum -= 1;
pointNum *= pointNum;
pointNum -= (int) ((EXIT_SIZE + 1) / mazeGrid)
* (int) ((EXIT_SIZE + 1) / mazeGrid);
break;
case 1 :
bn = 0;
pointNum = 0;
break;
case 2 :
bn = 1;
pointNum = 999;
turnCnt = 0;
break;
}
for (int i = 0; i < bn; i++) {
if (pointNum <= 0)
break;
if (mazePtn == 0) {
stx =
(int) random((MAZE_SIZE - 1) / mazeGrid - 1) * mazeGrid
+ mazeGrid;
sty =
(int) random((MAZE_SIZE - 1) / mazeGrid - 1) * mazeGrid
+ mazeGrid;
std = (int) random(4);
if (maze[stx][sty] == 1) {
if (!moveTillNoWall())
continue;
} else {
if (!moveTillWall())
continue;
}
} else {
switch (exitD) {
case 0 :
stx = ((int) (MAZE_SIZE / mazeGrid) / 2 + 1) * mazeGrid;
sty = 0;
std = 2;
break;
case 1 :
stx = MAZE_SIZE - 1;
sty = ((int) (MAZE_SIZE / mazeGrid) / 2 + 1) * mazeGrid;
std = 3;
break;
case 2 :
stx = ((int) (MAZE_SIZE / mazeGrid) / 2 - 1) * mazeGrid;
sty = MAZE_SIZE - 1;
std = 0;
break;
case 3 :
stx = 0;
sty = ((int) (MAZE_SIZE / mazeGrid) / 2 - 1) * mazeGrid;
std = 1;
break;
}
}
createMazeBranch();
}
// Create the exit hole.
fillMaze(ep - mazeGrid + 1, EXIT_SIZE + (mazeGrid - 1) * 2, 0);
fillMaze(ep, EXIT_SIZE, 1);
fillMaze(ep + 1, EXIT_SIZE - 2, 2);
exitD = (int) random(4);
int ex, ey;
switch (exitD) {
case 0 :
case 2 :
ex = ep + 2;
if (exitD == 0)
ey = ep;
else
ey = ep + EXIT_SIZE - 1;
for (int x = ex; x < ex + EXIT_SIZE - 4; x++)
maze[x][ey] = 0;
break;
default :
ey = ep + 2;
if (exitD == 3)
ex = ep;
else
ex = ep + EXIT_SIZE - 1;
for (int y = ey; y < ey + EXIT_SIZE - 4; y++)
maze[ex][y] = 0;
break;
}
}
/**
* 壁がない地点まで移動(壁延ばし開始地点探索用)
* @return 地点が見つかった
*/
boolean moveTillNoWall() {
int tx = stx, ty = sty;
for (;;) {
tx += DMX[std] * mazeGrid;
ty += DMY[std] * mazeGrid;
if (tx < 0 || tx >= MAZE_SIZE || ty < 0 || ty >= MAZE_SIZE)
return false;
if (maze[tx][ty] == 0)
return true;
stx = tx;
sty = ty;
}
}
/**
* 壁がある地点まで移動(壁延ばし開始地点探索用)
* @return 地点が見つかった
*/
boolean moveTillWall() {
for (;;) {
stx -= DMX[std] * mazeGrid;
sty -= DMY[std] * mazeGrid;
if (stx < 0 || stx >= MAZE_SIZE || sty < 0 || sty >= MAZE_SIZE)
return false;
if (maze[stx][sty] == 1)
return true;
}
}
/**
* 壁を延ばす(一定の確率で曲がり、四方がふさがれたら終了)
*/
void createMazeBranch() {
for (;;) {
if (maze[stx + DMX[std] * mazeGrid][sty + DMY[std] * mazeGrid]
== 0) {
for (int i = 0; i < mazeGrid; i++) {
stx += DMX[std];
sty += DMY[std];
maze[stx][sty] = 1;
}
if (mazePtn == 2) {
if ((turnCnt % 6) == 0) {
std++;
std &= 3;
turnCnt++;
}
} else {
if (random(1) < 0.4f) {
std += (int) random(2) * 2 - 1;
std &= 3;
}
}
pointNum--;
if (pointNum <= 0)
return;
continue;
} else {
if (mazePtn == 2) {
std++;
std &= 3;
turnCnt++;
} else {
std += (int) random(2) * 2 - 1;
std &= 3;
}
if (maze[stx + DMX[std] * mazeGrid][sty + DMY[std] * mazeGrid]
== 0)
continue;
std += 2;
std &= 3;
if (maze[stx + DMX[std] * mazeGrid][sty + DMY[std] * mazeGrid]
== 1)
return;
}
}
}
/**
* 出口作成用に迷路を正方形に埋める
* @param p 左上の座標
* @param w 大きさ
* @param v 埋める値
*/
void fillMaze(int p, int w, int v) {
for (int y = p; y < p + w; y++)
for (int x = p; x < p + w; x++)
maze[x][y] = v;
}
/**
* 1フレームごとの処理
*/
void loop() {
if (state == IN_GAME)
loopGame();
else
loopTitle();
}
/**
* マウスリリース時にゲームスタートするためのフラグ
*/
boolean startPressed = false;
/**
* タイトル時の1フレーム処理
*/
void loopTitle() {
background(255);
cx += cmx;
cy += cmy;
wx = (int) (cx / mazeWallSize);
wy = (int) (cy / mazeWallSize);
if (cx < 0 || cx > MAZE_SIZE * mazeWallSize)
cmx *= -1;
if (cy < 0 || cy > MAZE_SIZE * mazeWallSize)
cmy *= -1;
drawMaze();
boolean onStart;
if (mouseX > width / 2 - 50
&& mouseX < width / 2 + 50
&& mouseY > height - 100
&& mouseY < height - 75)
onStart = true;
else
onStart = false;
push();
translate(0, 0, 30);
textSize(42);
textMode(ALIGN_CENTER);
fill(0, 0, 0);
text("RallX", width / 2, height / 3);
stroke(250, 100, 50);
if (onStart)
fill(250, 180, 100);
else
fill(200, 150, 50);
strokeWeight(2);
rect(width / 2 - 50, height - 100, 100, 25);
strokeWeight(1);
fill(0, 0, 0);
textSize(25);
text("START", width / 2, height - 80);
pop();
drawStatus();
if (onStart && mousePressed)
startPressed = true;
if (!mousePressed && startPressed) {
startPressed = false;
if (onStart)
startGame();
}
}
/**
* ゲーム中の1フレーム処理
*/
void loopGame() {
background(255);
float pcx = cx, pcy = cy;
cx += cmx;
cy += cmy;
cmx += (sin(cd) * csp - cmx) * 0.04f;
cmy += (cos(cd) * csp - cmy) * 0.04f;
int mox = mouseX - width / 2, moy = mouseY - height / 2;
float mouseDst = sqrt(mox * mox + moy * moy);
float brk = 0.85f + (mouseDst / (width / 2)) * 0.15f;
if (brk > 1)
brk = 1;
cmx *= brk;
cmy *= brk;
cmd = atan2(cmx, cmy);
cmsp = sqrt(cmx * cmx + cmy * cmy);
score += cmsp * 0.05f;
float md = adjustDeg(atan2(mox, moy) - cd);
cd += md * 0.2f;
cd = adjustDeg(cd);
wx = (int) (cx / mazeWallSize);
wy = (int) (cy / mazeWallSize);
int pwx = (int) (pcx / mazeWallSize);
int pwy = (int) (pcy / mazeWallSize);
if (maze[wx][wy] == 1) {
if (maze[pwx][wy] == 0) {
cx = pcx;
cmx *= -0.8f;
} else if (maze[wx][pwy] == 0) {
cy = pcy;
cmy *= -0.8f;
} else {
cx = pcx;
cmx *= -0.8f;
cy = pcy;
cmy *= -0.8f;
}
} else if (maze[wx][wy] == 2 && ccnt == 0 && flagNum <= 0) {
ccnt = 1;
stop(clearSe);
play(clearSe);
} else if (maze[wx][wy] == 3) {
maze[wx][wy] = 0;
score += 500;
flagNum--;
stop(flagSe);
play(flagSe);
if (flagNum <= 0) {
msg = "Go to the exit.";
mcnt = 60;
}
} else if (maze[wx][wy] >= 10) {
int ri = maze[wx][wy] - 10;
if (abs(rock[ri].x - cx) + abs(rock[ri].y - cy) < 20)
miss();
}
float od = abs(adjustDeg(cd - cmd));
if (od > 0.5f && cmsp > 6)
addParticle(
width / 2,
height / 2,
cmd + PI + random(-0.3f, 0.3f),
cmsp);
if (mousePressed) {
csp += (5 - csp) * 0.3f;
if (rcnt < 8)
rcnt++;
} else {
csp += (20 - csp) * 0.3f;
if (rcnt > 0)
rcnt--;
}
if (ccnt > 0) {
ccnt++;
rcnt = 0;
cmx *= 0.8;
cmy *= 0.8;
csp *= 0.6;
if (time > 0) {
time -= 30;
score += 100;
if (time > 30) {
time -= 30;
score += 100;
}
}
if (ccnt > 30) {
initStage();
return;
}
} else if (ccnt < 0) {
ccnt++;
}
if (dcnt > 0) {
dcnt--;
rcnt = 0;
cmx *= 0.8;
cmy *= 0.8;
csp *= 0.6;
if (dcnt > 30) {
float v = 1 - (float) (250 - dcnt) / 60;
if (v < 0)
v = 0;
volume(bgm, v);
csp = 0;
push();
translate(0, 0, 30);
textSize(32);
textMode(ALIGN_CENTER);
fill(0, 0, 0);
text("Game Over", width / 2, height / 3);
pop();
if (dcnt < 100 || (dcnt < 230 && mousePressed)) {
startTitle();
return;
}
}
if (dcnt == 1)
time = STAGE_TIME;
}
if (dcnt == 0 && ccnt == 0) {
time--;
if (time <= 0)
miss();
}
if (rcnt < 8) {
push();
if (ccnt > 0) {
translate(0, 0, ccnt * 5);
ca = 255 - ccnt * 12;
if (ca < 0)
ca = 0;
} else {
translate(0, 0, -rcnt * 30);
ca = 255 - rcnt * 31;
if (ccnt < 0)
ca = 255 + ccnt * 31;
}
if (dcnt <= 0)
drawCar(width / 2, height / 2, cd, cmd);
drawMaze();
noStroke();
for (int i = 0; i < particle.length; i++)
if (particle[i].cnt >= 0)
particle[i].loop();
pop();
}
if (rcnt > 0)
drawMazeOnRadar();
drawStatus();
}
/**
* 自車が岩に突っ込んだ/時間切れ
*/
void miss() {
stop(crashSe);
play(crashSe);
dcnt = 30;
for (int i = 0; i < 24; i++)
addParticle(width / 2, height / 2, random(PI * 2), random(20));
maze[wx][wy] = 0;
left--;
if (left < 0)
dcnt = 250;
}
/**
* 方向を -PI〜PI に収めることで曲がる方向の計算を楽に
* @param d 補正前の角度
* @return 補正後の角度
*/
float adjustDeg(float d) {
if (d > PI)
return d - PI * 2;
else if (d < -PI)
return d + PI * 2;
else
return d;
}
/**
* 車を書く
* @param x x座標
* @param y y座標(残機表示兼用のため座標が指定できる)
* @param d1 前輪の方向(マウスの方向を向く)
* @param d2 後輪の方向(移動方向を向く後輪)
*/
void drawCar(int x, int y, float d1, float d2) {
fill(100, 150, 250, ca);
stroke(150, 200, 255, ca);
push();
translate(x, y);
rotateZ(-d1);
translate(0, 6);
rect(-3, -6, 6, 12);
pop();
push();
translate(x, y);
rotateZ(-d2);
translate(-6, -6);
rect(-3, -6, 6, 12);
translate(12, 0);
rect(-3, -6, 6, 12);
pop();
}
/**
* スクロール画面上の迷路表示
*/
void drawMaze() {
float wsx, wsy;
float swsx = -cx + (wx - wallSightRange) * mazeWallSize + width / 2;
float swsy = -cy + (wy - wallSightRange) * mazeWallSize + height / 2;
wsy = swsy;
beginShape(QUADS);
for (int y = wy - wallSightRange;
y <= wy + wallSightRange;
y++, wsy += mazeWallSize) {
wsx = swsx;
for (int x = wx - wallSightRange;
x <= wx + wallSightRange;
x++, wsx += mazeWallSize) {
if (x >= 0 && x < MAZE_SIZE && y >= 0 && y < MAZE_SIZE) {
if (maze[x][y] == 1)
drawWall(wsx, wsy);
else if (maze[x][y] == 2)
drawGoal(wsx, wsy);
else if (maze[x][y] == 3)
drawFlag(wsx, wsy);
else if (maze[x][y] >= 10) {
int ri = maze[x][y] - 10;
drawRock(wsx, wsy, rock[ri].ox, rock[ri].oy);
}
}
}
}
endShape();
}
/**
* 壁のz軸方向高さ
*/
float WALL_height = 20;
/**
* 壁を書く
* @param sx スクロール画面上のx座標
* @param sy スクロール画面上のy座標
*/
void drawWall(float sx, float sy) {
fill(200, 250, 50, ca);
stroke(100, 150, 100, ca);
vertex(sx, sy, WALL_height);
vertex(sx + mazeWallSize, sy, WALL_height);
vertex(sx + mazeWallSize, sy + mazeWallSize, WALL_height);
vertex(sx, sy + mazeWallSize, WALL_height);
fill(220, 250, 150, ca);
stroke(150, 200, 100, ca);
vertex(sx, sy, WALL_height);
vertex(sx + mazeWallSize, sy, WALL_height);
vertex(sx + mazeWallSize, sy, 0);
vertex(sx, sy, 0);
vertex(sx + mazeWallSize, sy, WALL_height);
vertex(sx + mazeWallSize, sy + mazeWallSize, WALL_height);
vertex(sx + mazeWallSize, sy + mazeWallSize, 0);
vertex(sx + mazeWallSize, sy, 0);
vertex(sx + mazeWallSize, sy + mazeWallSize, WALL_height);
vertex(sx, sy + mazeWallSize, WALL_height);
vertex(sx, sy + mazeWallSize, 0);
vertex(sx + mazeWallSize, sy + mazeWallSize, 0);
vertex(sx, sy + mazeWallSize, WALL_height);
vertex(sx, sy, WALL_height);
vertex(sx, sy, 0);
vertex(sx, sy + mazeWallSize, 0);
}
/**
* 旗を回収し終わっていたらゴールを書く
* @param sx スクロール画面上のx座標
* @param sy スクロール画面上のy座標
*/
void drawGoal(float sx, float sy) {
if (flagNum > 0)
return;
fill(250, 200, 150, ca);
stroke(250, 150, 200, ca);
vertex(sx, sy, 0);
vertex(sx + mazeWallSize, sy, 0);
vertex(sx + mazeWallSize, sy + mazeWallSize, 0);
vertex(sx, sy + mazeWallSize, 0);
}
/**
* 岩を書く
* @param x スクロール画面上のブロックのx座標
* @param y スクロール画面上のブロックのx座標
* @param ox ブロック座標からの補正xオフセット
* @param oy ブロック座標からの補正yオフセット
*/
void drawRock(float x, float y, float ox, float oy) {
float sx = x + ox, sy = y + oy;
sy -= 3;
stroke(250, 50, 100, ca);
fill(200, 100, 50, ca);
vertex(sx - 8, sy - 8, 0.2f);
vertex(sx + 8, sy - 8, 0.2f);
vertex(sx + 8, sy + 8, 0.2f);
vertex(sx - 8, sy + 8, 0.2f);
fill(240, 200, 100, ca);
sx += 5;
sy += 8;
vertex(sx - 8, sy - 8, 0.1f);
vertex(sx + 8, sy - 8, 0.1f);
vertex(sx + 8, sy + 8, 0.1f);
vertex(sx - 8, sy + 8, 0.1f);
fill(200, 220, 120, ca);
sx -= 9;
sy -= 4;
vertex(sx - 8, sy - 8, 0);
vertex(sx + 8, sy - 8, 0);
vertex(sx + 8, sy + 8, 0);
vertex(sx - 8, sy + 8, 0);
}
/**
* 旗を書く
* @param x スクロール画面上のx座標
* @param y スクロール画面上のy座標
*/
void drawFlag(float x, float y) {
float sx = x + mazeWallSize / 3, sy = y + mazeWallSize / 3;
fill(250, 250, 100, ca);
stroke(250, 100, 50, ca);
vertex(sx, sy, WALL_height);
vertex(sx + 3, sy, WALL_height);
vertex(sx + 3, sy + mazeWallSize / 3 * 2, 0);
vertex(sx, sy + mazeWallSize / 3 * 2, 0);
vertex(sx + 3, sy, WALL_height);
vertex(sx + 13, sy, WALL_height);
vertex(sx + 13, sy + 10, WALL_height / 3 * 2);
vertex(sx + 3, sy + 10, WALL_height / 3 * 2);
}
/**
* レーダー画面上の迷路と旗と自車を表示
*/
void drawMazeOnRadar() {
int a = rcnt * 32 - 1;
push();
translate(0, 0, -WALL_height * 2 + (8 - rcnt) * 20);
noStroke();
fill(255, 220, 180, a);
for (int y = 0; y < MAZE_SIZE; y++)
for (int x = 0; x < MAZE_SIZE; x++)
if (maze[x][y] == 1)
rect(
x * mazeRectSize,
y * mazeRectSize,
mazeRectSize,
mazeRectSize);
else if (maze[x][y] == 3) {
fill(200, 200, 50, a);
rect(
x * mazeRectSize,
y * mazeRectSize,
mazeRectSize,
mazeRectSize);
fill(255, 220, 180, a);
}
fill(100, 200, 255, a);
rect(wx * mazeRectSize, wy * mazeRectSize, mazeRectSize, mazeRectSize);
pop();
}
/**
* スコアと残機と残りタイムとメッセージを表示
*/
void drawStatus() {
push();
translate(0, 0, 30);
textSize(26);
textMode(ALIGN_RIGHT);
fill(0, 0, 0);
text((int) score, width - 18, 36);
if (time > -999) {
textMode(ALIGN_CENTER);
textSize(33);
text((time + 29) / 30, width / 2, height - 20);
}
for (int i = 0; i < left; i++)
drawCar(i * 20 + 30, 30, PI, PI);
if (mcnt > 0) {
mcnt--;
textMode(ALIGN_CENTER);
textSize(24);
fill(0, 0, 0);
text(msg, width / 2, height / 3);
}
pop();
}
/**
* スモーク状のパーティクル
*/
class Particle {
/**
* 表示サイズ
*/
float SIZE = 20;
/**
* 位置
*/
float x, y;
/**
* 広がる方向および速度
*/
float deg, speed;
/**
* アルファ値
*/
int alpha;
/**
* 消えるまでのカウンタ
*/
int cnt;
/**
* カウンタを-1に設定して非表示に
*/
Particle() {
cnt = -1;
}
/**
* cntを設定して有効にする
* @param x 初期x座標
* @param y 初期y座標
* @param d 方向
* @param s スピード
*/
void set(float x, float y, float d, float s) {
this.x = x;
this.y = y;
deg = d;
speed = s;
alpha = 200 + (int) random(50);
cnt = 15 + (int) random(15);
}
/**
* 1フレーム毎の処理
*/
void loop() {
x += sin(deg) * speed;
y += cos(deg) * speed;
speed *= 0.95f;
alpha *= 0.9f;
cnt--;
fill(200, 190, 120, alpha);
ellipse(x, y, SIZE, SIZE);
}
}
/**
* パーティクルプールから次のインスタンスを指し示すためのインデックス
*/
int particleIdx = 0;
/**
* パーティクル追加
* @param x 初期x座標
* @param y 初期y座標
* @param d 方向
* @param s スピード
*/
void addParticle(float x, float y, float d, float s) {
particleIdx--;
if (particleIdx < 0)
particleIdx += particle.length;
particle[particleIdx].set(x, y, d, s);
}
/**
* 岩(当たると痛い)
*/
class Rock {
/**
* 迷路ブロック内のオフセット
*/
float ox, oy;
/**
* どの迷路ブロックに配置されているか
*/
float x, y;
}
}