Implement concept of energy consumption

This commit is contained in:
tobspr 2020-07-02 17:43:47 +02:00
parent a977d4f9f4
commit a77911263d
22 changed files with 594 additions and 385 deletions

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:688b663c660bd9f92ec78bd1e4d0d10813bfb09ffe3c95408fab36a908553628
size 962903
oid sha256:aaf7ee9ed1cf6c7f1a0c496f24663c98ab308d3531a450a2d41bdee266221eb0
size 963227

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c334d77dabdc40fef4ece56ccef9eaa59b5b6b9381817c234f9bf07d00e676e5
size 12721033
oid sha256:5aa1330b9f7ec2babd99bf5f6de58ba80de0da10cfca9d3adca433b2fe34d3ff
size 12801882

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 67 KiB

View File

@ -1202,7 +1202,7 @@
},
"sprites/misc/lock_direction_indicator.png":
{
"frame": {"x":65,"y":1873,"w":48,"h":30},
"frame": {"x":1570,"y":1661,"w":48,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":48,"h":30},
@ -1258,7 +1258,7 @@
},
"sprites/wires/battery_full.png":
{
"frame": {"x":3,"y":1873,"w":58,"h":38},
"frame": {"x":1508,"y":1661,"w":58,"h":38},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":14,"w":58,"h":38},
@ -1266,7 +1266,7 @@
},
"sprites/wires/battery_low.png":
{
"frame": {"x":1508,"y":1661,"w":58,"h":38},
"frame": {"x":2548,"y":1172,"w":58,"h":38},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":14,"w":58,"h":38},
@ -1274,7 +1274,7 @@
},
"sprites/wires/battery_medium.png":
{
"frame": {"x":2548,"y":1172,"w":58,"h":38},
"frame": {"x":65,"y":1873,"w":58,"h":38},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":14,"w":58,"h":38},
@ -1327,6 +1327,14 @@
"trimmed": true,
"spriteSourceSize": {"x":11,"y":11,"w":42,"h":42},
"sourceSize": {"w":64,"h":64}
},
"sprites/wires/waste_piled.png":
{
"frame": {"x":3,"y":1873,"w":58,"h":55},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":4,"w":58,"h":55},
"sourceSize": {"w":64,"h":64}
}},
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
@ -1335,6 +1343,6 @@
"format": "RGBA8888",
"size": {"w":2764,"h":1933},
"scale": "1",
"smartupdate": "$TexturePacker:SmartUpdate:e8c413f60f96b12d878fb0fbf75d98e6:c8ebf93da8392443efe79b5d6c6bcd32:f159918d23e5952766c6d23ab52278c6$"
"smartupdate": "$TexturePacker:SmartUpdate:1caa58cc124d4a31029319d973957f35:dac5f0c449de47bf040f30c87841ea79:f159918d23e5952766c6d23ab52278c6$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -1146,7 +1146,7 @@
},
"sprites/debug/acceptor_slot.png":
{
"frame": {"x":336,"y":464,"w":14,"h":16},
"frame": {"x":404,"y":453,"w":14,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":14,"h":16},
@ -1154,7 +1154,7 @@
},
"sprites/debug/ejector_slot.png":
{
"frame": {"x":482,"y":450,"w":14,"h":16},
"frame": {"x":422,"y":453,"w":14,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":14,"h":16},
@ -1162,7 +1162,7 @@
},
"sprites/map_overview/belt_forward.png":
{
"frame": {"x":241,"y":311,"w":8,"h":8},
"frame": {"x":798,"y":193,"w":8,"h":8},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":8,"h":8},
@ -1170,7 +1170,7 @@
},
"sprites/map_overview/belt_left.png":
{
"frame": {"x":794,"y":193,"w":8,"h":8},
"frame": {"x":798,"y":205,"w":8,"h":8},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":8,"h":8},
@ -1178,7 +1178,7 @@
},
"sprites/map_overview/belt_right.png":
{
"frame": {"x":241,"y":323,"w":8,"h":8},
"frame": {"x":241,"y":311,"w":8,"h":8},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":8,"h":8},
@ -1194,7 +1194,7 @@
},
"sprites/misc/hub_direction_indicator.png":
{
"frame": {"x":565,"y":467,"w":8,"h":8},
"frame": {"x":356,"y":464,"w":8,"h":8},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":8,"h":8},
@ -1202,7 +1202,7 @@
},
"sprites/misc/lock_direction_indicator.png":
{
"frame": {"x":778,"y":193,"w":12,"h":10},
"frame": {"x":581,"y":467,"w":12,"h":10},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":1,"w":12,"h":10},
@ -1234,7 +1234,7 @@
},
"sprites/misc/waypoint.png":
{
"frame": {"x":577,"y":467,"w":8,"h":8},
"frame": {"x":241,"y":323,"w":8,"h":8},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":8,"h":8},
@ -1250,7 +1250,7 @@
},
"sprites/wires/battery_empty.png":
{
"frame": {"x":354,"y":464,"w":12,"h":16},
"frame": {"x":440,"y":453,"w":12,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":12,"h":16},
@ -1258,7 +1258,7 @@
},
"sprites/wires/battery_full.png":
{
"frame": {"x":370,"y":468,"w":16,"h":12},
"frame": {"x":280,"y":430,"w":16,"h":12},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":16,"h":12},
@ -1266,7 +1266,7 @@
},
"sprites/wires/battery_low.png":
{
"frame": {"x":280,"y":430,"w":16,"h":12},
"frame": {"x":300,"y":430,"w":16,"h":12},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":16,"h":12},
@ -1274,7 +1274,7 @@
},
"sprites/wires/battery_medium.png":
{
"frame": {"x":300,"y":430,"w":16,"h":12},
"frame": {"x":778,"y":193,"w":16,"h":12},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":16,"h":12},
@ -1322,11 +1322,19 @@
},
"sprites/wires/positive_energy.png":
{
"frame": {"x":390,"y":468,"w":12,"h":12},
"frame": {"x":565,"y":467,"w":12,"h":12},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":12,"h":12},
"sourceSize": {"w":16,"h":16}
},
"sprites/wires/waste_piled.png":
{
"frame": {"x":336,"y":464,"w":16,"h":16},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":16,"h":16},
"sourceSize": {"w":16,"h":16}
}},
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
@ -1335,6 +1343,6 @@
"format": "RGBA8888",
"size": {"w":809,"h":484},
"scale": "0.25",
"smartupdate": "$TexturePacker:SmartUpdate:e8c413f60f96b12d878fb0fbf75d98e6:c8ebf93da8392443efe79b5d6c6bcd32:f159918d23e5952766c6d23ab52278c6$"
"smartupdate": "$TexturePacker:SmartUpdate:1caa58cc124d4a31029319d973957f35:dac5f0c449de47bf040f30c87841ea79:f159918d23e5952766c6d23ab52278c6$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

After

Width:  |  Height:  |  Size: 214 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 503 KiB

After

Width:  |  Height:  |  Size: 508 KiB

View File

@ -1162,7 +1162,7 @@
},
"sprites/map_overview/belt_forward.png":
{
"frame": {"x":1139,"y":1427,"w":20,"h":24},
"frame": {"x":1863,"y":1089,"w":20,"h":24},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":20,"h":24},
@ -1202,7 +1202,7 @@
},
"sprites/misc/lock_direction_indicator.png":
{
"frame": {"x":1956,"y":490,"w":36,"h":24},
"frame": {"x":1139,"y":1427,"w":36,"h":24},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":6,"w":36,"h":24},
@ -1234,7 +1234,7 @@
},
"sprites/misc/waypoint.png":
{
"frame": {"x":1863,"y":1089,"w":20,"h":24},
"frame": {"x":796,"y":1478,"w":20,"h":24},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":20,"h":24},
@ -1258,7 +1258,7 @@
},
"sprites/wires/battery_full.png":
{
"frame": {"x":1483,"y":569,"w":44,"h":30},
"frame": {"x":1483,"y":616,"w":44,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":10,"w":44,"h":30},
@ -1266,7 +1266,7 @@
},
"sprites/wires/battery_low.png":
{
"frame": {"x":1483,"y":603,"w":44,"h":30},
"frame": {"x":1708,"y":621,"w":44,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":10,"w":44,"h":30},
@ -1274,7 +1274,7 @@
},
"sprites/wires/battery_medium.png":
{
"frame": {"x":1708,"y":621,"w":44,"h":30},
"frame": {"x":1956,"y":490,"w":44,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":10,"w":44,"h":30},
@ -1327,6 +1327,14 @@
"trimmed": true,
"spriteSourceSize": {"x":8,"y":8,"w":32,"h":32},
"sourceSize": {"w":48,"h":48}
},
"sprites/wires/waste_piled.png":
{
"frame": {"x":1483,"y":569,"w":44,"h":43},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":44,"h":43},
"sourceSize": {"w":48,"h":48}
}},
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
@ -1335,6 +1343,6 @@
"format": "RGBA8888",
"size": {"w":2035,"h":1506},
"scale": "0.75",
"smartupdate": "$TexturePacker:SmartUpdate:e8c413f60f96b12d878fb0fbf75d98e6:c8ebf93da8392443efe79b5d6c6bcd32:f159918d23e5952766c6d23ab52278c6$"
"smartupdate": "$TexturePacker:SmartUpdate:1caa58cc124d4a31029319d973957f35:dac5f0c449de47bf040f30c87841ea79:f159918d23e5952766c6d23ab52278c6$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1014 KiB

After

Width:  |  Height:  |  Size: 1016 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -72,7 +72,7 @@ export const globalConfig = {
painterQuad: 1 / 8,
mixer: 1 / 5,
stacker: 1 / 6,
advancedProcessor: 1 / 15,
advancedProcessor: 1 / 6,
},
// Zooming

View File

@ -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
*/

View File

@ -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,
},

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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;
}