for Proce55ing
La - Source code
(C) Kenta Cho(ABA."Saba")
La.java
/**
* L.A.<br>
* Life game meets shmup game.<br><br>
*
* Copyright (C) 2004 Kenta Cho. Some rights reserved.
*
* @p5 description
* - 画面中央の自機をマウスで操作してください
* - マウスボタンを押すと弾を発射します
* - 前方に発射される赤弾はセルを破壊します
* - 後方に発射される緑弾はセルを生成します
* - セルに接触するとゲームオーバーです
*/
public class La extends BApplet {
Ship ship;
Shot[] shot = new Shot[6];
Field field;
BFont font;
int TITLE = 0;
int IN_GAME = 1;
int GAMEOVER = 2;
int state;
Title title;
Gameover gameover;
int score;
void setup() {
size(300, 300);
framerate(30);
smooth();
cursor();
font = loadFont("OCR-A.vlw.gz");
textFont(font);
field = new Field();
for (int i = 0; i < shot.length; i++)
shot[i] = new Shot();
ship = new Ship();
title = new Title();
gameover = new Gameover();
startTitle();
}
void startTitle() {
state = TITLE;
field.start();
}
void startInGame() {
state = IN_GAME;
score = 0;
initShots();
ship.start();
field.start();
}
void startGameover() {
state = GAMEOVER;
gameover.start();
}
void loop() {
background(40, 60, 20);
switch (state) {
case 0 : // TITLE
field.move();
field.draw();
title.loop();
break;
case 1 : // IN_GAME
moveShots();
ship.move();
field.move();
drawShots();
ship.draw();
field.draw();
break;
case 2 : // GAMEOVER
ship.draw();
field.draw();
gameover.loop();
break;
}
drawStatus();
}
void drawStatus() {
push();
translate(0, 0, 30);
textSize(26);
textMode(ALIGN_RIGHT);
fill(255, 255, 255);
text((int) score, width - 18, 36);
pop();
}
float adjustDeg(float d) {
if (d > PI)
return d - PI * 2;
else if (d < -PI)
return d + PI * 2;
else
return d;
}
/**
* Vector.
*/
class Vector {
float x, y;
}
/**
* My ship.
*/
class Ship {
Vector pos = new Vector();
Vector vel = new Vector();
int FIRE_INTERVAL = 10;
float MAX_SPEED = 10;
float deg;
float speed;
int fireCnt;
public void start() {
pos.x = width / 2;
pos.y = height / 2;
vel.x = vel.y = 0;
restart();
}
public void restart() {
deg = 0;
speed = 0;
fireCnt = 0;
}
public void move() {
float pcx = pos.x, pcy = pos.y;
pos.x += vel.x;
pos.y += vel.y;
vel.x += (sin(deg) * speed - vel.x) * 0.1f;
vel.y += (cos(deg) * speed - vel.y) * 0.1f;
int mox = mouseX - (int) pos.x;
int moy = mouseY - (int) pos.y;
float mouseDst = sqrt(mox * mox + moy * moy);
float sd = mouseDst / (width / 2);
if (sd > 0.05f)
speed += (MAX_SPEED * sd - speed) * 0.3f;
else
speed *= 0.3f;
float md = adjustDeg(atan2(mox, moy) - deg);
if (sd > 0.05f)
deg += md * 0.2f;
deg = adjustDeg(deg);
if (mousePressed) {
if (fireCnt <= 0) {
fireCnt = FIRE_INTERVAL;
add2Shot(pos, -deg);
}
}
fireCnt--;
if (field.checkHit(pos, null, -1))
startGameover();
}
public void draw() {
fill(100, 100, 200);
stroke(180, 190, 250);
push();
translate(pos.x, pos.y, 0);
rotate(-deg, 0, 0, 1);
beginShape(TRIANGLE_STRIP);
vertex(-6, -8, 0);
vertex(0, 8, 0);
vertex(0, -2, 0);
vertex(6, -8, 0);
endShape();
pop();
}
}
/**
* My shot.
*/
class Shot {
int REMOVE = 0;
int CREATE = 1;
float SPEED = 6;
Vector pos = new Vector();
Vector ppos = new Vector();
float deg;
int type;
boolean isExist = false;
void set(Vector p, float d, int t) {
pos.x = p.x;
pos.y = p.y;
deg = d;
type = t;
isExist = true;
}
void remove() {
isExist = false;
}
void move() {
ppos.x = pos.x;
ppos.y = pos.y;
pos.x -= sin(deg) * SPEED;
pos.y += cos(deg) * SPEED;
if (field.checkHit(pos, ppos, type))
isExist = false;
}
public void draw() {
push();
translate(pos.x, pos.y, 0);
rotate(deg, 0, 0, 1);
if (type == REMOVE) {
fill(200, 100, 100);
stroke(250, 150, 150);
} else {
fill(100, 200, 100);
stroke(150, 250, 150);
}
beginShape(TRIANGLE_STRIP);
vertex(0, 5, 0);
vertex(-2, -5, 0);
vertex(2, -5, 0);
endShape();
pop();
}
}
void initShots() {
for (int i = 0; i < shot.length; i++)
shot[i].isExist = false;
}
void moveShots() {
for (int i = 0; i < shot.length; i++)
if (shot[i].isExist)
shot[i].move();
}
void drawShots() {
for (int i = 0; i < shot.length; i++)
if (shot[i].isExist)
shot[i].draw();
}
int shotIdx = 0;
Shot getShotInstance() {
for (int i = 0; i < shot.length; i++) {
if (!shot[shotIdx].isExist)
return shot[shotIdx];
shotIdx--;
if (shotIdx < 0)
shotIdx = shot.length - 1;
}
return null;
}
void add2Shot(Vector p, float d) {
Shot s = getShotInstance();
if (s == null)
return;
s.set(p, d, 0);
Shot s2 = getShotInstance();
if (s2 == null) {
s.isExist = false;
return;
}
s2.set(p, d + PI, 1);
}
/**
* Life game field.
*/
class Field {
int EMPTY = 0;
int EXIST = 1;
int TAINT = 2;
int WIDTH = 30, HEIGHT = 30;
float SIZE = 10.0f, DSIZE = 9.0f;
int[][] cell = new int[30][30];
int[][] cellCnt = new int[30][30];
boolean[][] cellTaint = new boolean[30][30];
float interval;
int cnt;
public void start() {
for (int y = 0; y < HEIGHT; y++)
for (int x = 0; x < WIDTH; x++)
cell[x][y] = EMPTY;
interval = 12.0f;
}
public void move() {
cnt--;
if (cnt > 0)
return;
cnt = (int) interval;
interval *= 0.998f;
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
if (x > 0 && x < WIDTH - 1 && y > 0 && y < HEIGHT - 1)
continue;
int c;
if (((int) random(4)) != 0)
c = EXIST;
else
c = EMPTY;
cell[x][y] = c;
}
}
for (int y = 1; y < HEIGHT - 1; y++) {
for (int x = 1; x < WIDTH - 1; x++) {
int c = 0;
boolean t = true;
for (int oy = -1; oy <= 1; oy++) {
for (int ox = -1; ox <= 1; ox++) {
if (cell[x + ox][y + oy] != EMPTY)
c++;
if (cell[x + ox][y + oy] == EXIST)
t = false;
}
}
cellCnt[x][y] = c;
cellTaint[x][y] = t;
}
}
for (int y = 1; y < HEIGHT - 1; y++) {
for (int x = 1; x < WIDTH - 1; x++) {
int c = cellCnt[x][y];
if (cell[x][y] != EMPTY) {
if (c < 3 || c > 4)
cell[x][y] = EMPTY;
} else {
if (c == 3) {
if (cellTaint[x][y])
cell[x][y] = TAINT;
else
cell[x][y] = EXIST;
}
}
}
}
}
public boolean checkHit(Vector p, Vector pp, int t) {
int cx = (int) (p.x / SIZE);
int cy = (int) (p.y / SIZE);
if (cx < 0 || cx >= WIDTH || cy < 0 || cy >= HEIGHT)
return true;
if (cell[cx][cy] != EMPTY) {
if (t == 0) {
cell[cx][cy] = EMPTY;
score++;
} else if (t == 1) {
int pcx = (int) (pp.x / SIZE);
int pcy = (int) (pp.y / SIZE);
cell[pcx][pcy] = TAINT;
}
return true;
}
return false;
}
public void draw() {
float sx, sy;
sy = 0;
for (int y = 0; y < HEIGHT; y++, sy += SIZE) {
sx = 0;
for (int x = 0; x < WIDTH; x++, sx += SIZE) {
if (cell[x][y] != EMPTY) {
if (cell[x][y] == TAINT) {
stroke(150, 220, 150);
fill(100, 150, 100);
} else {
stroke(180, 180, 150);
fill(120, 120, 100);
}
beginShape(QUADS);
vertex(sx, sy, 0);
vertex(sx + DSIZE, sy, 0);
vertex(sx + DSIZE, sy + DSIZE, 0);
vertex(sx, sy + DSIZE, 0);
endShape();
}
}
}
}
}
/**
* Title screen.
*/
class Title {
boolean startPressed;
void loop() {
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(255, 255, 255);
text("L.A.", width / 2, height / 3);
stroke(250, 100, 50);
if (onStart)
fill(200, 250, 150);
else
fill(150, 200, 100);
strokeWeight(2);
rect(width / 2 - 50, height - 100, 100, 25);
strokeWeight(1);
fill(255, 255, 255);
textSize(25);
text("START", width / 2, height - 80);
pop();
drawStatus();
if (onStart && mousePressed)
startPressed = true;
if (!mousePressed && startPressed) {
startPressed = false;
if (onStart)
startInGame();
}
}
}
/**
* Gameover screen.
*/
class Gameover {
int cnt;
void start() {
cnt = 0;
}
void loop() {
push();
translate(0, 0, 30);
textSize(32);
textMode(ALIGN_CENTER);
fill(255, 255, 255);
text("Game Over", width / 2, height / 3);
pop();
cnt++;
if (cnt > 300 || (cnt > 30 && mousePressed)) {
startTitle();
return;
}
}
}
}