mirror of
https://github.com/tobspr/shapez.io.git
synced 2024-10-27 20:34:29 +00:00
310 lines
9.3 KiB
JavaScript
310 lines
9.3 KiB
JavaScript
import { globalConfig } from "../../core/config";
|
|
import { DrawParameters } from "../../core/draw_parameters";
|
|
import { Rectangle } from "../../core/rectangle";
|
|
import { AtlasSprite } from "../../core/sprites";
|
|
import { enumDirection, Vector } from "../../core/vector";
|
|
import { types } from "../../savegame/serialization";
|
|
import { getBuildingDataFromCode } from "../building_codes";
|
|
import { Component } from "../component";
|
|
|
|
export class StaticMapEntityComponent extends Component {
|
|
static getId() {
|
|
return "StaticMapEntity";
|
|
}
|
|
|
|
static getSchema() {
|
|
return {
|
|
origin: types.tileVector,
|
|
rotation: types.float,
|
|
originalRotation: types.float,
|
|
|
|
// See building_codes.js
|
|
code: types.uintOrString,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Returns the effective tile size
|
|
* @returns {Vector}
|
|
*/
|
|
getTileSize() {
|
|
return getBuildingDataFromCode(this.code).tileSize;
|
|
}
|
|
|
|
/**
|
|
* Returns the sprite
|
|
* @returns {AtlasSprite}
|
|
*/
|
|
getSprite() {
|
|
return getBuildingDataFromCode(this.code).sprite;
|
|
}
|
|
|
|
/**
|
|
* Returns the blueprint sprite
|
|
* @returns {AtlasSprite}
|
|
*/
|
|
getBlueprintSprite() {
|
|
return getBuildingDataFromCode(this.code).blueprintSprite;
|
|
}
|
|
|
|
/**
|
|
* Returns the silhouette color
|
|
* @returns {string}
|
|
*/
|
|
getSilhouetteColor() {
|
|
return getBuildingDataFromCode(this.code).silhouetteColor;
|
|
}
|
|
|
|
/**
|
|
* Returns the meta building
|
|
* @returns {import("../meta_building").MetaBuilding}
|
|
*/
|
|
getMetaBuilding() {
|
|
return getBuildingDataFromCode(this.code).metaInstance;
|
|
}
|
|
|
|
/**
|
|
* Returns the buildings variant
|
|
* @returns {string}
|
|
*/
|
|
getVariant() {
|
|
return getBuildingDataFromCode(this.code).variant;
|
|
}
|
|
|
|
/**
|
|
* Returns the buildings rotation variant
|
|
* @returns {number}
|
|
*/
|
|
getRotationVariant() {
|
|
return getBuildingDataFromCode(this.code).rotationVariant;
|
|
}
|
|
|
|
/**
|
|
* Copy the current state to another component
|
|
* @param {Component} otherComponent
|
|
*/
|
|
copyAdditionalStateTo(otherComponent) {
|
|
return new StaticMapEntityComponent({
|
|
origin: this.origin.copy(),
|
|
rotation: this.rotation,
|
|
originalRotation: this.originalRotation,
|
|
code: this.code,
|
|
});
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {object} param0
|
|
* @param {Vector=} param0.origin Origin (Top Left corner) of the entity
|
|
* @param {Vector=} param0.tileSize Size of the entity in tiles
|
|
* @param {number=} param0.rotation Rotation in degrees. Must be multiple of 90
|
|
* @param {number=} param0.originalRotation Original Rotation in degrees. Must be multiple of 90
|
|
* @param {number|string=} param0.code Building code
|
|
*/
|
|
constructor({
|
|
origin = new Vector(),
|
|
tileSize = new Vector(1, 1),
|
|
rotation = 0,
|
|
originalRotation = 0,
|
|
code = 0,
|
|
}) {
|
|
super();
|
|
assert(
|
|
rotation % 90 === 0,
|
|
"Rotation of static map entity must be multiple of 90 (was " + rotation + ")"
|
|
);
|
|
|
|
this.origin = origin;
|
|
this.rotation = rotation;
|
|
this.code = code;
|
|
this.originalRotation = originalRotation;
|
|
}
|
|
|
|
/**
|
|
* Returns the effective rectangle of this entity in tile space
|
|
* @returns {Rectangle}
|
|
*/
|
|
getTileSpaceBounds() {
|
|
const size = this.getTileSize();
|
|
switch (this.rotation) {
|
|
case 0:
|
|
return new Rectangle(this.origin.x, this.origin.y, size.x, size.y);
|
|
case 90:
|
|
return new Rectangle(this.origin.x - size.y + 1, this.origin.y, size.y, size.x);
|
|
case 180:
|
|
return new Rectangle(this.origin.x - size.x + 1, this.origin.y - size.y + 1, size.x, size.y);
|
|
case 270:
|
|
return new Rectangle(this.origin.x, this.origin.y - size.x + 1, size.y, size.x);
|
|
default:
|
|
assert(false, "Invalid rotation");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Transforms the given vector/rotation from local space to world space
|
|
* @param {Vector} vector
|
|
* @returns {Vector}
|
|
*/
|
|
applyRotationToVector(vector) {
|
|
return vector.rotateFastMultipleOf90(this.rotation);
|
|
}
|
|
|
|
/**
|
|
* Transforms the given vector/rotation from world space to local space
|
|
* @param {Vector} vector
|
|
* @returns {Vector}
|
|
*/
|
|
unapplyRotationToVector(vector) {
|
|
return vector.rotateFastMultipleOf90(360 - this.rotation);
|
|
}
|
|
|
|
/**
|
|
* Transforms the given direction from local space
|
|
* @param {enumDirection} direction
|
|
* @returns {enumDirection}
|
|
*/
|
|
localDirectionToWorld(direction) {
|
|
return Vector.transformDirectionFromMultipleOf90(direction, this.rotation);
|
|
}
|
|
|
|
/**
|
|
* Transforms the given direction from world to local space
|
|
* @param {enumDirection} direction
|
|
* @returns {enumDirection}
|
|
*/
|
|
worldDirectionToLocal(direction) {
|
|
return Vector.transformDirectionFromMultipleOf90(direction, 360 - this.rotation);
|
|
}
|
|
|
|
/**
|
|
* Transforms from local tile space to global tile space
|
|
* @param {Vector} localTile
|
|
* @returns {Vector}
|
|
*/
|
|
localTileToWorld(localTile) {
|
|
const result = localTile.rotateFastMultipleOf90(this.rotation);
|
|
result.x += this.origin.x;
|
|
result.y += this.origin.y;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Transforms from world space to local space
|
|
* @param {Vector} worldTile
|
|
*/
|
|
worldToLocalTile(worldTile) {
|
|
const localUnrotated = worldTile.sub(this.origin);
|
|
return this.unapplyRotationToVector(localUnrotated);
|
|
}
|
|
|
|
/**
|
|
* Returns whether the entity should be drawn for the given parameters
|
|
* @param {DrawParameters} parameters
|
|
*/
|
|
shouldBeDrawn(parameters) {
|
|
let x = 0;
|
|
let y = 0;
|
|
let w = 0;
|
|
let h = 0;
|
|
const size = this.getTileSize();
|
|
|
|
switch (this.rotation) {
|
|
case 0: {
|
|
x = this.origin.x;
|
|
y = this.origin.y;
|
|
w = size.x;
|
|
h = size.y;
|
|
break;
|
|
}
|
|
case 90: {
|
|
x = this.origin.x - size.y + 1;
|
|
y = this.origin.y;
|
|
w = size.y;
|
|
h = size.x;
|
|
break;
|
|
}
|
|
case 180: {
|
|
x = this.origin.x - size.x + 1;
|
|
y = this.origin.y - size.y + 1;
|
|
w = size.x;
|
|
h = size.y;
|
|
break;
|
|
}
|
|
case 270: {
|
|
x = this.origin.x;
|
|
y = this.origin.y - size.x + 1;
|
|
w = size.y;
|
|
h = size.x;
|
|
break;
|
|
}
|
|
default:
|
|
assert(false, "Invalid rotation");
|
|
}
|
|
|
|
return parameters.visibleRect.containsRect4Params(
|
|
x * globalConfig.tileSize,
|
|
y * globalConfig.tileSize,
|
|
w * globalConfig.tileSize,
|
|
h * globalConfig.tileSize
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Draws a sprite over the whole space of the entity
|
|
* @param {DrawParameters} parameters
|
|
* @param {AtlasSprite} sprite
|
|
* @param {number=} extrudePixels How many pixels to extrude the sprite
|
|
* @param {Vector=} overridePosition Whether to drwa the entity at a different location
|
|
* @param {boolean=} extrude Whether to extrude
|
|
*/
|
|
drawSpriteOnBoundsClipped(
|
|
parameters,
|
|
sprite,
|
|
extrudePixels = 0,
|
|
overridePosition = null,
|
|
extrude = true
|
|
) {
|
|
if (!this.shouldBeDrawn(parameters) && !overridePosition) {
|
|
return;
|
|
}
|
|
const size = this.getTileSize();
|
|
let worldX = this.origin.x * globalConfig.tileSize;
|
|
let worldY = this.origin.y * globalConfig.tileSize;
|
|
|
|
if (overridePosition) {
|
|
worldX = overridePosition.x * globalConfig.tileSize;
|
|
worldY = overridePosition.y * globalConfig.tileSize;
|
|
}
|
|
|
|
if (this.rotation === 0) {
|
|
// Early out, is faster
|
|
sprite.drawCached(
|
|
parameters,
|
|
worldX - extrudePixels * size.x,
|
|
worldY - extrudePixels * size.y,
|
|
globalConfig.tileSize * size.x + 2 * extrudePixels * size.x,
|
|
globalConfig.tileSize * size.y + 2 * extrudePixels * size.y,
|
|
true,
|
|
extrude
|
|
);
|
|
} else {
|
|
const rotationCenterX = worldX + globalConfig.halfTileSize;
|
|
const rotationCenterY = worldY + globalConfig.halfTileSize;
|
|
|
|
parameters.context.translate(rotationCenterX, rotationCenterY);
|
|
parameters.context.rotate(Math.radians(this.rotation));
|
|
sprite.drawCached(
|
|
parameters,
|
|
-globalConfig.halfTileSize - extrudePixels * size.x,
|
|
-globalConfig.halfTileSize - extrudePixels * size.y,
|
|
globalConfig.tileSize * size.x + 2 * extrudePixels * size.x,
|
|
globalConfig.tileSize * size.y + 2 * extrudePixels * size.y,
|
|
false, // no clipping possible here
|
|
extrude
|
|
);
|
|
parameters.context.rotate(-Math.radians(this.rotation));
|
|
parameters.context.translate(-rotationCenterX, -rotationCenterY);
|
|
}
|
|
}
|
|
}
|