fix game loop timer
This commit is contained in:
+29
-3
@@ -249,6 +249,35 @@ function connectWebSocket() {
|
||||
terrain.position.set(t.position.x / 100, t.position.y / 100, 0)
|
||||
}
|
||||
|
||||
if (playerId != null) {
|
||||
const player = state.entities.find((e) => e.id == playerId)
|
||||
if (player != null) {
|
||||
for (let abilityIndex = 0; abilityIndex < 4; abilityIndex++) {
|
||||
if (player.abilities[abilityIndex] != null) {
|
||||
const ability = player.abilities[abilityIndex]
|
||||
const lastCast = player.cooldowns[ability.id] ?? -99999
|
||||
const cooldownDuration = (ability.cooldown * state.tickRate) ?? 0
|
||||
const remainingCooldown = (lastCast + cooldownDuration) - state.currentTick
|
||||
let cssPercentage = '100%'
|
||||
let text = ''
|
||||
if (remainingCooldown > 0) {
|
||||
const cooldownPercentage = 1 - (remainingCooldown / cooldownDuration)
|
||||
cssPercentage = `${Math.round(100 * cooldownPercentage)}%`
|
||||
if (remainingCooldown / state.tickRate <= 5) {
|
||||
text = `${(Math.round(10 * remainingCooldown / state.tickRate) / 10).toFixed(1)}`
|
||||
}
|
||||
else {
|
||||
text = `${Math.round(remainingCooldown / state.tickRate)}`
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById(`ability-${abilityIndex}-cooldown`).style.clipPath = `polygon(0 ${cssPercentage}, 100% ${cssPercentage}, 100% 100%, 0 100%)`
|
||||
document.getElementById(`ability-${abilityIndex}-cooldown-text`).innerHTML = text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('state').innerHTML = JSON.stringify(state, null, 2)
|
||||
}
|
||||
}
|
||||
@@ -291,9 +320,6 @@ window.addEventListener('load', () => {
|
||||
if (event.code == 'KeyE') {
|
||||
websocket.send(JSON.stringify({ action: 'cast', slot: 3, id: playerId, x, y }))
|
||||
}
|
||||
if (event.code == 'KeyR') {
|
||||
websocket.send(JSON.stringify({ action: 'cast', slot: 4, id: playerId, x, y }))
|
||||
}
|
||||
|
||||
if (event.code == 'KeyD') {
|
||||
websocket.send(JSON.stringify({ action: 'teleport', id: playerId, x, y }))
|
||||
|
||||
+69
-1
@@ -56,6 +56,53 @@
|
||||
border-bottom: none;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.hud {
|
||||
position: fixed;
|
||||
gap: 10px;
|
||||
padding: 15px;
|
||||
padding-bottom: 10px;
|
||||
display: flex;
|
||||
inset: auto 0 0 0;
|
||||
width: fit-content;
|
||||
margin: auto;
|
||||
border: 5px solid gray;
|
||||
background-color: black;
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.ability {
|
||||
position: relative;
|
||||
flex: 1 0 0;
|
||||
border: 1px solid white;
|
||||
width: 75px;
|
||||
height: 75px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.cooldown {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 73px;
|
||||
height: 73px;
|
||||
background-color: grey;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.cooldown-text {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 73px;
|
||||
height: 73px;
|
||||
line-height: 73px;
|
||||
text-align: center;
|
||||
color: white;
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -63,7 +110,28 @@
|
||||
<p>Connection: <span id="connection"></span></p>
|
||||
<pre id="state"></pre>
|
||||
</div>
|
||||
<!-- TODO: HUD -->
|
||||
<div class="hud">
|
||||
<div id="ability-0" class="ability">
|
||||
A
|
||||
<div id="ability-0-cooldown" class="cooldown"></div>
|
||||
<div id="ability-0-cooldown-text" class="cooldown-text"></div>
|
||||
</div>
|
||||
<div id="ability-1" class="ability">
|
||||
Q
|
||||
<div id="ability-1-cooldown" class="cooldown"></div>
|
||||
<div id="ability-1-cooldown-text" class="cooldown-text"></div>
|
||||
</div>
|
||||
<div id="ability-2" class="ability">
|
||||
W
|
||||
<div id="ability-2-cooldown" class="cooldown"></div>
|
||||
<div id="ability-2-cooldown-text" class="cooldown-text"></div>
|
||||
</div>
|
||||
<div id="ability-3" class="ability">
|
||||
E
|
||||
<div id="ability-3-cooldown" class="cooldown"></div>
|
||||
<div id="ability-3-cooldown-text" class="cooldown-text"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- TODO: cast indicator -->
|
||||
<script type="module" src="client.js"></script>
|
||||
</body>
|
||||
|
||||
+6
-2
@@ -4,12 +4,16 @@ export default class Ability {
|
||||
id = crypto.randomUUID()
|
||||
name = 'Ability'
|
||||
cooldown = 0
|
||||
effect = () => {}
|
||||
castTime = 0
|
||||
|
||||
#effect = () => {}
|
||||
|
||||
get effect() { return this.#effect }
|
||||
set effect(value) { this.#effect = value }
|
||||
|
||||
constructor(options) {
|
||||
if (options.name != null) { this.name = options.name }
|
||||
if (options.effect != null) { this.effect = options.effect }
|
||||
if (options.effect != null) { this.#effect = options.effect }
|
||||
if (options.cooldown != null) { this.cooldown = options.cooldown }
|
||||
if (options.castTime != null) { this.castTime = options.castTime }
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import SAT from 'sat'
|
||||
import SATX from './satx.js'
|
||||
import Pathfind from './pathfind.js'
|
||||
import Ability from './ability.js'
|
||||
import Effect from './effect.js'
|
||||
|
||||
export default class Entity {
|
||||
id = crypto.randomUUID()
|
||||
@@ -16,7 +15,6 @@ export default class Entity {
|
||||
Ability.straightShot(800, 7, 3000),
|
||||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
]
|
||||
casting = null
|
||||
// TODO: teams
|
||||
|
||||
+19
-4
@@ -8,12 +8,14 @@ export default class Game {
|
||||
currentTick = 0
|
||||
width = 2000
|
||||
height = 2000
|
||||
running = false
|
||||
nextTick = 0
|
||||
|
||||
#entities = []
|
||||
#eventEmitter = new EventEmitter()
|
||||
#projectiles = []
|
||||
#terrains = []
|
||||
#tickBudget = Math.floor(1000 / this.tickRate)
|
||||
#tickBudget = 1000 / this.tickRate
|
||||
|
||||
get entities() { return this.#entities }
|
||||
get eventEmitter() { return this.#eventEmitter }
|
||||
@@ -80,10 +82,23 @@ export default class Game {
|
||||
}
|
||||
}
|
||||
|
||||
start() {
|
||||
const start = performance.now()
|
||||
gameLoop() {
|
||||
const tickBudget = this.#tickBudget
|
||||
|
||||
if (this.nextTick != null) {
|
||||
const nextTick = this.nextTick
|
||||
this.nextTick = null
|
||||
|
||||
let start = performance.now()
|
||||
while (start < nextTick) { start = performance.now() }
|
||||
|
||||
this.update()
|
||||
setTimeout(() => this.start(), Math.max(0, this.#tickBudget - (performance.now() - start)))
|
||||
this.nextTick = start + tickBudget
|
||||
}
|
||||
}
|
||||
|
||||
start() {
|
||||
setInterval(() => this.gameLoop(), 1)
|
||||
}
|
||||
|
||||
update() {
|
||||
|
||||
@@ -3,7 +3,6 @@ import { WebSocketExpress } from 'websocket-express'
|
||||
import Game from './game.js'
|
||||
import Entity from './entity.js'
|
||||
import Terrain from './terrain.js'
|
||||
import SATX from './satx.js'
|
||||
import { Vector2 } from 'three'
|
||||
|
||||
const app = new WebSocketExpress()
|
||||
|
||||
Reference in New Issue
Block a user