import MrCroc from "./MrCroc.js"; import Gisela from "./Gisela.js"; import RetroArchitecture from "./retro/RetroArchitecture.js"; import Camera from "./Camera.js"; import TextMessageMrCroc from "./ui/TextMessageMrCroc.js"; import TextMessageGisela from "./ui/TextMessageGisela.js"; import UserInterface from "./ui/UserInterface.js"; import Key from "./Key.js"; import Setting from "./Setting.js"; import {EventBus} from "./events/EventBus.js"; import InterfaceEvent from "./events/InterfaceEvent.js"; import FrameRateMeasurer from "./FrameRateMeasurer.js"; export class Game { static GAME_SPEED = 1 constructor(level) { this.level = level; this.fps = 0; this.frameDuration = 0; this.lastRendered = undefined; this.lastTimestamp = undefined; this.canvas = document.getElementById('canvas'); this.context = this.canvas.getContext('2d'); this.mrCroc = new MrCroc(); this.gisela = new Gisela(); this.architecture = RetroArchitecture.createFromData(this.level); const cameraPosition = this.architecture.getStartPosition(); this.camera = new Camera(cameraPosition.x, cameraPosition.y); this.gameFinished = false; this.hasPlayerLeftArchitecture = false; this.textBoxGameStart = new TextMessageMrCroc('Mr. Croc: "Where is Gisela? I have to find her!"', this.context); this.textBoxGameFinished = new TextMessageGisela( 'Gisela: "Thanks for showing up, Mr. Croc, but I\'m not in danger."', this.context ); this.userInterface = new UserInterface(); this.isPaused = true; this.KeyLeft = new Key('ArrowLeft'); this.KeyRight = new Key('ArrowRight'); this.KeyJump = new Key('Space'); this.KeyLoad = new Key('KeyL'); } render(timestamp) { if (timestamp - this.lastRendered < this.frameDuration) { return; } if (this.gisela.currentAnimation !== 'LOOK_LEFT' && this.mrCroc.position.x < this.gisela.position.x) { this.gisela.currentAnimation = 'LOOK_LEFT'; } else if (this.gisela.currentAnimation !== 'LOOK_RIGHT' && this.mrCroc.position.x >= this.gisela.position.x) { this.gisela.currentAnimation = 'LOOK_RIGHT'; } this.context.clearRect(0, 0, window.innerWidth, window.innerHeight); this.architecture.draw(this.context, this.camera); this.mrCroc.draw(this.context, this.camera); this.gisela.draw(this.context, this.camera); this.userInterface.draw(this.context); this.lastRendered = timestamp; } canBeFinished() { return ( !this.gameFinished && this.mrCroc.isJumping === false && this.architecture.isMovableInsideTargetPosition(this.mrCroc) ); } handlePhysics(delta, timestamp) { const ceilingHeight = Math.max( this.architecture.getCeilingHeight(this.mrCroc.getPositionHeadLeft()), this.architecture.getCeilingHeight(this.mrCroc.getPositionHeadRight()), ); const groundHeight = Math.min( this.architecture.getGroundHeight(this.mrCroc.getPositionFootLeft()), this.architecture.getGroundHeight(this.mrCroc.getPositionFootRight()) ); /* Handle falling */ this.mrCroc.position.y += this.mrCroc.fallSpeed; this.mrCroc.fallSpeed += this.level.gravity * delta; /* Handle ground collision */ if (this.mrCroc.position.y > groundHeight && this.mrCroc.fallSpeed > 0) { this.mrCroc.position.y = groundHeight; this.mrCroc.fallSpeed = 0; } /* Handle ceiling collision */ if (this.mrCroc.position.y - this.mrCroc.getHeight() <= ceilingHeight) { this.mrCroc.fallSpeed = 0; this.mrCroc.position.y = ceilingHeight + this.mrCroc.getHeight() + 1; } this.handlePlayerMovement(delta, timestamp, groundHeight); } updateCamera() { this.camera.focusPosition( this.mrCroc.position.x - this.mrCroc.getWidth() * 0.5, this.mrCroc.position.y - this.mrCroc.getHeight() * 0.5, 20 ); this.camera.lockCameraIntoBorders(); } handlePlayerMovement(delta, timestamp, groundHeight) { /* Jumping */ if (!this.mrCroc.isJumping && this.mrCroc.fallSpeed === 0 && this.mrCroc.position.y === groundHeight && this.KeyJump.isPressed()) { this.mrCroc.jump(); } else if (!this.KeyJump.isPressed()) { this.mrCroc.isJumping = false; } /* Movement left and right */ if (!this.hasPlayerLeftArchitecture && this.KeyLeft.isPressed()) { const lastWallLeft = Math.min( this.architecture.getWallLeft(this.mrCroc.getPositionHeadLeft()), this.architecture.getWallLeft(this.mrCroc.getPositionFootLeft()) ); this.mrCroc.moveLeft(timestamp, delta); if (this.mrCroc.position.x <= lastWallLeft + this.mrCroc.getWidth() * 0.5) { this.mrCroc.position.x = lastWallLeft + this.mrCroc.getWidth() * 0.5 + 1; } } else if (!this.hasPlayerLeftArchitecture && this.KeyRight.isPressed()) { const lastWallRight = Math.max( this.architecture.getWallRight(this.mrCroc.getPositionHeadRight()), this.architecture.getWallRight(this.mrCroc.getPositionFootRight()) ); this.mrCroc.moveRight(timestamp, delta); if (this.mrCroc.position.x >= lastWallRight - this.mrCroc.getWidth() * 0.5) { this.mrCroc.position.x = lastWallRight - this.mrCroc.getWidth() * 0.5 - 1; } } if (!this.hasPlayerLeftArchitecture && !this.architecture.isInsideArchitecture(this.mrCroc.position)) { this.hasPlayerLeftArchitecture = true; setTimeout( () => { this.architecture.setMovableToStartPosition(this.mrCroc); this.hasPlayerLeftArchitecture = false; }, 2000 ); } } finish() { this.gameFinished = true; this.KeyLeft.pressed = false; this.KeyRight.pressed = false; this.KeyJump.pressed = false; this.lastTimestamp = undefined; this.lastRendered = undefined; this.textBoxGameFinished.updateLines(window.innerWidth - 40, this.context); this.textBoxGameFinished.animate(75); this.userInterface.addTextBox(this.textBoxGameFinished); } init(loopFunction) { if (this.isChromeBrowser()) { this.canvas.width = window.innerWidth - 1; this.canvas.height = window.innerHeight - 1; } this.canvas.style.backgroundAttachment = 'fixed'; this.canvas.style.backgroundSize = 'cover'; this.canvas.style.backgroundPosition = 'center center'; if (this.level.getBackgroundImage() !== undefined) { this.canvas.style.backgroundImage = "url("+ Setting.GRAPHICS_LOCATION + this.level.getBackgroundImage() + ")"; } else { this.canvas.style.backgroundImage = 'none'; } this.canvas.style.backgroundColor = this.level.getBackgroundColor(); this.canvas.width = window.innerWidth; this.canvas.height = window.innerHeight; EventBus.addEventListener( 'resize', function () { this.canvas.width = window.innerWidth; this.canvas.height = window.innerHeight; } ); this.textBoxGameStart.animate(75, 1000); this.textBoxGameStart.show(1000); this.textBoxGameStart.hide(10000); this.userInterface.addTextBox(this.textBoxGameStart); this.camera.borderRight = this.architecture.columns * this.architecture.tileWidth; this.camera.borderBottom = this.architecture.rows * this.architecture.tileHeight; this.architecture.setMovableToStartPosition(this.mrCroc); this.architecture.setMovableToTargetPosition(this.gisela); EventBus.addEventListener( InterfaceEvent.FRAME_RATE_MEASURED, (event) => { this.isPaused = false; this.fps = event.frameRate; this.frameDuration = 1000.0 / this.fps; window.requestAnimationFrame(loopFunction); } ); new FrameRateMeasurer(); } isChromeBrowser() { return navigator.userAgent.match('Chrome') !== null; } }