309 lines
8.5 KiB
JavaScript
309 lines
8.5 KiB
JavaScript
class Scene extends Screen {
|
|
|
|
constructor(canvas, player) {
|
|
super(canvas);
|
|
this.player = player;
|
|
this.currentHeight = 0;
|
|
|
|
if (this.maxHeight === undefined) {
|
|
this.maxHeight = 0;
|
|
}
|
|
|
|
this.initialize();
|
|
|
|
this.addEventListener('touchstart', (event) => {
|
|
this.onTouchStart(event);
|
|
});
|
|
}
|
|
|
|
get maxHeight() {
|
|
return window.localStorage.getItem("maxHeight");
|
|
}
|
|
|
|
set maxHeight(value) {
|
|
window.localStorage.setItem("maxHeight", value);
|
|
}
|
|
|
|
initialize() {
|
|
super.initialize();
|
|
this.player.reset();
|
|
this.platforms = [];
|
|
this.cameraHeight = 0;
|
|
this.cameraSpeed = 0;
|
|
this.currentHeight = 0;
|
|
this.started = false;
|
|
|
|
// The the line for the high score
|
|
this.currentMaxHeight = this.maxHeight;
|
|
|
|
// 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.0005;
|
|
}
|
|
}
|
|
|
|
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.02) {
|
|
|
|
if (this.wakingTimer !== undefined) {
|
|
this.wakingTimer -= time;
|
|
|
|
if (this.wakingTimer < 0) {
|
|
this.wakingTimer = undefined;
|
|
this.status = Status.Running;
|
|
}
|
|
}
|
|
|
|
if (this.status !== Status.Running) {
|
|
return;
|
|
}
|
|
|
|
// 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();
|
|
|
|
this.drawHighScoreLine();
|
|
|
|
for (let platform of this.platforms) {
|
|
this.drawPlatform(platform);
|
|
}
|
|
|
|
this.drawObject(this.player);
|
|
|
|
this.context.resetTransform();
|
|
|
|
this.drawHud();
|
|
}
|
|
|
|
drawHighScoreLine() {
|
|
if (this.currentMaxHeight <= 0) {
|
|
return;
|
|
}
|
|
|
|
let height = this.height() * (1 - this.currentMaxHeight - this.player.size / 2);
|
|
|
|
this.context.save();
|
|
this.context.translate(0, height);
|
|
|
|
let pattern = this.context.createPattern(Scene.highscore, 'repeat');
|
|
this.context.fillStyle = pattern;
|
|
this.context.beginPath();
|
|
this.context.rect(0, 0, this.width(), 32);
|
|
this.context.fill();
|
|
|
|
this.context.restore();
|
|
|
|
this.context.font = "15px Arial";
|
|
this.context.fillStyle = "rgb(255, 255, 255)";
|
|
this.context.fillText("High score: " + Math.floor(100 * this.currentMaxHeight), 0, height - 5);
|
|
}
|
|
|
|
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() {
|
|
// Draw scores
|
|
let fontSize = 20;
|
|
this.context.font = fontSize + "px Arial";
|
|
this.context.fillStyle = 'rgb(255, 255, 255)';
|
|
this.context.fillText("Score: " + Math.floor(100 * this.currentHeight), 0, 20);
|
|
|
|
// Draw pause buttons
|
|
let box = this.makePauseBox();
|
|
this.context.fillStyle = 'rgba(255, 255, 255, 0.5)';
|
|
this.context.beginPath();
|
|
this.context.rect(box.x, box.y, box.width, box.height);
|
|
this.context.fill();
|
|
|
|
this.context.fillStyle = 'rgba(0, 0, 0, 0.5)';
|
|
this.context.beginPath();
|
|
this.context.rect(
|
|
box.x + box.width * 0.3,
|
|
box.y + box.height * 0.1,
|
|
box.width * 0.1,
|
|
box.height * 0.8,
|
|
);
|
|
this.context.fill();
|
|
|
|
this.context.beginPath();
|
|
this.context.rect(
|
|
box.x + box.width * 0.6,
|
|
box.y + box.height * 0.1,
|
|
box.width * 0.1,
|
|
box.height * 0.8,
|
|
);
|
|
this.context.fill();
|
|
|
|
if (this.status === Status.Paused || this.status === Status.Waking) {
|
|
|
|
let fontSize = 50;
|
|
this.context.font = fontSize + "px Arial";
|
|
|
|
this.context.beginPath();
|
|
this.context.rect(0, 0, this.width(), this.height());
|
|
this.context.fill();
|
|
|
|
let text = this.status === Status.Paused ? "Paused" : Math.floor(this.wakingTimer + 1);
|
|
text = text + "";
|
|
|
|
this.context.fillStyle = 'rgb(255, 255, 255)';
|
|
let size = this.context.measureText(text).width;
|
|
|
|
this.context.fillText(text, (this.width() - size) / 2, this.height() / 2 + fontSize);
|
|
|
|
}
|
|
}
|
|
|
|
makePauseBox() {
|
|
|
|
let startX = 0.85;
|
|
let startY = 0.05;
|
|
let size = 0.1;
|
|
|
|
return {
|
|
x: startX * this.width(),
|
|
y: startY * this.width(),
|
|
width: size * this.width(),
|
|
height: size * this.width(),
|
|
};
|
|
}
|
|
|
|
onTouchStart(event) {
|
|
|
|
let e = event.changedTouches[0];
|
|
|
|
if (this.started) {
|
|
if (this.status === Status.Running && isInBox(position(e), this.makePauseBox())) {
|
|
this.status = Status.Paused;
|
|
} else if (this.status === Status.Paused) {
|
|
this.status = Status.Waking;
|
|
this.wakingTimer = 3;
|
|
}
|
|
}
|
|
|
|
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";
|
|
|
|
Scene.highscore = new Image();
|
|
Scene.highscore.src = "img/highscore.png";
|