mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-12-16 11:41:50 +00:00
Belt path drawing optimization
This commit is contained in:
parent
38cca33985
commit
670c07cba8
@ -1,7 +1,9 @@
|
|||||||
import { globalConfig } from "../core/config";
|
import { globalConfig } from "../core/config";
|
||||||
|
import { smoothenDpi } from "../core/dpi_manager";
|
||||||
import { DrawParameters } from "../core/draw_parameters";
|
import { DrawParameters } from "../core/draw_parameters";
|
||||||
import { createLogger } from "../core/logging";
|
import { createLogger } from "../core/logging";
|
||||||
import { Rectangle } from "../core/rectangle";
|
import { Rectangle } from "../core/rectangle";
|
||||||
|
import { ORIGINAL_SPRITE_SCALE } from "../core/sprites";
|
||||||
import { clamp, epsilonCompare, round4Digits } from "../core/utils";
|
import { clamp, epsilonCompare, round4Digits } from "../core/utils";
|
||||||
import { enumDirection, enumDirectionToVector, enumInvertedDirections, Vector } from "../core/vector";
|
import { enumDirection, enumDirectionToVector, enumInvertedDirections, Vector } from "../core/vector";
|
||||||
import { BasicSerializableObject, types } from "../savegame/serialization";
|
import { BasicSerializableObject, types } from "../savegame/serialization";
|
||||||
@ -1430,6 +1432,12 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
|
|
||||||
let trackPos = 0.0;
|
let trackPos = 0.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Array<[Vector, BaseItem]>}
|
||||||
|
*/
|
||||||
|
let drawStack = [];
|
||||||
|
let drawStackProp = "";
|
||||||
|
|
||||||
// Iterate whole track and check items
|
// Iterate whole track and check items
|
||||||
for (let i = 0; i < this.entityPath.length; ++i) {
|
for (let i = 0; i < this.entityPath.length; ++i) {
|
||||||
const entity = this.entityPath[i];
|
const entity = this.entityPath[i];
|
||||||
@ -1449,25 +1457,165 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
const worldPos = staticComp.localTileToWorld(localPos).toWorldSpaceCenterOfTile();
|
const worldPos = staticComp.localTileToWorld(localPos).toWorldSpaceCenterOfTile();
|
||||||
|
|
||||||
const distanceAndItem = this.items[currentItemIndex];
|
const distanceAndItem = this.items[currentItemIndex];
|
||||||
|
const item = distanceAndItem[1 /* item */];
|
||||||
|
const nextItemDistance = distanceAndItem[0 /* nextDistance */];
|
||||||
|
|
||||||
distanceAndItem[1 /* item */].drawItemCenteredClipped(
|
if (drawStack.length > 1) {
|
||||||
worldPos.x,
|
// Check if we can append to the stack, since its already a stack of two same items
|
||||||
worldPos.y,
|
const referenceItem = drawStack[0];
|
||||||
parameters,
|
if (Math.abs(referenceItem[0][drawStackProp] - worldPos[drawStackProp]) < 0.001) {
|
||||||
globalConfig.defaultItemDiameter
|
// Will continue stack
|
||||||
);
|
} else {
|
||||||
|
// Start a new stack, since item doesn't follow in row
|
||||||
|
this.drawDrawStack(drawStack, parameters, drawStackProp);
|
||||||
|
drawStack = [];
|
||||||
|
drawStackProp = "";
|
||||||
|
}
|
||||||
|
} else if (drawStack.length === 1) {
|
||||||
|
const firstItem = drawStack[0];
|
||||||
|
|
||||||
|
// Check if we can make it a stack
|
||||||
|
if (firstItem[1 /* item */].equals(item)) {
|
||||||
|
// Same item, check if it is either horizontal or vertical
|
||||||
|
const startPos = firstItem[0 /* pos */];
|
||||||
|
|
||||||
|
if (Math.abs(startPos.x - worldPos.x) < 0.001) {
|
||||||
|
drawStackProp = "x";
|
||||||
|
} else if (Math.abs(startPos.y - worldPos.y) < 0.001) {
|
||||||
|
drawStackProp = "y";
|
||||||
|
} else {
|
||||||
|
// Start a new stack
|
||||||
|
this.drawDrawStack(drawStack, parameters, drawStackProp);
|
||||||
|
drawStack = [];
|
||||||
|
drawStackProp = "";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Start a new stack, since item doesn't equal
|
||||||
|
this.drawDrawStack(drawStack, parameters, drawStackProp);
|
||||||
|
drawStack = [];
|
||||||
|
drawStackProp = "";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// First item of stack, do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
drawStack.push([worldPos, item]);
|
||||||
|
|
||||||
// Check for the next item
|
// Check for the next item
|
||||||
currentItemPos += distanceAndItem[0 /* nextDistance */];
|
currentItemPos += nextItemDistance;
|
||||||
++currentItemIndex;
|
++currentItemIndex;
|
||||||
|
|
||||||
|
if (nextItemDistance > globalConfig.itemSpacingOnBelts + 0.002 || drawStack.length > 20) {
|
||||||
|
// If next item is not directly following, abort drawing
|
||||||
|
this.drawDrawStack(drawStack, parameters, drawStackProp);
|
||||||
|
drawStack = [];
|
||||||
|
drawStackProp = "";
|
||||||
|
}
|
||||||
|
|
||||||
if (currentItemIndex >= this.items.length) {
|
if (currentItemIndex >= this.items.length) {
|
||||||
// We rendered all items
|
// We rendered all items
|
||||||
|
|
||||||
|
this.drawDrawStack(drawStack, parameters, drawStackProp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trackPos += beltLength;
|
trackPos += beltLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.drawDrawStack(drawStack, parameters, drawStackProp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {HTMLCanvasElement} canvas
|
||||||
|
* @param {CanvasRenderingContext2D} context
|
||||||
|
* @param {number} w
|
||||||
|
* @param {number} h
|
||||||
|
* @param {number} dpi
|
||||||
|
* @param {object} param0
|
||||||
|
* @param {string} param0.direction
|
||||||
|
* @param {Array<[Vector, BaseItem]>} param0.stack
|
||||||
|
* @param {GameRoot} param0.root
|
||||||
|
* @param {number} param0.zoomLevel
|
||||||
|
*/
|
||||||
|
drawShapesInARow(canvas, context, w, h, dpi, { direction, stack, root, zoomLevel }) {
|
||||||
|
context.scale(dpi, dpi);
|
||||||
|
context.fillStyle = "rgba(0, 0, 255, 0.1)";
|
||||||
|
context.fillRect(1, 1, w - 2, h - 2);
|
||||||
|
|
||||||
|
const parameters = new DrawParameters({
|
||||||
|
context,
|
||||||
|
desiredAtlasScale: ORIGINAL_SPRITE_SCALE,
|
||||||
|
root,
|
||||||
|
visibleRect: new Rectangle(-1000, -1000, 2000, 2000),
|
||||||
|
zoomLevel,
|
||||||
|
});
|
||||||
|
|
||||||
|
const itemSize = globalConfig.itemSpacingOnBelts * globalConfig.tileSize;
|
||||||
|
const item = stack[0];
|
||||||
|
const pos = new Vector(itemSize / 2, itemSize / 2);
|
||||||
|
|
||||||
|
for (let i = 0; i < stack.length; i++) {
|
||||||
|
item[1].drawItemCenteredClipped(pos.x, pos.y, parameters, globalConfig.defaultItemDiameter);
|
||||||
|
pos[direction] += globalConfig.itemSpacingOnBelts * globalConfig.tileSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array<[Vector, BaseItem]>} stack
|
||||||
|
* @param {DrawParameters} parameters
|
||||||
|
*/
|
||||||
|
drawDrawStack(stack, parameters, directionProp) {
|
||||||
|
if (stack.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstItem = stack[0];
|
||||||
|
const firstItemPos = firstItem[0];
|
||||||
|
if (stack.length === 1) {
|
||||||
|
firstItem[1].drawItemCenteredClipped(
|
||||||
|
firstItemPos.x,
|
||||||
|
firstItemPos.y,
|
||||||
|
parameters,
|
||||||
|
globalConfig.defaultItemDiameter
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const itemSize = globalConfig.itemSpacingOnBelts * globalConfig.tileSize;
|
||||||
|
const inverseDirection = directionProp === "x" ? "y" : "x";
|
||||||
|
|
||||||
|
const dimensions = new Vector(itemSize, itemSize);
|
||||||
|
dimensions[inverseDirection] *= stack.length;
|
||||||
|
|
||||||
|
const directionVector = firstItemPos.copy().sub(stack[1][0]);
|
||||||
|
|
||||||
|
const dpi = smoothenDpi(globalConfig.shapesSharpness * parameters.zoomLevel);
|
||||||
|
|
||||||
|
const sprite = this.root.buffers.getForKey({
|
||||||
|
key: "beltpaths",
|
||||||
|
subKey: "stack-" + directionProp + "-" + dpi + "-" + stack.length + firstItem[1].serialize(),
|
||||||
|
dpi,
|
||||||
|
w: dimensions.x,
|
||||||
|
h: dimensions.y,
|
||||||
|
redrawMethod: this.drawShapesInARow.bind(this),
|
||||||
|
additionalParams: {
|
||||||
|
direction: inverseDirection,
|
||||||
|
stack,
|
||||||
|
root: this.root,
|
||||||
|
zoomLevel: parameters.zoomLevel,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const anchor = directionVector[inverseDirection] < 0 ? firstItem : stack[stack.length - 1];
|
||||||
|
|
||||||
|
parameters.context.drawImage(
|
||||||
|
sprite,
|
||||||
|
anchor[0].x - itemSize / 2,
|
||||||
|
anchor[0].y - itemSize / 2,
|
||||||
|
dimensions.x,
|
||||||
|
dimensions.y
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,7 +58,7 @@ export class GameLogic {
|
|||||||
* @param {Vector=} param0.offset Optional, move the entity by the given offset first
|
* @param {Vector=} param0.offset Optional, move the entity by the given offset first
|
||||||
* @returns {boolean} true if the entity could be placed there
|
* @returns {boolean} true if the entity could be placed there
|
||||||
*/
|
*/
|
||||||
checkCanPlaceEntity(entity, { allowReplaceBuildings = false, offset = null }) {
|
checkCanPlaceEntity(entity, { allowReplaceBuildings = true, offset = null }) {
|
||||||
// Compute area of the building
|
// Compute area of the building
|
||||||
const rect = entity.components.StaticMapEntity.getTileSpaceBounds();
|
const rect = entity.components.StaticMapEntity.getTileSpaceBounds();
|
||||||
if (offset) {
|
if (offset) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user