From 989ed2db87d09a20d2491f59999a912b06343ea3 Mon Sep 17 00:00:00 2001 From: tobspr Date: Tue, 30 Jun 2020 08:23:05 +0200 Subject: [PATCH] Fix wires placement not snapping --- src/js/game/buildings/belt.js | 52 +++++ src/js/game/buildings/belt_base.js | 67 ++----- src/js/game/buildings/underground_belt.js | 13 +- src/js/game/buildings/wire_base.js | 182 +----------------- src/js/game/hud/parts/building_placer.js | 38 ++-- .../game/hud/parts/building_placer_logic.js | 11 +- src/js/game/logic.js | 6 +- src/js/game/meta_building.js | 12 +- src/js/game/meta_building_registry.js | 3 +- src/js/game/systems/belt.js | 72 ++++--- 10 files changed, 154 insertions(+), 302 deletions(-) create mode 100644 src/js/game/buildings/belt.js diff --git a/src/js/game/buildings/belt.js b/src/js/game/buildings/belt.js new file mode 100644 index 00000000..1fb80b88 --- /dev/null +++ b/src/js/game/buildings/belt.js @@ -0,0 +1,52 @@ +import { Loader } from "../../core/loader"; +import { enumDirection } from "../../core/vector"; +import { SOUNDS } from "../../platform/sound"; +import { arrayBeltVariantToRotation, MetaBeltBaseBuilding } from "./belt_base"; + +export class MetaBeltBuilding extends MetaBeltBaseBuilding { + constructor() { + super("belt"); + } + + getSilhouetteColor() { + return "#777"; + } + + getPlacementSound() { + return SOUNDS.placeBelt; + } + + getPreviewSprite(rotationVariant) { + switch (arrayBeltVariantToRotation[rotationVariant]) { + case enumDirection.top: { + return Loader.getSprite("sprites/buildings/belt_top.png"); + } + case enumDirection.left: { + return Loader.getSprite("sprites/buildings/belt_left.png"); + } + case enumDirection.right: { + return Loader.getSprite("sprites/buildings/belt_right.png"); + } + default: { + assertAlways(false, "Invalid belt rotation variant"); + } + } + } + + getBlueprintSprite(rotationVariant) { + switch (arrayBeltVariantToRotation[rotationVariant]) { + case enumDirection.top: { + return Loader.getSprite("sprites/blueprints/belt_top.png"); + } + case enumDirection.left: { + return Loader.getSprite("sprites/blueprints/belt_left.png"); + } + case enumDirection.right: { + return Loader.getSprite("sprites/blueprints/belt_right.png"); + } + default: { + assertAlways(false, "Invalid belt rotation variant"); + } + } + } +} diff --git a/src/js/game/buildings/belt_base.js b/src/js/game/buildings/belt_base.js index 57f1e32b..fa91af97 100644 --- a/src/js/game/buildings/belt_base.js +++ b/src/js/game/buildings/belt_base.js @@ -14,14 +14,6 @@ import { GameRoot, enumLayer } from "../root"; export const arrayBeltVariantToRotation = [enumDirection.top, enumDirection.left, enumDirection.right]; export class MetaBeltBaseBuilding extends MetaBuilding { - constructor() { - super("belt"); - } - - getSilhouetteColor() { - return "#777"; - } - getHasDirectionLockAvailable() { return true; } @@ -33,44 +25,9 @@ export class MetaBeltBaseBuilding extends MetaBuilding { */ getAdditionalStatistics(root, variant) { const beltSpeed = root.hubGoals.getBeltBaseSpeed(); - return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(beltSpeed)]]; } - getPreviewSprite(rotationVariant) { - switch (arrayBeltVariantToRotation[rotationVariant]) { - case enumDirection.top: { - return Loader.getSprite("sprites/buildings/belt_top.png"); - } - case enumDirection.left: { - return Loader.getSprite("sprites/buildings/belt_left.png"); - } - case enumDirection.right: { - return Loader.getSprite("sprites/buildings/belt_right.png"); - } - default: { - assertAlways(false, "Invalid belt rotation variant"); - } - } - } - - getBlueprintSprite(rotationVariant) { - switch (arrayBeltVariantToRotation[rotationVariant]) { - case enumDirection.top: { - return Loader.getSprite("sprites/blueprints/belt_top.png"); - } - case enumDirection.left: { - return Loader.getSprite("sprites/blueprints/belt_left.png"); - } - case enumDirection.right: { - return Loader.getSprite("sprites/blueprints/belt_right.png"); - } - default: { - assertAlways(false, "Invalid belt rotation variant"); - } - } - } - getStayInPlacementMode() { return true; } @@ -93,6 +50,8 @@ export class MetaBeltBaseBuilding extends MetaBuilding { direction: enumDirection.top, // updated later }) ); + // Make this entity replaceabel + entity.addComponent(new ReplaceableMapEntityComponent()); entity.addComponent( new ItemAcceptorComponent({ @@ -100,6 +59,7 @@ export class MetaBeltBaseBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.bottom], + layer: this.getLayer(), }, ], animated: false, @@ -112,13 +72,12 @@ export class MetaBeltBaseBuilding extends MetaBuilding { { pos: new Vector(0, 0), direction: enumDirection.top, // updated later + layer: this.getLayer(), }, ], instantEject: true, }) ); - // Make this entity replaceabel - entity.addComponent(new ReplaceableMapEntityComponent()); } /** @@ -133,20 +92,22 @@ export class MetaBeltBaseBuilding extends MetaBuilding { } /** - * Computes optimal belt rotation variant - * @param {GameRoot} root - * @param {Vector} tile - * @param {number} rotation - * @param {string} variant - * @return {{ rotation: number, rotationVariant: number }} + * Should compute the optimal rotation variant on the given tile + * @param {object} param0 + * @param {GameRoot} param0.root + * @param {Vector} param0.tile + * @param {number} param0.rotation + * @param {string} param0.variant + * @param {string} param0.layer + * @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array }} */ - computeOptimalDirectionAndRotationVariantAtTile(root, tile, rotation, variant) { + computeOptimalDirectionAndRotationVariantAtTile({ root, tile, rotation, variant, layer }) { const topDirection = enumAngleToDirection[rotation]; const rightDirection = enumAngleToDirection[(rotation + 90) % 360]; const bottomDirection = enumAngleToDirection[(rotation + 180) % 360]; const leftDirection = enumAngleToDirection[(rotation + 270) % 360]; - const { ejectors, acceptors } = root.logic.getEjectorsAndAcceptorsAtTile(tile, enumLayer.regular); + const { ejectors, acceptors } = root.logic.getEjectorsAndAcceptorsAtTile(tile, layer); let hasBottomEjector = false; let hasRightEjector = false; diff --git a/src/js/game/buildings/underground_belt.js b/src/js/game/buildings/underground_belt.js index 99d9c406..99004b99 100644 --- a/src/js/game/buildings/underground_belt.js +++ b/src/js/game/buildings/underground_belt.js @@ -131,13 +131,16 @@ export class MetaUndergroundBeltBuilding extends MetaBuilding { } /** - * @param {GameRoot} root - * @param {Vector} tile - * @param {number} rotation - * @param {string} variant + * Should compute the optimal rotation variant on the given tile + * @param {object} param0 + * @param {GameRoot} param0.root + * @param {Vector} param0.tile + * @param {number} param0.rotation + * @param {string} param0.variant + * @param {string} param0.layer * @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array }} */ - computeOptimalDirectionAndRotationVariantAtTile(root, tile, rotation, variant) { + computeOptimalDirectionAndRotationVariantAtTile({ root, tile, rotation, variant, layer }) { const searchDirection = enumAngleToDirection[rotation]; const searchVector = enumDirectionToVector[searchDirection]; const tier = enumUndergroundBeltVariantToTier[variant]; diff --git a/src/js/game/buildings/wire_base.js b/src/js/game/buildings/wire_base.js index b89dc109..6f3ffec8 100644 --- a/src/js/game/buildings/wire_base.js +++ b/src/js/game/buildings/wire_base.js @@ -1,17 +1,9 @@ import { Loader } from "../../core/loader"; -import { enumAngleToDirection, enumDirection, Vector } from "../../core/vector"; -import { SOUNDS } from "../../platform/sound"; -import { BeltComponent } from "../components/belt"; -import { ItemAcceptorComponent } from "../components/item_acceptor"; -import { ItemEjectorComponent } from "../components/item_ejector"; -import { ReplaceableMapEntityComponent } from "../components/replaceable_map_entity"; -import { Entity } from "../entity"; -import { MetaBuilding } from "../meta_building"; -import { enumLayer, GameRoot } from "../root"; +import { enumDirection } from "../../core/vector"; +import { enumLayer } from "../root"; +import { arrayBeltVariantToRotation, MetaBeltBaseBuilding } from "./belt_base"; -export const arrayBeltVariantToRotation = [enumDirection.top, enumDirection.left, enumDirection.right]; - -export class MetaWireBaseBuilding extends MetaBuilding { +export class MetaWireBaseBuilding extends MetaBeltBaseBuilding { constructor() { super("wire"); } @@ -24,10 +16,6 @@ export class MetaWireBaseBuilding extends MetaBuilding { return enumLayer.wires; } - getHasDirectionLockAvailable() { - return true; - } - getPreviewSprite(rotationVariant) { switch (arrayBeltVariantToRotation[rotationVariant]) { case enumDirection.top: { @@ -61,166 +49,4 @@ export class MetaWireBaseBuilding extends MetaBuilding { } } } - - getStayInPlacementMode() { - return true; - } - - getRotateAutomaticallyWhilePlacing() { - return true; - } - - getPlacementSound() { - return SOUNDS.placeBelt; - } - - /** - * Creates the entity at the given location - * @param {Entity} entity - */ - setupEntityComponents(entity) { - entity.addComponent( - new BeltComponent({ - direction: enumDirection.top, // updated later - }) - ); - - entity.addComponent( - new ItemAcceptorComponent({ - slots: [ - { - pos: new Vector(0, 0), - directions: [enumDirection.bottom], - layer: enumLayer.wires, - }, - ], - animated: false, - }) - ); - - entity.addComponent( - new ItemEjectorComponent({ - slots: [ - { - pos: new Vector(0, 0), - direction: enumDirection.top, // updated later - layer: enumLayer.wires, - }, - ], - instantEject: true, - }) - ); - // Make this entity replaceable - entity.addComponent(new ReplaceableMapEntityComponent()); - } - - /** - * @param {Entity} entity - * @param {number} rotationVariant - */ - updateVariants(entity, rotationVariant) { - entity.components.Belt.direction = arrayBeltVariantToRotation[rotationVariant]; - entity.components.ItemEjector.slots[0].direction = arrayBeltVariantToRotation[rotationVariant]; - entity.components.StaticMapEntity.spriteKey = null; - } - - /** - * Computes optimal belt rotation variant - * @param {GameRoot} root - * @param {Vector} tile - * @param {number} rotation - * @param {string} variant - * @return {{ rotation: number, rotationVariant: number }} - */ - computeOptimalDirectionAndRotationVariantAtTile(root, tile, rotation, variant) { - const topDirection = enumAngleToDirection[rotation]; - const rightDirection = enumAngleToDirection[(rotation + 90) % 360]; - const bottomDirection = enumAngleToDirection[(rotation + 180) % 360]; - const leftDirection = enumAngleToDirection[(rotation + 270) % 360]; - - const { ejectors, acceptors } = root.logic.getEjectorsAndAcceptorsAtTile(tile, enumLayer.wires); - - let hasBottomEjector = false; - let hasRightEjector = false; - let hasLeftEjector = false; - - let hasTopAcceptor = false; - let hasLeftAcceptor = false; - let hasRightAcceptor = false; - - // Check all ejectors - for (let i = 0; i < ejectors.length; ++i) { - const ejector = ejectors[i]; - - if (ejector.toDirection === topDirection) { - hasBottomEjector = true; - } else if (ejector.toDirection === leftDirection) { - hasRightEjector = true; - } else if (ejector.toDirection === rightDirection) { - hasLeftEjector = true; - } - } - - // Check all acceptors - for (let i = 0; i < acceptors.length; ++i) { - const acceptor = acceptors[i]; - if (acceptor.fromDirection === bottomDirection) { - hasTopAcceptor = true; - } else if (acceptor.fromDirection === rightDirection) { - hasLeftAcceptor = true; - } else if (acceptor.fromDirection === leftDirection) { - hasRightAcceptor = true; - } - } - - // Soo .. if there is any ejector below us we always prioritize - // this ejector - if (!hasBottomEjector) { - // When something ejects to us from the left and nothing from the right, - // do a curve from the left to the top - - if (hasRightEjector && !hasLeftEjector) { - return { - rotation: (rotation + 270) % 360, - rotationVariant: 2, - }; - } - - // When something ejects to us from the right and nothing from the left, - // do a curve from the right to the top - if (hasLeftEjector && !hasRightEjector) { - return { - rotation: (rotation + 90) % 360, - rotationVariant: 1, - }; - } - } - - // When there is a top acceptor, ignore sides - // NOTICE: This makes the belt prefer side turns *way* too much! - if (!hasTopAcceptor) { - // When there is an acceptor to the right but no acceptor to the left, - // do a turn to the right - if (hasRightAcceptor && !hasLeftAcceptor) { - return { - rotation, - rotationVariant: 2, - }; - } - - // When there is an acceptor to the left but no acceptor to the right, - // do a turn to the left - if (hasLeftAcceptor && !hasRightAcceptor) { - return { - rotation, - rotationVariant: 1, - }; - } - } - - return { - rotation, - rotationVariant: 0, - }; - } } diff --git a/src/js/game/hud/parts/building_placer.js b/src/js/game/hud/parts/building_placer.js index 970d7870..1621bf43 100644 --- a/src/js/game/hud/parts/building_placer.js +++ b/src/js/game/hud/parts/building_placer.js @@ -230,12 +230,13 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { rotation, rotationVariant, connectedEntities, - } = metaBuilding.computeOptimalDirectionAndRotationVariantAtTile( - this.root, - mouseTile, - this.currentBaseRotation, - this.currentVariant.get() - ); + } = metaBuilding.computeOptimalDirectionAndRotationVariantAtTile({ + root: this.root, + tile: mouseTile, + rotation: this.currentBaseRotation, + variant: this.currentVariant.get(), + layer: metaBuilding.getLayer(), + }); // Check if there are connected entities if (connectedEntities) { @@ -411,12 +412,15 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { const worldDirection = staticComp.localDirectionToWorld(direction); const sourceTile = acceptorSlotWsTile.add(enumDirectionToVector[worldDirection]); - const sourceEntity = this.root.map.getTileContent(sourceTile, this.root.currentLayer); - let sprite = goodArrowSprite; - let alpha = 0.5; + let alpha = 0.3; - if (sourceEntity) { + const sourceEntities = this.root.map.getLayersContentsMultipleXY( + sourceTile.x, + sourceTile.y + ); + for (let i = 0; i < sourceEntities.length; ++i) { + const sourceEntity = sourceEntities[i]; sprite = badArrowSprite; const sourceEjector = sourceEntity.components.ItemEjector; const sourceStaticComp = sourceEntity.components.StaticMapEntity; @@ -462,15 +466,19 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { const ejectorSLotWsPos = ejectorSlotWsTile.toWorldSpaceCenterOfTile(); const ejectorSlotWsDirection = staticComp.localDirectionToWorld(slot.direction); - const destEntity = this.root.map.getTileContent(ejectorSlotWsTile, this.root.currentLayer); - let sprite = goodArrowSprite; - let alpha = 0.5; - if (destEntity) { + let alpha = 0.3; + + const destEntities = this.root.map.getLayersContentsMultipleXY( + ejectorSlotWsTile.x, + ejectorSlotWsTile.y + ); + + for (let i = 0; i < destEntities.length; ++i) { alpha = 1; + const destEntity = destEntities[i]; const destAcceptor = destEntity.components.ItemAcceptor; const destStaticComp = destEntity.components.StaticMapEntity; - if (destAcceptor) { const destLocalTile = destStaticComp.worldToLocalTile(ejectorSlotWsTile); const destLocalDir = destStaticComp.worldDirectionToLocal(ejectorSlotWsDirection); diff --git a/src/js/game/hud/parts/building_placer_logic.js b/src/js/game/hud/parts/building_placer_logic.js index 147a34b5..d0737df8 100644 --- a/src/js/game/hud/parts/building_placer_logic.js +++ b/src/js/game/hud/parts/building_placer_logic.js @@ -444,12 +444,13 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { } const metaBuilding = this.currentMetaBuilding.get(); - const { rotation, rotationVariant } = metaBuilding.computeOptimalDirectionAndRotationVariantAtTile( - this.root, + const { rotation, rotationVariant } = metaBuilding.computeOptimalDirectionAndRotationVariantAtTile({ + root: this.root, tile, - this.currentBaseRotation, - this.currentVariant.get() - ); + rotation: this.currentBaseRotation, + variant: this.currentVariant.get(), + layer: metaBuilding.getLayer(), + }); const entity = this.root.logic.tryPlaceBuilding({ origin: tile, diff --git a/src/js/game/logic.js b/src/js/game/logic.js index e6ca02bf..075c27fe 100644 --- a/src/js/game/logic.js +++ b/src/js/game/logic.js @@ -272,8 +272,10 @@ export class GameLogic { continue; } - const entity = this.root.map.getLayerContentXY(tile.x + dx, tile.y + dy, layer); - if (entity) { + const entities = this.root.map.getLayersContentsMultipleXY(tile.x + dx, tile.y + dy); + for (let i = 0; i < entities.length; ++i) { + const entity = entities[i]; + const staticComp = entity.components.StaticMapEntity; const itemEjector = entity.components.ItemEjector; if (itemEjector) { diff --git a/src/js/game/meta_building.js b/src/js/game/meta_building.js index 335f1b17..15919d02 100644 --- a/src/js/game/meta_building.js +++ b/src/js/game/meta_building.js @@ -204,13 +204,15 @@ export class MetaBuilding { /** * Should compute the optimal rotation variant on the given tile - * @param {GameRoot} root - * @param {Vector} tile - * @param {number} rotation - * @param {string} variant + * @param {object} param0 + * @param {GameRoot} param0.root + * @param {Vector} param0.tile + * @param {number} param0.rotation + * @param {string} param0.variant + * @param {string} param0.layer * @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array }} */ - computeOptimalDirectionAndRotationVariantAtTile(root, tile, rotation, variant) { + computeOptimalDirectionAndRotationVariantAtTile({ root, tile, rotation, variant, layer }) { if (!this.isRotateable(variant)) { return { rotation: 0, diff --git a/src/js/game/meta_building_registry.js b/src/js/game/meta_building_registry.js index 2d175365..2e99ce43 100644 --- a/src/js/game/meta_building_registry.js +++ b/src/js/game/meta_building_registry.js @@ -13,6 +13,7 @@ import { MetaHubBuilding } from "./buildings/hub"; import { MetaEnergyGenerator } from "./buildings/energy_generator"; import { MetaWireBaseBuilding } from "./buildings/wire_base"; import { MetaAdvancedProcessorBuilding } from "./buildings/advanced_processor"; +import { MetaBeltBuilding } from "./buildings/belt"; export function initMetaBuildingRegistry() { gMetaBuildingRegistry.register(MetaSplitterBuilding); @@ -23,7 +24,7 @@ export function initMetaBuildingRegistry() { gMetaBuildingRegistry.register(MetaMixerBuilding); gMetaBuildingRegistry.register(MetaPainterBuilding); gMetaBuildingRegistry.register(MetaTrashBuilding); - gMetaBuildingRegistry.register(MetaBeltBaseBuilding); + gMetaBuildingRegistry.register(MetaBeltBuilding); gMetaBuildingRegistry.register(MetaUndergroundBeltBuilding); gMetaBuildingRegistry.register(MetaHubBuilding); gMetaBuildingRegistry.register(MetaEnergyGenerator); diff --git a/src/js/game/systems/belt.js b/src/js/game/systems/belt.js index be8a8973..2ea544e6 100644 --- a/src/js/game/systems/belt.js +++ b/src/js/game/systems/belt.js @@ -132,11 +132,7 @@ export class BeltSystem extends GameSystemWithFilter { return; } - /* BIG HACK: We don't actually store the meta building */ - const metaBelt = gMetaBuildingRegistry.findByClass( - entity.layer === enumLayer.regular ? MetaBeltBaseBuilding : MetaWireBaseBuilding - ); - + const metaBelt = gMetaBuildingRegistry.findByClass(MetaBeltBaseBuilding); // Compute affected area const originalRect = staticComp.getTileSpaceBounds(); const affectedArea = originalRect.expandedInAllDirections(1); @@ -148,47 +144,47 @@ export class BeltSystem extends GameSystemWithFilter { continue; } - const targetEntity = this.root.map.getLayerContentXY(x, y, entity.layer); - if (!targetEntity) { - // Empty tile - continue; - } + const targetEntities = this.root.map.getLayersContentsMultipleXY(x, y, entity.layer); + for (let i = 0; i < targetEntities.length; ++i) { + const targetEntity = targetEntities[i]; - const targetBeltComp = targetEntity.components.Belt; - const targetStaticComp = targetEntity.components.StaticMapEntity; + const targetBeltComp = targetEntity.components.Belt; + const targetStaticComp = targetEntity.components.StaticMapEntity; - if (!targetBeltComp) { - // Not a belt - continue; - } + if (!targetBeltComp) { + // Not a belt + continue; + } - const { - rotation, - rotationVariant, - } = metaBelt.computeOptimalDirectionAndRotationVariantAtTile( - this.root, - new Vector(x, y), - targetStaticComp.originalRotation, - defaultBuildingVariant - ); + const { + rotation, + rotationVariant, + } = metaBelt.computeOptimalDirectionAndRotationVariantAtTile({ + root: this.root, + tile: new Vector(x, y), + rotation: targetStaticComp.originalRotation, + variant: defaultBuildingVariant, + layer: targetEntity.layer, + }); - // Compute delta to see if anything changed - const newDirection = arrayBeltVariantToRotation[rotationVariant]; + // Compute delta to see if anything changed + const newDirection = arrayBeltVariantToRotation[rotationVariant]; - if (targetStaticComp.rotation !== rotation || newDirection !== targetBeltComp.direction) { - // Ok, first remove it from its current path - this.deleteEntityFromPath(targetBeltComp.assignedPath, targetEntity); + if (targetStaticComp.rotation !== rotation || newDirection !== targetBeltComp.direction) { + // Ok, first remove it from its current path + this.deleteEntityFromPath(targetBeltComp.assignedPath, targetEntity); - // Change stuff - targetStaticComp.rotation = rotation; - metaBelt.updateVariants(targetEntity, rotationVariant, defaultBuildingVariant); + // Change stuff + targetStaticComp.rotation = rotation; + metaBelt.updateVariants(targetEntity, rotationVariant, defaultBuildingVariant); - // Now add it again - this.addEntityToPaths(targetEntity); + // Now add it again + this.addEntityToPaths(targetEntity); - // Sanity - if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { - this.debug_verifyBeltPaths(); + // Sanity + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_verifyBeltPaths(); + } } } }