refactor: moving into App
This commit is contained in:
parent
1f51d6e035
commit
bac0dd8989
|
@ -1,5 +1,10 @@
|
|||
import {compose} from '@avocado/core';
|
||||
import {Stage} from '@avocado/graphics';
|
||||
import {EventEmitter, Property} from '@avocado/mixins';
|
||||
import {World} from '@avocado/physics/matter/world';
|
||||
import {Room, RoomView} from '@avocado/topdown';
|
||||
|
||||
import {WorldTime} from '../common/world-time';
|
||||
|
||||
const decorate = compose(
|
||||
EventEmitter,
|
||||
|
@ -16,9 +21,85 @@ const decorate = compose(
|
|||
|
||||
export class App extends decorate(class {}) {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const config = this.readConfig();
|
||||
// Physics.
|
||||
this.world = config.doPhysicsSimulation ? new World() : undefined;
|
||||
// Room.
|
||||
this.room = new Room();
|
||||
this.room.world = this.world;
|
||||
// Graphics stage.
|
||||
this.stage = new Stage(config.visibleSize, config.visibleScale);
|
||||
// World time.
|
||||
this.worldTime = new WorldTime();
|
||||
// Room view.
|
||||
const roomView = new RoomView(this.room, this.stage.renderer);
|
||||
this.stage.addChild(roomView);
|
||||
// Listen for new entities.
|
||||
this.room.on('entityAdded', this.onRoomEntityAdded, this);
|
||||
}
|
||||
|
||||
injectStageIntoDom(node) {
|
||||
// Lol, Apple...
|
||||
node.addEventListener('touchmove', (event) => {
|
||||
event.preventDefault();
|
||||
});
|
||||
this.stage.addToDom(node);
|
||||
}
|
||||
|
||||
onRoomEntityAdded(entity) {
|
||||
// Traits that shouldn't be on client.
|
||||
const noClientTraits = [
|
||||
'behaved',
|
||||
'informed',
|
||||
];
|
||||
// If there's no physics, then remove physical trait.
|
||||
if (!this.room.world) {
|
||||
noClientTraits.push('physical');
|
||||
}
|
||||
// Traits that only make sense for our self entity on the client.
|
||||
const selfEntityOnlyTraits = [
|
||||
'controllable',
|
||||
'followed',
|
||||
];
|
||||
const nixedTraits = selfEntityOnlyTraits.concat(noClientTraits);
|
||||
for (let i = 0; i < nixedTraits.length; ++i) {
|
||||
const type = nixedTraits[i];
|
||||
if (entity.is(type)) {
|
||||
entity.removeTrait(type);
|
||||
}
|
||||
}
|
||||
// Client only traits.
|
||||
const clientOnlyTraits = [
|
||||
'staged',
|
||||
];
|
||||
for (let i = 0; i < clientOnlyTraits.length; ++i) {
|
||||
const type = clientOnlyTraits[i];
|
||||
entity.addTrait(type);
|
||||
}
|
||||
entity.stage = this.stage;
|
||||
// Set self entity.
|
||||
if (this.selfEntityUuid) {
|
||||
if (entity === this.room.findEntity(this.selfEntityUuid)) {
|
||||
this.selfEntity = entity;
|
||||
this.selfEntityUuid = undefined;
|
||||
// Add back our self entity traits.
|
||||
for (const type of selfEntityOnlyTraits) {
|
||||
entity.addTrait(type);
|
||||
}
|
||||
const {camera} = entity;
|
||||
this.stage.camera = camera;
|
||||
// Avoid the initial 'lerp.
|
||||
camera.realPosition = camera.position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stub for now!
|
||||
readConfig() {
|
||||
return {
|
||||
doPhysicsSimulation: true,
|
||||
visibleScale: [2, 2],
|
||||
visibleSize: [320, 180],
|
||||
};
|
||||
|
|
124
client/index.js
124
client/index.js
|
@ -1,12 +1,10 @@
|
|||
// 3rd party.
|
||||
import msgpack from 'msgpack-lite';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
// 2nd party.
|
||||
import {create as createClient} from '@avocado/client/socket';
|
||||
import {EntityList} from '@avocado/entity';
|
||||
import {ActionRegistry, InputPacket} from '@avocado/input';
|
||||
import {Stage} from '@avocado/graphics';
|
||||
import {Vector} from '@avocado/math';
|
||||
import {SocketIoParser} from '@avocado/packet';
|
||||
import {
|
||||
|
@ -15,81 +13,19 @@ import {
|
|||
Synchronizer,
|
||||
Unpacker,
|
||||
} from '@avocado/state';
|
||||
import {Room, RoomView} from '@avocado/topdown';
|
||||
import {World} from '@avocado/physics/matter/world';
|
||||
import {clearAnimation, setAnimation, Ticker} from '@avocado/timing';
|
||||
// 1st party.
|
||||
import {augmentParserWithThroughput} from '../common/parser-throughput';
|
||||
import {WorldTime} from '../common/world-time';
|
||||
import {App} from './app';
|
||||
import Ui from './ui';
|
||||
import DebugUi from './ui/debug';
|
||||
// Application.
|
||||
const app = new App();
|
||||
const config = app.readConfig();
|
||||
// DOM.
|
||||
const appNode = document.querySelector('.app');
|
||||
// Graphics stage.
|
||||
const stage = new Stage(config.visibleSize, config.visibleScale);
|
||||
// Create room.
|
||||
const room = new Room();
|
||||
room.world = new World();
|
||||
const roomView = new RoomView(room, stage.renderer);
|
||||
stage.addChild(roomView);
|
||||
// Time.
|
||||
const worldTime = new WorldTime();
|
||||
// Synchronize state.
|
||||
let state = undefined;
|
||||
const synchronizer = new Synchronizer({
|
||||
room,
|
||||
worldTime,
|
||||
});
|
||||
room.on('entityAdded', (entity) => {
|
||||
// Traits that shouldn't be on client.
|
||||
const noClientTraits = [
|
||||
'behaved',
|
||||
'informed',
|
||||
];
|
||||
// If there's no physics, then remove physical trait.
|
||||
if (!room.world) {
|
||||
noClientTraits.push('physical');
|
||||
}
|
||||
// Traits that only make sense for our self entity on the client.
|
||||
const selfEntityOnlyTraits = [
|
||||
'controllable',
|
||||
'followed',
|
||||
];
|
||||
const nixedTraits = selfEntityOnlyTraits.concat(noClientTraits);
|
||||
for (let i = 0; i < nixedTraits.length; ++i) {
|
||||
const type = nixedTraits[i];
|
||||
if (entity.is(type)) {
|
||||
entity.removeTrait(type);
|
||||
}
|
||||
}
|
||||
// Client only traits.
|
||||
const clientOnlyTraits = [
|
||||
'staged',
|
||||
];
|
||||
for (let i = 0; i < clientOnlyTraits.length; ++i) {
|
||||
const type = clientOnlyTraits[i];
|
||||
entity.addTrait(type);
|
||||
}
|
||||
entity.stage = stage;
|
||||
// Set self entity.
|
||||
if (app.selfEntityUuid) {
|
||||
if (entity === room.findEntity(app.selfEntityUuid)) {
|
||||
app.selfEntity = entity;
|
||||
app.selfEntityUuid = undefined;
|
||||
// Add back our self entity traits.
|
||||
for (const type of selfEntityOnlyTraits) {
|
||||
entity.addTrait(type);
|
||||
}
|
||||
const {camera} = entity;
|
||||
stage.camera = camera;
|
||||
// Avoid the initial 'lerp.
|
||||
camera.realPosition = camera.position;
|
||||
}
|
||||
}
|
||||
room: app.room,
|
||||
worldTime: app.worldTime,
|
||||
});
|
||||
// Accept input.
|
||||
window.addEventListener('keydown', (event) => {
|
||||
|
@ -105,11 +41,7 @@ actionRegistry.mapKeysToActions({
|
|||
's': 'MoveDown',
|
||||
'd': 'MoveRight',
|
||||
});
|
||||
actionRegistry.listen(stage.element);
|
||||
// Lol Apple
|
||||
appNode.addEventListener('touchmove', (event) => {
|
||||
event.preventDefault();
|
||||
});
|
||||
actionRegistry.listen(app.stage.element);
|
||||
// Mouse/touch movement.
|
||||
function createMoveToNormal(position) {
|
||||
if (!app.selfEntity) {
|
||||
|
@ -133,20 +65,20 @@ function isPointingAtAnything() {
|
|||
function isInUi(node) {
|
||||
let walk = node;
|
||||
while (walk) {
|
||||
if (walk === stage.ui) {
|
||||
if (walk === app.stage.ui) {
|
||||
return true;
|
||||
}
|
||||
walk = walk.parentNode;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
stage.on('pointerDown', (event) => {
|
||||
app.stage.on('pointerDown', (event) => {
|
||||
if (!isInUi(event.target)) {
|
||||
return;
|
||||
}
|
||||
pointingAt = event.position;
|
||||
});
|
||||
stage.on('pointerMove', (event) => {
|
||||
app.stage.on('pointerMove', (event) => {
|
||||
if (!isInUi(event.target)) {
|
||||
return;
|
||||
}
|
||||
|
@ -155,7 +87,7 @@ stage.on('pointerMove', (event) => {
|
|||
}
|
||||
pointingAt = event.position;
|
||||
});
|
||||
stage.on('pointerUp', (event) => {
|
||||
app.stage.on('pointerUp', (event) => {
|
||||
pointingAt = [-1, -1];
|
||||
});
|
||||
let actionState = actionRegistry.state;
|
||||
|
@ -166,7 +98,7 @@ const socket = createClient(window.location.href, {
|
|||
});
|
||||
let isConnected = false;
|
||||
socket.on('connect', () => {
|
||||
room.layers.destroy();
|
||||
app.room.layers.destroy();
|
||||
app.selfEntity = undefined;
|
||||
app.selfEntityUuid = undefined;
|
||||
isConnected = true;
|
||||
|
@ -259,33 +191,33 @@ function onPacket(packet) {
|
|||
socket.on('packet', onPacket);
|
||||
// Apply stage lighting.
|
||||
let isFocused = false;
|
||||
stage.element.addEventListener('blur', () => {
|
||||
app.stage.element.addEventListener('blur', () => {
|
||||
isFocused = false;
|
||||
});
|
||||
stage.element.addEventListener('focus', () => {
|
||||
app.stage.element.addEventListener('focus', () => {
|
||||
isFocused = true;
|
||||
});
|
||||
let lastIntensity = undefined;
|
||||
let lastIsFocused = undefined;
|
||||
function applyStageLighting() {
|
||||
let intensity = 0;
|
||||
if (worldTime.hour >= 21 || worldTime.hour < 4) {
|
||||
if (app.worldTime.hour >= 21 || app.worldTime.hour < 4) {
|
||||
intensity = 0.8;
|
||||
}
|
||||
if (worldTime.hour >= 4 && worldTime.hour < 7) {
|
||||
intensity = 0.8 * ((7 - worldTime.hour) / 3);
|
||||
if (app.worldTime.hour >= 4 && app.worldTime.hour < 7) {
|
||||
intensity = 0.8 * ((7 - app.worldTime.hour) / 3);
|
||||
}
|
||||
if (worldTime.hour >= 18 && worldTime.hour < 21) {
|
||||
intensity = 0.8 * ((3 - (21 - worldTime.hour)) / 3);
|
||||
if (app.worldTime.hour >= 18 && app.worldTime.hour < 21) {
|
||||
intensity = 0.8 * ((3 - (21 - app.worldTime.hour)) / 3);
|
||||
}
|
||||
intensity = Math.floor(intensity * 1000) / 1000;
|
||||
if (intensity !== lastIntensity || isFocused !== lastIsFocused) {
|
||||
stage.removeAllFilters();
|
||||
app.stage.removeAllFilters();
|
||||
if (!isFocused) {
|
||||
stage.paused(intensity);
|
||||
app.stage.paused(intensity);
|
||||
}
|
||||
else {
|
||||
stage.night(intensity);
|
||||
app.stage.night(intensity);
|
||||
}
|
||||
lastIntensity = intensity;
|
||||
lastIsFocused = isFocused;
|
||||
|
@ -302,23 +234,23 @@ function render() {
|
|||
mayRender = false;
|
||||
// Lighting.
|
||||
applyStageLighting();
|
||||
stage.render();
|
||||
app.stage.render();
|
||||
}
|
||||
const renderHandle = setAnimation(render);
|
||||
// UI.
|
||||
const UiComponent = <Ui
|
||||
socket={socket}
|
||||
worldTime={worldTime}
|
||||
worldTime={app.worldTime}
|
||||
/>;
|
||||
// Create UI layer for react.
|
||||
const reactContainer = window.document.createElement('div');
|
||||
reactContainer.className = 'react';
|
||||
stage.on('displaySizeChanged', () => {
|
||||
const displaySize = stage.displaySize;
|
||||
app.stage.on('displaySizeChanged', () => {
|
||||
const displaySize = app.stage.displaySize;
|
||||
reactContainer.style.width = '100%';
|
||||
reactContainer.style.height = '100%';
|
||||
})
|
||||
stage.ui.appendChild(reactContainer);
|
||||
app.stage.ui.appendChild(reactContainer);
|
||||
ReactDOM.render(UiComponent, reactContainer);
|
||||
// Debug UI.
|
||||
const debugUiNode = document.querySelector('.debug-container');
|
||||
|
@ -327,18 +259,18 @@ const DebugUiComponent = <DebugUi
|
|||
app={app}
|
||||
Parser={AugmentedParser}
|
||||
socket={socket}
|
||||
stage={stage}
|
||||
stage={app.stage}
|
||||
/>;
|
||||
ReactDOM.render(DebugUiComponent, debugUiNode, () => {
|
||||
stage.resolveUiRendered();
|
||||
app.stage.resolveUiRendered();
|
||||
});
|
||||
// Inject the stage last.
|
||||
stage.addToDom(appNode);
|
||||
app.injectStageIntoDom(document.querySelector('.app'));
|
||||
// Eval.
|
||||
const evaluationContext = {
|
||||
room,
|
||||
room: app.room,
|
||||
selfEntity: app.selfEntity,
|
||||
stage,
|
||||
stage: app.stage,
|
||||
};
|
||||
app.on('selfEntityChanged', () => {
|
||||
evaluationContext.selfEntity = app.selfEntity;
|
||||
|
|
Loading…
Reference in New Issue
Block a user