Skip to content

Commit

Permalink
Add door
Browse files Browse the repository at this point in the history
Closes #6
  • Loading branch information
SnowyCoder committed Oct 11, 2020
1 parent 7435a10 commit f2e6adf
Show file tree
Hide file tree
Showing 6 changed files with 368 additions and 6 deletions.
247 changes: 247 additions & 0 deletions src/app/ecs/systems/doorSystem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
import {System} from "../system";
import {World} from "../ecs";
import {SingleEcsStorage} from "../storage";
import {EditMapPhase} from "../../phase/editMap/editMapPhase";
import {Component, HideableComponent, PositionComponent} from "../component";
import {VisibilityComponent} from "./visibilitySystem";
import * as PointLightRender from "../../game/pointLightRenderer";
import {DESTROY_ALL} from "../../util/pixi";
import {newVisibilityAwareComponent, VisibilityAwareComponent} from "./visibilityAwareSystem";
import {LightComponent, LightSettings} from "./lightSystem";
import {Aabb} from "../../geometry/aabb";
import PIXI from "../../PIXI";
import {Resource} from "../resource";
import {Line} from "../../geometry/line";
import {WallComponent} from "./wallSystem";
import {rotatePointByOrig} from "../../geometry/collision";
import {EditMapDisplayPrecedence} from "../../phase/editMap/displayPrecedence";
import {app} from "../../index";


export enum DoorType {
NORMAL_LEFT = "normall",
NORMAL_RIGHT = "normalr",
ROTATE = "rotate",
}

export interface DoorComponent extends Component, HideableComponent {
type: "door";
doorType: DoorType;
locked: boolean;
open: boolean;
clientVisible: boolean;
_display?: PIXI.Graphics;
}


export class DoorSystem implements System {
readonly ecs: World;

storage = new SingleEcsStorage<DoorComponent>('door', true, true);
phase: EditMapPhase;

layer: PIXI.display.Layer;
displayContainer: PIXI.Container;

constructor(ecs: World, phase: EditMapPhase) {
this.ecs = ecs;
this.phase = phase;

this.ecs.addStorage(this.storage);
this.ecs.events.on('component_add', this.onComponentAdd, this);
this.ecs.events.on('component_edited', this.onComponentEdited, this);
this.ecs.events.on('component_remove', this.onComponentRemove, this);
}

redrawComponent(door: DoorComponent): void {
let wall = this.ecs.getComponent(door.entity, 'wall') as WallComponent;
let pos = this.ecs.getComponent(door.entity, 'position') as PositionComponent;

let visible = wall.visible || this.phase.lightSystem.localLightSettings.visionType === 'dm';
if (!visible) {
door._display.clear();
return;
}

// TODO: use interaction shape? (might bug out on translations)
let line = new Line(
pos.x, pos.y,
pos.x + wall.vec[0], pos.y + wall.vec[1]
);
this.drawLines(door, line);
}

private drawLines(door: DoorComponent, line: Line): void {
let g = door._display;
if (g === undefined) return;
g.clear();
g.lineStyle(2, 0, 0.5);
switch (door.doorType) {
case DoorType.NORMAL_LEFT: {
let r = line.distance();
let startAngle = Math.atan2(line.toY - line.fromY, line.toX - line.fromX);
if (door.open) startAngle -= Math.PI / 2;
g.arc(line.fromX, line.fromY, r, startAngle, startAngle + Math.PI / 2);
break;
}
case DoorType.NORMAL_RIGHT: {
let r = line.distance();
let startAngle = Math.atan2(line.fromY - line.toY, line.fromX - line.toX);
if (!door.open) startAngle -= Math.PI / 2;
g.arc(line.toX, line.toY, r, startAngle, startAngle + Math.PI / 2);
break;
}
case DoorType.ROTATE: {
let r = line.distance() / 2;
let cx = (line.fromX + line.toX) / 2;
let cy = (line.fromY + line.toY) / 2;
g.drawCircle(cx, cy, r);
break;
}
default:
console.warn("Unknown door type: " + door.doorType);
}
}

private openDoor(door: DoorComponent, doorType: DoorType, open: boolean): void {
if (!this.ecs.isMaster) return;// This operation should only be done once!
let wall = this.ecs.getComponent(door.entity, 'wall') as WallComponent;
let pos = this.ecs.getComponent(door.entity, 'position') as PositionComponent;

let newPos = undefined;
let newVec = undefined;

switch (doorType) {
case DoorType.NORMAL_LEFT: {
newVec = rotatePointByOrig(
{ x: 0, y: 0 },
Math.PI / 2 * (open ? -1 : 1),
{ x: wall.vec[0], y: wall.vec[1] }
);

break;
}
case DoorType.NORMAL_RIGHT: {
let angle = Math.PI / 2 * (open ? 1 : -1);
newPos = rotatePointByOrig(
{ x: pos.x + wall.vec[0], y: pos.y + wall.vec[1] },
angle,
{ x: pos.x, y: pos.y }
);

newVec = rotatePointByOrig(
{ x: 0, y: 0 },
angle,
{ x: wall.vec[0], y: wall.vec[1] }
)

break;
}
case DoorType.ROTATE: {
let hvx = wall.vec[0] / 2;
let hvy = wall.vec[1] / 2;
let origin = { x: pos.x + hvx, y: pos.y + hvy };
let angle = Math.PI / 2 * (open ? 1 : -1);
newPos = rotatePointByOrig(
origin, angle,
{ x: pos.x, y: pos.y },
);
newVec = rotatePointByOrig(
origin, angle,
{ x: pos.x + wall.vec[0], y: pos.y + wall.vec[1] }
);
newVec.x -= newPos.x;
newVec.y -= newPos.y;

break;
}
default:
console.warn("Unknown door type: " + doorType);
}

if (newPos !== undefined) {
this.ecs.editComponent(door.entity, 'position', {
x: newPos.x,
y: newPos.y,
});
}
if (newVec !== undefined) {
this.ecs.editComponent(door.entity, 'wall', {
vec: [newVec.x, newVec.y],
});
}
}


private onComponentAdd(comp: Component): void {
if (comp.type === 'door') {
let d = comp as DoorComponent;
d._display = new PIXI.Graphics();
this.displayContainer.addChild(d._display);
if (d.open) {
this.openDoor(d, d.doorType, true);
}
this.redrawComponent(d);

let wall = this.ecs.getComponent(comp.entity, 'wall') as WallComponent;
wall._dontMerge++;
}
}


private onComponentEdited(comp: Component, changed: any): void {
if (comp.type === 'door') {
let d = comp as DoorComponent;
if ('open' in changed) {
this.openDoor(d, d.doorType, d.open);
}
if ('doorType' in changed) {
if (d.open) {
this.openDoor(d, changed['doorType'], false);
this.openDoor(d, d.doorType, true);
}
}
this.redrawComponent(d);
} else if (comp.type === 'wall') {
let d = this.storage.getComponent(comp.entity);
if (d !== undefined) this.redrawComponent(d);
} else if (comp.type === 'position') {
let d = this.storage.getComponent(comp.entity);
if (d !== undefined) this.redrawComponent(d);
}
}

private onComponentRemove(comp: Component): void {
if (comp.type === 'door') {
let d = comp as DoorComponent;

if (d.open) {
this.openDoor(d, d.doorType, false);
}

d._display.destroy(DESTROY_ALL);

let wall = this.ecs.getComponent(comp.entity, 'wall') as WallComponent;
wall._dontMerge--;
}
}


enable(): void {
this.layer = new PIXI.display.Layer();
this.layer.zIndex = EditMapDisplayPrecedence.WALL + 1;
this.layer.interactive = false;
app.stage.addChild(this.layer);

this.displayContainer = new PIXI.Container();
this.displayContainer.parentLayer = this.layer;
this.displayContainer.interactive = false;
this.displayContainer.interactiveChildren = false;
this.phase.board.addChild(this.displayContainer);
}

destroy(): void {
this.displayContainer.destroy(DESTROY_ALL);
this.layer.destroy(DESTROY_ALL);
}
}
15 changes: 11 additions & 4 deletions src/app/ecs/systems/wallSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface WallComponent extends Component {
visible: boolean,
_display: PIXI.Graphics;
_selected?: boolean;
_dontMerge?: number;
}

const SELECTION_COLOR = 0x7986CB;
Expand Down Expand Up @@ -68,6 +69,7 @@ export class WallSystem implements System {
console.warn("Found wall without position, please add first the position, then the wall");
return;
}
wall._dontMerge = 0;

if (wall.visible === undefined) wall.visible = false;
this.addWallDisplay(pos, wall);
Expand Down Expand Up @@ -118,6 +120,7 @@ export class WallSystem implements System {
};

for (let wall of walls) {
if (wall._dontMerge !== 0) continue;
let pos = posStorage.getComponent(wall.entity);

let p1 = pos.x + "@" + pos.y;
Expand Down Expand Up @@ -184,10 +187,6 @@ export class WallSystem implements System {
insertInIndex(p1, wall);
insertInIndex(p2, wall);
}


// TODO: we need to remove the intersection breaks from the selected walls and also to
// remove them from the unselected walls (?).
}

fixWallPostTranslation(walls: WallComponent[]) {
Expand Down Expand Up @@ -266,6 +265,14 @@ export class WallSystem implements System {
this.fixWallPreTranslation([wall]);
this.fixWallPostTranslation([wall]);
}
if (comp.type === 'wall' && 'vec' in changed) {
this.ecs.editComponent(wall.entity, 'interaction', {
shape: shapeLine(new Line(
position.x, position.y,
position.x + wall.vec[0], position.y + wall.vec[1],
)),
});
}

if (comp.type === 'position') {
wall._display.position.set(position.x, position.y);
Expand Down
15 changes: 15 additions & 0 deletions src/app/game/selectionGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {World} from "../ecs/ecs";
import {Component, NameComponent, NoteComponent, PositionComponent} from "../ecs/component";
import {LightComponent} from "../ecs/systems/lightSystem";
import {PlayerComponent} from "../ecs/systems/playerSystem";
import {DoorComponent, DoorType} from "../ecs/systems/doorSystem";

const MULTI_TYPES = ['name', 'note'];
const ELIMINABLE_TYPES = ['name', 'note', 'player', 'light'];
Expand Down Expand Up @@ -253,6 +254,11 @@ export class SelectionGroup {
type: 'player',
name: 'Player',
});
} else if (this.hasEveryoneType('wall') && !this.hasComponentType('door')) {
res.push({
type: "door",
name: "Door"
});
}

return res;
Expand Down Expand Up @@ -313,6 +319,15 @@ export class SelectionGroup {
range: 50,
} as PlayerComponent;
break;
case 'door':
comp = {
type: 'door',
doorType: DoorType.NORMAL_LEFT,
locked: false,
open: false,
clientVisible: true,
} as DoorComponent;
break;
default: throw 'Cannot add unknown component: ' + propertyValue;
}
for (let entity of [...this.selectedEntities]) {
Expand Down
6 changes: 5 additions & 1 deletion src/app/phase/editMap/editMapPhase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {BirdEyePhase} from "../birdEyePhase";
import PIXI from "../../PIXI";
import {app, stage} from "../../index";
import {BackgroundSystem} from "../../ecs/systems/backgroundSystem";
import {PointDB} from "../../game/pointDB";
import {SelectionGroup} from "../../game/selectionGroup";
import {NetworkManager} from "../../network/networkManager";
import {HostEditMapPhase} from "./hostEditMapPhase";
Expand All @@ -17,6 +16,7 @@ import {VisibilitySystem} from "../../ecs/systems/visibilitySystem";
import {InteractionSystem} from "../../ecs/systems/interactionSystem";
import {PlayerSystem} from "../../ecs/systems/playerSystem";
import {VisibilityAwareSystem} from "../../ecs/systems/visibilityAwareSystem";
import {DoorSystem} from "../../ecs/systems/doorSystem";


export class EditMapPhase extends BirdEyePhase {
Expand All @@ -29,6 +29,7 @@ export class EditMapPhase extends BirdEyePhase {
backgroundSystem: BackgroundSystem;
textSystem: TextSystem;
wallSystem: WallSystem;
doorSystem: DoorSystem;
visibilitySystem: VisibilitySystem;
visibilityAwareSystem: VisibilityAwareSystem;
pinSystem: PinSystem;
Expand Down Expand Up @@ -57,6 +58,7 @@ export class EditMapPhase extends BirdEyePhase {
this.backgroundSystem = new BackgroundSystem(this.ecs, this);
this.textSystem = new TextSystem(this.ecs);
this.wallSystem = new WallSystem(this.ecs, this);
this.doorSystem = new DoorSystem(this.ecs, this);
this.visibilitySystem = new VisibilitySystem(this.ecs, this);
this.visibilityAwareSystem = new VisibilityAwareSystem(this.ecs, this);
this.pinSystem = new PinSystem(this.ecs, this);
Expand Down Expand Up @@ -284,6 +286,7 @@ export class EditMapPhase extends BirdEyePhase {
this.backgroundSystem.enable();
this.textSystem.enable();
this.wallSystem.enable();
this.doorSystem.enable();
this.visibilitySystem.enable();
this.visibilityAwareSystem.enable();
this.pinSystem.enable();
Expand All @@ -297,6 +300,7 @@ export class EditMapPhase extends BirdEyePhase {
this.pinSystem.destroy();
this.visibilityAwareSystem.destroy();
this.visibilitySystem.destroy();
this.doorSystem.destroy();
this.wallSystem.destroy();
this.textSystem.destroy();
this.backgroundSystem.destroy();
Expand Down
3 changes: 2 additions & 1 deletion src/app/ui/ecs/compWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import ecsTransform from "./ecsTransform.vue";
import ecsLight from "./ecsLight.vue";
import ecsPlayer from "./ecsPlayer.vue";
import ecsDoor from "./ecsDoor.vue";
export default {
name: "ecs-component-wrapper",
Expand All @@ -54,7 +55,7 @@
}
},
components: {
ecsName, ecsNote, ecsPosition, ecsWall, ecsBackgroundImage, ecsPin, ecsTransform, ecsLight, ecsPlayer
ecsName, ecsNote, ecsPosition, ecsWall, ecsBackgroundImage, ecsPin, ecsTransform, ecsLight, ecsPlayer, ecsDoor
}
}
</script>
Expand Down
Loading

0 comments on commit f2e6adf

Please sign in to comment.