上下左右キーで視点を移動し、スペースキーで弾丸を発射します。制限時間内にすべての戦車を倒してください。戦車はパーリンノイズを使ってランダムに移動させています。戦車の3DモデルはTinkerCADで作成しました。
Shotクラスは弾丸を実装したものですが、PVectorを継承してみました。現在の実装では、自分の弾丸しか扱っていませんが、敵の戦車が発射した弾丸などを実装してみるのもよいかもしれません。
class Tank {
PVector pos = new PVector(random(-area, area), 0, random(-area, area));
float xn = random(100), zn = random(100);
boolean valid = true;
void draw() {
float dx = (noise(xn) - 0.5)*5;
float dz = (noise(zn) - 0.5)*5;
pos.x = max(-area, min(area, pos.x + dx));
pos.z = max(-area, min(area, pos.z + dz));
xn += 0.002;
zn += 0.002;
pushMatrix();
translate(pos.x, 0, pos.z);
rotateY(atan2(dx, dz));
shape(tank);
popMatrix();
}
}
class Shot extends PVector {
boolean mine, valid = true;
PVector speed;
Shot(boolean mine, PVector p) {
super(p.x, 0, p.z);
this.mine = mine;
this.speed = new PVector(cos(p.y), 0, sin(p.y)).mult(20);
}
void draw() {
add(speed);
pushMatrix();
translate(x, -10, z);
fill(255, 255, 0);
sphere(3);
popMatrix();
if (x < -area || x > area || z < -area || z > area) {
valid = false;
}
}
}
int count = 3000, score = 0;
float area = 2000;
boolean gameOver = false;
PShape tank;
PVector pos;
ArrayList<Tank> tanks = new ArrayList<Tank>();
ArrayList<Shot> shots = new ArrayList<Shot>();
void setup() {
size(600, 600, P3D);
tank = loadShape("tank.obj");
pos = new PVector(0, 0, 0);
for (int i = 0; i < 10; i++) {
tanks.add(new Tank());
}
noStroke();
textSize(40);
}
void draw() {
if (gameOver) {
textAlign(CENTER);
if (tanks.size() == 0){
text("CLEAR", width/2, height/2);
}else {
text("GAME OVER", width/2, height/2);
}
return;
}
background(0);
lights();
updateCamera();
fill(200);
pushMatrix();
translate(0, 10, 0);
box(area*2, 1, area*2);
popMatrix();
if (keyPressed) {
if (keyCode == LEFT) {
pos.y -= 0.05;
}
if (keyCode == RIGHT) {
pos.y += 0.05;
}
if (keyCode == UP) {
pos.x += cos(pos.y)*10;
pos.z += sin(pos.y)*10;
}
if (keyCode == DOWN) {
pos.x -= cos(pos.y)*5;
pos.z -= sin(pos.y)*5;
}
pos.x = max(-area, min(area, pos.x));
pos.z = max(-area, min(area, pos.z));
}
for (Tank t : tanks) {
t.draw();
}
for (Shot b : shots) {
b.draw();
}
for (Tank t : tanks) {
for (Shot b : shots) {
if (dist(b.x, b.z, t.pos.x, t.pos.z) < 20 && b.valid && t.valid) {
b.valid = false;
t.valid = false;
score += 10;
}
}
}
for (int i = shots.size()-1; i >= 0; i--) {
if (shots.get(i).valid == false) {
shots.remove(i);
}
}
for (int i = tanks.size()-1; i >= 0; i--) {
if (tanks.get(i).valid == false) {
tanks.remove(i);
}
}
camera();
fill(255);
textAlign(RIGHT);
text(nf(score, 5), width, 50);
fill(255, 255, 0);
count--;
rect(0, height-10, width*count/3000.0, 10);
if (count < 0 || tanks.size() == 0) {
gameOver = true;
}
}
void keyPressed() {
if (key == ' ') {
shots.add(new Shot(true, pos));
}
}
void updateCamera() {
float x = pos.x + 500 * cos(pos.y);
float z = pos.z + 500 * sin(pos.y);
camera(pos.x, -20, pos.z, x, 0, z, 0, 1, 0);
}