for Proce55ing
PongPod - Source code
(C) Kenta Cho(ABA."Saba")
PongPod.java
/**
* PongPod.<br>
* Play a pong with a wheel.<br><br>
*
* Copyright (C) 2005 Kenta Cho. Some rights reserved.
*
* @p5 description
* - 画面下の灰色の丸(ホイール)にカーソルを合わせてください
* - クリックするとゲームが始まります
* - ホイールに沿って丸くカーソルを動かすとラケットが動きます
* - ラケットでボールをはじき返してください
* - ボールが中央の黒丸に入るとミスです
* - ミス3つでゲームオーバー
*/
//import processing.core.*;
//public class PongPod extends PApplet {
public class PongPod extends BApplet {
Field field;
Wheel wheel;
Racket racket;
Ball[] ball = new Ball[25];
//PFont font;
BFont font;
int TITLE = 0;
int IN_GAME = 1;
int GAMEOVER = 2;
int state;
Title title;
Gameover gameover;
int score;
Se se;
public void setup() {
size(340, 550);
framerate(30);
cursor(ARROW);
noStroke();
//
ellipseMode(CENTER_DIAMETER);
//font = loadFont("Verdana-48.vlw");
font = loadFont("Futura-BoldCon.vlw.gz");
textFont(font);
field = new Field();
field.init();
wheel = new Wheel();
wheel.init();
racket = new Racket();
racket.init();
for (int i = 0; i < ball.length; i++)
ball[i] = new Ball();
title = new Title();
gameover = new Gameover();
se = new Se();
se.load();
startTitle();
}
void startTitle() {
state = TITLE;
title.start();
}
void startInGame() {
state = IN_GAME;
score = 0;
se.init();
initBalls();
field.start();
racket.start();
}
void startGameover() {
state = GAMEOVER;
gameover.start();
}
//public void draw() {
public void loop() {
background(250, 250, 250);
smooth();
switch (state) {
case 0 : // TITLE
field.draw();
wheel.draw();
wheel.move();
title.draw();
break;
case 1 : // IN_GAME
field.draw();
wheel.draw();
field.move();
wheel.move();
moveBalls();
racket.move();
racket.draw();
drawBalls();
drawStatus();
se.playAllSes();
break;
case 2 : // GAMEOVER
field.draw();
wheel.draw();
wheel.move();
gameover.draw();
drawStatus();
break;
}
}
void drawStatus() {
textSize(26);
//textAlign(RIGHT);
textMode(ALIGN_RIGHT);
fill(255, 255, 255);
text(score, width - 14, 35);
}
float adjustDeg(float d) {
if (d > PI)
return d - PI * 2;
else if (d < -PI)
return d + PI * 2;
else
return d;
}
/**
* 2D vector.
*/
class Vector {
float x, y;
}
/**
* My racket.
*/
class Racket {
float SENSITIVITY = 0.7f;
float radius;
float deg;
Vector[] pos;
Vector p1, p2;
float rWidth, rHeight;
void init() {
radius = field.bwRadius * 1.5f;
pos = new Vector[2];
for (int i = 0; i < pos.length; i++)
pos[i] = new Vector();
p1 = new Vector();
p2 = new Vector();
rWidth = 70;
rHeight = 7;
}
void start() {
deg = 0;
}
void move() {
deg -= wheel.angVel * SENSITIVITY;
deg = adjustDeg(deg);
float d = deg;
for (int i = 0; i < pos.length; i++) {
pos[i].x = field.centerPos.x - sin(d) * radius;
pos[i].y = field.centerPos.y + cos(d) * radius;
p1.x = pos[i].x - sin(d + HALF_PI) * rWidth / 2;
p1.y = pos[i].y + cos(d + HALF_PI) * rWidth / 2;
p2.x = pos[i].x - sin(d - HALF_PI) * rWidth / 2;
p2.y = pos[i].y + cos(d - HALF_PI) * rWidth / 2;
for (int j = 0; j < ball.length; j++)
if (ball[j].isExist)
if (ball[j].checkHit(p1, p2))
ball[j].reflectWithRacket(d + HALF_PI);
d += PI;
}
}
void draw() {
fill(0, 0, 0);
//rectMode(CENTER);
rectMode(CENTER_DIAMETER);
float d = deg;
for (int i = 0; i < pos.length; i++) {
//pushMatrix();
push();
translate(pos[i].x + field.pos.x, pos[i].y + field.pos.y);
rotate(d);
rect(0, 0, rWidth, rHeight);
//popMatrix();
pop();
d += PI;
}
rectMode(CORNER);
}
}
/**
* Balls.
*/
class Ball {
Vector pos = new Vector();
Vector ppos = new Vector();
float deg;
float speed;
float size, trgSize;
boolean isExist = false;
int reflectCnt;
int idx;
void set(float x, float y, float d, float sp, float sz) {
pos.x = x;
pos.y = y;
deg = adjustDeg(d);
speed = sp;
trgSize = sz;
size = 0.1f;
reflectCnt = 0;
isExist = true;
}
void move() {
ppos.x = pos.x;
ppos.y = pos.y;
pos.x -= sin(deg) * speed;
pos.y += cos(deg) * speed;
size += (trgSize - size) * 0.1f;
if (pos.x < size || pos.x >= field.size.x - size)
reflect(0);
if (pos.y < size || pos.y >= field.size.y - size)
reflect(HALF_PI);
if (reflectCnt > 0)
reflectCnt--;
if (dist(pos.x, pos.y, field.centerPos.x, field.centerPos.y)
< field.bwRadius * 0.75f + size) {
field.incOutCnt();
isExist = false;
return;
}
}
void reflect(float d) {
float aod1 = abs(adjustDeg(deg - d));
float aod2 = abs(adjustDeg(deg - (d + PI)));
float od, aod;
if (aod1 < aod2) {
od = adjustDeg(deg - d);
aod = aod1;
} else {
od = adjustDeg(deg - (d + PI));
aod = aod2;
}
if (od < 0)
deg += aod * 2;
else
deg -= aod * 2;
pos.x = ppos.x;
pos.y = ppos.y;
pos.x -= sin(deg) * speed;
pos.y += cos(deg) * speed;
se.playSe(idx % 7);
}
void reflectWithRacket(float d) {
if (reflectCnt <= 0) {
reflect(d);
se.playSe(7);
score++;
}
reflectCnt = 3;
}
boolean checkHit(Vector p, Vector pp) {
float bmvx, bmvy, inaa;
bmvx = pp.x;
bmvy = pp.y;
bmvx -= p.x;
bmvy -= p.y;
inaa = bmvx * bmvx + bmvy * bmvy;
if (inaa > 0.00001) {
float sofsx, sofsy, inab, hd;
sofsx = pos.x;
sofsy = pos.y;
sofsx -= p.x;
sofsy -= p.y;
inab = bmvx * sofsx + bmvy * sofsy;
if (inab >= 0 && inab <= inaa) {
hd = sofsx * sofsx + sofsy * sofsy - inab * inab / inaa;
if (hd >= 0 && hd <= size * 0.7f + 7.0f) {
return true;
}
}
}
return false;
}
void draw() {
fill(255, 255, 255);
ellipse(
field.pos.x + pos.x,
field.pos.y + pos.y,
size * 2,
size * 2);
}
}
void initBalls() {
for (int i = 0; i < ball.length; i++) {
ball[i].idx = i;
ball[i].isExist = false;
}
ballIdx = 0;
}
void moveBalls() {
for (int i = 0; i < ball.length; i++)
if (ball[i].isExist)
ball[i].move();
}
void drawBalls() {
for (int i = 0; i < ball.length; i++)
if (ball[i].isExist)
ball[i].draw();
}
int ballIdx = 0;
Ball getBallInstance() {
for (int i = 0; i < ball.length; i++) {
if (!ball[ballIdx].isExist)
return ball[ballIdx];
ballIdx++;
if (ballIdx >= ball.length)
ballIdx = 0;
}
return null;
}
/**
* Game field (main screen).
*/
class Field {
Vector pos = new Vector();
Vector size = new Vector();
float bwRadius;
Vector centerPos = new Vector();
float brightness;
float bwSize;
int cnt;
int outCnt;
void init() {
size.x = 320;
size.y = 240;
pos.x = pos.y = (width - size.x) / 2;
bwRadius = size.y * 0.1f;
centerPos.x = size.x / 2;
centerPos.y = size.y / 2;
brightness = 0;
bwSize = 1.0f;
}
void start() {
bwSize = 1;
cnt = 0;
outCnt = 0;
for (int i = 0; i < 3; i++)
addBall();
}
void addBall() {
Ball b = getBallInstance();
if (b == null)
return;
float x, y;
if (random(2) >= 1) {
x = random(field.size.x - 40) + 20;
if (random(2) >= 1)
y = 20;
else
y = field.size.y - 20;
} else {
y = random(field.size.y - 40) + 20;
if (random(2) >= 1)
x = 20;
else
x = field.size.x - 20;
}
b.set(x, y, random(TWO_PI), 1.5f + random(1.0f), 4 + random(3.0f));
}
void incOutCnt() {
se.playSe(8);
outCnt++;
if (outCnt >= 3)
startGameover();
}
void move() {
cnt++;
if (cnt % 300 == 0)
addBall();
}
void draw() {
fill(80 * brightness, 200 * brightness, 80 * brightness);
rect(pos.x, pos.y, size.x, size.y);
fill(0, 0, 0);
ellipse(
pos.x + size.x / 2,
pos.y + size.y / 2,
bwRadius * 2 * bwSize,
bwRadius * 2 * bwSize);
if (state == IN_GAME) {
fill(255, 255, 255);
for (int i = 0; i < outCnt; i++)
ellipse(
pos.x + size.x / 2 - 10 + i * 10,
pos.y + size.y / 2,
10,
10);
}
}
}
/**
* Wheel that controls a racket.
*/
class Wheel {
Vector centerPos;
float radFrom, radTo;
boolean cursorOn;
float angVel;
float pdeg;
void init() {
centerPos = new Vector();
centerPos.x = width / 2;
centerPos.y = height * 0.75f;
radFrom = width * 0.35f / 2;
radTo = width * 0.7f / 2;
cursorOn = false;
angVel = 0;
pdeg = 0;
}
void move() {
float d = dist(mouseX, mouseY, centerPos.x, centerPos.y);
if (d >= radFrom * 0.05f && d <= radTo * 1.4f) {
if (!cursorOn) {
cursorOn = true;
cursor(HAND);
pdeg = atan2(mouseX - centerPos.x, mouseY - centerPos.y);
}
} else {
if (cursorOn) {
cursorOn = false;
cursor(ARROW);
}
}
if (cursorOn) {
float deg = atan2(mouseX - centerPos.x, mouseY - centerPos.y);
angVel = adjustDeg(deg - pdeg);
pdeg = deg;
} else {
angVel = 0;
}
}
void draw() {
fill(210, 210, 210);
ellipse(centerPos.x, centerPos.y, radTo * 2, radTo * 2);
fill(255, 255, 255);
ellipse(centerPos.x, centerPos.y, radFrom * 2, radFrom * 2);
}
}
/**
* Title screen.
*/
class Title {
int cnt;
void start() {
cnt = 0;
field.brightness = 0;
field.bwSize = 0;
}
void draw() {
cnt++;
if (cnt > 30 && mousePressed && wheel.cursorOn) {
startInGame();
return;
}
if (cnt <= 30)
field.brightness = cnt * (1.0f / 30);
if (cnt > 45) {
textSize(42);
//textAlign(CENTER);
textMode(ALIGN_CENTER);
fill(255, 255, 255);
text(
"PongPod",
field.pos.x + field.size.x / 2,
field.pos.y + field.size.y / 2);
}
}
}
/**
* Gameover screen.
*/
class Gameover {
int cnt;
void start() {
cnt = 0;
}
void draw() {
cnt++;
if (cnt > 300 || (cnt > 30 && mousePressed && wheel.cursorOn)) {
startTitle();
return;
}
if (cnt <= 30) {
field.bwSize = 1.0f + cnt * 0.1f;
field.brightness = 1.0f - cnt * (1.0f / 30);
}
if (cnt > 45) {
textSize(32);
//textAlign(CENTER);
textMode(ALIGN_CENTER);
fill(255, 255, 255);
text(
"GameOver",
field.pos.x + field.size.x / 2,
field.pos.y + field.size.y / 2);
}
}
}
/**
* Sound effect.
*/
class Se {
int SE_NUM = 9;
//PSound[] se;
BSound[] se;
boolean[] play;
int cnt;
int interval = 7;
void load() {
//se = new PSound[SE_NUM];
se = new BSound[SE_NUM];
play = new boolean[SE_NUM];
for (int i = 0; i < SE_NUM; i++)
se[i] = loadSound("se0" + (i + 1) + ".wav");
}
void init() {
for (int i = 0; i < SE_NUM; i++)
play[i] = false;
cnt = 0;
}
void playSe(int n) {
play[n] = true;
}
void playAllSes() {
cnt++;
int ci = cnt % interval;
if (ci == interval - 1) {
for (int i = 0; i < SE_NUM; i++) {
if (play[i])
//se[i].stop();
stop(se[i]);
}
}
if (ci == 0) {
for (int i = 0; i < SE_NUM; i++) {
if (play[i]) {
//se[i].play();
play(se[i]);
play[i] = false;
}
}
}
}
}
}