diff --git a/front/src/Phaser/Game/Game.ts b/front/src/Phaser/Game/Game.ts new file mode 100644 index 00000000..6a48572a --- /dev/null +++ b/front/src/Phaser/Game/Game.ts @@ -0,0 +1,85 @@ +const Events = Phaser.Core.Events; + +/** + * A specialization of the main Phaser Game scene. + * It comes with an optimization to skip rendering. + * + * Beware, the "step" function might vary in future versions of Phaser. + */ +export class Game extends Phaser.Game { + public step(time: number, delta: number) + { + // @ts-ignore + if (this.pendingDestroy) + { + // @ts-ignore + return this.runDestroy(); + } + + const eventEmitter = this.events; + + // Global Managers like Input and Sound update in the prestep + + eventEmitter.emit(Events.PRE_STEP, time, delta); + + // This is mostly meant for user-land code and plugins + + eventEmitter.emit(Events.STEP, time, delta); + + // Update the Scene Manager and all active Scenes + + this.scene.update(time, delta); + + // Our final event before rendering starts + + eventEmitter.emit(Events.POST_STEP, time, delta); + + // This "if" is the changed introduced by the new "Game" class to avoid rendering unnecessarily. + if (this.isDirty()) { + const renderer = this.renderer; + + // Run the Pre-render (clearing the canvas, setting background colors, etc) + + renderer.preRender(); + + eventEmitter.emit(Events.PRE_RENDER, renderer, time, delta); + + // The main render loop. Iterates all Scenes and all Cameras in those scenes, rendering to the renderer instance. + + this.scene.render(renderer); + + // The Post-Render call. Tidies up loose end, takes snapshots, etc. + + renderer.postRender(); + + // The final event before the step repeats. Your last chance to do anything to the canvas before it all starts again. + + eventEmitter.emit(Events.POST_RENDER, renderer, time, delta); + } + } + + private isDirty(): boolean { + // Loop through the scenes in forward order + for (let i = 0; i < this.scene.scenes.length; i++) + { + const scene = this.scene.scenes[i]; + const sys = scene.sys; + + if (sys.settings.visible && sys.settings.status >= Phaser.Scenes.LOADING && sys.settings.status < Phaser.Scenes.SLEEPING) + { + // @ts-ignore + if(typeof scene.isDirty === 'function') { + // @ts-ignore + const isDirty = scene.isDirty() || scene.tweens.getAllTweens().length > 0; + if (isDirty) { + return true; + } + } else { + return true; + } + } + } + + return false; + } +} diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 7e709cc6..672de5e6 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -1061,6 +1061,7 @@ ${escapedMessage} } createCollisionWithPlayer() { + this.physics.disableUpdate(); //add collision layer this.Layers.forEach((Layer: Phaser.Tilemaps.TilemapLayer) => { this.physics.add.collider(this.CurrentPlayer, Layer, (object1: GameObject, object2: GameObject) => { @@ -1186,17 +1187,36 @@ ${escapedMessage} }); } + private dirty:boolean = true; + /** * @param time * @param delta The delta time in ms since the last frame. This is a smoothed and capped value based on the FPS rate. */ update(time: number, delta: number) : void { + // TODO: add Events.ADDED_TO_SCENE to the scene to track new objects. + // When an object is added, add ANIMATION_UPDATE event on this object (and remove the listener on Events.REMOVE_FROM_SCENE) + // This way, we can set the dirty flag only when an animation is added!!! + + + this.dirty = false; mediaManager.setLastUpdateScene(); this.currentTick = time; + if (this.CurrentPlayer.isMoving() === true) { + this.dirty = true; + } this.CurrentPlayer.moveUser(delta); + if (this.CurrentPlayer.isMoving() === true) { + this.dirty = true; + this.physics.enableUpdate(); + } else { + this.physics.disableUpdate(); + } + // Let's handle all events while (this.pendingEvents.length !== 0) { + this.dirty = true; const event = this.pendingEvents.dequeue(); switch (event.type) { case "InitUserPositionEvent": @@ -1222,6 +1242,7 @@ ${escapedMessage} // Let's move all users const updatedPlayersPositions = this.playersPositionInterpolator.getUpdatedPositions(time); updatedPlayersPositions.forEach((moveEvent: HasMovedEvent, userId: number) => { + this.dirty = true; const player: RemotePlayer | undefined = this.MapPlayersByKey.get(userId); if (player === undefined) { throw new Error('Cannot find player with ID "' + userId + '"'); @@ -1491,4 +1512,8 @@ ${escapedMessage} message: 'If you want more information, you may contact us at: workadventure@thecodingmachine.com' }); } + + public isDirty(): boolean { + return this.dirty; + } } diff --git a/front/src/Phaser/Menu/MenuScene.ts b/front/src/Phaser/Menu/MenuScene.ts index 187f98c1..c5611139 100644 --- a/front/src/Phaser/Menu/MenuScene.ts +++ b/front/src/Phaser/Menu/MenuScene.ts @@ -349,4 +349,8 @@ export class MenuScene extends Phaser.Scene { } } } + + public isDirty(): boolean { + return false; + } } diff --git a/front/src/Phaser/Player/Player.ts b/front/src/Phaser/Player/Player.ts index 438f1228..3db7f051 100644 --- a/front/src/Phaser/Player/Player.ts +++ b/front/src/Phaser/Player/Player.ts @@ -7,6 +7,7 @@ export const hasMovedEventName = "hasMoved"; export interface CurrentGamerInterface extends Character{ moveUser(delta: number) : void; say(text : string) : void; + isMoving(): boolean; } export class Player extends Character implements CurrentGamerInterface { @@ -83,4 +84,8 @@ export class Player extends Character implements CurrentGamerInterface { } this.wasMoving = moving; } + + public isMoving(): boolean { + return this.wasMoving; + } } diff --git a/front/src/index.ts b/front/src/index.ts index 89582cd4..de6aeb1a 100644 --- a/front/src/index.ts +++ b/front/src/index.ts @@ -18,6 +18,7 @@ import {localUserStore} from "./Connexion/LocalUserStore"; import {ErrorScene} from "./Phaser/Reconnecting/ErrorScene"; import {iframeListener} from "./Api/IframeListener"; import {discussionManager} from "./WebRtc/DiscussionManager"; +import {Game} from "./Phaser/Game/Game"; const {width, height} = coWebsiteManager.getGameSize(); @@ -103,7 +104,8 @@ const config: GameConfig = { } }; -const game = new Phaser.Game(config); +//const game = new Phaser.Game(config); +const game = new Game(config); window.addEventListener('resize', function (event) { coWebsiteManager.resetStyle();