1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-06-13 13:04:03 +00:00

Replace enumSubShape with SubShape

This commit is contained in:
Bjorn Stromberg 2020-08-18 10:26:38 +09:00
parent 1dfb5f7476
commit a508c99333
6 changed files with 68 additions and 90 deletions

View File

@ -4,7 +4,7 @@ import { BasicSerializableObject, types } from "../savegame/serialization";
import { enumColors } from "./colors";
import { enumItemProcessorTypes } from "./components/item_processor";
import { GameRoot } from "./root";
import { enumSubShape, ShapeDefinition } from "./shape_definition";
import { ShapeDefinition, subShapes } from "./shape_definition";
import { enumHubGoalRewards, tutorialGoals } from "./tutorial_goals";
import { UPGRADES } from "./upgrades";
@ -328,7 +328,7 @@ export class HubGoals extends BasicSerializableObject {
let layers = [];
const randomColor = () => randomChoice(Object.values(enumColors));
const randomShape = () => randomChoice(Object.values(enumSubShape));
const randomShape = () => randomChoice(Object.values(subShapes));
let anyIsMissingTwo = false;

View File

@ -2,7 +2,7 @@ import { InputReceiver } from "../../../core/input_receiver";
import { makeDiv, removeAllChildren } from "../../../core/utils";
import { T } from "../../../translations";
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
import { ShapeDefinition } from "../../shape_definition";
import { ShapeDefinition, ShapeLayer } from "../../shape_definition";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
@ -82,12 +82,13 @@ export class HUDShapeViewer extends BaseHUDPart {
this.currentShapeKey = definition.getHash();
const layers = definition.layers;
this.contentDiv.setAttribute("data-layers", layers.length);
this.contentDiv.setAttribute("data-layers", `${layers.length}`);
for (let i = 0; i < layers.length; ++i) {
const layerElem = makeDiv(this.renderArea, null, ["layer", "layer-" + i]);
let fakeLayers = [];
/** @type {Array<ShapeLayer>} **/
const fakeLayers = [];
for (let k = 0; k < i; ++k) {
fakeLayers.push([null, null, null, null]);
}

View File

@ -8,7 +8,7 @@ import { enumColors } from "./colors";
import { Entity } from "./entity";
import { COLOR_ITEM_SINGLETONS } from "./items/color_item";
import { GameRoot } from "./root";
import { enumSubShape } from "./shape_definition";
import { subShapes } from "./shape_definition";
import { Rectangle } from "../core/rectangle";
const logger = createLogger("map_chunk");
@ -179,31 +179,30 @@ export class MapChunk {
* @param {number} distanceToOriginInChunks
*/
internalGenerateShapePatch(rng, shapePatchSize, distanceToOriginInChunks) {
/** @type {[enumSubShape, enumSubShape, enumSubShape, enumSubShape]} */
/** @type {[SubShape, SubShape, SubShape, SubShape]} */
let subShapes = null;
let weights = {};
// Later there is a mix of everything
weights = {
[enumSubShape.rect]: 100,
[enumSubShape.circle]: Math.round(50 + clamp(distanceToOriginInChunks * 2, 0, 50)),
[enumSubShape.star]: Math.round(20 + clamp(distanceToOriginInChunks, 0, 30)),
[enumSubShape.windmill]: Math.round(6 + clamp(distanceToOriginInChunks / 2, 0, 20)),
/** @type {Record<SubShape, number>} **/
const weights = {
rect: 100,
circle: Math.round(50 + clamp(distanceToOriginInChunks * 2, 0, 50)),
star: Math.round(20 + clamp(distanceToOriginInChunks, 0, 30)),
windmill: Math.round(6 + clamp(distanceToOriginInChunks / 2, 0, 20)),
};
if (distanceToOriginInChunks < 7) {
// Initial chunks can not spawn the good stuff
weights[enumSubShape.star] = 0;
weights[enumSubShape.windmill] = 0;
weights.star = 0;
weights.windmill = 0;
}
if (distanceToOriginInChunks < 10) {
// Initial chunk patches always have the same shape
// Initial chunk patches always have the same subshape
const subShape = this.internalGenerateRandomSubShape(rng, weights);
subShapes = [subShape, subShape, subShape, subShape];
} else if (distanceToOriginInChunks < 15) {
// Later patches can also have mixed ones
// Later patches can have mixed halves
const subShapeA = this.internalGenerateRandomSubShape(rng, weights);
const subShapeB = this.internalGenerateRandomSubShape(rng, weights);
subShapes = [subShapeA, subShapeA, subShapeB, subShapeB];
@ -218,15 +217,13 @@ export class MapChunk {
}
// Makes sure windmills never spawn as whole
let windmillCount = 0;
for (let i = 0; i < subShapes.length; ++i) {
if (subShapes[i] === enumSubShape.windmill) {
++windmillCount;
}
}
const windmillCount = subShapes.reduce((sum, subShape) => {
return sum + Number(subShape === "windmill");
}, 0);
if (windmillCount > 1) {
subShapes[0] = enumSubShape.rect;
subShapes[1] = enumSubShape.rect;
subShapes[0] = "rect";
subShapes[1] = "rect";
}
const definition = this.root.shapeDefinitionMgr.getDefinitionFromSimpleShapes(subShapes);
@ -240,25 +237,26 @@ export class MapChunk {
/**
* Chooses a random shape with the given weights
* @param {RandomNumberGenerator} rng
* @param {Object.<enumSubShape, number>} weights
* @returns {enumSubShape}
* @param {Record<SubShape, number>} weights
* @returns {SubShape}
*/
internalGenerateRandomSubShape(rng, weights) {
// @ts-ignore
const sum = Object.values(weights).reduce((a, b) => a + b, 0);
const chosenNumber = rng.nextIntRange(0, sum - 1);
let accumulated = 0;
for (const key in weights) {
const weight = weights[key];
for (let i = 0; i < subShapes.length; i += 1) {
const shape = subShapes[i];
const weight = weights[shape];
if (accumulated + weight > chosenNumber) {
return key;
return shape;
}
accumulated += weight;
}
logger.error("Failed to find matching shape in chunk generation");
return enumSubShape.circle;
return "circle";
}
/**

View File

@ -9,16 +9,35 @@ import { THEME } from "./theme";
/**
* @typedef {{
* subShape: enumSubShape,
* subShape: SubShape,
* color: enumColors,
* }} ShapeLayerItem
*/
/**
*
* Order is Q1 (tr), Q2(br), Q3(bl), Q4(tl)
* @typedef {[ShapeLayerItem?, ShapeLayerItem?, ShapeLayerItem?, ShapeLayerItem?]} ShapeLayer
*
* @typedef {"R" | "C" | "S" | "W"} SubShapeShortCode;
*/
/** @type {SubShape[]} **/
export const subShapes = ["rect", "circle", "star", "windmill"];
/** @type {Record<SubShape, SubShapeShortCode>} **/
const subShapeShortCodeMap = {
rect: "R",
circle: "C",
star: "S",
windmill: "W",
};
/** @type {Record<SubShapeShortCode, SubShape>} **/
const shortCodeSubShapeMap = {
R: "rect",
C: "circle",
S: "star",
W: "windmill",
};
const arrayQuadrantIndexToOffset = [
new Vector(1, -1), // tr
new Vector(1, 1), // br
@ -26,44 +45,6 @@ const arrayQuadrantIndexToOffset = [
new Vector(-1, -1), // tl
];
/** @enum {string} */
export const enumSubShape = {
rect: "rect",
circle: "circle",
star: "star",
windmill: "windmill",
};
/** @enum {string} */
export const enumSubShapeToShortcode = {
[enumSubShape.rect]: "R",
[enumSubShape.circle]: "C",
[enumSubShape.star]: "S",
[enumSubShape.windmill]: "W",
};
/** @enum {enumSubShape} */
export const enumShortcodeToSubShape = {};
for (const key in enumSubShapeToShortcode) {
enumShortcodeToSubShape[enumSubShapeToShortcode[key]] = key;
}
/**
* Converts the given parameters to a valid shape definition
* @param {*} layers
* @returns {Array<import("./shape_definition").ShapeLayer>}
*/
export function createSimpleShape(layers) {
layers.forEach(layer => {
layer.forEach(item => {
if (item) {
item.color = item.color || enumColors.uncolored;
}
});
});
return layers;
}
/**
* Cache which shapes are valid short keys and which not
* @type {Map<string, boolean>}
@ -120,6 +101,7 @@ export class ShapeDefinition extends BasicSerializableObject {
static fromShortKey(key) {
const sourceLayers = key.split(":");
let layers = [];
for (let i = 0; i < sourceLayers.length; ++i) {
const text = sourceLayers[i];
assert(text.length === 8, "Invalid shape short key: " + key);
@ -128,7 +110,7 @@ export class ShapeDefinition extends BasicSerializableObject {
const quads = [null, null, null, null];
for (let quad = 0; quad < 4; ++quad) {
const shapeText = text[quad * 2 + 0];
const subShape = enumShortcodeToSubShape[shapeText];
const subShape = shortCodeSubShapeMap[shapeText];
const color = enumShortcodeToColor[text[quad * 2 + 1]];
if (subShape) {
assert(color, "Invalid shape short key:", key);
@ -173,6 +155,7 @@ export class ShapeDefinition extends BasicSerializableObject {
static isValidShortKeyInternal(key) {
const sourceLayers = key.split(":");
let layers = [];
for (let i = 0; i < sourceLayers.length; ++i) {
const text = sourceLayers[i];
if (text.length !== 8) {
@ -185,7 +168,7 @@ export class ShapeDefinition extends BasicSerializableObject {
for (let quad = 0; quad < 4; ++quad) {
const shapeText = text[quad * 2 + 0];
const colorText = text[quad * 2 + 1];
const subShape = enumShortcodeToSubShape[shapeText];
const subShape = shortCodeSubShapeMap[shapeText];
const color = enumShortcodeToColor[colorText];
// Valid shape
@ -256,7 +239,7 @@ export class ShapeDefinition extends BasicSerializableObject {
for (let quadrant = 0; quadrant < layer.length; ++quadrant) {
const item = layer[quadrant];
if (item) {
id += enumSubShapeToShortcode[item.subShape] + enumColorToShortcode[item.color];
id += subShapeShortCodeMap[item.subShape] + enumColorToShortcode[item.color];
} else {
id += "--";
}
@ -359,7 +342,7 @@ export class ShapeDefinition extends BasicSerializableObject {
const insetPadding = 0.0;
switch (subShape) {
case enumSubShape.rect: {
case "rect": {
context.beginPath();
const dims = quadrantSize * layerScale;
context.rect(
@ -371,7 +354,7 @@ export class ShapeDefinition extends BasicSerializableObject {
break;
}
case enumSubShape.star: {
case "star": {
context.beginPath();
const dims = quadrantSize * layerScale;
@ -387,7 +370,7 @@ export class ShapeDefinition extends BasicSerializableObject {
break;
}
case enumSubShape.windmill: {
case "windmill": {
context.beginPath();
const dims = quadrantSize * layerScale;
@ -402,7 +385,7 @@ export class ShapeDefinition extends BasicSerializableObject {
break;
}
case enumSubShape.circle: {
case "circle": {
context.beginPath();
context.moveTo(insetPadding + -quadrantHalfSize, -insetPadding + quadrantHalfSize);
context.arc(

View File

@ -3,9 +3,7 @@ import { BasicSerializableObject } from "../savegame/serialization";
import { enumColors } from "./colors";
import { ShapeItem } from "./items/shape_item";
import { GameRoot } from "./root";
import { enumSubShape, ShapeDefinition } from "./shape_definition";
const logger = createLogger("shape_definition_manager");
import { ShapeDefinition, ShapeLayer } from "./shape_definition";
export class ShapeDefinitionManager extends BasicSerializableObject {
static getId() {
@ -246,14 +244,11 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
/**
*
* @param {[enumSubShape, enumSubShape, enumSubShape, enumSubShape]} subShapes
* @param {[SubShape, SubShape, SubShape, SubShape]} subShapes
* @returns {ShapeDefinition}
*/
getDefinitionFromSimpleShapes(subShapes, color = enumColors.uncolored) {
const shapeLayer = /** @type {import("./shape_definition").ShapeLayer} */ (subShapes.map(
subShape => ({ subShape, color })
));
const shapeLayer = /** @type {ShapeLayer} */ (subShapes.map(subShape => ({ subShape, color })));
return this.registerOrReturnHandle(new ShapeDefinition({ layers: [shapeLayer] }));
}
}

1
src/js/globals.d.ts vendored
View File

@ -195,6 +195,7 @@ declare interface TypedSignal<T extends Array<any>> {
declare type Layer = "regular" | "wires";
declare type ItemType = "shape" | "color" | "boolean";
declare type SubShape = "rect" | "circle" | "star" | "windmill";
declare module "worker-loader?inline=true&fallback=false!*" {
class WebpackWorker extends Worker {