commit 786fc9b293f1c7de7c5be37c265d710b44c6de91 Author: Florian Sylvain Date: Tue Jun 16 02:18:42 2026 +0200 first commit diff --git a/index.html b/index.html new file mode 100644 index 0000000..39fa0b5 --- /dev/null +++ b/index.html @@ -0,0 +1,12 @@ + + + + + + game js + + + + + + \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 0000000..060fe0a --- /dev/null +++ b/main.js @@ -0,0 +1,282 @@ +"use strict" + +class Clock { + constructor() { + this.currentFrametime = 0 + this.currentFps = 0 + this.frames = 0 + this.timeSpan = 0 + } + + update(deltaT) { + if (typeof deltaT !== 'number') return; + + this.timeSpan += deltaT + this.frames++ + + if (this.timeSpan >= 500) { + this.currentFrametime = this.timeSpan / this.frames + this.currentFps = 1000 / this.currentFrametime + + this.timeSpan = 0 + this.frames = 0 + } + } +} + +class UI { + constructor(context, clock) { + this.context = context + this.context.font = "32px monospace" + + this.clock = clock + } + + draw() { + this.context.fillStyle = '#FFF' + this.context.fillText(`frametime: ${this.clock.currentFrametime.toFixed(1)} ms`, 10, 32); + this.context.fillText(`fps: ${Math.round(this.clock.currentFps)}`, 10, 64); + } +} + +class Vector2 { + constructor(x, y) { + this.x = x + this.y = y + } + + length() { + return Math.sqrt((this.x * this.x) + (this.y * this.y)) + } + + normalize() { + const magnitude = this.length() + if (magnitude === 0) return; + this.x /= magnitude + this.y /= magnitude + } + + add(vector2) { + this.x += vector2.x + this.y += vector2.y + } + + multiply(scalar) { + this.x *= scalar + this.y *= scalar + } + + dot(vector2) { + return vector2.x * this.x + vector2.y * this.y + } +} + +class Weapon { + constructor(player, canvas) { + this.player = player + this.angle = 0 + + this.mousePosition = new Vector2(0, 0) + + this.rect = canvas.getBoundingClientRect() + + this.width = 10 + this.height = 50 + + document.addEventListener("mousemove", (event) => { + this.mousePosition.x = event.clientX - this.rect.left + this.mousePosition.y = event.clientY - this.rect.top + }) + } + + get pivotX() { + return this.player.position.x + (this.player.width / 2) + } + + get pivotY() { + return this.player.position.y + (this.player.height / 2) + } + + update(deltaT, camera) { + const worldMouseX = (this.mousePosition.x / camera.zoom) + camera.x + const worldMouseY = (this.mousePosition.y / camera.zoom) + camera.y + + const dx = worldMouseX - this.pivotX + const dy = worldMouseY - this.pivotY + + this.angle = Math.atan2(dy, dx) - Math.PI / 2 + } + + draw(context) { + context.save() + + context.translate(this.pivotX, this.pivotY) + context.rotate(this.angle) + + context.fillStyle = '#F00' + context.fillRect(-(this.width / 2), 0, this.width, this.height) + + context.restore() + } +} + +class Player { + constructor(position) { + this.position = position + this.direction = new Vector2(0, 0) + this.velocity = new Vector2(0, 0) + this.speed = 500 + + this.width = 50 + this.height = 50 + + this.keys = { + w: false, + a: false, + s: false, + d: false + } + + document.addEventListener('keydown', (event) => { + if (this.keys[event.key] !== undefined) { + this.keys[event.key] = true + } + }) + + document.addEventListener('keyup', (event) => { + if (this.keys[event.key] !== undefined) { + this.keys[event.key] = false + } + }) + } + + update(deltaT) { + this.direction.x = 0 + this.direction.y = 0 + if (this.keys.w) this.direction.y -= 1 + if (this.keys.a) this.direction.x -= 1 + if (this.keys.s) this.direction.y += 1 + if (this.keys.d) this.direction.x += 1 + + this.direction.normalize() + + this.velocity.x = this.direction.x * this.speed + this.velocity.y = this.direction.y * this.speed + + this.velocity.multiply(deltaT) + this.position.add(this.velocity) + } + + draw(context) { + context.fillStyle = '#00A' + context.fillRect(this.position.x, this.position.y, this.width, this.height) + } +} + +class Camera { + constructor(viewportWidth, viewportHeight) { + this.x = 0 + this.y = 0 + this.zoom = 2.0 + this.viewportWidth = viewportWidth + this.viewportHeight = viewportHeight + } + + follow(target) { + this.x = target.x - (this.viewportWidth / 2) / this.zoom + this.y = target.y - (this.viewportHeight / 2) / this.zoom + } + + begin(context) { + context.save() + context.scale(this.zoom, this.zoom) + context.translate(-this.x, -this.y) + } + + end(context) { + context.restore() + } +} + +class Game { + constructor (canvas, context) { + this._WIDTH = 1920 + this._HEIGHT = 1080 + + this.isRunning = true + this.lastTime = undefined + this.deltaTime = undefined + + this.context = context + this.canvas = canvas + + this.canvas.width = this._WIDTH + this.canvas.height = this._HEIGHT + + this.clock = new Clock() + this.UI = new UI(this.context, this.clock) + + this.player = new Player(new Vector2(200, 200)) + this.weapon = new Weapon(this.player, this.canvas) + + this.camera = new Camera(this._WIDTH, this._HEIGHT) + } + + update() { + this.clock.update(this.deltaTime) + + const deltaTInSeconds = this.deltaTime / 1000 + + if (!isNaN(deltaTInSeconds)) { + this.player.update(deltaTInSeconds) + this.weapon.update(deltaTInSeconds, this.camera) + } + + this.camera.follow(new Vector2(this.player.position.x + 25, this.player.position.y + 25)) + } + + clear() { + this.context.fillStyle = "#777" + this.context.fillRect(0, 0, this._WIDTH, this._HEIGHT) + } + + draw() { + this.clear() + + this.camera.begin(this.context) + + this.context.fillStyle = '#BB0022' + const c = 20 + for (let x = 100; x < this._WIDTH - 100; x += c) { + for (let y = 100; y < this._HEIGHT - 100; y += c) { + this.context.fillRect(x, y, c/2, c/2) + } + } + this.player.draw(this.context) + this.weapon.draw(this.context) + + this.camera.end(this.context) + + this.UI.draw() + } + + run(timeSpan) { + if (this.lastTime === undefined) { + this.lastTime = timeSpan + } else { + this.deltaTime = timeSpan - this.lastTime + this.lastTime = timeSpan + } + + this.update() + this.draw() + + if (!this.isRunning) return; + requestAnimationFrame((d) => this.run(d)) + } +} + +const canvas = document.querySelector("canvas") +const context = canvas.getContext("2d") +const game = new Game(canvas, context) +game.run()