initial commit

This commit is contained in:
Urban Modig
2025-04-20 16:02:36 +02:00
commit 7175db2b54
15 changed files with 479 additions and 0 deletions

View File

@ -0,0 +1,28 @@
class Background {
constructor(game){
this.game = game;
this.image = document.getElementById('background');
this.width = 2400;
this.height = this.game.baseHeight;
this.scaledWidth;
this.scaledHeight;
this.x
}
update(){
this.x -= this.game.speed;
if(this.x <= -this.scaledWidth) this.x = 0;
}
draw(){
this.game.ctx.drawImage(this.image, this.x, 0, this.scaledWidth, this.scaledHeight)
this.game.ctx.drawImage(this.image, this.x + this.scaledWidth -1 , 0, this.scaledWidth, this.scaledHeight)
this.game.ctx.drawImage(this.image, this.x + 2 * this.scaledWidth -1 , 0, this.scaledWidth, this.scaledHeight)
}
resize(){
this.scaledWidth = this.width * this.game.ratio;
this.scaledHeight = this.height * this.game.ratio;
this.x = 0;
}
}

167
src/assets/scripts/main.js Normal file
View File

@ -0,0 +1,167 @@
class Game {
constructor(canvas, context) {
this.canvas = canvas;
this.ctx = context;
this.width = this.canvas.width;
this.height = this.canvas.height;
this.baseHeight = 720;
this.ratio = this.height / this.baseHeight;
this.background = new Background(this);
this.player = new Player(this);
this.obstacles = [];
this.numberOfObstacles = 2;
this.gravity;
this.speed;
this.minSpeed;
this.maxSpeed;
this.score;
this.gameOver;
this.timer;
this.message1;
this.message2;
this.eventTimer = 0;
this.eventInterval = 150;
this.eventUpdate = true;
this.touchStartX;
this.swipeDistance = 50;
this.resize(window.innerWidth, window.innerHeight);
window.addEventListener('resize', e => {
this.resize(e.currentTarget.innerWidth, e.currentTarget.innerHeight);
});
window.addEventListener('mousedown', e => {
this.player.flap();
})
window.addEventListener('keydown', e => {
if (e.key === ' ' || e.key === 'Enter') this.player.flap();
if (e.key === 'Shift' || e.key.toLowerCase() === 'c') this.player.startCharge();
})
this.canvas.addEventListener('touchstart', e => {
this.player.flap();
this.touchStartX = e.changedTouches[0].pageX;
})
this.canvas.addEventListener('touchmove', e => {
if(e.changedTouches[0].pageX - this.touchStartX > this.swipeDistance ){
this.player.startCharge();
}
})
}
resize(width, height) {
this.canvas.width = width;
this.canvas.height = height;
//this.ctx.fillStyle = 'blue';
this.ctx.font = '15px Bungee'
this.ctx.textAlign = 'right';
this.ctx.lineWidth = 3;
this.ctx.strokeStyle = 'white'
this.width = this.canvas.width;
this.height = this.canvas.height;
this.ratio = this.height / this.baseHeight;
this.gravity = 0.15 * this.ratio;
this.speed = 2 * this.ratio;
this.minSpeed = this.speed;
this.maxSpeed = this.speed * 5;
this.background.resize();
this.player.resize();
this.createObstacles();
this.obstacles.forEach(obstacle => {
obstacle.resize();
});
this.score = 0;
this.gameOver = false;
this.timer = 0;
}
render(deltaTime) {
if (!this.gameOver) this.timer += deltaTime;
this.handlePeriodicEvents(deltaTime);
this.background.update();
this.background.draw();
this.drawStatusText();
this.player.update();
this.player.draw();
this.obstacles.forEach(obstacle => {
obstacle.update();
obstacle.draw();
});
}
createObstacles() {
this.obstacles = [];
const firstX = 100;
const obstacleSpacing = 600 * this.ratio;
for (let i = 0; i < this.numberOfObstacles; i++) {
this.obstacles.push(new Obstacle(this, firstX + i * obstacleSpacing))
}
}
checkCollision(a, b) {
const dx = a.collisionX - b.collisionX;
const dy = a.collisionY - b.collisionY;
const distance = Math.sqrt(dx * dx + dy * dy);
const sumOfRadii = a.collisionRadius + b.collisionRadius;
return distance <= sumOfRadii;
}
formatTimer() {
return (this.timer * 0.001).toFixed(1)
}
handlePeriodicEvents(deltaTime){
if(this.eventTimer < this.eventInterval){
this.eventTimer += deltaTime;
this.eventUpdate = false;
} else {
this.eventTimer = this.eventTimer % this.eventInterval;
this.eventUpdate = true;
}
}
drawStatusText() {
this.ctx.save();
this.ctx.fillText('Score: ' + this.score, this.width - 10, 30);
this.ctx.textAlign = 'left';
this.ctx.fillText('Timer: ' + this.formatTimer(), 10, 30);
if (this.gameOver) {
if (this.player.collided) {
this.message1 = "Getting Rusty?";
this.message2 = "Collision time " + this.formatTimer() + " seconds!";
} else if (this.obstacles.length <= 0) {
this.message1 = "Nailed it!";
this.message2 = "Can you do it faster than " + this.formatTimer() + " seconds?";
}
this.ctx.textAlign = 'center'
this.ctx.font = '30px Bungee'
this.ctx.fillText(this.message1, this.width * 0.5, this.height * 0.5 - 40);
this.ctx.font = '15px Bungee'
this.ctx.fillText(this.message2, this.width * 0.5, this.height * 0.5 - 20);
this.ctx.fillText("Press 'R' to try again", this.width * 0.5, this.height * 0.5);
}
if (this.player.energy <= 20) this.ctx.fillStyle = 'red'
else if (this.player.energy >= this.player.maxEnergy) this.ctx.fillStyle = 'red';
for (let i = 0; i < this.player.energy; i++) {
//this.ctx.fillRect(10 + i * 6, 40, 5, 15);
this.ctx.fillRect(10, this.height - 10 - this.player.barSize * i, this.player.barSize * 5, this.player.barSize);
}
this.ctx.restore();
}
}
window.addEventListener('load', function () {
const canvas = document.getElementById('canvas1');
const ctx = canvas.getContext('2d');
canvas.width = 720;
canvas.height = 720;
const game = new Game(canvas, ctx);
let lastTime = 0;
function animate(timeStamp) {
const deltaTime = timeStamp - lastTime;
lastTime = timeStamp;
ctx.clearRect(0, 0, canvas.width, canvas.height);
game.render(deltaTime);
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
});

View File

@ -0,0 +1,51 @@
class Obstacle{
constructor(game, x){
this.game = game;
this.spriteWidth = 120;
this.spriteHeight = 120;
this.scaledWidth = this.spriteWidth * this.game.ratio;
this.scaledHeight = this.spriteHeight * this.game.ratio;
this.x = x;
this.y = Math.random() * this.game.height - this.scaledHeight
this.collisionX;
this.collisiony;
this.collisionRadius = this.scaledWidth * 0.5;
this.speedY = this.game.ratio * (Math.random() < 0.5 ? -1 : 1);
this.markedForDeletion;
}
update(){
this.x -= this.game.speed;
this.y += this.speedY;
this.collisionX = this.x + this.scaledWidth * 0.5;
this.collisionY = this.y + this.scaledHeight * 0.5;
if(this.y < 0 || this.y >= this.game.height - this.scaledHeight){
this.speedY *= -1;
}
if(this.isOffScreen()) {
this.markedForDeletion = true;
this.game.obstacles = this.game.obstacles.filter(o => !o.markedForDeletion);
console.log(this.game.obstacles.length)
this.game.score++;
if(this.game.obstacles.length <= 0) this.game.gameOver = true;
}
if(this.game.checkCollision(this, this.game.player)){
this.game.gameOver = true;
this.game.player.collided=true;
}
}
draw(){
this.game.ctx.fillRect(this.x, this.y, this.scaledWidth, this.scaledHeight);
this.game.ctx.beginPath();
this.game.ctx.arc(this.collisionX, this.collisionY, this.collisionRadius, 0, Math.PI * 2)
this.game.ctx.stroke();
}
resize(){
this.scaledWidth = this.spriteWidth * this.game.ratio;
this.scaledHeight = this.spriteHeight * this.game.ratio;
}
isOffScreen(){
return this.x < 0 - this.scaledWidth;
}
}

View File

@ -0,0 +1,87 @@
class Player {
constructor(game){
this.game = game;
this.x = 20;
this.y;
this.spriteWidth = 200;
this.spriteHeight = 200;
this.width;
this.height;
this.speedY;
this.flapSpeed;
this.collisionX;
this.collisionY;
this.collisionRadius;
this.collided = false;
this.energy = 30;
this.maxEnergy = this.energy * 2;
this.minEnergy = 15;
this.charging = false;
this.barSize = 5 * this.game.ratio;
}
draw(){
this.game.ctx.strokeRect(this.x, this.y, this.width, this.height);
this.game.ctx.beginPath();
this.game.ctx.arc(this.collisionX, this.collisionY, this.collisionRadius, 0, Math.PI * 2)
this.game.ctx.stroke();
}
update(){
this.handleEnergy();
this.y += this.speedY;
this.collisionY = this.y + this.height * 0.5;
if (!this.isTouchingBottom()){
this.speedY += this.game.gravity;
}
// bottom boundary
if (this.isTouchingBottom()){
this.y = this.game.height - this.height;
}
}
resize(){
this.width = this.spriteWidth * this.game.ratio;
this.height = this.spriteHeight * this.game.ratio;
this.y = this.game.height * 0.5 - this.height * 0.5;
this.speedY = -8 * this.game.ratio;
this.flapSpeed = 5 * this.game.ratio;
this.collisionRadius = this.width * 0.5
this.collisionX = this.x + this.width * 0.5;
this.collided = false;
this.barSize = Math.ceil(5 * this.game.ratio);
}
startCharge(){
this.charging = true;
this.game.speed = this.game.maxSpeed;
}
stopCharge(){
this.charging = false;
this.game.speed = this.game.minSpeed;
}
isTouchingTop(){
return this.y <= 0;
}
isTouchingBottom(){
return this.y >= this.game.height - this.height;
}
handleEnergy(){
if(this.game.eventUpdate){
if(this.energy < this.maxEnergy){
this.energy += 1;
}
if(this.charging){
this.energy -= 6;
if(this.energy <= 0){
this.energy = 0;
this.stopCharge();
}
}
}
}
flap(){
this.stopCharge();
if(!this.isTouchingTop()) {
this.speedY = -this.flapSpeed;
}
}
}