From 8344f8ad686ccbb9ba734a8183b52be505af64c0 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Mon, 22 Nov 2021 15:20:55 -0600 Subject: [PATCH 01/14] slightly refactor belt drawing --- src/js/game/systems/belt.js | 52 +++++++++++---------------- src/js/game/systems/belt_underlays.js | 14 ++++---- 2 files changed, 27 insertions(+), 39 deletions(-) diff --git a/src/js/game/systems/belt.js b/src/js/game/systems/belt.js index 00491eff..c083df24 100644 --- a/src/js/game/systems/belt.js +++ b/src/js/game/systems/belt.js @@ -496,51 +496,41 @@ export class BeltSystem extends GameSystemWithFilter { drawChunk(parameters, chunk) { // Limit speed to avoid belts going backwards const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(), 10); - - // SYNC with systems/item_acceptor.js:drawEntityUnderlays! + // SYNC with systems/belt_underlays.js:drawChunk! // 126 / 42 is the exact animation speed of the png animation const animationIndex = Math.floor( ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * globalConfig.itemSpacingOnBelts ); - const contents = chunk.containedEntitiesByLayer.regular; - if (this.root.app.settings.getAllSettings().simplifiedBelts) { + const simplifiedBelts = this.root.app.settings.getAllSettings().simplifiedBelts; + + let hoveredBeltPath = null; + if (simplifiedBelts) { // POTATO Mode: Only show items when belt is hovered - let hoveredBeltPath = null; const mousePos = this.root.app.mousePosition; if (mousePos && this.root.currentLayer === "regular") { const tile = this.root.camera.screenToWorld(mousePos).toTileSpace(); - const contents = this.root.map.getLayerContentXY(tile.x, tile.y, "regular"); - if (contents && contents.components.Belt) { - hoveredBeltPath = contents.components.Belt.assignedPath; + const entity = this.root.map.getLayerContentXY(tile.x, tile.y, "regular"); + if (entity && entity.components.Belt) { + hoveredBeltPath = entity.components.Belt.assignedPath; } } + } - for (let i = 0; i < contents.length; ++i) { - const entity = contents[i]; - if (entity.components.Belt) { - const direction = entity.components.Belt.direction; - let sprite = this.beltAnimations[direction][0]; + const contents = chunk.containedEntitiesByLayer.regular; + for (let i = 0; i < contents.length; ++i) { + const entity = contents[i]; + if (entity.components.Belt) { + const { direction, assignedPath } = entity.components.Belt; + const sprite = this.beltAnimations[direction][ + !simplifiedBelts || assignedPath === hoveredBeltPath + ? animationIndex % BELT_ANIM_COUNT + : 0 + ]; - if (entity.components.Belt.assignedPath === hoveredBeltPath) { - sprite = this.beltAnimations[direction][animationIndex % BELT_ANIM_COUNT]; - } - - // Culling happens within the static map entity component - entity.components.StaticMapEntity.drawSpriteOnBoundsClipped(parameters, sprite, 0); - } - } - } else { - for (let i = 0; i < contents.length; ++i) { - const entity = contents[i]; - if (entity.components.Belt) { - const direction = entity.components.Belt.direction; - const sprite = this.beltAnimations[direction][animationIndex % BELT_ANIM_COUNT]; - - // Culling happens within the static map entity component - entity.components.StaticMapEntity.drawSpriteOnBoundsClipped(parameters, sprite, 0); - } + // Culling happens within the static map entity component + entity.components.StaticMapEntity.drawSpriteOnBoundsClipped(parameters, sprite, 0); } } } diff --git a/src/js/game/systems/belt_underlays.js b/src/js/game/systems/belt_underlays.js index c5c69d26..9cd59112 100644 --- a/src/js/game/systems/belt_underlays.js +++ b/src/js/game/systems/belt_underlays.js @@ -224,6 +224,11 @@ export class BeltUnderlaysSystem extends GameSystemWithFilter { drawChunk(parameters, chunk) { // Limit speed to avoid belts going backwards const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(), 10); + // SYNC with systems/belt.js:drawChunk! + const animationIndex = Math.floor( + ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * + globalConfig.itemSpacingOnBelts + ); const contents = chunk.containedEntitiesByLayer.regular; for (let i = 0; i < contents.length; ++i) { @@ -275,16 +280,9 @@ export class BeltUnderlaysSystem extends GameSystemWithFilter { const y = destY + globalConfig.halfTileSize; const angleRadians = Math.radians(angle); - // SYNC with systems/belt.js:drawSingleEntity! - const animationIndex = Math.floor( - ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * - globalConfig.itemSpacingOnBelts - ); parameters.context.translate(x, y); parameters.context.rotate(angleRadians); - this.underlayBeltSprites[ - animationIndex % this.underlayBeltSprites.length - ].drawCachedWithClipRect( + this.underlayBeltSprites[animationIndex % BELT_ANIM_COUNT].drawCachedWithClipRect( parameters, -globalConfig.halfTileSize, -globalConfig.halfTileSize, From 654643c5b032979e3d4b89714583e7448c38c205 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Tue, 23 Nov 2021 21:03:55 -0600 Subject: [PATCH 02/14] infer underlays from acceptors and ejectors --- src/js/game/game_system_manager.js | 14 +- src/js/game/map_chunk_view.js | 3 +- src/js/game/systems/acceptor_belt.js | 117 ++++++++++ src/js/game/systems/belt_underlays.js | 298 -------------------------- src/js/game/systems/ejector_belt.js | 113 ++++++++++ 5 files changed, 242 insertions(+), 303 deletions(-) create mode 100644 src/js/game/systems/acceptor_belt.js delete mode 100644 src/js/game/systems/belt_underlays.js create mode 100644 src/js/game/systems/ejector_belt.js diff --git a/src/js/game/game_system_manager.js b/src/js/game/game_system_manager.js index 08609f89..ef1e53fc 100644 --- a/src/js/game/game_system_manager.js +++ b/src/js/game/game_system_manager.js @@ -14,7 +14,6 @@ import { StaticMapEntitySystem } from "./systems/static_map_entity"; import { ItemAcceptorSystem } from "./systems/item_acceptor"; import { StorageSystem } from "./systems/storage"; import { WiredPinsSystem } from "./systems/wired_pins"; -import { BeltUnderlaysSystem } from "./systems/belt_underlays"; import { WireSystem } from "./systems/wire"; import { ConstantSignalSystem } from "./systems/constant_signal"; import { LogicGateSystem } from "./systems/logic_gate"; @@ -27,6 +26,8 @@ import { ItemProducerSystem } from "./systems/item_producer"; import { ConstantProducerSystem } from "./systems/constant_producer"; import { GoalAcceptorSystem } from "./systems/goal_acceptor"; import { ZoneSystem } from "./systems/zone"; +import { AcceptorBeltSystem } from "./systems/acceptor_belt"; +import { EjectorBeltSystem } from "./systems/ejector_belt"; const logger = createLogger("game_system_manager"); @@ -73,8 +74,11 @@ export class GameSystemManager { /** @type {WiredPinsSystem} */ wiredPins: null, - /** @type {BeltUnderlaysSystem} */ - beltUnderlays: null, + /** @type {AcceptorBeltSystem} */ + acceptorBelt: null, + + /** @type {EjectorBeltSystem} */ + ejectorBelt: null, /** @type {WireSystem} */ wire: null, @@ -160,7 +164,9 @@ export class GameSystemManager { add("wiredPins", WiredPinsSystem); - add("beltUnderlays", BeltUnderlaysSystem); + add("acceptorBelt", AcceptorBeltSystem); + + add("ejectorBelt", EjectorBeltSystem); add("constantSignal", ConstantSignalSystem); diff --git a/src/js/game/map_chunk_view.js b/src/js/game/map_chunk_view.js index 947b7a9f..d824e4d4 100644 --- a/src/js/game/map_chunk_view.js +++ b/src/js/game/map_chunk_view.js @@ -50,7 +50,8 @@ export class MapChunkView extends MapChunk { systems.mapResources.drawChunk(parameters, this); } - systems.beltUnderlays.drawChunk(parameters, this); + systems.acceptorBelt.drawChunk(parameters, this); + systems.ejectorBelt.drawChunk(parameters, this); systems.belt.drawChunk(parameters, this); } diff --git a/src/js/game/systems/acceptor_belt.js b/src/js/game/systems/acceptor_belt.js new file mode 100644 index 00000000..7c8ecfdd --- /dev/null +++ b/src/js/game/systems/acceptor_belt.js @@ -0,0 +1,117 @@ +import { globalConfig } from "../../core/config"; +import { DrawParameters } from "../../core/draw_parameters"; +import { Loader } from "../../core/loader"; +import { Rectangle } from "../../core/rectangle"; +import { FULL_CLIP_RECT } from "../../core/sprites"; +import { enumDirectionToAngle, enumInvertedDirections } from "../../core/vector"; +import { enumClippedBeltUnderlayType } from "../components/belt_underlays"; +import { ItemAcceptorComponent } from "../components/item_acceptor"; +import { GameSystemWithFilter } from "../game_system_with_filter"; +import { MapChunkView } from "../map_chunk_view"; +import { BELT_ANIM_COUNT } from "./belt"; + +/** + * Mapping from underlay type to clip rect + * @type {Object} + */ +const enumUnderlayTypeToClipRect = { + [enumClippedBeltUnderlayType.none]: null, + [enumClippedBeltUnderlayType.full]: FULL_CLIP_RECT, + [enumClippedBeltUnderlayType.topOnly]: new Rectangle(0, 0, 1, 0.5), + [enumClippedBeltUnderlayType.bottomOnly]: new Rectangle(0, 0.5, 1, 0.5), +}; + +export class AcceptorBeltSystem extends GameSystemWithFilter { + constructor(root) { + super(root, [ItemAcceptorComponent]); + + this.underlayBeltSprites = []; + + for (let i = 0; i < BELT_ANIM_COUNT; ++i) { + this.underlayBeltSprites.push(Loader.getSprite("sprites/belt/built/forward_" + i + ".png")); + } + } + + /** + * Draws a given chunk + * @param {DrawParameters} parameters + * @param {MapChunkView} chunk + */ + drawChunk(parameters, chunk) { + // Limit speed to avoid belts going backwards + const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(), 10); + // SYNC with systems/belt.js:drawChunk! + const animationIndex = Math.floor( + ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * + globalConfig.itemSpacingOnBelts + ); + + const contents = chunk.containedEntitiesByLayer.regular; + for (let i = 0; i < contents.length; ++i) { + const entity = contents[i]; + const acceptorComp = entity.components.ItemAcceptor; + if (!acceptorComp) { + continue; + } + + const staticComp = entity.components.StaticMapEntity; + for (let i = 0; i < acceptorComp.slots.length; ++i) { + // Extract underlay parameters + const { pos, directions } = acceptorComp.slots[i]; + const transformedPos = staticComp.localTileToWorld(pos); + const destX = transformedPos.x * globalConfig.tileSize; + const destY = transformedPos.y * globalConfig.tileSize; + + // Culling, Part 1: Check if the chunk contains the tile + if (!chunk.tileSpaceRectangle.containsPoint(transformedPos.x, transformedPos.y)) { + continue; + } + + // Culling, Part 2: Check if the overlay is visible + if ( + !parameters.visibleRect.containsRect4Params( + destX, + destY, + globalConfig.tileSize, + globalConfig.tileSize + ) + ) { + continue; + } + + for (let j = 0; j < directions.length; ++j) { + const direction = directions[j]; + + // Extract direction and angle + const worldDirection = staticComp.localDirectionToWorld(direction); + const angle = enumDirectionToAngle[enumInvertedDirections[worldDirection]]; + + const underlayType = enumClippedBeltUnderlayType.bottomOnly; + const clipRect = enumUnderlayTypeToClipRect[underlayType]; + if (!clipRect) { + // Empty + continue; + } + + // Actually draw the sprite + const x = destX + globalConfig.halfTileSize; + const y = destY + globalConfig.halfTileSize; + const angleRadians = Math.radians(angle); + + parameters.context.translate(x, y); + parameters.context.rotate(angleRadians); + this.underlayBeltSprites[animationIndex % BELT_ANIM_COUNT].drawCachedWithClipRect( + parameters, + -globalConfig.halfTileSize, + -globalConfig.halfTileSize, + globalConfig.tileSize, + globalConfig.tileSize, + clipRect + ); + parameters.context.rotate(-angleRadians); + parameters.context.translate(-x, -y); + } + } + } + } +} diff --git a/src/js/game/systems/belt_underlays.js b/src/js/game/systems/belt_underlays.js deleted file mode 100644 index 9cd59112..00000000 --- a/src/js/game/systems/belt_underlays.js +++ /dev/null @@ -1,298 +0,0 @@ -import { globalConfig } from "../../core/config"; -import { DrawParameters } from "../../core/draw_parameters"; -import { Loader } from "../../core/loader"; -import { Rectangle } from "../../core/rectangle"; -import { FULL_CLIP_RECT } from "../../core/sprites"; -import { StaleAreaDetector } from "../../core/stale_area_detector"; -import { - enumDirection, - enumDirectionToAngle, - enumDirectionToVector, - enumInvertedDirections, - Vector, -} from "../../core/vector"; -import { BeltComponent } from "../components/belt"; -import { BeltUnderlaysComponent, enumClippedBeltUnderlayType } from "../components/belt_underlays"; -import { ItemAcceptorComponent } from "../components/item_acceptor"; -import { ItemEjectorComponent } from "../components/item_ejector"; -import { Entity } from "../entity"; -import { GameSystemWithFilter } from "../game_system_with_filter"; -import { MapChunkView } from "../map_chunk_view"; -import { BELT_ANIM_COUNT } from "./belt"; - -/** - * Mapping from underlay type to clip rect - * @type {Object} - */ -const enumUnderlayTypeToClipRect = { - [enumClippedBeltUnderlayType.none]: null, - [enumClippedBeltUnderlayType.full]: FULL_CLIP_RECT, - [enumClippedBeltUnderlayType.topOnly]: new Rectangle(0, 0, 1, 0.5), - [enumClippedBeltUnderlayType.bottomOnly]: new Rectangle(0, 0.5, 1, 0.5), -}; - -export class BeltUnderlaysSystem extends GameSystemWithFilter { - constructor(root) { - super(root, [BeltUnderlaysComponent]); - - this.underlayBeltSprites = []; - - for (let i = 0; i < BELT_ANIM_COUNT; ++i) { - this.underlayBeltSprites.push(Loader.getSprite("sprites/belt/built/forward_" + i + ".png")); - } - - // Automatically recompute areas - this.staleArea = new StaleAreaDetector({ - root, - name: "belt-underlay", - recomputeMethod: this.recomputeStaleArea.bind(this), - }); - - this.staleArea.recomputeOnComponentsChanged( - [BeltUnderlaysComponent, BeltComponent, ItemAcceptorComponent, ItemEjectorComponent], - 1 - ); - } - - update() { - this.staleArea.update(); - } - - /** - * Called when an area changed - Resets all caches in the given area - * @param {Rectangle} area - */ - recomputeStaleArea(area) { - for (let x = 0; x < area.w; ++x) { - for (let y = 0; y < area.h; ++y) { - const tileX = area.x + x; - const tileY = area.y + y; - const entity = this.root.map.getLayerContentXY(tileX, tileY, "regular"); - if (entity) { - const underlayComp = entity.components.BeltUnderlays; - if (underlayComp) { - for (let i = 0; i < underlayComp.underlays.length; ++i) { - underlayComp.underlays[i].cachedType = null; - } - } - } - } - } - } - - /** - * Checks if a given tile is connected and has an acceptor - * @param {Vector} tile - * @param {enumDirection} fromDirection - * @returns {boolean} - */ - checkIsAcceptorConnected(tile, fromDirection) { - const contents = this.root.map.getLayerContentXY(tile.x, tile.y, "regular"); - if (!contents) { - return false; - } - - const staticComp = contents.components.StaticMapEntity; - - // Check if its a belt, since then its simple - const beltComp = contents.components.Belt; - if (beltComp) { - return staticComp.localDirectionToWorld(enumDirection.bottom) === fromDirection; - } - - // Check if there's an item acceptor - const acceptorComp = contents.components.ItemAcceptor; - if (acceptorComp) { - // Check each slot to see if its connected - for (let i = 0; i < acceptorComp.slots.length; ++i) { - const slot = acceptorComp.slots[i]; - const slotTile = staticComp.localTileToWorld(slot.pos); - - // Step 1: Check if the tile matches - if (!slotTile.equals(tile)) { - continue; - } - - // Step 2: Check if any of the directions matches - for (let j = 0; j < slot.directions.length; ++j) { - const slotDirection = staticComp.localDirectionToWorld(slot.directions[j]); - if (slotDirection === fromDirection) { - return true; - } - } - } - } - - return false; - } - - /** - * Checks if a given tile is connected and has an ejector - * @param {Vector} tile - * @param {enumDirection} toDirection - * @returns {boolean} - */ - checkIsEjectorConnected(tile, toDirection) { - const contents = this.root.map.getLayerContentXY(tile.x, tile.y, "regular"); - if (!contents) { - return false; - } - - const staticComp = contents.components.StaticMapEntity; - - // Check if its a belt, since then its simple - const beltComp = contents.components.Belt; - if (beltComp) { - return staticComp.localDirectionToWorld(beltComp.direction) === toDirection; - } - - // Check for an ejector - const ejectorComp = contents.components.ItemEjector; - if (ejectorComp) { - // Check each slot to see if its connected - for (let i = 0; i < ejectorComp.slots.length; ++i) { - const slot = ejectorComp.slots[i]; - const slotTile = staticComp.localTileToWorld(slot.pos); - - // Step 1: Check if the tile matches - if (!slotTile.equals(tile)) { - continue; - } - - // Step 2: Check if the direction matches - const slotDirection = staticComp.localDirectionToWorld(slot.direction); - if (slotDirection === toDirection) { - return true; - } - } - } - - return false; - } - - /** - * Computes the flag for a given tile - * @param {Entity} entity - * @param {import("../components/belt_underlays").BeltUnderlayTile} underlayTile - * @returns {enumClippedBeltUnderlayType} The type of the underlay - */ - computeBeltUnderlayType(entity, underlayTile) { - if (underlayTile.cachedType) { - return underlayTile.cachedType; - } - - const staticComp = entity.components.StaticMapEntity; - - const transformedPos = staticComp.localTileToWorld(underlayTile.pos); - const destX = transformedPos.x * globalConfig.tileSize; - const destY = transformedPos.y * globalConfig.tileSize; - - // Extract direction and angle - const worldDirection = staticComp.localDirectionToWorld(underlayTile.direction); - const worldDirectionVector = enumDirectionToVector[worldDirection]; - - // Figure out if there is anything connected at the top - const connectedTop = this.checkIsAcceptorConnected( - transformedPos.add(worldDirectionVector), - enumInvertedDirections[worldDirection] - ); - - // Figure out if there is anything connected at the bottom - const connectedBottom = this.checkIsEjectorConnected( - transformedPos.sub(worldDirectionVector), - worldDirection - ); - - let flag = enumClippedBeltUnderlayType.none; - - if (connectedTop && connectedBottom) { - flag = enumClippedBeltUnderlayType.full; - } else if (connectedTop) { - flag = enumClippedBeltUnderlayType.topOnly; - } else if (connectedBottom) { - flag = enumClippedBeltUnderlayType.bottomOnly; - } - - return (underlayTile.cachedType = flag); - } - - /** - * Draws a given chunk - * @param {DrawParameters} parameters - * @param {MapChunkView} chunk - */ - drawChunk(parameters, chunk) { - // Limit speed to avoid belts going backwards - const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(), 10); - // SYNC with systems/belt.js:drawChunk! - const animationIndex = Math.floor( - ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * - globalConfig.itemSpacingOnBelts - ); - - const contents = chunk.containedEntitiesByLayer.regular; - for (let i = 0; i < contents.length; ++i) { - const entity = contents[i]; - const underlayComp = entity.components.BeltUnderlays; - if (!underlayComp) { - continue; - } - - const staticComp = entity.components.StaticMapEntity; - const underlays = underlayComp.underlays; - for (let i = 0; i < underlays.length; ++i) { - // Extract underlay parameters - const { pos, direction } = underlays[i]; - const transformedPos = staticComp.localTileToWorld(pos); - const destX = transformedPos.x * globalConfig.tileSize; - const destY = transformedPos.y * globalConfig.tileSize; - - // Culling, Part 1: Check if the chunk contains the tile - if (!chunk.tileSpaceRectangle.containsPoint(transformedPos.x, transformedPos.y)) { - continue; - } - - // Culling, Part 2: Check if the overlay is visible - if ( - !parameters.visibleRect.containsRect4Params( - destX, - destY, - globalConfig.tileSize, - globalConfig.tileSize - ) - ) { - continue; - } - - // Extract direction and angle - const worldDirection = staticComp.localDirectionToWorld(direction); - const angle = enumDirectionToAngle[worldDirection]; - - const underlayType = this.computeBeltUnderlayType(entity, underlays[i]); - const clipRect = enumUnderlayTypeToClipRect[underlayType]; - if (!clipRect) { - // Empty - continue; - } - - // Actually draw the sprite - const x = destX + globalConfig.halfTileSize; - const y = destY + globalConfig.halfTileSize; - const angleRadians = Math.radians(angle); - - parameters.context.translate(x, y); - parameters.context.rotate(angleRadians); - this.underlayBeltSprites[animationIndex % BELT_ANIM_COUNT].drawCachedWithClipRect( - parameters, - -globalConfig.halfTileSize, - -globalConfig.halfTileSize, - globalConfig.tileSize, - globalConfig.tileSize, - clipRect - ); - parameters.context.rotate(-angleRadians); - parameters.context.translate(-x, -y); - } - } - } -} diff --git a/src/js/game/systems/ejector_belt.js b/src/js/game/systems/ejector_belt.js new file mode 100644 index 00000000..cb0c86fa --- /dev/null +++ b/src/js/game/systems/ejector_belt.js @@ -0,0 +1,113 @@ +import { globalConfig } from "../../core/config"; +import { DrawParameters } from "../../core/draw_parameters"; +import { Loader } from "../../core/loader"; +import { Rectangle } from "../../core/rectangle"; +import { FULL_CLIP_RECT } from "../../core/sprites"; +import { enumDirectionToAngle } from "../../core/vector"; +import { enumClippedBeltUnderlayType } from "../components/belt_underlays"; +import { ItemEjectorComponent } from "../components/item_ejector"; +import { GameSystemWithFilter } from "../game_system_with_filter"; +import { MapChunkView } from "../map_chunk_view"; +import { BELT_ANIM_COUNT } from "./belt"; + +/** + * Mapping from underlay type to clip rect + * @type {Object} + */ +const enumUnderlayTypeToClipRect = { + [enumClippedBeltUnderlayType.none]: null, + [enumClippedBeltUnderlayType.full]: FULL_CLIP_RECT, + [enumClippedBeltUnderlayType.topOnly]: new Rectangle(0, 0, 1, 0.5), + [enumClippedBeltUnderlayType.bottomOnly]: new Rectangle(0, 0.5, 1, 0.5), +}; + +export class EjectorBeltSystem extends GameSystemWithFilter { + constructor(root) { + super(root, [ItemEjectorComponent]); + + this.underlayBeltSprites = []; + + for (let i = 0; i < BELT_ANIM_COUNT; ++i) { + this.underlayBeltSprites.push(Loader.getSprite("sprites/belt/built/forward_" + i + ".png")); + } + } + + /** + * Draws a given chunk + * @param {DrawParameters} parameters + * @param {MapChunkView} chunk + */ + drawChunk(parameters, chunk) { + // Limit speed to avoid belts going backwards + const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(), 10); + // SYNC with systems/belt.js:drawChunk! + const animationIndex = Math.floor( + ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * + globalConfig.itemSpacingOnBelts + ); + + const contents = chunk.containedEntitiesByLayer.regular; + for (let i = 0; i < contents.length; ++i) { + const entity = contents[i]; + const ejectorComp = entity.components.ItemEjector; + if (!ejectorComp) { + continue; + } + + const staticComp = entity.components.StaticMapEntity; + for (let i = 0; i < ejectorComp.slots.length; ++i) { + // Extract underlay parameters + const { pos, direction } = ejectorComp.slots[i]; + const transformedPos = staticComp.localTileToWorld(pos); + const destX = transformedPos.x * globalConfig.tileSize; + const destY = transformedPos.y * globalConfig.tileSize; + + // Culling, Part 1: Check if the chunk contains the tile + if (!chunk.tileSpaceRectangle.containsPoint(transformedPos.x, transformedPos.y)) { + continue; + } + + // Culling, Part 2: Check if the overlay is visible + if ( + !parameters.visibleRect.containsRect4Params( + destX, + destY, + globalConfig.tileSize, + globalConfig.tileSize + ) + ) { + continue; + } + + // Extract direction and angle + const worldDirection = staticComp.localDirectionToWorld(direction); + const angle = enumDirectionToAngle[worldDirection]; + + const underlayType = enumClippedBeltUnderlayType.topOnly; + const clipRect = enumUnderlayTypeToClipRect[underlayType]; + if (!clipRect) { + // Empty + continue; + } + + // Actually draw the sprite + const x = destX + globalConfig.halfTileSize; + const y = destY + globalConfig.halfTileSize; + const angleRadians = Math.radians(angle); + + parameters.context.translate(x, y); + parameters.context.rotate(angleRadians); + this.underlayBeltSprites[animationIndex % BELT_ANIM_COUNT].drawCachedWithClipRect( + parameters, + -globalConfig.halfTileSize, + -globalConfig.halfTileSize, + globalConfig.tileSize, + globalConfig.tileSize, + clipRect + ); + parameters.context.rotate(-angleRadians); + parameters.context.translate(-x, -y); + } + } + } +} From 10db2af21caf6a366cc7742a1cae2c95b7a912f0 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Tue, 23 Nov 2021 23:08:49 -0600 Subject: [PATCH 03/14] remove belt underlays component --- src/js/game/buildings/balancer.js | 16 -- src/js/game/buildings/reader.js | 218 +++++++++++------------ src/js/game/component_registry.js | 2 - src/js/game/components/belt_underlays.js | 41 ----- src/js/game/entity_components.js | 4 - src/js/game/systems/acceptor_belt.js | 20 +-- src/js/game/systems/ejector_belt.js | 20 +-- 7 files changed, 105 insertions(+), 216 deletions(-) delete mode 100644 src/js/game/components/belt_underlays.js diff --git a/src/js/game/buildings/balancer.js b/src/js/game/buildings/balancer.js index 38a568e1..fceae40a 100644 --- a/src/js/game/buildings/balancer.js +++ b/src/js/game/buildings/balancer.js @@ -8,7 +8,6 @@ import { GameRoot } from "../root"; import { enumHubGoalRewards } from "../tutorial_goals"; import { T } from "../../translations"; import { formatItemsPerSecond, generateMatrixRotations } from "../../core/utils"; -import { BeltUnderlaysComponent } from "../components/belt_underlays"; /** @enum {string} */ export const enumBalancerVariants = { @@ -138,8 +137,6 @@ export class MetaBalancerBuilding extends MetaBuilding { renderFloatingItems: false, }) ); - - entity.addComponent(new BeltUnderlaysComponent({ underlays: [] })); } /** @@ -167,11 +164,6 @@ export class MetaBalancerBuilding extends MetaBuilding { { pos: new Vector(1, 0), direction: enumDirection.top }, ]); - entity.components.BeltUnderlays.underlays = [ - { pos: new Vector(0, 0), direction: enumDirection.top }, - { pos: new Vector(1, 0), direction: enumDirection.top }, - ]; - break; } case enumBalancerVariants.merger: @@ -195,10 +187,6 @@ export class MetaBalancerBuilding extends MetaBuilding { { pos: new Vector(0, 0), direction: enumDirection.top }, ]); - entity.components.BeltUnderlays.underlays = [ - { pos: new Vector(0, 0), direction: enumDirection.top }, - ]; - break; } case enumBalancerVariants.splitter: @@ -224,10 +212,6 @@ export class MetaBalancerBuilding extends MetaBuilding { }, ]); - entity.components.BeltUnderlays.underlays = [ - { pos: new Vector(0, 0), direction: enumDirection.top }, - ]; - break; } default: diff --git a/src/js/game/buildings/reader.js b/src/js/game/buildings/reader.js index 006d6582..0af95b6d 100644 --- a/src/js/game/buildings/reader.js +++ b/src/js/game/buildings/reader.js @@ -1,115 +1,103 @@ -import { enumDirection, Vector } from "../../core/vector"; -import { ItemAcceptorComponent } from "../components/item_acceptor"; -import { ItemEjectorComponent } from "../components/item_ejector"; -import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; -import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins"; -import { Entity } from "../entity"; -import { MetaBuilding } from "../meta_building"; -import { GameRoot } from "../root"; -import { BeltUnderlaysComponent } from "../components/belt_underlays"; -import { BeltReaderComponent } from "../components/belt_reader"; -import { enumHubGoalRewards } from "../tutorial_goals"; -import { generateMatrixRotations } from "../../core/utils"; - -const overlayMatrix = generateMatrixRotations([0, 1, 0, 0, 1, 0, 0, 1, 0]); - -export class MetaReaderBuilding extends MetaBuilding { - constructor() { - super("reader"); - } - - getSilhouetteColor() { - return "#25fff2"; - } - - /** - * @param {GameRoot} root - */ - getIsUnlocked(root) { - return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_belt_reader); - } - - getDimensions() { - return new Vector(1, 1); - } - - getShowWiresLayerPreview() { - return true; - } - - /** - * @param {number} rotation - * @param {number} rotationVariant - * @param {string} variant - * @param {Entity} entity - * @returns {Array|null} - */ - getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) { - return overlayMatrix[rotation]; - } - - /** - * Creates the entity at the given location - * @param {Entity} entity - */ - setupEntityComponents(entity) { - entity.addComponent( - new WiredPinsComponent({ - slots: [ - { - pos: new Vector(0, 0), - direction: enumDirection.right, - type: enumPinSlotType.logicalEjector, - }, - { - pos: new Vector(0, 0), - direction: enumDirection.left, - type: enumPinSlotType.logicalEjector, - }, - ], - }) - ); - - entity.addComponent( - new ItemAcceptorComponent({ - slots: [ - { - pos: new Vector(0, 0), - directions: [enumDirection.bottom], - }, - ], - }) - ); - - entity.addComponent( - new ItemEjectorComponent({ - slots: [ - { - pos: new Vector(0, 0), - direction: enumDirection.top, - }, - ], - }) - ); - - entity.addComponent( - new ItemProcessorComponent({ - processorType: enumItemProcessorTypes.reader, - inputsPerCharge: 1, - }) - ); - - entity.addComponent( - new BeltUnderlaysComponent({ - underlays: [ - { - pos: new Vector(0, 0), - direction: enumDirection.top, - }, - ], - }) - ); - - entity.addComponent(new BeltReaderComponent()); - } -} +import { enumDirection, Vector } from "../../core/vector"; +import { ItemAcceptorComponent } from "../components/item_acceptor"; +import { ItemEjectorComponent } from "../components/item_ejector"; +import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; +import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins"; +import { Entity } from "../entity"; +import { MetaBuilding } from "../meta_building"; +import { GameRoot } from "../root"; +import { BeltReaderComponent } from "../components/belt_reader"; +import { enumHubGoalRewards } from "../tutorial_goals"; +import { generateMatrixRotations } from "../../core/utils"; + +const overlayMatrix = generateMatrixRotations([0, 1, 0, 0, 1, 0, 0, 1, 0]); + +export class MetaReaderBuilding extends MetaBuilding { + constructor() { + super("reader"); + } + + getSilhouetteColor() { + return "#25fff2"; + } + + /** + * @param {GameRoot} root + */ + getIsUnlocked(root) { + return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_belt_reader); + } + + getDimensions() { + return new Vector(1, 1); + } + + getShowWiresLayerPreview() { + return true; + } + + /** + * @param {number} rotation + * @param {number} rotationVariant + * @param {string} variant + * @param {Entity} entity + * @returns {Array|null} + */ + getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) { + return overlayMatrix[rotation]; + } + + /** + * Creates the entity at the given location + * @param {Entity} entity + */ + setupEntityComponents(entity) { + entity.addComponent( + new WiredPinsComponent({ + slots: [ + { + pos: new Vector(0, 0), + direction: enumDirection.right, + type: enumPinSlotType.logicalEjector, + }, + { + pos: new Vector(0, 0), + direction: enumDirection.left, + type: enumPinSlotType.logicalEjector, + }, + ], + }) + ); + + entity.addComponent( + new ItemAcceptorComponent({ + slots: [ + { + pos: new Vector(0, 0), + directions: [enumDirection.bottom], + }, + ], + }) + ); + + entity.addComponent( + new ItemEjectorComponent({ + slots: [ + { + pos: new Vector(0, 0), + direction: enumDirection.top, + }, + ], + }) + ); + + entity.addComponent( + new ItemProcessorComponent({ + processorType: enumItemProcessorTypes.reader, + inputsPerCharge: 1, + }) + ); + + entity.addComponent(new BeltReaderComponent()); + } +} diff --git a/src/js/game/component_registry.js b/src/js/game/component_registry.js index 9c9247e6..daba7987 100644 --- a/src/js/game/component_registry.js +++ b/src/js/game/component_registry.js @@ -9,7 +9,6 @@ import { UndergroundBeltComponent } from "./components/underground_belt"; import { HubComponent } from "./components/hub"; import { StorageComponent } from "./components/storage"; import { WiredPinsComponent } from "./components/wired_pins"; -import { BeltUnderlaysComponent } from "./components/belt_underlays"; import { WireComponent } from "./components/wire"; import { ConstantSignalComponent } from "./components/constant_signal"; import { LogicGateComponent } from "./components/logic_gate"; @@ -32,7 +31,6 @@ export function initComponentRegistry() { gComponentRegistry.register(HubComponent); gComponentRegistry.register(StorageComponent); gComponentRegistry.register(WiredPinsComponent); - gComponentRegistry.register(BeltUnderlaysComponent); gComponentRegistry.register(WireComponent); gComponentRegistry.register(ConstantSignalComponent); gComponentRegistry.register(LogicGateComponent); diff --git a/src/js/game/components/belt_underlays.js b/src/js/game/components/belt_underlays.js deleted file mode 100644 index 63b265d0..00000000 --- a/src/js/game/components/belt_underlays.js +++ /dev/null @@ -1,41 +0,0 @@ -import { enumDirection, Vector } from "../../core/vector"; -import { Component } from "../component"; - -/** - * Store which type an underlay is, this is cached so we can easily - * render it. - * - * Full: Render underlay at top and bottom of tile - * Bottom Only: Only render underlay at the bottom half - * Top Only: - * @enum {string} - */ -export const enumClippedBeltUnderlayType = { - full: "full", - bottomOnly: "bottomOnly", - topOnly: "topOnly", - none: "none", -}; - -/** - * @typedef {{ - * pos: Vector, - * direction: enumDirection, - * cachedType?: enumClippedBeltUnderlayType - * }} BeltUnderlayTile - */ - -export class BeltUnderlaysComponent extends Component { - static getId() { - return "BeltUnderlays"; - } - - /** - * @param {object} param0 - * @param {Array=} param0.underlays Where to render belt underlays - */ - constructor({ underlays = [] }) { - super(); - this.underlays = underlays; - } -} diff --git a/src/js/game/entity_components.js b/src/js/game/entity_components.js index 163be9f9..f0bd2a06 100644 --- a/src/js/game/entity_components.js +++ b/src/js/game/entity_components.js @@ -1,6 +1,5 @@ /* typehints:start */ import { BeltComponent } from "./components/belt"; -import { BeltUnderlaysComponent } from "./components/belt_underlays"; import { HubComponent } from "./components/hub"; import { ItemAcceptorComponent } from "./components/item_acceptor"; import { ItemEjectorComponent } from "./components/item_ejector"; @@ -60,9 +59,6 @@ export class EntityComponentStorage { /** @type {WiredPinsComponent} */ this.WiredPins; - /** @type {BeltUnderlaysComponent} */ - this.BeltUnderlays; - /** @type {WireComponent} */ this.Wire; diff --git a/src/js/game/systems/acceptor_belt.js b/src/js/game/systems/acceptor_belt.js index 7c8ecfdd..f8e2e3e4 100644 --- a/src/js/game/systems/acceptor_belt.js +++ b/src/js/game/systems/acceptor_belt.js @@ -2,25 +2,12 @@ import { globalConfig } from "../../core/config"; import { DrawParameters } from "../../core/draw_parameters"; import { Loader } from "../../core/loader"; import { Rectangle } from "../../core/rectangle"; -import { FULL_CLIP_RECT } from "../../core/sprites"; import { enumDirectionToAngle, enumInvertedDirections } from "../../core/vector"; -import { enumClippedBeltUnderlayType } from "../components/belt_underlays"; import { ItemAcceptorComponent } from "../components/item_acceptor"; import { GameSystemWithFilter } from "../game_system_with_filter"; import { MapChunkView } from "../map_chunk_view"; import { BELT_ANIM_COUNT } from "./belt"; -/** - * Mapping from underlay type to clip rect - * @type {Object} - */ -const enumUnderlayTypeToClipRect = { - [enumClippedBeltUnderlayType.none]: null, - [enumClippedBeltUnderlayType.full]: FULL_CLIP_RECT, - [enumClippedBeltUnderlayType.topOnly]: new Rectangle(0, 0, 1, 0.5), - [enumClippedBeltUnderlayType.bottomOnly]: new Rectangle(0, 0.5, 1, 0.5), -}; - export class AcceptorBeltSystem extends GameSystemWithFilter { constructor(root) { super(root, [ItemAcceptorComponent]); @@ -86,12 +73,7 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { const worldDirection = staticComp.localDirectionToWorld(direction); const angle = enumDirectionToAngle[enumInvertedDirections[worldDirection]]; - const underlayType = enumClippedBeltUnderlayType.bottomOnly; - const clipRect = enumUnderlayTypeToClipRect[underlayType]; - if (!clipRect) { - // Empty - continue; - } + const clipRect = new Rectangle(0, 0.5, 1, 0.5); // Actually draw the sprite const x = destX + globalConfig.halfTileSize; diff --git a/src/js/game/systems/ejector_belt.js b/src/js/game/systems/ejector_belt.js index cb0c86fa..18ef4981 100644 --- a/src/js/game/systems/ejector_belt.js +++ b/src/js/game/systems/ejector_belt.js @@ -2,25 +2,12 @@ import { globalConfig } from "../../core/config"; import { DrawParameters } from "../../core/draw_parameters"; import { Loader } from "../../core/loader"; import { Rectangle } from "../../core/rectangle"; -import { FULL_CLIP_RECT } from "../../core/sprites"; import { enumDirectionToAngle } from "../../core/vector"; -import { enumClippedBeltUnderlayType } from "../components/belt_underlays"; import { ItemEjectorComponent } from "../components/item_ejector"; import { GameSystemWithFilter } from "../game_system_with_filter"; import { MapChunkView } from "../map_chunk_view"; import { BELT_ANIM_COUNT } from "./belt"; -/** - * Mapping from underlay type to clip rect - * @type {Object} - */ -const enumUnderlayTypeToClipRect = { - [enumClippedBeltUnderlayType.none]: null, - [enumClippedBeltUnderlayType.full]: FULL_CLIP_RECT, - [enumClippedBeltUnderlayType.topOnly]: new Rectangle(0, 0, 1, 0.5), - [enumClippedBeltUnderlayType.bottomOnly]: new Rectangle(0, 0.5, 1, 0.5), -}; - export class EjectorBeltSystem extends GameSystemWithFilter { constructor(root) { super(root, [ItemEjectorComponent]); @@ -83,12 +70,7 @@ export class EjectorBeltSystem extends GameSystemWithFilter { const worldDirection = staticComp.localDirectionToWorld(direction); const angle = enumDirectionToAngle[worldDirection]; - const underlayType = enumClippedBeltUnderlayType.topOnly; - const clipRect = enumUnderlayTypeToClipRect[underlayType]; - if (!clipRect) { - // Empty - continue; - } + const clipRect = new Rectangle(0, 0, 1, 0.5); // Actually draw the sprite const x = destX + globalConfig.halfTileSize; From 88b12c685dc3e222555debf63c69985d94eec6b5 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Wed, 24 Nov 2021 00:05:13 -0600 Subject: [PATCH 04/14] optional belt length for acceptors/ejectors --- src/js/game/buildings/balancer.js | 15 ++++++++++++--- src/js/game/buildings/reader.js | 2 ++ src/js/game/components/item_acceptor.js | 3 +++ src/js/game/components/item_ejector.js | 6 ++++-- src/js/game/systems/acceptor_belt.js | 9 +++++++-- src/js/game/systems/ejector_belt.js | 9 +++++++-- 6 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/js/game/buildings/balancer.js b/src/js/game/buildings/balancer.js index fceae40a..42b54e82 100644 --- a/src/js/game/buildings/balancer.js +++ b/src/js/game/buildings/balancer.js @@ -152,16 +152,18 @@ export class MetaBalancerBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.bottom], + beltLength: 0.5, }, { pos: new Vector(1, 0), directions: [enumDirection.bottom], + beltLength: 0.5, }, ]); entity.components.ItemEjector.setSlots([ - { pos: new Vector(0, 0), direction: enumDirection.top }, - { pos: new Vector(1, 0), direction: enumDirection.top }, + { pos: new Vector(0, 0), direction: enumDirection.top, beltLength: 0.5 }, + { pos: new Vector(1, 0), direction: enumDirection.top, beltLength: 0.5 }, ]); break; @@ -172,6 +174,7 @@ export class MetaBalancerBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.bottom], + beltLength: 0.5, }, { pos: new Vector(0, 0), @@ -180,11 +183,14 @@ export class MetaBalancerBuilding extends MetaBuilding { ? enumDirection.left : enumDirection.right, ], + // distance to edge of perpendicular belt, ignoring border width + // see generate_belt_sprites.js + beltLength: 23.5 / 192, }, ]); entity.components.ItemEjector.setSlots([ - { pos: new Vector(0, 0), direction: enumDirection.top }, + { pos: new Vector(0, 0), direction: enumDirection.top, beltLength: 0.5 }, ]); break; @@ -195,6 +201,7 @@ export class MetaBalancerBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.bottom], + beltLength: 0.5, }, ]); @@ -202,6 +209,7 @@ export class MetaBalancerBuilding extends MetaBuilding { { pos: new Vector(0, 0), direction: enumDirection.top, + beltLength: 0.5, }, { pos: new Vector(0, 0), @@ -209,6 +217,7 @@ export class MetaBalancerBuilding extends MetaBuilding { variant === enumBalancerVariants.splitterInverse ? enumDirection.left : enumDirection.right, + beltLength: 23.5 / 192, }, ]); diff --git a/src/js/game/buildings/reader.js b/src/js/game/buildings/reader.js index 0af95b6d..dfbb7b03 100644 --- a/src/js/game/buildings/reader.js +++ b/src/js/game/buildings/reader.js @@ -75,6 +75,7 @@ export class MetaReaderBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.bottom], + beltLength: 0.5, }, ], }) @@ -86,6 +87,7 @@ export class MetaReaderBuilding extends MetaBuilding { { pos: new Vector(0, 0), direction: enumDirection.top, + beltLength: 0.5, }, ], }) diff --git a/src/js/game/components/item_acceptor.js b/src/js/game/components/item_acceptor.js index 354f9024..3827f08f 100644 --- a/src/js/game/components/item_acceptor.js +++ b/src/js/game/components/item_acceptor.js @@ -6,6 +6,7 @@ import { Component } from "../component"; /** @typedef {{ * pos: Vector, * directions: enumDirection[], + * beltLength?: number, * filter?: ItemType * }} ItemAcceptorSlot */ @@ -20,6 +21,7 @@ import { Component } from "../component"; /** @typedef {{ * pos: Vector, * directions: enumDirection[], + * beltLength?: number, * filter?: ItemType * }} ItemAcceptorSlotConfig */ @@ -65,6 +67,7 @@ export class ItemAcceptorComponent extends Component { this.slots.push({ pos: slot.pos, directions: slot.directions, + beltLength: slot.beltLength, // Which type of item to accept (shape | color | all) @see ItemType filter: slot.filter, diff --git a/src/js/game/components/item_ejector.js b/src/js/game/components/item_ejector.js index bfc54cd8..1a993dd0 100644 --- a/src/js/game/components/item_ejector.js +++ b/src/js/game/components/item_ejector.js @@ -10,6 +10,7 @@ import { typeItemSingleton } from "../item_resolver"; * @typedef {{ * pos: Vector, * direction: enumDirection, + * beltLength?: number, * item: BaseItem, * lastItem: BaseItem, * progress: number?, @@ -39,7 +40,7 @@ export class ItemEjectorComponent extends Component { /** * * @param {object} param0 - * @param {Array<{pos: Vector, direction: enumDirection }>=} param0.slots The slots to eject on + * @param {Array<{pos: Vector, direction: enumDirection, beltLength?: number }>=} param0.slots The slots to eject on * @param {boolean=} param0.renderFloatingItems Whether to render items even if they are not connected */ constructor({ slots = [], renderFloatingItems = true }) { @@ -58,7 +59,7 @@ export class ItemEjectorComponent extends Component { } /** - * @param {Array<{pos: Vector, direction: enumDirection }>} slots The slots to eject on + * @param {Array<{pos: Vector, direction: enumDirection, beltLength?: number }>} slots The slots to eject on */ setSlots(slots) { /** @type {Array} */ @@ -68,6 +69,7 @@ export class ItemEjectorComponent extends Component { this.slots.push({ pos: slot.pos, direction: slot.direction, + beltLength: slot.beltLength, item: null, lastItem: null, progress: 0, diff --git a/src/js/game/systems/acceptor_belt.js b/src/js/game/systems/acceptor_belt.js index f8e2e3e4..9efa36aa 100644 --- a/src/js/game/systems/acceptor_belt.js +++ b/src/js/game/systems/acceptor_belt.js @@ -43,8 +43,13 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { const staticComp = entity.components.StaticMapEntity; for (let i = 0; i < acceptorComp.slots.length; ++i) { + // skips both missing and 0 belt lengths + if (!acceptorComp.slots[i].beltLength) { + continue; + } + // Extract underlay parameters - const { pos, directions } = acceptorComp.slots[i]; + const { pos, directions, beltLength } = acceptorComp.slots[i]; const transformedPos = staticComp.localTileToWorld(pos); const destX = transformedPos.x * globalConfig.tileSize; const destY = transformedPos.y * globalConfig.tileSize; @@ -73,7 +78,7 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { const worldDirection = staticComp.localDirectionToWorld(direction); const angle = enumDirectionToAngle[enumInvertedDirections[worldDirection]]; - const clipRect = new Rectangle(0, 0.5, 1, 0.5); + const clipRect = new Rectangle(0, 1 - beltLength, 1, beltLength); // Actually draw the sprite const x = destX + globalConfig.halfTileSize; diff --git a/src/js/game/systems/ejector_belt.js b/src/js/game/systems/ejector_belt.js index 18ef4981..0955e570 100644 --- a/src/js/game/systems/ejector_belt.js +++ b/src/js/game/systems/ejector_belt.js @@ -43,8 +43,13 @@ export class EjectorBeltSystem extends GameSystemWithFilter { const staticComp = entity.components.StaticMapEntity; for (let i = 0; i < ejectorComp.slots.length; ++i) { + // skips both missing and 0 belt lengths + if (!ejectorComp.slots[i].beltLength) { + continue; + } + // Extract underlay parameters - const { pos, direction } = ejectorComp.slots[i]; + const { pos, direction, beltLength } = ejectorComp.slots[i]; const transformedPos = staticComp.localTileToWorld(pos); const destX = transformedPos.x * globalConfig.tileSize; const destY = transformedPos.y * globalConfig.tileSize; @@ -70,7 +75,7 @@ export class EjectorBeltSystem extends GameSystemWithFilter { const worldDirection = staticComp.localDirectionToWorld(direction); const angle = enumDirectionToAngle[worldDirection]; - const clipRect = new Rectangle(0, 0, 1, 0.5); + const clipRect = new Rectangle(0, 0, 1, beltLength); // Actually draw the sprite const x = destX + globalConfig.halfTileSize; From ec54093fc64b8aa94be009898672179005e942f8 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Wed, 24 Nov 2021 00:15:53 -0600 Subject: [PATCH 05/14] update belt comments --- src/js/game/systems/acceptor_belt.js | 4 ++-- src/js/game/systems/belt.js | 2 +- src/js/game/systems/ejector_belt.js | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/js/game/systems/acceptor_belt.js b/src/js/game/systems/acceptor_belt.js index 9efa36aa..70f8ed45 100644 --- a/src/js/game/systems/acceptor_belt.js +++ b/src/js/game/systems/acceptor_belt.js @@ -8,6 +8,7 @@ import { GameSystemWithFilter } from "../game_system_with_filter"; import { MapChunkView } from "../map_chunk_view"; import { BELT_ANIM_COUNT } from "./belt"; +// nearly identical to systems/ejector_belt.js export class AcceptorBeltSystem extends GameSystemWithFilter { constructor(root) { super(root, [ItemAcceptorComponent]); @@ -25,9 +26,8 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { * @param {MapChunkView} chunk */ drawChunk(parameters, chunk) { - // Limit speed to avoid belts going backwards - const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(), 10); // SYNC with systems/belt.js:drawChunk! + const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(), 10); const animationIndex = Math.floor( ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * globalConfig.itemSpacingOnBelts diff --git a/src/js/game/systems/belt.js b/src/js/game/systems/belt.js index c083df24..8912d098 100644 --- a/src/js/game/systems/belt.js +++ b/src/js/game/systems/belt.js @@ -494,9 +494,9 @@ export class BeltSystem extends GameSystemWithFilter { * @param {MapChunkView} chunk */ drawChunk(parameters, chunk) { + // SYNC with systems/acceptor_belt.js:drawChunk and systems/ejector_belt.js:drawChunk! // Limit speed to avoid belts going backwards const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(), 10); - // SYNC with systems/belt_underlays.js:drawChunk! // 126 / 42 is the exact animation speed of the png animation const animationIndex = Math.floor( ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * diff --git a/src/js/game/systems/ejector_belt.js b/src/js/game/systems/ejector_belt.js index 0955e570..fcbb869a 100644 --- a/src/js/game/systems/ejector_belt.js +++ b/src/js/game/systems/ejector_belt.js @@ -8,6 +8,7 @@ import { GameSystemWithFilter } from "../game_system_with_filter"; import { MapChunkView } from "../map_chunk_view"; import { BELT_ANIM_COUNT } from "./belt"; +// nearly identical to systems/acceptor_belt.js export class EjectorBeltSystem extends GameSystemWithFilter { constructor(root) { super(root, [ItemEjectorComponent]); @@ -25,9 +26,8 @@ export class EjectorBeltSystem extends GameSystemWithFilter { * @param {MapChunkView} chunk */ drawChunk(parameters, chunk) { - // Limit speed to avoid belts going backwards - const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(), 10); // SYNC with systems/belt.js:drawChunk! + const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(), 10); const animationIndex = Math.floor( ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * globalConfig.itemSpacingOnBelts From fc3de1b58689e3e58ab809688a56a8e23cfd64f4 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Wed, 24 Nov 2021 18:03:59 -0600 Subject: [PATCH 06/14] add acceptor/ejector belts to other buildings --- src/js/game/buildings/balancer.js | 7 +++---- src/js/game/buildings/hub.js | 14 ++++++++++++++ src/js/game/buildings/mixer.js | 2 ++ src/js/game/buildings/painter.js | 1 + src/js/game/buildings/stacker.js | 2 ++ src/js/game/systems/belt.js | 4 ++++ 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/js/game/buildings/balancer.js b/src/js/game/buildings/balancer.js index 42b54e82..35402d15 100644 --- a/src/js/game/buildings/balancer.js +++ b/src/js/game/buildings/balancer.js @@ -8,6 +8,7 @@ import { GameRoot } from "../root"; import { enumHubGoalRewards } from "../tutorial_goals"; import { T } from "../../translations"; import { formatItemsPerSecond, generateMatrixRotations } from "../../core/utils"; +import { BELT_BORDER } from "../systems/belt"; /** @enum {string} */ export const enumBalancerVariants = { @@ -183,9 +184,7 @@ export class MetaBalancerBuilding extends MetaBuilding { ? enumDirection.left : enumDirection.right, ], - // distance to edge of perpendicular belt, ignoring border width - // see generate_belt_sprites.js - beltLength: 23.5 / 192, + beltLength: BELT_BORDER, }, ]); @@ -217,7 +216,7 @@ export class MetaBalancerBuilding extends MetaBuilding { variant === enumBalancerVariants.splitterInverse ? enumDirection.left : enumDirection.right, - beltLength: 23.5 / 192, + beltLength: BELT_BORDER, }, ]); diff --git a/src/js/game/buildings/hub.js b/src/js/game/buildings/hub.js index b9929b31..95647006 100644 --- a/src/js/game/buildings/hub.js +++ b/src/js/game/buildings/hub.js @@ -67,71 +67,85 @@ export class MetaHubBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.top, enumDirection.left], + beltLength: 0.5, filter: "shape", }, { pos: new Vector(1, 0), directions: [enumDirection.top], + beltLength: 0.5, filter: "shape", }, { pos: new Vector(2, 0), directions: [enumDirection.top], + beltLength: 0.5, filter: "shape", }, { pos: new Vector(3, 0), directions: [enumDirection.top, enumDirection.right], + beltLength: 0.5, filter: "shape", }, { pos: new Vector(0, 3), directions: [enumDirection.bottom, enumDirection.left], + beltLength: 0.5, filter: "shape", }, { pos: new Vector(1, 3), directions: [enumDirection.bottom], + beltLength: 0.5, filter: "shape", }, { pos: new Vector(2, 3), directions: [enumDirection.bottom], + beltLength: 0.5, filter: "shape", }, { pos: new Vector(3, 3), directions: [enumDirection.bottom, enumDirection.right], + beltLength: 0.5, filter: "shape", }, { pos: new Vector(0, 1), directions: [enumDirection.left], + beltLength: 0.5, filter: "shape", }, { pos: new Vector(0, 2), directions: [enumDirection.left], + beltLength: 0.5, filter: "shape", }, { pos: new Vector(0, 3), directions: [enumDirection.left], + beltLength: 0.5, filter: "shape", }, { pos: new Vector(3, 1), directions: [enumDirection.right], + beltLength: 0.5, filter: "shape", }, { pos: new Vector(3, 2), directions: [enumDirection.right], + beltLength: 0.5, filter: "shape", }, { pos: new Vector(3, 3), directions: [enumDirection.right], + beltLength: 0.5, filter: "shape", }, ], diff --git a/src/js/game/buildings/mixer.js b/src/js/game/buildings/mixer.js index e572bbba..b69ddd5e 100644 --- a/src/js/game/buildings/mixer.js +++ b/src/js/game/buildings/mixer.js @@ -65,11 +65,13 @@ export class MetaMixerBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.bottom], + beltLength: 0.5, filter: "color", }, { pos: new Vector(1, 0), directions: [enumDirection.bottom], + beltLength: 0.5, filter: "color", }, ], diff --git a/src/js/game/buildings/painter.js b/src/js/game/buildings/painter.js index e7a0b72d..b0b1b06b 100644 --- a/src/js/game/buildings/painter.js +++ b/src/js/game/buildings/painter.js @@ -231,6 +231,7 @@ export class MetaPainterBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.left], + beltLength: 0.5, filter: "shape", }, { diff --git a/src/js/game/buildings/stacker.js b/src/js/game/buildings/stacker.js index 6b70365d..9337fef6 100644 --- a/src/js/game/buildings/stacker.js +++ b/src/js/game/buildings/stacker.js @@ -65,11 +65,13 @@ export class MetaStackerBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.bottom], + beltLength: 0.5, filter: "shape", }, { pos: new Vector(1, 0), directions: [enumDirection.bottom], + beltLength: 0.5, filter: "shape", }, ], diff --git a/src/js/game/systems/belt.js b/src/js/game/systems/belt.js index 8912d098..6d3c0ef5 100644 --- a/src/js/game/systems/belt.js +++ b/src/js/game/systems/belt.js @@ -17,6 +17,10 @@ import { defaultBuildingVariant } from "../meta_building"; export const BELT_ANIM_COUNT = 14; +// width of the empty space to the side of the belt sprite, ignoring border width, in tiles +// see generate_belt_sprites.js +export const BELT_BORDER = 23.5 / 192; + const logger = createLogger("belt"); /** From a239e405c90c8d34d74a22ab619af4c7cedc3eb6 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Wed, 24 Nov 2021 21:42:24 -0600 Subject: [PATCH 07/14] slight variable rearranging --- src/js/game/systems/acceptor_belt.js | 7 ++++--- src/js/game/systems/ejector_belt.js | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/js/game/systems/acceptor_belt.js b/src/js/game/systems/acceptor_belt.js index 70f8ed45..806efad9 100644 --- a/src/js/game/systems/acceptor_belt.js +++ b/src/js/game/systems/acceptor_belt.js @@ -43,13 +43,14 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { const staticComp = entity.components.StaticMapEntity; for (let i = 0; i < acceptorComp.slots.length; ++i) { + // Extract underlay parameters + const { pos, directions, beltLength } = acceptorComp.slots[i]; + // skips both missing and 0 belt lengths - if (!acceptorComp.slots[i].beltLength) { + if (!beltLength) { continue; } - // Extract underlay parameters - const { pos, directions, beltLength } = acceptorComp.slots[i]; const transformedPos = staticComp.localTileToWorld(pos); const destX = transformedPos.x * globalConfig.tileSize; const destY = transformedPos.y * globalConfig.tileSize; diff --git a/src/js/game/systems/ejector_belt.js b/src/js/game/systems/ejector_belt.js index fcbb869a..9d00437f 100644 --- a/src/js/game/systems/ejector_belt.js +++ b/src/js/game/systems/ejector_belt.js @@ -43,13 +43,14 @@ export class EjectorBeltSystem extends GameSystemWithFilter { const staticComp = entity.components.StaticMapEntity; for (let i = 0; i < ejectorComp.slots.length; ++i) { + // Extract underlay parameters + const { pos, direction, beltLength } = ejectorComp.slots[i]; + // skips both missing and 0 belt lengths - if (!ejectorComp.slots[i].beltLength) { + if (!beltLength) { continue; } - // Extract underlay parameters - const { pos, direction, beltLength } = ejectorComp.slots[i]; const transformedPos = staticComp.localTileToWorld(pos); const destX = transformedPos.x * globalConfig.tileSize; const destY = transformedPos.y * globalConfig.tileSize; From b2a8224ad33615665014e2aa66e8de910dbb9961 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Wed, 24 Nov 2021 21:44:40 -0600 Subject: [PATCH 08/14] only show ejector belt if connected --- src/js/game/systems/ejector_belt.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/js/game/systems/ejector_belt.js b/src/js/game/systems/ejector_belt.js index 9d00437f..f1ee4114 100644 --- a/src/js/game/systems/ejector_belt.js +++ b/src/js/game/systems/ejector_belt.js @@ -44,13 +44,18 @@ export class EjectorBeltSystem extends GameSystemWithFilter { const staticComp = entity.components.StaticMapEntity; for (let i = 0; i < ejectorComp.slots.length; ++i) { // Extract underlay parameters - const { pos, direction, beltLength } = ejectorComp.slots[i]; + const { pos, direction, beltLength, cachedTargetEntity } = ejectorComp.slots[i]; // skips both missing and 0 belt lengths if (!beltLength) { continue; } + // check if connected + if (!cachedTargetEntity) { + continue; + } + const transformedPos = staticComp.localTileToWorld(pos); const destX = transformedPos.x * globalConfig.tileSize; const destY = transformedPos.y * globalConfig.tileSize; From 97d45e8aa77294a1805f87a49d5e47f236729108 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Wed, 24 Nov 2021 22:42:16 -0600 Subject: [PATCH 09/14] fix protruding underlays --- src/js/game/buildings/mixer.js | 5 +++-- src/js/game/buildings/painter.js | 3 ++- src/js/game/buildings/stacker.js | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/js/game/buildings/mixer.js b/src/js/game/buildings/mixer.js index b69ddd5e..b61ac0ed 100644 --- a/src/js/game/buildings/mixer.js +++ b/src/js/game/buildings/mixer.js @@ -7,6 +7,7 @@ import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/it import { Entity } from "../entity"; import { MetaBuilding } from "../meta_building"; import { GameRoot } from "../root"; +import { BELT_BORDER } from "../systems/belt"; import { enumHubGoalRewards } from "../tutorial_goals"; export class MetaMixerBuilding extends MetaBuilding { @@ -65,13 +66,13 @@ export class MetaMixerBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.bottom], - beltLength: 0.5, + beltLength: BELT_BORDER, filter: "color", }, { pos: new Vector(1, 0), directions: [enumDirection.bottom], - beltLength: 0.5, + beltLength: BELT_BORDER, filter: "color", }, ], diff --git a/src/js/game/buildings/painter.js b/src/js/game/buildings/painter.js index b0b1b06b..eddffcb5 100644 --- a/src/js/game/buildings/painter.js +++ b/src/js/game/buildings/painter.js @@ -13,6 +13,7 @@ import { defaultBuildingVariant, MetaBuilding } from "../meta_building"; import { GameRoot } from "../root"; import { enumHubGoalRewards } from "../tutorial_goals"; import { WiredPinsComponent, enumPinSlotType } from "../components/wired_pins"; +import { BELT_BORDER } from "../systems/belt"; /** @enum {string} */ export const enumPainterVariants = { mirrored: "mirrored", double: "double", quad: "quad" }; @@ -231,7 +232,7 @@ export class MetaPainterBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.left], - beltLength: 0.5, + beltLength: BELT_BORDER, filter: "shape", }, { diff --git a/src/js/game/buildings/stacker.js b/src/js/game/buildings/stacker.js index 9337fef6..35d2b64e 100644 --- a/src/js/game/buildings/stacker.js +++ b/src/js/game/buildings/stacker.js @@ -7,6 +7,7 @@ import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/it import { Entity } from "../entity"; import { MetaBuilding } from "../meta_building"; import { GameRoot } from "../root"; +import { BELT_BORDER } from "../systems/belt"; import { enumHubGoalRewards } from "../tutorial_goals"; export class MetaStackerBuilding extends MetaBuilding { @@ -65,13 +66,13 @@ export class MetaStackerBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.bottom], - beltLength: 0.5, + beltLength: BELT_BORDER, filter: "shape", }, { pos: new Vector(1, 0), directions: [enumDirection.bottom], - beltLength: 0.5, + beltLength: BELT_BORDER, filter: "shape", }, ], From 24d6238d17d49717172146c922b281a35851f634 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Wed, 24 Nov 2021 22:43:39 -0600 Subject: [PATCH 10/14] only show acceptor belt if connected --- src/js/game/systems/acceptor_belt.js | 68 ++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/src/js/game/systems/acceptor_belt.js b/src/js/game/systems/acceptor_belt.js index 806efad9..10d4a7b2 100644 --- a/src/js/game/systems/acceptor_belt.js +++ b/src/js/game/systems/acceptor_belt.js @@ -2,7 +2,13 @@ import { globalConfig } from "../../core/config"; import { DrawParameters } from "../../core/draw_parameters"; import { Loader } from "../../core/loader"; import { Rectangle } from "../../core/rectangle"; -import { enumDirectionToAngle, enumInvertedDirections } from "../../core/vector"; +import { + enumDirection, + enumDirectionToAngle, + enumDirectionToVector, + enumInvertedDirections, + Vector, +} from "../../core/vector"; import { ItemAcceptorComponent } from "../components/item_acceptor"; import { GameSystemWithFilter } from "../game_system_with_filter"; import { MapChunkView } from "../map_chunk_view"; @@ -20,6 +26,50 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { } } + /** + * Checks if a given tile is connected and has an ejector + * @param {Vector} tile + * @param {enumDirection} toDirection + * @returns {boolean} + */ + checkIsEjectorConnected(tile, toDirection) { + const contents = this.root.map.getLayerContentXY(tile.x, tile.y, "regular"); + if (!contents) { + return false; + } + + const staticComp = contents.components.StaticMapEntity; + + // Check if its a belt, since then its simple + const beltComp = contents.components.Belt; + if (beltComp) { + return staticComp.localDirectionToWorld(beltComp.direction) === toDirection; + } + + // Check for an ejector + const ejectorComp = contents.components.ItemEjector; + if (ejectorComp) { + // Check each slot to see if its connected + for (let i = 0; i < ejectorComp.slots.length; ++i) { + const slot = ejectorComp.slots[i]; + const slotTile = staticComp.localTileToWorld(slot.pos); + + // Step 1: Check if the tile matches + if (!slotTile.equals(tile)) { + continue; + } + + // Step 2: Check if the direction matches + const slotDirection = staticComp.localDirectionToWorld(slot.direction); + if (slotDirection === toDirection) { + return true; + } + } + } + + return false; + } + /** * Draws a given chunk * @param {DrawParameters} parameters @@ -76,8 +126,20 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { const direction = directions[j]; // Extract direction and angle - const worldDirection = staticComp.localDirectionToWorld(direction); - const angle = enumDirectionToAngle[enumInvertedDirections[worldDirection]]; + const worldDirection = + enumInvertedDirections[staticComp.localDirectionToWorld(direction)]; + const worldDirectionVector = enumDirectionToVector[worldDirection]; + const angle = enumDirectionToAngle[worldDirection]; + + // check if connected + if ( + !this.checkIsEjectorConnected( + transformedPos.sub(worldDirectionVector), + worldDirection + ) + ) { + continue; + } const clipRect = new Rectangle(0, 1 - beltLength, 1, beltLength); From 6ea9f91641f73c928702cd483fd722634211b4c8 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Wed, 24 Nov 2021 22:54:19 -0600 Subject: [PATCH 11/14] respect simplified belts for underlays --- src/js/game/systems/acceptor_belt.js | 6 +++++- src/js/game/systems/ejector_belt.js | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/js/game/systems/acceptor_belt.js b/src/js/game/systems/acceptor_belt.js index 10d4a7b2..0a015da4 100644 --- a/src/js/game/systems/acceptor_belt.js +++ b/src/js/game/systems/acceptor_belt.js @@ -83,6 +83,8 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { globalConfig.itemSpacingOnBelts ); + const simplifiedBelts = this.root.app.settings.getAllSettings().simplifiedBelts; + const contents = chunk.containedEntitiesByLayer.regular; for (let i = 0; i < contents.length; ++i) { const entity = contents[i]; @@ -150,7 +152,9 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { parameters.context.translate(x, y); parameters.context.rotate(angleRadians); - this.underlayBeltSprites[animationIndex % BELT_ANIM_COUNT].drawCachedWithClipRect( + this.underlayBeltSprites[ + !simplifiedBelts ? animationIndex % BELT_ANIM_COUNT : 0 + ].drawCachedWithClipRect( parameters, -globalConfig.halfTileSize, -globalConfig.halfTileSize, diff --git a/src/js/game/systems/ejector_belt.js b/src/js/game/systems/ejector_belt.js index f1ee4114..06ca68a6 100644 --- a/src/js/game/systems/ejector_belt.js +++ b/src/js/game/systems/ejector_belt.js @@ -33,6 +33,8 @@ export class EjectorBeltSystem extends GameSystemWithFilter { globalConfig.itemSpacingOnBelts ); + const simplifiedBelts = this.root.app.settings.getAllSettings().simplifiedBelts; + const contents = chunk.containedEntitiesByLayer.regular; for (let i = 0; i < contents.length; ++i) { const entity = contents[i]; @@ -90,7 +92,9 @@ export class EjectorBeltSystem extends GameSystemWithFilter { parameters.context.translate(x, y); parameters.context.rotate(angleRadians); - this.underlayBeltSprites[animationIndex % BELT_ANIM_COUNT].drawCachedWithClipRect( + this.underlayBeltSprites[ + !simplifiedBelts ? animationIndex % BELT_ANIM_COUNT : 0 + ].drawCachedWithClipRect( parameters, -globalConfig.halfTileSize, -globalConfig.halfTileSize, From e23c3c17e20483facc2c1b8d3b6e4a1b1aaba407 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Wed, 24 Nov 2021 23:34:09 -0600 Subject: [PATCH 12/14] consolidate belt drawing logic --- src/js/game/map_chunk_view.js | 2 - src/js/game/systems/acceptor_belt.js | 14 ++----- src/js/game/systems/belt.js | 60 ++++++++++++++++++---------- src/js/game/systems/ejector_belt.js | 14 ++----- 4 files changed, 48 insertions(+), 42 deletions(-) diff --git a/src/js/game/map_chunk_view.js b/src/js/game/map_chunk_view.js index d824e4d4..f81add4b 100644 --- a/src/js/game/map_chunk_view.js +++ b/src/js/game/map_chunk_view.js @@ -50,8 +50,6 @@ export class MapChunkView extends MapChunk { systems.mapResources.drawChunk(parameters, this); } - systems.acceptorBelt.drawChunk(parameters, this); - systems.ejectorBelt.drawChunk(parameters, this); systems.belt.drawChunk(parameters, this); } diff --git a/src/js/game/systems/acceptor_belt.js b/src/js/game/systems/acceptor_belt.js index 0a015da4..4a086ac6 100644 --- a/src/js/game/systems/acceptor_belt.js +++ b/src/js/game/systems/acceptor_belt.js @@ -74,17 +74,11 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { * Draws a given chunk * @param {DrawParameters} parameters * @param {MapChunkView} chunk + * @param {object} param0 + * @param {number} param0.animationIndex + * @param {boolean} param0.simplifiedBelts */ - drawChunk(parameters, chunk) { - // SYNC with systems/belt.js:drawChunk! - const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(), 10); - const animationIndex = Math.floor( - ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * - globalConfig.itemSpacingOnBelts - ); - - const simplifiedBelts = this.root.app.settings.getAllSettings().simplifiedBelts; - + internalDrawChunk(parameters, chunk, { animationIndex, simplifiedBelts }) { const contents = chunk.containedEntitiesByLayer.regular; for (let i = 0; i < contents.length; ++i) { const entity = contents[i]; diff --git a/src/js/game/systems/belt.js b/src/js/game/systems/belt.js index 6d3c0ef5..60d5c976 100644 --- a/src/js/game/systems/belt.js +++ b/src/js/game/systems/belt.js @@ -496,16 +496,42 @@ export class BeltSystem extends GameSystemWithFilter { * Draws a given chunk * @param {DrawParameters} parameters * @param {MapChunkView} chunk + * @param {object} param0 + * @param {number} param0.animationIndex + * @param {boolean} param0.simplifiedBelts + * @param {BeltPath} param0.hoveredBeltPath + * + */ + internalDrawChunk(parameters, chunk, { animationIndex, simplifiedBelts, hoveredBeltPath }) { + const contents = chunk.containedEntitiesByLayer.regular; + for (let i = 0; i < contents.length; ++i) { + const entity = contents[i]; + if (entity.components.Belt) { + const { direction, assignedPath } = entity.components.Belt; + const sprite = this.beltAnimations[direction][ + !simplifiedBelts || assignedPath === hoveredBeltPath ? animationIndex : 0 + ]; + + // Culling happens within the static map entity component + entity.components.StaticMapEntity.drawSpriteOnBoundsClipped(parameters, sprite, 0); + } + } + } + + /** + * Draws a given chunk, including acceptor/ejector belts + * @param {DrawParameters} parameters + * @param {MapChunkView} chunk */ drawChunk(parameters, chunk) { - // SYNC with systems/acceptor_belt.js:drawChunk and systems/ejector_belt.js:drawChunk! // Limit speed to avoid belts going backwards const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(), 10); // 126 / 42 is the exact animation speed of the png animation - const animationIndex = Math.floor( - ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * - globalConfig.itemSpacingOnBelts - ); + const animationIndex = + Math.floor( + ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * + globalConfig.itemSpacingOnBelts + ) % BELT_ANIM_COUNT; const simplifiedBelts = this.root.app.settings.getAllSettings().simplifiedBelts; @@ -522,21 +548,15 @@ export class BeltSystem extends GameSystemWithFilter { } } - const contents = chunk.containedEntitiesByLayer.regular; - for (let i = 0; i < contents.length; ++i) { - const entity = contents[i]; - if (entity.components.Belt) { - const { direction, assignedPath } = entity.components.Belt; - const sprite = this.beltAnimations[direction][ - !simplifiedBelts || assignedPath === hoveredBeltPath - ? animationIndex % BELT_ANIM_COUNT - : 0 - ]; - - // Culling happens within the static map entity component - entity.components.StaticMapEntity.drawSpriteOnBoundsClipped(parameters, sprite, 0); - } - } + this.internalDrawChunk(parameters, chunk, { animationIndex, simplifiedBelts, hoveredBeltPath }); + this.root.systemMgr.systems.acceptorBelt.internalDrawChunk(parameters, chunk, { + animationIndex, + simplifiedBelts, + }); + this.root.systemMgr.systems.ejectorBelt.internalDrawChunk(parameters, chunk, { + animationIndex, + simplifiedBelts, + }); } /** diff --git a/src/js/game/systems/ejector_belt.js b/src/js/game/systems/ejector_belt.js index 06ca68a6..f4b1f1c1 100644 --- a/src/js/game/systems/ejector_belt.js +++ b/src/js/game/systems/ejector_belt.js @@ -24,17 +24,11 @@ export class EjectorBeltSystem extends GameSystemWithFilter { * Draws a given chunk * @param {DrawParameters} parameters * @param {MapChunkView} chunk + * @param {object} param0 + * @param {number} param0.animationIndex + * @param {boolean} param0.simplifiedBelts */ - drawChunk(parameters, chunk) { - // SYNC with systems/belt.js:drawChunk! - const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(), 10); - const animationIndex = Math.floor( - ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * - globalConfig.itemSpacingOnBelts - ); - - const simplifiedBelts = this.root.app.settings.getAllSettings().simplifiedBelts; - + internalDrawChunk(parameters, chunk, { animationIndex, simplifiedBelts }) { const contents = chunk.containedEntitiesByLayer.regular; for (let i = 0; i < contents.length; ++i) { const entity = contents[i]; From 0d3a1efa67ca03b3a4d97690a211f4c389bec995 Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Thu, 25 Nov 2021 14:15:33 -0600 Subject: [PATCH 13/14] belt hover for ejector belts --- src/js/game/systems/belt.js | 1 + src/js/game/systems/ejector_belt.js | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/js/game/systems/belt.js b/src/js/game/systems/belt.js index 60d5c976..45722c34 100644 --- a/src/js/game/systems/belt.js +++ b/src/js/game/systems/belt.js @@ -556,6 +556,7 @@ export class BeltSystem extends GameSystemWithFilter { this.root.systemMgr.systems.ejectorBelt.internalDrawChunk(parameters, chunk, { animationIndex, simplifiedBelts, + hoveredBeltPath, }); } diff --git a/src/js/game/systems/ejector_belt.js b/src/js/game/systems/ejector_belt.js index f4b1f1c1..83fa95ed 100644 --- a/src/js/game/systems/ejector_belt.js +++ b/src/js/game/systems/ejector_belt.js @@ -3,6 +3,7 @@ import { DrawParameters } from "../../core/draw_parameters"; import { Loader } from "../../core/loader"; import { Rectangle } from "../../core/rectangle"; import { enumDirectionToAngle } from "../../core/vector"; +import { BeltPath } from "../belt_path"; import { ItemEjectorComponent } from "../components/item_ejector"; import { GameSystemWithFilter } from "../game_system_with_filter"; import { MapChunkView } from "../map_chunk_view"; @@ -27,8 +28,9 @@ export class EjectorBeltSystem extends GameSystemWithFilter { * @param {object} param0 * @param {number} param0.animationIndex * @param {boolean} param0.simplifiedBelts + * @param {BeltPath} param0.hoveredBeltPath */ - internalDrawChunk(parameters, chunk, { animationIndex, simplifiedBelts }) { + internalDrawChunk(parameters, chunk, { animationIndex, simplifiedBelts, hoveredBeltPath }) { const contents = chunk.containedEntitiesByLayer.regular; for (let i = 0; i < contents.length; ++i) { const entity = contents[i]; @@ -40,7 +42,9 @@ export class EjectorBeltSystem extends GameSystemWithFilter { const staticComp = entity.components.StaticMapEntity; for (let i = 0; i < ejectorComp.slots.length; ++i) { // Extract underlay parameters - const { pos, direction, beltLength, cachedTargetEntity } = ejectorComp.slots[i]; + const { pos, direction, beltLength, cachedTargetEntity, cachedBeltPath } = ejectorComp.slots[ + i + ]; // skips both missing and 0 belt lengths if (!beltLength) { @@ -87,7 +91,9 @@ export class EjectorBeltSystem extends GameSystemWithFilter { parameters.context.translate(x, y); parameters.context.rotate(angleRadians); this.underlayBeltSprites[ - !simplifiedBelts ? animationIndex % BELT_ANIM_COUNT : 0 + !simplifiedBelts || (cachedBeltPath && cachedBeltPath === hoveredBeltPath) + ? animationIndex % BELT_ANIM_COUNT + : 0 ].drawCachedWithClipRect( parameters, -globalConfig.halfTileSize, From 247e4dc2e0866fe50b90f9a463946e9f57ddff7b Mon Sep 17 00:00:00 2001 From: EmeraldBlock Date: Fri, 26 Nov 2021 00:45:59 -0600 Subject: [PATCH 14/14] belt hover for acceptor belts --- src/js/game/systems/acceptor_belt.js | 39 ++++++++++++++++------------ src/js/game/systems/belt.js | 1 + 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/js/game/systems/acceptor_belt.js b/src/js/game/systems/acceptor_belt.js index 4a086ac6..718ccdec 100644 --- a/src/js/game/systems/acceptor_belt.js +++ b/src/js/game/systems/acceptor_belt.js @@ -9,7 +9,9 @@ import { enumInvertedDirections, Vector, } from "../../core/vector"; +import { BeltPath } from "../belt_path"; import { ItemAcceptorComponent } from "../components/item_acceptor"; +import { Entity } from "../entity"; import { GameSystemWithFilter } from "../game_system_with_filter"; import { MapChunkView } from "../map_chunk_view"; import { BELT_ANIM_COUNT } from "./belt"; @@ -27,15 +29,18 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { } /** - * Checks if a given tile is connected and has an ejector - * @param {Vector} tile + * Gets the adjacent entity that ejects to a tile + * @param {Vector} toTile * @param {enumDirection} toDirection - * @returns {boolean} + * @returns {Entity} */ - checkIsEjectorConnected(tile, toDirection) { + getSourceEntity(toTile, toDirection) { + const toDirectionVector = enumDirectionToVector[toDirection]; + const tile = toTile.sub(toDirectionVector); + const contents = this.root.map.getLayerContentXY(tile.x, tile.y, "regular"); if (!contents) { - return false; + return null; } const staticComp = contents.components.StaticMapEntity; @@ -43,7 +48,7 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { // Check if its a belt, since then its simple const beltComp = contents.components.Belt; if (beltComp) { - return staticComp.localDirectionToWorld(beltComp.direction) === toDirection; + return staticComp.localDirectionToWorld(beltComp.direction) === toDirection ? contents : null; } // Check for an ejector @@ -62,12 +67,12 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { // Step 2: Check if the direction matches const slotDirection = staticComp.localDirectionToWorld(slot.direction); if (slotDirection === toDirection) { - return true; + return contents; } } } - return false; + return null; } /** @@ -77,8 +82,9 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { * @param {object} param0 * @param {number} param0.animationIndex * @param {boolean} param0.simplifiedBelts + * @param {BeltPath} param0.hoveredBeltPath */ - internalDrawChunk(parameters, chunk, { animationIndex, simplifiedBelts }) { + internalDrawChunk(parameters, chunk, { animationIndex, simplifiedBelts, hoveredBeltPath }) { const contents = chunk.containedEntitiesByLayer.regular; for (let i = 0; i < contents.length; ++i) { const entity = contents[i]; @@ -128,15 +134,14 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { const angle = enumDirectionToAngle[worldDirection]; // check if connected - if ( - !this.checkIsEjectorConnected( - transformedPos.sub(worldDirectionVector), - worldDirection - ) - ) { + const sourceEntity = this.getSourceEntity(transformedPos, worldDirection); + if (!sourceEntity) { continue; } + const sourceBeltComp = sourceEntity.components.Belt; + const sourceBeltPath = sourceBeltComp ? sourceBeltComp.assignedPath : null; + const clipRect = new Rectangle(0, 1 - beltLength, 1, beltLength); // Actually draw the sprite @@ -147,7 +152,9 @@ export class AcceptorBeltSystem extends GameSystemWithFilter { parameters.context.translate(x, y); parameters.context.rotate(angleRadians); this.underlayBeltSprites[ - !simplifiedBelts ? animationIndex % BELT_ANIM_COUNT : 0 + !simplifiedBelts || (sourceBeltPath && sourceBeltPath === hoveredBeltPath) + ? animationIndex % BELT_ANIM_COUNT + : 0 ].drawCachedWithClipRect( parameters, -globalConfig.halfTileSize, diff --git a/src/js/game/systems/belt.js b/src/js/game/systems/belt.js index 45722c34..0f17cdf2 100644 --- a/src/js/game/systems/belt.js +++ b/src/js/game/systems/belt.js @@ -552,6 +552,7 @@ export class BeltSystem extends GameSystemWithFilter { this.root.systemMgr.systems.acceptorBelt.internalDrawChunk(parameters, chunk, { animationIndex, simplifiedBelts, + hoveredBeltPath, }); this.root.systemMgr.systems.ejectorBelt.internalDrawChunk(parameters, chunk, { animationIndex,