mirror of
https://github.com/tobspr/shapez.io.git
synced 2026-03-02 03:39:21 +00:00
Huge refactoring of the whole placement logic
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { DrawParameters } from "../../core/draw_parameters";
|
||||
import { WiredPinsComponent, enumPinSlotType } from "../components/wired_pins";
|
||||
import { Loader } from "../../core/loader";
|
||||
import { Vector } from "../../core/vector";
|
||||
import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins";
|
||||
import { Entity } from "../entity";
|
||||
import { GameSystemWithFilter } from "../game_system_with_filter";
|
||||
import { MapChunkView } from "../map_chunk_view";
|
||||
import { Loader } from "../../core/loader";
|
||||
import { enumLayer } from "../root";
|
||||
|
||||
export class WiredPinsSystem extends GameSystemWithFilter {
|
||||
constructor(root) {
|
||||
@@ -20,6 +21,127 @@ export class WiredPinsSystem extends GameSystemWithFilter {
|
||||
"sprites/wires/pin_negative_accept.png"
|
||||
),
|
||||
};
|
||||
|
||||
this.root.signals.prePlacementCheck.add(this.prePlacementCheck, this);
|
||||
this.root.signals.freeEntityAreaBeforeBuild.add(this.freeEntityAreaBeforeBuild, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs pre-placement checks
|
||||
* @param {Entity} entity
|
||||
* @param {Vector} offset
|
||||
*/
|
||||
prePlacementCheck(entity, offset) {
|
||||
// Compute area of the building
|
||||
const rect = entity.components.StaticMapEntity.getTileSpaceBounds();
|
||||
if (offset) {
|
||||
rect.x += offset.x;
|
||||
rect.y += offset.y;
|
||||
}
|
||||
|
||||
// If this entity is placed on the wires layer, make sure we don't
|
||||
// place it above a pin
|
||||
if (entity.layer === enumLayer.wires) {
|
||||
for (let x = rect.x; x < rect.x + rect.w; ++x) {
|
||||
for (let y = rect.y; y < rect.y + rect.h; ++y) {
|
||||
// Find which entities are in same tiles of both layers
|
||||
const entities = this.root.map.getLayersContentsMultipleXY(x, y);
|
||||
for (let i = 0; i < entities.length; ++i) {
|
||||
const otherEntity = entities[i];
|
||||
|
||||
// Check if entity has a wired component
|
||||
const pinComponent = otherEntity.components.WiredPins;
|
||||
const staticComp = otherEntity.components.StaticMapEntity;
|
||||
if (!pinComponent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (otherEntity.components.ReplaceableMapEntity) {
|
||||
// Don't mind here, even if there would be a collision we
|
||||
// could replace it
|
||||
continue;
|
||||
}
|
||||
|
||||
// Go over all pins and check if they are blocking
|
||||
const pins = pinComponent.slots;
|
||||
for (let pinSlot = 0; pinSlot < pins.length; ++pinSlot) {
|
||||
const pos = staticComp.localTileToWorld(pins[pinSlot].pos);
|
||||
// Occupied by a pin
|
||||
if (pos.x === x && pos.y === y) {
|
||||
return STOP_PROPAGATION;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for collisions on the wires layer
|
||||
if (this.checkEntityPinsCollide(entity, offset)) {
|
||||
return STOP_PROPAGATION;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the pins of the given entity collide on the wires layer
|
||||
* @param {Entity} entity
|
||||
* @param {Vector=} offset Optional, move the entity by the given offset first
|
||||
* @returns {boolean} True if the pins collide
|
||||
*/
|
||||
checkEntityPinsCollide(entity, offset) {
|
||||
const pinsComp = entity.components.WiredPins;
|
||||
if (!pinsComp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Go over all slots
|
||||
for (let slotIndex = 0; slotIndex < pinsComp.slots.length; ++slotIndex) {
|
||||
const slot = pinsComp.slots[slotIndex];
|
||||
|
||||
// Figure out which tile this slot is on
|
||||
const worldPos = entity.components.StaticMapEntity.localTileToWorld(slot.pos);
|
||||
if (offset) {
|
||||
worldPos.x += offset.x;
|
||||
worldPos.y += offset.y;
|
||||
}
|
||||
|
||||
// Check if there is any entity on that tile (Wired pins are always on the wires layer)
|
||||
const collidingEntity = this.root.map.getLayerContentXY(worldPos.x, worldPos.y, enumLayer.wires);
|
||||
|
||||
// If there's an entity, and it can't get removed -> That's a collision
|
||||
if (collidingEntity && !collidingEntity.components.ReplaceableMapEntity) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to free space for the given entity
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
freeEntityAreaBeforeBuild(entity) {
|
||||
const pinsComp = entity.components.WiredPins;
|
||||
if (!pinsComp) {
|
||||
// Entity has no pins
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove any stuff which collides with the pins
|
||||
for (let i = 0; i < pinsComp.slots.length; ++i) {
|
||||
const slot = pinsComp.slots[i];
|
||||
const worldPos = entity.components.StaticMapEntity.localTileToWorld(slot.pos);
|
||||
const collidingEntity = this.root.map.getLayerContentXY(worldPos.x, worldPos.y, enumLayer.wires);
|
||||
if (collidingEntity) {
|
||||
assertAlways(
|
||||
collidingEntity.components.ReplaceableMapEntity,
|
||||
"Tried to replace non-repleaceable entity for pins"
|
||||
);
|
||||
if (!this.root.logic.tryDeleteBuilding(collidingEntity)) {
|
||||
assertAlways(false, "Tried to replace non-repleaceable entity for pins #2");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
|
||||
Reference in New Issue
Block a user