From 9b2115b13a04c9c9a6fb82ee6e25f7bc71e7d65b Mon Sep 17 00:00:00 2001 From: Optimizitor Date: Sat, 5 Aug 2023 18:25:53 +0300 Subject: [PATCH] fix: remove game lags on low frame rate (#110) --- packages/client/package.json | 2 +- .../client/src/game/services/Loop/Loop.ts | 35 +++++++++++++++---- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/packages/client/package.json b/packages/client/package.json index e4ad67df..6136d283 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "vite", + "dev": "vite --host 0.0.0.0", "build:ssr": "tsc && vite build --config ssr.config.ts", "build:client": "tsc && vite build --config vite.config.ts", "build": "yarn build:ssr && yarn build:client", diff --git a/packages/client/src/game/services/Loop/Loop.ts b/packages/client/src/game/services/Loop/Loop.ts index 80cc1cb3..59bc030f 100644 --- a/packages/client/src/game/services/Loop/Loop.ts +++ b/packages/client/src/game/services/Loop/Loop.ts @@ -3,11 +3,19 @@ import { EntityEvent } from '../../entities/Entity/typings'; import { type LoopDelays, type LoopIntervals } from './typings'; export class Loop { + /** Минимальное время игрового цикла в миллисекундах */ loopTimeMs = 16; + /** Количество игровых циклов, которые могут быть выполнены за раз в случае задержек */ + maxConsecutiveLoops = 4; + /** Счётчик игровых циклов */ loopCount = 0; + /** Список внутриигровых таймаутов */ loopDelays: LoopDelays = {}; + /** Список внутриигровых интервалов */ loopIntervals: LoopIntervals = {}; + /** Список динамических игровых сущностей */ loopEntities: Set = new Set(); + /** Запущен ли данный сервис */ active = false; lastTimestamp = 0; @@ -28,6 +36,7 @@ export class Loop { start() { this.active = true; + this.lastTimestamp = 0; this.loop(); } @@ -53,6 +62,18 @@ export class Loop { this.loopEntities = new Set(); } + tick() { + ++this.loopCount; + this.checkLoopDelays(); + this.checkLoopIntervals(); + for (const entity of this.loopEntities) { + entity.update(); + if (entity.shouldBeDestroyed) { + this.loopEntities.delete(entity); + } + } + } + loop(timestamp = 0) { if (!this.active) { return; @@ -60,16 +81,16 @@ export class Loop { if (timestamp) { const timeDifference = timestamp - this.lastTimestamp; + if (timeDifference >= this.loopTimeMs) { - ++this.loopCount; - this.checkLoopDelays(); - this.checkLoopIntervals(); - for (const entity of this.loopEntities) { - entity.update(); - if (entity.shouldBeDestroyed) { - this.loopEntities.delete(entity); + if (this.lastTimestamp !== 0) { + const ticksCount = Math.min(Math.round(timeDifference / this.loopTimeMs), this.maxConsecutiveLoops); + + for (let i = ticksCount; i > 0; --i) { + this.tick(); } } + this.lastTimestamp = timestamp; } }