mirror of
https://github.com/Floriansylvain/js-game.git
synced 2026-08-19 11:43:20 +02:00
first commit
This commit is contained in:
@@ -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()
|
||||
Reference in New Issue
Block a user