mirror of
https://github.com/tobspr/shapez.io.git
synced 2026-03-02 03:39:21 +00:00
Implement concept of energy consumption
This commit is contained in:
@@ -72,7 +72,7 @@ export const globalConfig = {
|
||||
painterQuad: 1 / 8,
|
||||
mixer: 1 / 5,
|
||||
stacker: 1 / 6,
|
||||
advancedProcessor: 1 / 15,
|
||||
advancedProcessor: 1 / 6,
|
||||
},
|
||||
|
||||
// Zooming
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DrawParameters } from "../core/draw_parameters";
|
||||
import { BasicSerializableObject } from "../savegame/serialization";
|
||||
import { enumLayer } from "./root";
|
||||
|
||||
/** @enum {string} */
|
||||
export const enumItemType = {
|
||||
@@ -9,6 +10,14 @@ export const enumItemType = {
|
||||
negativeEnergy: "negativeEnergy",
|
||||
};
|
||||
|
||||
/** @enum {enumLayer} */
|
||||
export const enumItemTypeToLayer = {
|
||||
[enumItemType.shape]: enumLayer.regular,
|
||||
[enumItemType.color]: enumLayer.regular,
|
||||
[enumItemType.positiveEnergy]: enumLayer.wires,
|
||||
[enumItemType.negativeEnergy]: enumLayer.wires,
|
||||
};
|
||||
|
||||
/**
|
||||
* Class for items on belts etc. Not an entity for performance reasons
|
||||
*/
|
||||
|
||||
@@ -65,8 +65,10 @@ export class MetaAdvancedProcessorBuilding extends MetaBuilding {
|
||||
entity.addComponent(
|
||||
new EnergyConsumerComponent({
|
||||
bufferSize: 3,
|
||||
perCharge: 1,
|
||||
perCharge: 0.25,
|
||||
batteryPosition: new Vector(4, 6.5),
|
||||
acceptorSlotIndex: 1,
|
||||
ejectorSlotIndex: 1,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -90,7 +92,7 @@ export class MetaAdvancedProcessorBuilding extends MetaBuilding {
|
||||
new ItemAcceptorComponent({
|
||||
slots: [
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
pos: new Vector(0, 1),
|
||||
directions: [enumDirection.left],
|
||||
filter: enumItemType.shape,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component } from "../component";
|
||||
import { types } from "../../savegame/serialization";
|
||||
import { Vector } from "../../core/vector";
|
||||
import { BaseItem, enumItemTypeToLayer, enumItemType } from "../base_item";
|
||||
|
||||
export class EnergyConsumerComponent extends Component {
|
||||
static getId() {
|
||||
@@ -9,10 +10,15 @@ export class EnergyConsumerComponent extends Component {
|
||||
|
||||
static getSchema() {
|
||||
return {
|
||||
bufferSize: types.uint,
|
||||
perCharge: types.uint,
|
||||
stored: types.uint,
|
||||
bufferSize: types.float,
|
||||
perCharge: types.float,
|
||||
stored: types.float,
|
||||
piledOutput: types.float,
|
||||
batteryPosition: types.vector,
|
||||
energyType: types.enum(enumItemType),
|
||||
wasteType: types.enum(enumItemType),
|
||||
acceptorSlotIndex: types.uint,
|
||||
ejectorSlotIndex: types.uint,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,13 +28,95 @@ export class EnergyConsumerComponent extends Component {
|
||||
* @param {number} param0.bufferSize How much energy this consumer can store
|
||||
* @param {number} param0.perCharge How much energy this consumer needs per charge
|
||||
* @param {Vector} param0.batteryPosition world space render offset of the battery icon
|
||||
* @param {number} param0.acceptorSlotIndex Which slot to accept energy on
|
||||
* @param {number} param0.ejectorSlotIndex Which slot to eject energy off
|
||||
*
|
||||
*/
|
||||
constructor({ bufferSize = 3, perCharge = 1, batteryPosition = new Vector() }) {
|
||||
constructor({
|
||||
bufferSize = 3,
|
||||
perCharge = 1,
|
||||
batteryPosition = new Vector(),
|
||||
acceptorSlotIndex = 0,
|
||||
ejectorSlotIndex = 0,
|
||||
}) {
|
||||
super();
|
||||
this.bufferSize = bufferSize;
|
||||
this.perCharge = perCharge;
|
||||
this.batteryPosition = batteryPosition;
|
||||
this.energyType = enumItemType.positiveEnergy;
|
||||
this.wasteType = enumItemType.negativeEnergy;
|
||||
this.acceptorSlotIndex = acceptorSlotIndex;
|
||||
this.ejectorSlotIndex = ejectorSlotIndex;
|
||||
|
||||
/**
|
||||
* How much energy we have stored right now
|
||||
*/
|
||||
this.stored = 0;
|
||||
|
||||
/**
|
||||
* How much waste we have piled up so far
|
||||
*/
|
||||
this.piledOutput = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to accept a given item
|
||||
* @param {BaseItem} item
|
||||
* @param {number} slotIndex
|
||||
*/
|
||||
tryAcceptItem(item, slotIndex) {
|
||||
if (slotIndex !== this.acceptorSlotIndex) {
|
||||
// Wrong slot
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.getItemType() !== this.energyType) {
|
||||
// Not the right type
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.stored >= this.bufferSize) {
|
||||
// We are full
|
||||
return false;
|
||||
}
|
||||
|
||||
// All good, consume
|
||||
this.stored = Math.min(this.stored + 1, this.bufferSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to start the next charge
|
||||
*/
|
||||
tryStartNextCharge() {
|
||||
if (this.hasTooMuchWastePiled()) {
|
||||
// Too much waste remaining
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.stored < this.perCharge) {
|
||||
// Not enough energy stored
|
||||
return false;
|
||||
}
|
||||
|
||||
this.stored -= this.perCharge;
|
||||
this.piledOutput += this.perCharge;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if there is too much waste piled
|
||||
*/
|
||||
hasTooMuchWastePiled() {
|
||||
return this.piledOutput >= 1.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces the waste by the given amount
|
||||
* @param {number} amount
|
||||
*/
|
||||
reduceWaste(amount) {
|
||||
this.piledOutput = Math.max(0, this.piledOutput - amount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { GameSystemWithFilter } from "../game_system_with_filter";
|
||||
import { EnergyConsumerComponent } from "../components/energy_consumer";
|
||||
import { Loader } from "../../core/loader";
|
||||
import { DrawParameters } from "../../core/draw_parameters";
|
||||
import { Loader } from "../../core/loader";
|
||||
import { clamp } from "../../core/utils";
|
||||
import { enumItemType } from "../base_item";
|
||||
import { EnergyConsumerComponent } from "../components/energy_consumer";
|
||||
import { Entity } from "../entity";
|
||||
import { enableImageSmoothing } from "../../core/buffer_utils";
|
||||
import { GameSystemWithFilter } from "../game_system_with_filter";
|
||||
import { NEGATIVE_ENERGY_ITEM_SINGLETON } from "../items/negative_energy_item";
|
||||
import { POSITIVE_ENERGY_ITEM_SINGLETON } from "../items/positive_energy_item";
|
||||
|
||||
export class EnergyConsumerSystem extends GameSystemWithFilter {
|
||||
constructor(root) {
|
||||
@@ -15,6 +18,41 @@ export class EnergyConsumerSystem extends GameSystemWithFilter {
|
||||
Loader.getSprite("sprites/wires/battery_medium.png"),
|
||||
Loader.getSprite("sprites/wires/battery_full.png"),
|
||||
];
|
||||
|
||||
this.piledWasteSprite = Loader.getSprite("sprites/wires/waste_piled.png");
|
||||
}
|
||||
|
||||
update() {
|
||||
for (let i = 0; i < this.allEntities.length; ++i) {
|
||||
const entity = this.allEntities[i];
|
||||
const energyConsumerComp = entity.components.EnergyConsumer;
|
||||
|
||||
if (energyConsumerComp.piledOutput >= 1.0) {
|
||||
// Try to get rid of waste
|
||||
|
||||
const ejectorComp = entity.components.ItemEjector;
|
||||
const item = this.getItemSingletonByType(energyConsumerComp.wasteType);
|
||||
if (ejectorComp.tryEject(energyConsumerComp.ejectorSlotIndex, item)) {
|
||||
// Got rid of waste
|
||||
energyConsumerComp.reduceWaste(1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {enumItemType} itemType
|
||||
*/
|
||||
getItemSingletonByType(itemType) {
|
||||
switch (itemType) {
|
||||
case enumItemType.positiveEnergy:
|
||||
return POSITIVE_ENERGY_ITEM_SINGLETON;
|
||||
case enumItemType.negativeEnergy:
|
||||
return NEGATIVE_ENERGY_ITEM_SINGLETON;
|
||||
default:
|
||||
assertAlways(false, "Bad item type: " + itemType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,9 +78,17 @@ export class EnergyConsumerSystem extends GameSystemWithFilter {
|
||||
.toWorldSpace()
|
||||
.add(consumerComp.batteryPosition);
|
||||
|
||||
const percentage = consumerComp.stored / consumerComp.bufferSize;
|
||||
if (consumerComp.hasTooMuchWastePiled()) {
|
||||
this.piledWasteSprite.drawCachedCentered(parameters, position.x, position.y, 12);
|
||||
} else {
|
||||
const percentage = consumerComp.stored / consumerComp.bufferSize;
|
||||
const index = clamp(
|
||||
Math.round(percentage * this.batterySprites.length),
|
||||
0,
|
||||
this.batterySprites.length - 1
|
||||
);
|
||||
|
||||
const index = Math.floor(percentage * this.batterySprites.length);
|
||||
this.batterySprites[index].drawCachedCentered(parameters, position.x, position.y, 12);
|
||||
this.batterySprites[index].drawCachedCentered(parameters, position.x, position.y, 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { DrawParameters } from "../../core/draw_parameters";
|
||||
import { createLogger } from "../../core/logging";
|
||||
import { Rectangle } from "../../core/rectangle";
|
||||
import { enumDirectionToVector, Vector } from "../../core/vector";
|
||||
import { BaseItem } from "../base_item";
|
||||
import { BaseItem, enumItemType, enumItemTypeToLayer } from "../base_item";
|
||||
import { ItemEjectorComponent } from "../components/item_ejector";
|
||||
import { Entity } from "../entity";
|
||||
import { GameSystemWithFilter } from "../game_system_with_filter";
|
||||
@@ -257,6 +257,8 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
||||
// TODO: Kinda hacky. How to solve this properly? Don't want to go through inheritance hell.
|
||||
// Also its just a few cases (hope it stays like this .. :x).
|
||||
|
||||
const itemLayer = enumItemTypeToLayer[item.getItemType()];
|
||||
|
||||
const beltComp = receiver.components.Belt;
|
||||
if (beltComp) {
|
||||
const path = beltComp.assignedPath;
|
||||
@@ -268,14 +270,27 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
||||
return false;
|
||||
}
|
||||
|
||||
const itemProcessorComp = receiver.components.ItemProcessor;
|
||||
if (itemProcessorComp) {
|
||||
// Its an item processor ..
|
||||
if (itemProcessorComp.tryTakeItem(item, slotIndex)) {
|
||||
const energyConsumerComp = receiver.components.EnergyConsumer;
|
||||
if (energyConsumerComp) {
|
||||
if (energyConsumerComp.tryAcceptItem(item, slotIndex)) {
|
||||
// All good
|
||||
return true;
|
||||
}
|
||||
// Item processor can have nothing else
|
||||
return false;
|
||||
|
||||
// Energy consumer can have more components
|
||||
}
|
||||
|
||||
const itemProcessorComp = receiver.components.ItemProcessor;
|
||||
if (itemProcessorComp) {
|
||||
// Make sure its the same layer
|
||||
if (itemLayer === receiver.layer) {
|
||||
// Its an item processor ..
|
||||
if (itemProcessorComp.tryTakeItem(item, slotIndex)) {
|
||||
return true;
|
||||
}
|
||||
// Item processor can have nothing else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const undergroundBeltComp = receiver.components.UndergroundBelt;
|
||||
|
||||
@@ -75,7 +75,16 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
||||
// Check if we have an empty queue and can start a new charge
|
||||
if (processorComp.itemsToEject.length === 0) {
|
||||
if (processorComp.inputSlots.length >= processorComp.inputsPerCharge) {
|
||||
this.startNewCharge(entity);
|
||||
const energyConsumerComp = entity.components.EnergyConsumer;
|
||||
if (energyConsumerComp) {
|
||||
// Check if we have enough energy
|
||||
if (energyConsumerComp.tryStartNextCharge()) {
|
||||
this.startNewCharge(entity);
|
||||
}
|
||||
} else {
|
||||
// No further checks required
|
||||
this.startNewCharge(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -339,10 +348,10 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
||||
// ADVANCED PROCESSING
|
||||
|
||||
case enumItemProcessorTypes.advancedProcessor: {
|
||||
// TODO
|
||||
|
||||
entity.components.ItemEjector.tryEject(1, NEGATIVE_ENERGY_ITEM_SINGLETON);
|
||||
|
||||
outItems.push({
|
||||
item: items[0].item,
|
||||
requiredSlot: 0,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user