Improve placement of belts
BIN
res_raw/sprites/blueprints/belt_left.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
res_raw/sprites/blueprints/belt_right.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
res_raw/sprites/blueprints/belt_top.png
Normal file
After Width: | Height: | Size: 1022 B |
BIN
res_raw/sprites/blueprints/cutter.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
res_raw/sprites/blueprints/miner.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
res_raw/sprites/blueprints/mixer.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
res_raw/sprites/blueprints/painter.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
res_raw/sprites/blueprints/rotater.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
res_raw/sprites/blueprints/splitter.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
res_raw/sprites/blueprints/stacker.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
res_raw/sprites/blueprints/trash.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
res_raw/sprites/blueprints/underground_belt_entry.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
res_raw/sprites/blueprints/underground_belt_exit.png
Normal file
After Width: | Height: | Size: 11 KiB |
96
res_raw/sprites/create_blueprint_previews.py
Normal file
@ -0,0 +1,96 @@
|
||||
# Requirements: numpy, scipy, Pillow,
|
||||
|
||||
import sys
|
||||
import numpy as np
|
||||
from scipy import ndimage
|
||||
from PIL import Image, ImageFilter, ImageChops
|
||||
import math
|
||||
from os import listdir
|
||||
from os.path import isdir, isfile
|
||||
|
||||
roberts_cross_v = np.array([[0, 0, 0],
|
||||
[0, 1, 0],
|
||||
[0, 0, -1]])
|
||||
|
||||
roberts_cross_h = np.array([[0, 0, 0],
|
||||
[0, 0, 1],
|
||||
[0, -1, 0]])
|
||||
|
||||
|
||||
def rgb2gray(rgb):
|
||||
return np.dot(rgb[..., :3], [0.2989, 0.5870, 0.1140])
|
||||
|
||||
|
||||
def save_image(data, outfilename, src_image):
|
||||
img = Image.fromarray(np.asarray(
|
||||
np.clip(data, 0, 255), dtype="uint8"), "L")
|
||||
dest = Image.new("RGBA", (img.width, img.height))
|
||||
src = img.load()
|
||||
dst = dest.load()
|
||||
|
||||
realSrc = src_image.load()
|
||||
mask = src_image.filter(ImageFilter.GaussianBlur(10)).load()
|
||||
orig = src_image.load()
|
||||
|
||||
for x in range(img.width):
|
||||
for y in range(img.height):
|
||||
realpixl = realSrc[x, y]
|
||||
greyval = float(src[x, y])
|
||||
greyval = min(255.0, greyval)
|
||||
greyval = math.pow(
|
||||
min(1, float(greyval / 255.0 * 1)), 1.5) * 255.0 * 1
|
||||
greyval = max(0, greyval)
|
||||
alpha = mask[x, y][3] / 255.0 * 1
|
||||
|
||||
edgeFactor = src[x, y] / 255.0
|
||||
noEdge = 1 - edgeFactor
|
||||
|
||||
shadow = min(1, 1 - realpixl[3] / 255.0 - edgeFactor)
|
||||
noShadow = 1 - shadow
|
||||
|
||||
dst[x, y] = (
|
||||
min(255, int((realpixl[0] / 255.0 * 0.4 + 0.6) * 104 * 1.1)),
|
||||
min(255, int((realpixl[1] / 255.0 * 0.4 + 0.6) * 200 * 1.1)),
|
||||
min(255, int((realpixl[2] / 255.0 * 0.4 + 0.6) * 255 * 1.1)),
|
||||
min(255, int(float(realpixl[3]) * (0.6 + 5 * edgeFactor))))
|
||||
|
||||
|
||||
dest.save(outfilename)
|
||||
|
||||
|
||||
def roberts_cross(infilename, outfilename):
|
||||
print "Processing", infilename
|
||||
img = Image.open(infilename)
|
||||
img.load()
|
||||
img = img.filter(ImageFilter.GaussianBlur(0.5))
|
||||
|
||||
image = rgb2gray(np.asarray(img, dtype="int32"))
|
||||
vertical = ndimage.convolve(image, roberts_cross_v)
|
||||
horizontal = ndimage.convolve(image, roberts_cross_h)
|
||||
output_image = np.sqrt(np.square(horizontal) + np.square(vertical))
|
||||
save_image(output_image, outfilename, img)
|
||||
|
||||
|
||||
def generateUiPreview(srcPath, buildingId):
|
||||
print srcPath, buildingId
|
||||
img = Image.open(srcPath)
|
||||
img.load()
|
||||
img.thumbnail((110, 110), Image.ANTIALIAS)
|
||||
img.save("../res/ui/hud/building_previews/" + buildingId + ".png")
|
||||
|
||||
img = img.convert("LA")
|
||||
|
||||
data = img.load()
|
||||
for x in range(img.width):
|
||||
for y in range(img.height):
|
||||
data[x, y] = (data[x, y][0], int(data[x, y][1] * 0.5))
|
||||
|
||||
img.save("../res/ui/hud/building_previews/" + buildingId + "_disabled.png")
|
||||
|
||||
|
||||
buildings = listdir("buildings")
|
||||
|
||||
for buildingId in buildings:
|
||||
if "hub" in buildingId:
|
||||
continue
|
||||
roberts_cross("buildings/" + buildingId + "", "blueprints/" + buildingId + "")
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.1 KiB |
@ -175,13 +175,14 @@ export class Rectangle {
|
||||
return new Rectangle(this.x * factor, this.y * factor, this.w * factor, this.h * factor);
|
||||
}
|
||||
|
||||
// Increases the rectangle in all directions
|
||||
expandInAllDirections(amount) {
|
||||
this.x -= amount;
|
||||
this.y -= amount;
|
||||
this.w += 2 * amount;
|
||||
this.h += 2 * amount;
|
||||
return this;
|
||||
/**
|
||||
* Expands the rectangle in all directions
|
||||
* @param {number} amount
|
||||
* @returns {Rectangle} new rectangle
|
||||
*/
|
||||
|
||||
expandedInAllDirections(amount) {
|
||||
return new Rectangle(this.x - amount, this.y - amount, this.w + 2 * amount, this.h + 2 * amount);
|
||||
}
|
||||
|
||||
// Culling helpers
|
||||
|
@ -19,6 +19,52 @@ export class MetaBeltBaseBuilding extends MetaBuilding {
|
||||
return "#777";
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Belt";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Transports items, hold and drag to place multiple, press 'R' to rotate.";
|
||||
}
|
||||
|
||||
getPreviewSprite(rotationVariant) {
|
||||
switch (arrayBeltVariantToRotation[rotationVariant]) {
|
||||
case enumDirection.top: {
|
||||
return Loader.getSprite("sprites/buildings/belt_top.png");
|
||||
}
|
||||
case enumDirection.left: {
|
||||
return Loader.getSprite("sprites/buildings/belt_left.png");
|
||||
}
|
||||
case enumDirection.right: {
|
||||
return Loader.getSprite("sprites/buildings/belt_right.png");
|
||||
}
|
||||
default: {
|
||||
assertAlways(false, "Invalid belt rotation variant");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getBlueprintSprite(rotationVariant) {
|
||||
switch (arrayBeltVariantToRotation[rotationVariant]) {
|
||||
case enumDirection.top: {
|
||||
return Loader.getSprite("sprites/blueprints/belt_top.png");
|
||||
}
|
||||
case enumDirection.left: {
|
||||
return Loader.getSprite("sprites/blueprints/belt_left.png");
|
||||
}
|
||||
case enumDirection.right: {
|
||||
return Loader.getSprite("sprites/blueprints/belt_right.png");
|
||||
}
|
||||
default: {
|
||||
assertAlways(false, "Invalid belt rotation variant");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getStayInPlacementMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
@ -140,65 +186,29 @@ export class MetaBeltBaseBuilding extends MetaBuilding {
|
||||
|
||||
// When there is a top acceptor, ignore sides
|
||||
// NOTICE: This makes the belt prefer side turns *way* too much!
|
||||
// if (!hasTopAcceptor) {
|
||||
// // When there is an acceptor to the right but no acceptor to the left,
|
||||
// // do a turn to the right
|
||||
// if (hasRightAcceptor && !hasLeftAcceptor) {
|
||||
// return {
|
||||
// rotation,
|
||||
// rotationVariant: 2,
|
||||
// };
|
||||
// }
|
||||
if (!hasTopAcceptor) {
|
||||
// When there is an acceptor to the right but no acceptor to the left,
|
||||
// do a turn to the right
|
||||
if (hasRightAcceptor && !hasLeftAcceptor) {
|
||||
return {
|
||||
rotation,
|
||||
rotationVariant: 2,
|
||||
};
|
||||
}
|
||||
|
||||
// // When there is an acceptor to the left but no acceptor to the right,
|
||||
// // do a turn to the left
|
||||
// if (hasLeftAcceptor && !hasRightAcceptor) {
|
||||
// return {
|
||||
// rotation,
|
||||
// rotationVariant: 1,
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// When there is an acceptor to the left but no acceptor to the right,
|
||||
// do a turn to the left
|
||||
if (hasLeftAcceptor && !hasRightAcceptor) {
|
||||
return {
|
||||
rotation,
|
||||
rotationVariant: 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
rotation,
|
||||
rotationVariant: 0,
|
||||
};
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Belt";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Transports items, hold and drag to place multiple, press 'R' to rotate.";
|
||||
}
|
||||
|
||||
getPreviewSprite(rotationVariant) {
|
||||
switch (arrayBeltVariantToRotation[rotationVariant]) {
|
||||
case enumDirection.top: {
|
||||
return Loader.getSprite("sprites/belt/forward_0.png");
|
||||
}
|
||||
case enumDirection.left: {
|
||||
return Loader.getSprite("sprites/belt/left_0.png");
|
||||
}
|
||||
case enumDirection.right: {
|
||||
return Loader.getSprite("sprites/belt/right_0.png");
|
||||
}
|
||||
default: {
|
||||
assertAlways(false, "Invalid belt rotation variant");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getStayInPlacementMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be overridden
|
||||
*/
|
||||
internalGetBeltDirection(rotationVariant) {
|
||||
return enumDirection.top;
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,17 @@ export class MetaUndergroundBeltBuilding extends MetaBuilding {
|
||||
}
|
||||
}
|
||||
|
||||
getBlueprintSprite(rotationVariant) {
|
||||
switch (arrayUndergroundRotationVariantToMode[rotationVariant]) {
|
||||
case enumUndergroundBeltMode.sender:
|
||||
return Loader.getSprite("sprites/blueprints/underground_belt_entry.png");
|
||||
case enumUndergroundBeltMode.receiver:
|
||||
return Loader.getSprite("sprites/blueprints/underground_belt_exit.png");
|
||||
default:
|
||||
assertAlways(false, "Invalid rotation variant");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
|
@ -13,7 +13,7 @@ import {
|
||||
import { pulseAnimation, makeDiv } from "../../../core/utils";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
import { TrackedState } from "../../../core/tracked_state";
|
||||
import { Math_abs, Math_radians } from "../../../core/builtins";
|
||||
import { Math_abs, Math_radians, Math_degrees } from "../../../core/builtins";
|
||||
import { Loader } from "../../../core/loader";
|
||||
import { drawRotatedSprite } from "../../../core/draw_utils";
|
||||
import { Entity } from "../../entity";
|
||||
@ -96,6 +96,9 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
||||
|
||||
if (!oldPos.equals(newPos)) {
|
||||
const delta = newPos.sub(oldPos);
|
||||
const angleDeg = Math_degrees(delta.angle());
|
||||
this.currentBaseRotation = (Math.round(angleDeg / 90) * 90 + 360) % 360;
|
||||
|
||||
// - Using bresenhams algorithmus
|
||||
|
||||
let x0 = oldPos.x;
|
||||
@ -351,36 +354,49 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
||||
metaBuilding.updateRotationVariant(this.fakeEntity, rotationVariant);
|
||||
|
||||
// Check if we could place the buildnig
|
||||
const canBuild = this.root.logic.checkCanPlaceBuilding(tile, rotation, metaBuilding);
|
||||
const canBuild = this.root.logic.checkCanPlaceBuilding({
|
||||
origin: tile,
|
||||
rotation,
|
||||
rotationVariant,
|
||||
building: metaBuilding,
|
||||
});
|
||||
|
||||
// Fade in / out
|
||||
parameters.context.lineWidth = 1;
|
||||
// parameters.context.globalAlpha = 0.3 + pulseAnimation(this.root.time.realtimeNow(), 0.9) * 0.7;
|
||||
|
||||
// Determine the bounds and visualize them
|
||||
const entityBounds = staticComp.getTileSpaceBounds();
|
||||
const drawBorder = 2;
|
||||
parameters.context.globalAlpha = 0.5;
|
||||
const drawBorder = -3;
|
||||
if (canBuild) {
|
||||
parameters.context.fillStyle = "rgba(0, 255, 0, 0.2)";
|
||||
parameters.context.strokeStyle = "rgba(56, 235, 111, 0.5)";
|
||||
parameters.context.fillStyle = "rgba(56, 235, 111, 0.2)";
|
||||
} else {
|
||||
parameters.context.strokeStyle = "rgba(255, 0, 0, 0.2)";
|
||||
parameters.context.fillStyle = "rgba(255, 0, 0, 0.2)";
|
||||
}
|
||||
parameters.context.fillRect(
|
||||
|
||||
parameters.context.beginRoundedRect(
|
||||
entityBounds.x * globalConfig.tileSize - drawBorder,
|
||||
entityBounds.y * globalConfig.tileSize - drawBorder,
|
||||
entityBounds.w * globalConfig.tileSize + 2 * drawBorder,
|
||||
entityBounds.h * globalConfig.tileSize + 2 * drawBorder
|
||||
entityBounds.h * globalConfig.tileSize + 2 * drawBorder,
|
||||
4
|
||||
);
|
||||
parameters.context.stroke();
|
||||
// parameters.context.fill();
|
||||
parameters.context.globalAlpha = 1;
|
||||
|
||||
// HACK to draw the entity sprite
|
||||
const previewSprite = metaBuilding.getBlueprintSprite(rotationVariant);
|
||||
staticComp.origin = worldPos.divideScalar(globalConfig.tileSize).subScalars(0.5, 0.5);
|
||||
staticComp.drawSpriteOnFullEntityBounds(parameters, previewSprite);
|
||||
staticComp.origin = tile;
|
||||
|
||||
// Draw ejectors
|
||||
if (canBuild) {
|
||||
this.drawMatchingAcceptorsAndEjectors(parameters);
|
||||
}
|
||||
|
||||
// HACK to draw the entity sprite
|
||||
const previewSprite = metaBuilding.getPreviewSprite(rotationVariant);
|
||||
parameters.context.globalAlpha = 0.8 + pulseAnimation(this.root.time.realtimeNow(), 1) * 0.1;
|
||||
staticComp.origin = worldPos.divideScalar(globalConfig.tileSize).subScalars(0.5, 0.5);
|
||||
staticComp.drawSpriteOnFullEntityBounds(parameters, previewSprite);
|
||||
staticComp.origin = tile;
|
||||
parameters.context.globalAlpha = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -397,6 +413,8 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
||||
|
||||
// Just ignore this code ...
|
||||
|
||||
const offsetShift = 10;
|
||||
|
||||
if (acceptorComp) {
|
||||
const slots = acceptorComp.slots;
|
||||
for (let acceptorSlotIndex = 0; acceptorSlotIndex < slots.length; ++acceptorSlotIndex) {
|
||||
@ -437,7 +455,7 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
||||
y: acceptorSlotWsPos.y,
|
||||
angle: Math_radians(enumDirectionToAngle[enumInvertedDirections[worldDirection]]),
|
||||
size: 13,
|
||||
offsetY: 15,
|
||||
offsetY: offsetShift + 13,
|
||||
});
|
||||
parameters.context.globalAlpha = 1;
|
||||
}
|
||||
@ -483,7 +501,7 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
||||
y: ejectorSLotWsPos.y,
|
||||
angle: Math_radians(enumDirectionToAngle[ejectorSlotWsDirection]),
|
||||
size: 13,
|
||||
offsetY: 15,
|
||||
offsetY: offsetShift,
|
||||
});
|
||||
parameters.context.globalAlpha = 1;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import { StaticMapEntityComponent } from "./components/static_map_entity";
|
||||
import { Math_abs } from "../core/builtins";
|
||||
import { Rectangle } from "../core/rectangle";
|
||||
import { createLogger } from "../core/logging";
|
||||
import { MetaBeltBaseBuilding, arrayBeltVariantToRotation } from "./buildings/belt_base";
|
||||
|
||||
const logger = createLogger("ingame/logic");
|
||||
|
||||
@ -46,12 +47,14 @@ export class GameLogic {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Vector} origin
|
||||
* @param {number} rotation
|
||||
* @param {MetaBuilding} building
|
||||
* @param {object} param0
|
||||
* @param {Vector} param0.origin
|
||||
* @param {number} param0.rotation
|
||||
* @param {number} param0.rotationVariant
|
||||
* @param {MetaBuilding} param0.building
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isAreaFreeToBuild(origin, rotation, building) {
|
||||
isAreaFreeToBuild({ origin, rotation, rotationVariant, building }) {
|
||||
const checker = new StaticMapEntityComponent({
|
||||
origin,
|
||||
tileSize: building.getDimensions(),
|
||||
@ -63,8 +66,19 @@ export class GameLogic {
|
||||
for (let x = rect.x; x < rect.x + rect.w; ++x) {
|
||||
for (let y = rect.y; y < rect.y + rect.h; ++y) {
|
||||
const contents = this.root.map.getTileContentXY(x, y);
|
||||
if (contents && !contents.components.ReplaceableMapEntity) {
|
||||
return false;
|
||||
if (contents) {
|
||||
if (
|
||||
!this.checkCanReplaceBuilding({
|
||||
original: contents,
|
||||
origin,
|
||||
building,
|
||||
rotation,
|
||||
rotationVariant,
|
||||
})
|
||||
) {
|
||||
// Content already has same rotation
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -72,16 +86,54 @@ export class GameLogic {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Vector} origin
|
||||
* @param {number} rotation
|
||||
* @param {MetaBuilding} building
|
||||
* Checks if the given building can be replaced by another
|
||||
* @param {object} param0
|
||||
* @param {Entity} param0.original
|
||||
* @param {Vector} param0.origin
|
||||
* @param {number} param0.rotation
|
||||
* @param {number} param0.rotationVariant
|
||||
* @param {MetaBuilding} param0.building
|
||||
* @returns {boolean}
|
||||
*/
|
||||
checkCanPlaceBuilding(origin, rotation, building) {
|
||||
checkCanReplaceBuilding({ original, origin, building, rotation, rotationVariant }) {
|
||||
if (!original.components.ReplaceableMapEntity) {
|
||||
// Can not get replaced at all
|
||||
return false;
|
||||
}
|
||||
|
||||
const staticComp = original.components.StaticMapEntity;
|
||||
assert(staticComp, "Building is not static");
|
||||
const beltComp = original.components.Belt;
|
||||
if (beltComp) {
|
||||
// Its a belt, check if it differs in either rotation or rotation variant
|
||||
if (staticComp.rotationDegrees !== rotation) {
|
||||
return true;
|
||||
}
|
||||
if (beltComp.direction !== arrayBeltVariantToRotation[rotationVariant]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} param0
|
||||
* @param {Vector} param0.origin
|
||||
* @param {number} param0.rotation
|
||||
* @param {number} param0.rotationVariant
|
||||
* @param {MetaBuilding} param0.building
|
||||
*/
|
||||
checkCanPlaceBuilding({ origin, rotation, rotationVariant, building }) {
|
||||
if (!building.getIsUnlocked(this.root)) {
|
||||
return false;
|
||||
}
|
||||
return this.isAreaFreeToBuild(origin, rotation, building);
|
||||
return this.isAreaFreeToBuild({
|
||||
origin,
|
||||
rotation,
|
||||
rotationVariant,
|
||||
building,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,7 +145,7 @@ export class GameLogic {
|
||||
* @param {MetaBuilding} param0.building
|
||||
*/
|
||||
tryPlaceBuilding({ origin, rotation, rotationVariant, building }) {
|
||||
if (this.checkCanPlaceBuilding(origin, rotation, building)) {
|
||||
if (this.checkCanPlaceBuilding({ origin, rotation, rotationVariant, building })) {
|
||||
// Remove any removeable entities below
|
||||
const checker = new StaticMapEntityComponent({
|
||||
origin,
|
||||
@ -106,7 +158,7 @@ export class GameLogic {
|
||||
for (let x = rect.x; x < rect.x + rect.w; ++x) {
|
||||
for (let y = rect.y; y < rect.y + rect.h; ++y) {
|
||||
const contents = this.root.map.getTileContentXY(x, y);
|
||||
if (contents && contents.components.ReplaceableMapEntity) {
|
||||
if (contents) {
|
||||
if (!this.tryDeleteBuilding(contents)) {
|
||||
logger.error("Building has replaceable component but is also unremovable");
|
||||
return false;
|
||||
|
@ -65,6 +65,14 @@ export class MetaBuilding {
|
||||
return Loader.getSprite("sprites/buildings/" + this.id + ".png");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sprite for blueprints
|
||||
* @returns {AtlasSprite}
|
||||
*/
|
||||
getBlueprintSprite(rotationVariant = 0) {
|
||||
return Loader.getSprite("sprites/blueprints/" + this.id + ".png");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this building is rotateable
|
||||
* @returns {boolean}
|
||||
@ -110,8 +118,8 @@ export class MetaBuilding {
|
||||
this.setupEntityComponents(entity, root);
|
||||
this.updateRotationVariant(entity, rotationVariant);
|
||||
|
||||
root.entityMgr.registerEntity(entity);
|
||||
root.map.placeStaticEntity(entity);
|
||||
root.entityMgr.registerEntity(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,8 @@ import { Entity } from "../entity";
|
||||
import { GameSystemWithFilter } from "../game_system_with_filter";
|
||||
import { enumDirection, enumDirectionToVector, Vector } from "../../core/vector";
|
||||
import { MapChunkView } from "../map_chunk_view";
|
||||
import { gMetaBuildingRegistry } from "../../core/global_registries";
|
||||
import { MetaBeltBaseBuilding } from "../buildings/belt_base";
|
||||
|
||||
const BELT_ANIM_COUNT = 6;
|
||||
|
||||
@ -51,6 +53,49 @@ export class BeltSystem extends GameSystemWithFilter {
|
||||
Loader.getSprite("sprites/belt/right_5.png"),
|
||||
],
|
||||
};
|
||||
|
||||
this.root.signals.entityAdded.add(this.updateSurroundingBeltPlacement, this);
|
||||
this.root.signals.entityDestroyed.add(this.updateSurroundingBeltPlacement, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the belt placement after an entity has been added / deleted
|
||||
* @param {Entity} entity
|
||||
*/
|
||||
updateSurroundingBeltPlacement(entity) {
|
||||
const staticComp = entity.components.StaticMapEntity;
|
||||
if (!staticComp) {
|
||||
return;
|
||||
}
|
||||
|
||||
const metaBelt = gMetaBuildingRegistry.findByClass(MetaBeltBaseBuilding);
|
||||
|
||||
// Compute affected area
|
||||
const originalRect = staticComp.getTileSpaceBounds();
|
||||
const affectedArea = originalRect.expandedInAllDirections(1);
|
||||
for (let x = affectedArea.x; x < affectedArea.right(); ++x) {
|
||||
for (let y = affectedArea.y; y < affectedArea.bottom(); ++y) {
|
||||
if (!originalRect.containsPoint(x, y)) {
|
||||
const targetEntity = this.root.map.getTileContentXY(x, y);
|
||||
if (targetEntity) {
|
||||
const targetBeltComp = targetEntity.components.Belt;
|
||||
if (targetBeltComp) {
|
||||
const targetStaticComp = targetEntity.components.StaticMapEntity;
|
||||
const {
|
||||
rotation,
|
||||
rotationVariant,
|
||||
} = metaBelt.computeOptimalDirectionAndRotationVariantAtTile(
|
||||
this.root,
|
||||
new Vector(x, y),
|
||||
targetStaticComp.rotationDegrees
|
||||
);
|
||||
targetStaticComp.rotationDegrees = rotation;
|
||||
metaBelt.updateRotationVariant(targetEntity, rotationVariant);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
draw(parameters) {
|
||||
|