xxxxxxxxxx
136
// Just some rough ideas in 3D. No collision detection.
const MARGIN = 0.5;
class Roller {
constructor() {
this.width = 1;
this.groundY = MARGIN + this.width / 2;
this.dir = random(1) < 0.5 ? 1 : -1;
this.x = -this.dir * 15;
const minimumSpeed = 0.2;
const speedVariance = random(0.1);
this.v = this.dir * (minimumSpeed + speedVariance);
this.gone = false;
}
draw() {
pushed(() => {
translate(this.x, this.groundY, -2);
rotateX(TAU / 4);
noStroke();
ambientMaterial('red');
cylinder(this.width, this.width * 3);
});
}
update() {
this.x += this.v;
if (abs(this.x) > 100) {
this.gone = true;
}
}
}
class Jumper {
constructor() {
this.width = 1;
this.groundY = MARGIN + this.width / 2;
this.y = this.oldY = this.groundY;
this.gravity = -9.81;
this.lastUpdate = this.secsNow();
}
secsNow() {
return millis() / 1000;
}
draw() {
pushed(() => {
translate(0, this.y, -1);
ambientMaterial('blue');
rotateY(millis() / 1000);
box(this.width);
});
}
update() {
// Is this a correct Verlet integration implementation?
const now = this.secsNow();
const dt = now - this.lastUpdate;
this.lastUpdate = now;
const velX = this.y - this.oldY;
this.oldY = this.y;
const dtSq = dt * dt;
this.y = max(this.groundY, this.y + velX + this.gravity * dtSq);
}
jump() {
if (this.y === this.groundY)
this.y += 0.3;
}
}
let jumper;
let rollers = [];
const generateNextEnemyTime = () => millis() + 3000 + random(2000);
let nextEnemyAt;
function setup() {
createCanvas(800, 400, WEBGL);
nextEnemyAt = generateNextEnemyTime();
jumper = new Jumper();
}
function draw() {
if (millis() > nextEnemyAt) {
rollers.push(new Roller());
nextEnemyAt = generateNextEnemyTime();
rollers = rollers.filter(e => !e.gone);
}
background('lightblue');
ambientLight(128);
directionalLight(255, 255, 255, 1, 1, -1);
translateAndScaleWorld(() => {
pushed(() => {
rotateX(TAU / 4);
noStroke();
ambientMaterial('white');
plane(100, 30);
});
[jumper, rollers].forEach(object => {
object.draw();
object.update();
});
});
}
function keyPressed() {
if (key === ' ') {
jumper.jump();
}
}
function mouseClicked() {
jumper.jump();
}
/** Places the origin at the bottom center, and makes y increase going up, and scales meters to pixels */
function translateAndScaleWorld(block) {
pushed(() => {
translate(0, height / 2, 0);
const pixelsPerMeter = 30;
scale(pixelsPerMeter, -pixelsPerMeter, pixelsPerMeter);
block();
});
}
function pushed(block) {
push();
block();
pop();
}