avocado-old/packages/topdown/room.js
2019-04-07 12:43:50 -04:00

157 lines
3.6 KiB
JavaScript

import * as I from 'immutable';
import {compose} from '@avocado/core';
import {Vector} from '@avocado/math';
import {EventEmitter, Property} from '@avocado/mixins';
import {RectangleShape} from '@avocado/physics';
import {Synchronized} from '@avocado/state';
import {Layers} from './layers';
const decorate = compose(
EventEmitter,
Property('world', {
track: true,
}),
Vector.Mixin('size', 'width', 'height', {
default: [0, 0],
track: true,
})
);
export class Room extends decorate(Synchronized) {
constructor() {
super();
this.bounds = [];
this.layers = new Layers();
// Listeners.
this.onEntityAddedToRoom = this.onEntityAddedToRoom.bind(this);
this.onEntityRemovedFromRoom = this.onEntityRemovedFromRoom.bind(this);
this.layers.on('entityAdded', this.onEntityAddedToRoom);
this.layers.on('entityRemoved', this.onEntityRemovedFromRoom);
this.onSizeChanged = this.onSizeChanged.bind(this);
this.on('sizeChanged', this.onSizeChanged);
this.onWorldChanged = this.onWorldChanged.bind(this);
this.on('worldChanged', this.onWorldChanged);
}
addEntityToLayer(entity, layerIndex = 0) {
this.layers.addEntityToLayer(entity, layerIndex);
}
destroy() {
this.layers.destroy();
this.layers.off('entityAdded', this.onEntityAddedToRoom);
this.layers.off('entityRemoved', this.onEntityRemovedFromRoom);
this.off('worldChanged', this.onWorldChanged);
}
findEntity(uuid) {
return this.layers.findEntity(uuid);
}
fromJSON(json) {
if (json.layers) {
this.layers.fromJSON(json.layers);
}
if (json.size) {
this.size = json.size;
}
return this;
}
layer(index) {
return this.layers.layer(index);
}
onEntityAddedToRoom(entity) {
entity.addTrait('roomed');
entity.room = this;
this.emit('entityAdded', entity)
}
onEntityRemovedFromRoom(entity) {
if (entity.is('roomed')) {
entity.removeTrait('roomed');
}
this.emit('entityRemoved', entity);
}
onSizeChanged() {
this.updateBounds();
}
onWorldChanged() {
const world = this.world;
for (const {layer} of this.layers) {
for (const entity of layer.entityList) {
if (entity.is('physical')) {
entity.world = world;
}
}
}
// Update bounds.
this.updateBounds();
}
removeEntityFromLayer(entity, layerIndex = 0) {
this.layers.removeEntityFromLayer(entity, layerIndex);
}
synchronizedChildren() {
return [
'width',
'height',
'layers',
];
}
updateBounds() {
const world = this.world;
if (!world) {
return;
}
for (const bound of this.bounds) {
world.removeBody(bound);
}
if (Vector.isZero(this.size)) {
return;
}
this.bounds = [
// Top.
world.createBody((new RectangleShape()).fromJSON({
position: [this.width / 2, -8],
size: [this.width, 16],
})),
// Right.
world.createBody((new RectangleShape()).fromJSON({
position: [this.width + 8, this.height / 2],
size: [16, this.height],
})),
// Bottom.
world.createBody((new RectangleShape()).fromJSON({
position: [this.width / 2, this.height + 8],
size: [this.width, 16],
})),
// Left.
world.createBody((new RectangleShape()).fromJSON({
position: [-8, this.height / 2],
size: [16, this.height],
})),
];
this.bounds.forEach((bound) => {
bound.static = true;
world.addBody(bound);
});
}
tick(elapsed) {
super.tick(elapsed);
if (this.world) {
this.world.tick(elapsed);
}
}
}