diff --git a/client/index.js b/client/index.js index 7a8a14f..b47efda 100644 --- a/client/index.js +++ b/client/index.js @@ -13,8 +13,12 @@ import {WorldTime} from '../common/world-time'; // DOM. const appNode = document.querySelector('.app'); // Graphics stage. -const stage = new Stage([640, 360]); -stage.scale = [2, 2]; +let dirty = false; +const visibleSize = [320, 180]; +const halfVisibleSize = Vector.scale(visibleSize, 0.5); +const visibleScale = [2, 2]; +const stage = new Stage(Vector.mul(visibleSize, visibleScale)); +stage.scale = visibleScale; let isFocused = false; stage.element.addEventListener('blur', () => { isFocused = false; @@ -27,11 +31,21 @@ stage.addToDom(appNode); const timeUi = document.createElement('div'); timeUi.className = 'time unselectable'; stage.ui.appendChild(timeUi); +// Handle "own" entity. +let selfEntity; +function hasSelfEntity() { + return selfEntity && 'string' !== typeof selfEntity; +} // Create room. const room = new Room(); room.world = new World(); const roomView = new RoomView(room, stage.renderer); stage.addChild(roomView); +room.on('sizeChanged', () => { + if (hasSelfEntity() && selfEntity.is('followed')) { + selfEntity.camera.areaSize = room.size; + } +}); // Time. const worldTime = new WorldTime(); let lastWorldTime = worldTime.humanReadable(); @@ -40,11 +54,6 @@ const stateSynchronizer = new StateSynchronizer({ room, worldTime, }); -// Handle "own" entity. -let selfEntity; -function hasSelfEntity() { - return selfEntity && 'string' !== typeof selfEntity; -} room.on('entityAdded', (entity) => { entity.removeTrait('controllable'); // Set self entity. @@ -53,6 +62,18 @@ room.on('entityAdded', (entity) => { selfEntity = entity; // Only self entity should be controllable. entity.addTrait('controllable'); + // Camera tracking. + entity.addTrait('followed'); + const {camera} = entity; + camera.areaSize = room.size; + camera.on('realPositionChanged', () => { + roomView.position = Vector.round( + Vector.sub(halfVisibleSize, camera.realPosition) + ); + dirty = true; + }); + // Avoid the initial 'lerp. + camera.realPosition = camera.position; } } }); @@ -154,7 +175,6 @@ const predictionHandle = setInterval(() => { } }, 1000 / 80); // State updates. -let dirty = false; function onMessage({type, payload}) { switch (type) { case 'state-update':