Skip to content

Commit

Permalink
Fix wall intersections removal
Browse files Browse the repository at this point in the history
  • Loading branch information
SnowyCoder committed Oct 11, 2020
1 parent 76278c6 commit 7435a10
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 53 deletions.
18 changes: 11 additions & 7 deletions src/app/ecs/systems/interactionSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,8 @@ export interface InteractionComponent extends Component {
queryCheck?: (shape: Shape) => boolean;

_treeId?: number;
_snaps?: number[]
_snaps?: number[];
_translateStartLoc?: [number, number];
}

export class InteractionSystem implements System {
Expand Down Expand Up @@ -351,14 +352,17 @@ export class InteractionSystem implements System {
}
}

private worldToLocal(comp: InteractionComponent): void {
private savePosPreTranslate(comp: InteractionComponent): void {
let pos = this.ecs.getComponent(comp.entity, 'position') as PositionComponent;
shapeTranslate(comp.shape, -pos.x, -pos.y)
comp._translateStartLoc = [pos.x, pos.y];
}

private localToWorld(comp: InteractionComponent): void {
private updatePosPostTranslate(comp: InteractionComponent): void {
let pos = this.ecs.getComponent(comp.entity, 'position') as PositionComponent;
shapeTranslate(comp.shape, pos.x, pos.y)

let oldPos = comp._translateStartLoc;
shapeTranslate(comp.shape, pos.x - oldPos[0], pos.y - oldPos[1]);
comp._translateStartLoc = undefined;
}

private onComponentAdd(comp: Component): void {
Expand Down Expand Up @@ -415,7 +419,7 @@ export class InteractionSystem implements System {
for (let comp of this.phase.selection.getSelectedByType("interaction")) {
let c = comp as InteractionComponent;
this.unregisterComponent(c);
this.worldToLocal(c);
this.savePosPreTranslate(c);
}
this.isTranslating = true;
}
Expand All @@ -424,7 +428,7 @@ export class InteractionSystem implements System {
this.isTranslating = false;
for (let comp of this.phase.selection.getSelectedByType("interaction")) {
let c = comp as InteractionComponent;
this.localToWorld(c);
this.updatePosPostTranslate(c);
this.updateComponent(c);
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/app/ecs/systems/visibilitySystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ export class VisibilitySystem implements System {
if (vis !== undefined) {
this.updatePolygon(vis);
}
let blk = this.blockerStorage.getComponent(c.entity);
if (blk !== undefined) {
let inter = this.ecs.getComponent(blk.entity,'interaction') as InteractionComponent;
this.recomputeArea(shapeToAabb(inter.shape));
}
}
else if (c.type === 'interaction' && 'shape' in changes && this.blockerStorage.getComponent(c.entity) !== undefined) {
let i = c as InteractionComponent;
Expand Down
150 changes: 138 additions & 12 deletions src/app/ecs/systems/wallSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {Component, PositionComponent} from "../component";
import {distSquared2d, Point} from "../../util/geometry";
import {Aabb} from "../../geometry/aabb";
import {Line} from "../../geometry/line";
import {intersectSegmentVsSegment, SegmentVsSegmentRes} from "../../geometry/collision";
import {intersectSegmentVsSegment, lineSameSlope, SegmentVsSegmentRes} from "../../geometry/collision";
import {app} from "../../index";
import {InteractionComponent, LineShape, shapeAabb, shapeLine} from "./interactionSystem";
import {VisibilityBlocker} from "./visibilitySystem";
Expand Down Expand Up @@ -96,18 +96,146 @@ export class WallSystem implements System {
}

fixWallPreTranslation(walls: WallComponent[]) {
for (let wall of walls) {
let visBlock = this.ecs.getComponent(wall.entity, 'visibility_blocker');
if (visBlock !== undefined) this.ecs.removeComponent(visBlock);
}


// what changes here? a little bittle thing:
// we need to unfix the wall (remove the intersection breaks).

let wall_index = new Map<string, WallComponent[]>();
let posStorage = this.ecs.storages.get('position') as SingleEcsStorage<PositionComponent>;

let insertInIndex = (index: string, wall: WallComponent) => {
let list = wall_index.get(index);
if (list === undefined) {
list = [];
wall_index.set(index, list);
}
list.push(wall);
};

for (let wall of walls) {
let pos = posStorage.getComponent(wall.entity);

let p1 = pos.x + "@" + pos.y;
let p2 = (pos.x + wall.vec[0]) + "@" + (pos.y + wall.vec[1]);

let tryMerge = (index: string): boolean => {
let mergeWithIndex = undefined;

let walls = wall_index.get(index);

if (walls === undefined) return;

let wlen = walls.length;
for (let i = 0; i < wlen; i++) {
let owall = walls[i];
if (lineSameSlope(wall.vec[0], wall.vec[1], owall.vec[0], owall.vec[1])) {
mergeWithIndex = i;
break;
}
}

if (mergeWithIndex === undefined) return false;

let mwall = walls[mergeWithIndex];
let mpos = posStorage.getComponent(mwall.entity);
let minChanged = false;
let x = pos.x;
let y = pos.y;
let dx = wall.vec[0];
let dy = wall.vec[1];

if (p2 === index) {
x += dx;
y += dy;
dx = -dx;
dy = -dy;
}

if (mpos.x === x && mpos.y === y) {
mpos.x += dx;
mpos.y += dy;
minChanged = true;
} else {
mwall.vec[0] += wall.vec[0];
mwall.vec[1] += wall.vec[1];
}

walls.splice(mergeWithIndex, 1);
let p;
if (minChanged) {
p = mpos.x + "@" + mpos.y;
} else {
p = (mpos.x + mwall.vec[0]) + "@" + (mpos.y + mwall.vec[1]);
}
insertInIndex(p, mwall);
this.ecs.despawnEntity(wall.entity);
this.redrawWall(mpos, mwall);

return true;
};

if (tryMerge(p1) || tryMerge(p2)) continue;

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[]) {
// Recompute intersections with other walls.
// Why not all everything directly? we want to compute also the self-intersections
// TODO

let posStorage = this.ecs.storages.get('position') as SingleEcsStorage<PositionComponent>;

for (let wall of walls) {
let pos = posStorage.getComponent(wall.entity);
let points = [pos.x, pos.y, pos.x + wall.vec[0], pos.y + wall.vec[1]];
this.fixIntersections(points, 0);

this.ecs.editComponent(pos.entity, "interaction", {
shape: shapeLine(new Line(points[0], points[1], points[2], points[3])),
});

if (points.length > 4) {
pos.x = points[0];
pos.y = points[1];
wall.vec[0] = points[2] - pos.x;
wall.vec[1] = points[3] - pos.y;
}

this.redrawWall(pos, wall);

let plen = points.length;
let cIds = [];
for (let i = 4; i < plen; i += 2) {
cIds.push(this.createWall(
points[i - 2], points[i - 1],
points[i], points[i + 1]
));
}
if (cIds.length > 0) {
this.phase.selection.addEntities(cIds);
// TODO: optimization, update the selection only once!
}
}
for (let wall of walls) {
this.ecs.addComponent(wall.entity, {
type: "visibility_blocker",
entity: -1
} as VisibilityBlocker);
}
}


private onComponentEdited(comp: Component, changed: any): void {
if (comp.type === 'player_visible') {
let c = comp as PlayerVisibleComponent;
Expand All @@ -134,10 +262,10 @@ export class WallSystem implements System {

if (wall === undefined || position === undefined) return;

/*if (!this.isTranslating) {
this.fixWallPreTranslation(wall);
this.fixWallPostTranslation(wall);
}*/
if (!this.isTranslating) {
this.fixWallPreTranslation([wall]);
this.fixWallPostTranslation([wall]);
}

if (comp.type === 'position') {
wall._display.position.set(position.x, position.y);
Expand Down Expand Up @@ -191,7 +319,6 @@ export class WallSystem implements System {
let lls = res as LocalLightSettings;
let visAll = lls.visionType === 'dm';
for (let c of this.storage.allComponents()) {
console.log("Setting visibility: " + visAll + ", " + c.visible + " to " + c.entity);
c._display.visible = visAll || c.visible;
}
}
Expand Down Expand Up @@ -264,8 +391,8 @@ export class WallSystem implements System {
return end;
}

private createWall(minX: number, minY: number, maxX: number, maxY: number): void {
let id = this.ecs.spawnEntity(
private createWall(minX: number, minY: number, maxX: number, maxY: number): number {
return this.ecs.spawnEntity(
{
type: 'position',
entity: -1,
Expand All @@ -279,7 +406,6 @@ export class WallSystem implements System {
_selected: true,
} as WallComponent,
);
this.createdIds.push(id);
}

addVertex(point: PIXI.Point): void {
Expand All @@ -295,10 +421,10 @@ export class WallSystem implements System {
let plen = points.length;

for (let i = 2; i < plen; i += 2) {
this.createWall(
this.createdIds.push(this.createWall(
points[i - 2], points[i - 1],
points[i ], points[i + 1]
);
));
}
this.createdLastPos = [point.x, point.y];
}
Expand Down
70 changes: 39 additions & 31 deletions src/app/game/selectionGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ export class SelectionGroup {

onEntityDespawn(entity: number) {
if (!this.selectedEntities.has(entity)) return;
this.removeEntity(entity);
this.update();
this.removeEntities([entity]);
}

clear(callListeners: boolean = true, update: boolean = true) {
Expand All @@ -96,7 +95,7 @@ export class SelectionGroup {

setOnlyEntity(id: number): void {
this.clear(true, false);
this.addEntity(id);
this.addEntities([id]);
}

setOnlyEntities(ids: number[]): void {
Expand All @@ -106,44 +105,53 @@ export class SelectionGroup {
for (let id of this.selectedEntities) {
if (!idSet.has(id)) removeIds.push(id);
}
for (let id of removeIds) {
this.removeEntity(id);
}
for (let id of ids) {
if (this.selectedEntities.has(id)) continue;
this.addEntity(id);
}
this.removeEntities(removeIds, false);
this.addEntities(ids, false);
this.update();
}

toggleEntity(id: number): void {
if (this.selectedEntities.has(id)) {
this.removeEntity(id);
} else {
this.addEntity(id);
toggleEntities(ids: number[], update: boolean=true): void {
for (let id of ids) {
if (this.selectedEntities.has(id)) {
this.removeEntities([id], false);
} else {
this.addEntities([id], false);
}
}
if (update) this.update();
}

addEntity(id: number): void {
this.selectedEntities.add(id);
addEntities(ids: number[], update: boolean=true): void {
let count = 0;
for (let id of ids) {
if (this.selectedEntities.has(id)) continue;
count++;
this.selectedEntities.add(id);

let comps = this.ecs.getAllComponents(id);
for (let c of comps) {
this.getOrCreateData(c.type).entities.add(c);
let comps = this.ecs.getAllComponents(id);
for (let c of comps) {
this.getOrCreateData(c.type).entities.add(c);
}
this.ecs.events.emit('selection_begin', id);
}
this.ecs.events.emit('selection_begin', id);
this.update();
if (update && count !== 0) this.update();
}

removeEntity(id: number): void {
this.selectedEntities.delete(id)
let comps = this.ecs.getAllComponents(id);
for (let c of comps) {
let data = this.dataByType.get(c.type);
data.entities.delete(c);
if (data.entities.size === 0) this.dataByType.delete(c.type);
removeEntities(ids: number[], update: boolean=true): void {
let count = 0;
for (let id of ids) {
if (!this.selectedEntities.has(id)) continue;
count++;
this.selectedEntities.delete(id)
let comps = this.ecs.getAllComponents(id);
for (let c of comps) {
let data = this.dataByType.get(c.type);
data.entities.delete(c);
if (data.entities.size === 0) this.dataByType.delete(c.type);
}
this.ecs.events.emit('selection_end', id);
}
this.ecs.events.emit('selection_end', id);
this.update();
if (update && count !== 0) this.update();
}

getSelectedByType(type: string): Iterable<Component> {
Expand Down
6 changes: 6 additions & 0 deletions src/app/geometry/collision.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,9 @@ export function triangleContainsPoint(p: StupidPoint, p0: StupidPoint, p1: Stupi
return s - EPSILON > 0 && t - EPSILON > 0 && (s + t) < 2 * A * sign - EPSILON;
}

export function lineSameSlope(ax: number, ay: number, bx: number, by: number): boolean {
// We need to remove divisions, (this is not real code)
// ay / ax == by / bx ==> ay * bx == by * ax
return Math.abs(ay * bx - by * ax) < EPSILON;
}

4 changes: 1 addition & 3 deletions src/app/phase/editMap/editMapPhase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,7 @@ export class EditMapPhase extends BirdEyePhase {
this.selection.clear();
}
} else {
for (let id of entities) {
this.selection.toggleEntity(id);
}
this.selection.toggleEntities(entities);
}
}
}
Expand Down

0 comments on commit 7435a10

Please sign in to comment.