escalator-web/src/scene.js

182 lines
5.0 KiB
JavaScript

class Scene extends Screen {
constructor(canvas, player) {
super(canvas);
this.player = player;
this.currentHeight = 0;
this.maxHeight = 0;
this.initialize();
this.addEventListener('touchstart', (event) => {
this.onTouchStart(event);
});
}
initialize() {
super.initialize();
this.player.reset();
this.platforms = [];
this.cameraHeight = 0;
this.cameraSpeed = 0;
this.currentHeight = 0;
this.started = false;
// Generate random initial platforms
for (let i = 0.25; i <= 2; i += 0.33) {
let platform = new Platform(Math.random(), i, 0.2);
this.addPlatform(platform);
}
}
start() {
if (!this.started) {
this.started = true;
this.cameraSpeed = 0.005;
}
}
drawBackground() {
let pattern = this.context.createPattern(Scene.background, 'repeat');
this.context.fillStyle = pattern;
this.context.beginPath();
this.context.rect(0, - this.cameraHeight * this.height(), this.width(), this.height());
this.context.fill();
}
update(time = 0.002) {
// Check if the game is lost
if (this.player.y + this.player.size < this.cameraHeight) {
this.initialize();
}
// The last platform is the highest.
let last = this.platforms[this.platforms.length - 1];
// If the last platform is on screen, we need to create the next platform.
if (last.y <= this.cameraHeight + 1) {
let diff = 0.1 + Math.random() * 0.4;
let platform = new Platform(Math.random(), last.y + diff, 0.2);
this.platforms.push(platform);
}
// Increase position of the camera
this.cameraHeight += this.cameraSpeed * time * this.height();
// Update high score
this.maxHeight = Math.max(this.player.y, this.maxHeight);
this.currentHeight = Math.max(this.player.y, this.currentHeight);
let previous = {
x: this.player.x,
y: this.player.y + this.player.size / 2,
};
this.player.update(time);
let next = {
x: this.player.x,
y: this.player.y + this.player.size / 2,
size: this.player.size,
};
// Detect collision with platform
for (let platform of this.platforms) {
let p = {
x: platform.x,
y: platform.y + platform.height / 2,
width: platform.width,
height: platform.height,
};
if (previous.y >= p.y && next.y < p.y) {
if (next.x >= p.x - p.width / 2 - next.size / 4) {
if (next.x <= p.x + p.width / 2 + next.size / 4) {
// Collision detected
this.player.collide(p.y - next.size/2);
}
}
}
}
// Collision with the ground
if (this.player.y <= 0) {
this.player.collide(0);
}
// Collisions with the border of the screen
this.player.x = Math.max(this.player.x, this.player.size / 4);
this.player.x = Math.min(this.player.x, 1 - this.player.size / 4);
}
addPlatform(object) {
this.platforms.push(object);
}
render() {
this.clear();
this.context.translate(0, this.cameraHeight * this.height());
this.drawBackground();
for (let platform of this.platforms) {
this.drawPlatform(platform);
}
this.drawObject(this.player);
this.context.resetTransform();
this.drawHud();
}
drawObject(object) {
let size = object.size * this.width();
this.context.drawImage(
Box.texture,
0, 64 * this.player.frameNumber, 64, 64,
(object.x - object.size / 2) * this.width(),
(1 - object.y - object.size / 2) * this.height(),
size, size
);
}
drawPlatform(object) {
let width = object.width * this.width();
let height = object.height * this.height();
this.context.drawImage(
Platform.texture,
0, 0, 64, 64,
(object.x - object.width / 2) * this.width(),
(1 - object.y - object.height / 2) * this.height(),
width, width,
);
}
drawHud() {
this.context.font = "20px Arial";
this.context.fillStyle = 'rgb(255, 255, 255)';
this.context.fillText("Current score: " + Math.floor(100 * this.currentHeight), 0, 20);
this.context.fillText("High score: " + Math.floor(100 * this.maxHeight), 0, 50);
}
onTouchStart(event) {
let e = event.changedTouches[0];
this.start();
if (e !== undefined) {
this.player.jump(e.clientX / window.innerWidth, e.clientY / window.innerHeight);
}
}
}
Scene.background = new Image();
Scene.background.src = "img/background.png";