From b3b8da04a14be60313f44aaee24f372f3c207a38 Mon Sep 17 00:00:00 2001 From: tobspr Date: Mon, 10 Aug 2020 20:26:47 +0200 Subject: [PATCH] Refactor belt underlay feature into seperate component --- src/js/game/buildings/splitter.js | 16 ++--- src/js/game/component_registry.js | 2 + src/js/game/components/belt_underlays.js | 44 ++++++++++++++ src/js/game/components/item_acceptor.js | 45 +++----------- src/js/game/core.js | 2 +- src/js/game/entity_components.js | 4 ++ src/js/game/game_system_manager.js | 6 ++ src/js/game/systems/belt_underlays.js | 75 ++++++++++++++++++++++++ src/js/game/systems/item_acceptor.js | 59 ------------------- 9 files changed, 148 insertions(+), 105 deletions(-) create mode 100644 src/js/game/components/belt_underlays.js create mode 100644 src/js/game/systems/belt_underlays.js diff --git a/src/js/game/buildings/splitter.js b/src/js/game/buildings/splitter.js index 12f0e6e7..219f02cf 100644 --- a/src/js/game/buildings/splitter.js +++ b/src/js/game/buildings/splitter.js @@ -1,14 +1,14 @@ -import { globalConfig } from "../../core/config"; 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 { Entity } from "../entity"; import { MetaBuilding, defaultBuildingVariant } from "../meta_building"; -import { GameRoot, enumLayer } from "../root"; +import { GameRoot } from "../root"; import { enumHubGoalRewards } from "../tutorial_goals"; import { T } from "../../translations"; import { formatItemsPerSecond } from "../../core/utils"; +import { BeltUnderlaysComponent } from "../components/belt_underlays"; /** @enum {string} */ export const enumSplitterVariants = { compact: "compact", compactInverse: "compact-inverse" }; @@ -88,6 +88,8 @@ export class MetaSplitterBuilding extends MetaBuilding { slots: [], // set later }) ); + + entity.addComponent(new BeltUnderlaysComponent({ underlays: [] })); } /** @@ -115,9 +117,9 @@ export class MetaSplitterBuilding extends MetaBuilding { { pos: new Vector(1, 0), direction: enumDirection.top }, ]); - entity.components.ItemAcceptor.beltUnderlays = [ - { pos: new Vector(0, 0), direction: enumDirection.top, layer: enumLayer.regular }, - { pos: new Vector(1, 0), direction: enumDirection.top, layer: enumLayer.regular }, + entity.components.BeltUnderlays.underlays = [ + { pos: new Vector(0, 0), direction: enumDirection.top }, + { pos: new Vector(1, 0), direction: enumDirection.top }, ]; break; @@ -143,8 +145,8 @@ export class MetaSplitterBuilding extends MetaBuilding { { pos: new Vector(0, 0), direction: enumDirection.top }, ]); - entity.components.ItemAcceptor.beltUnderlays = [ - { pos: new Vector(0, 0), direction: enumDirection.top, layer: enumLayer.regular }, + entity.components.BeltUnderlays.underlays = [ + { pos: new Vector(0, 0), direction: enumDirection.top }, ]; break; diff --git a/src/js/game/component_registry.js b/src/js/game/component_registry.js index d3398937..ea0e43e8 100644 --- a/src/js/game/component_registry.js +++ b/src/js/game/component_registry.js @@ -13,6 +13,7 @@ import { StorageComponent } from "./components/storage"; import { EnergyGeneratorComponent } from "./components/energy_generator"; import { WiredPinsComponent } from "./components/wired_pins"; import { EnergyConsumerComponent } from "./components/energy_consumer"; +import { BeltUnderlaysComponent } from "./components/belt_underlays"; export function initComponentRegistry() { gComponentRegistry.register(StaticMapEntityComponent); @@ -29,6 +30,7 @@ export function initComponentRegistry() { gComponentRegistry.register(EnergyGeneratorComponent); gComponentRegistry.register(WiredPinsComponent); gComponentRegistry.register(EnergyConsumerComponent); + gComponentRegistry.register(BeltUnderlaysComponent); // IMPORTANT ^^^^^ UPDATE ENTITY COMPONENT STORAGE AFTERWARDS diff --git a/src/js/game/components/belt_underlays.js b/src/js/game/components/belt_underlays.js new file mode 100644 index 00000000..cdc3473f --- /dev/null +++ b/src/js/game/components/belt_underlays.js @@ -0,0 +1,44 @@ +import { Component } from "../component"; +import { types } from "../../savegame/serialization"; +import { enumDirection, Vector } from "../../core/vector"; + +export class BeltUnderlaysComponent extends Component { + static getId() { + return "BeltUnderlays"; + } + + static getSchema() { + return { + underlays: types.array( + types.structured({ + pos: types.vector, + direction: types.enum(enumDirection), + }) + ), + }; + } + + duplicateWithoutContents() { + const beltUnderlaysCopy = []; + for (let i = 0; i < this.underlays.length; ++i) { + const underlay = this.underlays[i]; + beltUnderlaysCopy.push({ + pos: underlay.pos.copy(), + direction: underlay.direction, + }); + } + + return new BeltUnderlaysComponent({ + underlays: beltUnderlaysCopy, + }); + } + + /** + * @param {object} param0 + * @param {Array<{pos: Vector, direction: enumDirection}>=} param0.underlays Where to render belt underlays + */ + constructor({ underlays }) { + super(); + this.underlays = underlays; + } +} diff --git a/src/js/game/components/item_acceptor.js b/src/js/game/components/item_acceptor.js index a5676119..fd38651f 100644 --- a/src/js/game/components/item_acceptor.js +++ b/src/js/game/components/item_acceptor.js @@ -39,16 +39,6 @@ export class ItemAcceptorComponent extends Component { directions: types.array(types.enum(enumDirection)), filter: types.nullable(types.enum(enumItemType)), - // TODO: MIGRATE - layer: types.enum(enumLayer), - }) - ), - animated: types.bool, - beltUnderlays: types.array( - types.structured({ - pos: types.vector, - direction: types.enum(enumDirection), - // TODO: MIGRATE layer: types.enum(enumLayer), }) @@ -68,20 +58,8 @@ export class ItemAcceptorComponent extends Component { }); } - const beltUnderlaysCopy = []; - for (let i = 0; i < this.beltUnderlays.length; ++i) { - const underlay = this.beltUnderlays[i]; - beltUnderlaysCopy.push({ - pos: underlay.pos.copy(), - direction: underlay.direction, - layer: underlay.layer, - }); - } - return new ItemAcceptorComponent({ slots: slotsCopy, - beltUnderlays: beltUnderlaysCopy, - animated: this.animated, }); } @@ -89,23 +67,16 @@ export class ItemAcceptorComponent extends Component { * * @param {object} param0 * @param {Array} param0.slots The slots from which we accept items - * @param {boolean=} param0.animated Whether to animate item consumption - * @param {Array<{pos: Vector, direction: enumDirection, layer: enumLayer}>=} param0.beltUnderlays Where to render belt underlays */ - constructor({ slots = [], beltUnderlays = [], animated = true }) { + constructor({ slots = [] }) { super(); - this.animated = animated; - /** * Fixes belt animations * @type {Array<{ item: BaseItem, slotIndex: number, animProgress: number, direction: enumDirection }>} */ this.itemConsumptionAnimations = []; - /* Which belt underlays to render */ - this.beltUnderlays = beltUnderlays; - this.setSlots(slots); } @@ -164,14 +135,12 @@ export class ItemAcceptorComponent extends Component { * @param {BaseItem} item */ onItemAccepted(slotIndex, direction, item) { - if (this.animated) { - this.itemConsumptionAnimations.push({ - item, - slotIndex, - direction, - animProgress: 0.0, - }); - } + this.itemConsumptionAnimations.push({ + item, + slotIndex, + direction, + animProgress: 0.0, + }); } /** diff --git a/src/js/game/core.js b/src/js/game/core.js index 960a83e3..e48c01e7 100644 --- a/src/js/game/core.js +++ b/src/js/game/core.js @@ -398,7 +398,7 @@ export class GameCore { if (!this.root.camera.getIsMapOverlayActive()) { // Underlays for splitters / balancers - systems.itemAcceptor.drawUnderlays(params, enumLayer.regular); + systems.beltUnderlays.drawUnderlays(params, enumLayer.regular); // Belt items systems.belt.drawLayerBeltItems(params, enumLayer.regular); diff --git a/src/js/game/entity_components.js b/src/js/game/entity_components.js index 24430dd2..f670b227 100644 --- a/src/js/game/entity_components.js +++ b/src/js/game/entity_components.js @@ -13,6 +13,7 @@ import { StorageComponent } from "./components/storage"; import { EnergyGeneratorComponent } from "./components/energy_generator"; import { WiredPinsComponent } from "./components/wired_pins"; import { EnergyConsumerComponent } from "./components/energy_consumer"; +import { BeltUnderlaysComponent } from "./components/belt_underlays"; /* typehints:end */ /** @@ -65,6 +66,9 @@ export class EntityComponentStorage { /** @type {EnergyConsumerComponent} */ this.EnergyConsumer; + /** @type {BeltUnderlaysComponent} */ + this.BeltUnderlays; + /* typehints:end */ } } diff --git a/src/js/game/game_system_manager.js b/src/js/game/game_system_manager.js index ed9d1155..bfdb1407 100644 --- a/src/js/game/game_system_manager.js +++ b/src/js/game/game_system_manager.js @@ -16,6 +16,7 @@ import { StorageSystem } from "./systems/storage"; import { EnergyGeneratorSystem } from "./systems/energy_generator"; import { WiredPinsSystem } from "./systems/wired_pins"; import { EnergyConsumerSystem } from "./systems/energy_consumer"; +import { BeltUnderlaysSystem } from "./systems/belt_underlays"; const logger = createLogger("game_system_manager"); @@ -68,6 +69,9 @@ export class GameSystemManager { /** @type {EnergyConsumerSystem} */ energyConsumer: null, + /** @type {BeltUnderlaysSystem} */ + beltUnderlays: null, + /* typehints:end */ }; this.systemUpdateOrder = []; @@ -110,6 +114,8 @@ export class GameSystemManager { add("energyConsumer", EnergyConsumerSystem); + add("beltUnderlays", BeltUnderlaysSystem); + // IMPORTANT: Must be after belt system since belt system can change the // orientation of an entity after it is placed -> the item acceptor cache // then would be invalid diff --git a/src/js/game/systems/belt_underlays.js b/src/js/game/systems/belt_underlays.js new file mode 100644 index 00000000..28d6b71d --- /dev/null +++ b/src/js/game/systems/belt_underlays.js @@ -0,0 +1,75 @@ +import { GameSystemWithFilter } from "../game_system_with_filter"; +import { BeltUnderlaysComponent } from "../components/belt_underlays"; +import { BELT_ANIM_COUNT } from "./belt"; +import { Loader } from "../../core/loader"; +import { enumLayer } from "../root"; +import { Entity } from "../entity"; +import { enumDirectionToAngle } from "../../core/vector"; +import { globalConfig } from "../../core/config"; +import { drawRotatedSprite } from "../../core/draw_utils"; + +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/forward_" + i + ".png")); + } + } + + /** + * Draws the acceptor underlays + * @param {import("../../core/draw_utils").DrawParameters} parameters + * @param {enumLayer} layer + */ + drawUnderlays(parameters, layer) { + this.forEachMatchingEntityOnScreen(parameters, this.drawEntityUnderlays.bind(this, layer)); + } + + /** + * @param {enumLayer} layer + * @param {import("../../core/draw_utils").DrawParameters} parameters + * @param {Entity} entity + */ + drawEntityUnderlays(layer, parameters, entity) { + const staticComp = entity.components.StaticMapEntity; + const underlayComp = entity.components.BeltUnderlays; + + if (entity.layer !== layer) { + // Not our layer + return; + } + + if (!staticComp.shouldBeDrawn(parameters)) { + return; + } + + // Limit speed to avoid belts going backwards + const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(layer), 10); + + const underlays = underlayComp.underlays; + for (let i = 0; i < underlays.length; ++i) { + const { pos, direction } = underlays[i]; + + const transformedPos = staticComp.localTileToWorld(pos); + const angle = enumDirectionToAngle[staticComp.localDirectionToWorld(direction)]; + + // SYNC with systems/belt.js:drawSingleEntity! + const animationIndex = Math.floor( + ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * + globalConfig.beltItemSpacingByLayer[layer] + ); + + drawRotatedSprite({ + parameters, + sprite: this.underlayBeltSprites[animationIndex % this.underlayBeltSprites.length], + x: (transformedPos.x + 0.5) * globalConfig.tileSize, + y: (transformedPos.y + 0.5) * globalConfig.tileSize, + angle: Math.radians(angle), + size: globalConfig.tileSize, + }); + } + } +} diff --git a/src/js/game/systems/item_acceptor.js b/src/js/game/systems/item_acceptor.js index 2c0f1686..a813fdbe 100644 --- a/src/js/game/systems/item_acceptor.js +++ b/src/js/game/systems/item_acceptor.js @@ -13,12 +13,6 @@ import { enumLayer } from "../root"; export class ItemAcceptorSystem 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/forward_" + i + ".png")); - } } update() { @@ -59,15 +53,6 @@ export class ItemAcceptorSystem extends GameSystemWithFilter { this.forEachMatchingEntityOnScreen(parameters, this.drawEntityRegularLayer.bind(this, layer)); } - /** - * Draws the acceptor underlays - * @param {DrawParameters} parameters - * @param {enumLayer} layer - */ - drawUnderlays(parameters, layer) { - this.forEachMatchingEntityOnScreen(parameters, this.drawEntityUnderlays.bind(this, layer)); - } - /** * @param {enumLayer} layer * @param {DrawParameters} parameters @@ -105,48 +90,4 @@ export class ItemAcceptorSystem extends GameSystemWithFilter { ); } } - - /** - * @param {enumLayer} layer - * @param {DrawParameters} parameters - * @param {Entity} entity - */ - drawEntityUnderlays(layer, parameters, entity) { - const staticComp = entity.components.StaticMapEntity; - const acceptorComp = entity.components.ItemAcceptor; - - if (!staticComp.shouldBeDrawn(parameters)) { - return; - } - - // Limit speed to avoid belts going backwards - const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(layer), 10); - - const underlays = acceptorComp.beltUnderlays; - for (let i = 0; i < underlays.length; ++i) { - const { pos, direction, layer: underlayLayer } = underlays[i]; - if (underlayLayer !== layer) { - // Not our layer - continue; - } - - const transformedPos = staticComp.localTileToWorld(pos); - const angle = enumDirectionToAngle[staticComp.localDirectionToWorld(direction)]; - - // SYNC with systems/belt.js:drawSingleEntity! - const animationIndex = Math.floor( - ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * - globalConfig.beltItemSpacingByLayer[layer] - ); - - drawRotatedSprite({ - parameters, - sprite: this.underlayBeltSprites[animationIndex % this.underlayBeltSprites.length], - x: (transformedPos.x + 0.5) * globalConfig.tileSize, - y: (transformedPos.y + 0.5) * globalConfig.tileSize, - angle: Math.radians(angle), - size: globalConfig.tileSize, - }); - } - } }