mirror of
https://github.com/tobspr/shapez.io.git
synced 2024-10-27 20:34:29 +00:00
Further blueprint improvements
This commit is contained in:
parent
19c770201f
commit
dfe1e64b27
@ -20,8 +20,7 @@
|
||||
@include SuperSmallText;
|
||||
@include S(padding-left, 20px);
|
||||
strong {
|
||||
background: $colorBlueBright;
|
||||
color: #fff;
|
||||
color: #aaa;
|
||||
text-transform: uppercase;
|
||||
@include S(padding, 1px, 2px);
|
||||
@include S(margin-right, 3px);
|
||||
|
@ -3,24 +3,27 @@ export const CHANGELOG = [
|
||||
version: "1.1.0",
|
||||
date: "unreleased",
|
||||
entries: [
|
||||
"<strong>UX</strong> Added background to toolbar to increase contrast",
|
||||
"<strong>UX</strong> Added confirmation when deleting more than 500 buildings at a time",
|
||||
"Allow changing all keybindings, including CTRL, ALT and SHIFT",
|
||||
"Allow holding SHIFT to rotate counter clockwise",
|
||||
"Added confirmation when deleting more than 500 buildings at a time",
|
||||
"Added background to toolbar to increase contrast",
|
||||
"Allow placing extractors anywhere again, but they don't work at all if not placed on a resource",
|
||||
],
|
||||
},
|
||||
{
|
||||
version: "1.0.4",
|
||||
date: "26.05.2020",
|
||||
entries: [
|
||||
"<strong>Balancing</strong> Reduce cost of first painting upgrade, and change 'Shape Processing' to 'Cutting, Rotating & Stacking'",
|
||||
"<strong>Tutorial</strong> Add dialog after completing level 2 to check out the upgrades tab.",
|
||||
"<strong>Misc</strong> Allow changing the keybindings in the demo version",
|
||||
"Reduce cost of first painting upgrade, and change 'Shape Processing' to 'Cutting, Rotating & Stacking'",
|
||||
"Add dialog after completing level 2 to check out the upgrades tab.",
|
||||
"Allow changing the keybindings in the demo version",
|
||||
],
|
||||
},
|
||||
{
|
||||
version: "1.0.3",
|
||||
date: "24.05.2020",
|
||||
entries: [
|
||||
"<strong>Balancing</strong> Reduced the amount of shapes required for the first 5 levels to make it easier to get into the game.",
|
||||
"Reduced the amount of shapes required for the first 5 levels to make it easier to get into the game.",
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -40,7 +40,7 @@ export const globalConfig = {
|
||||
|
||||
// Map
|
||||
mapChunkSize: 16,
|
||||
mapChunkPrerenderMinZoom: 1.3,
|
||||
mapChunkPrerenderMinZoom: 1.15,
|
||||
mapChunkOverviewMinZoom: 0.7,
|
||||
|
||||
// Belt speeds
|
||||
|
@ -23,10 +23,6 @@ export class InputDistributor {
|
||||
/** @type {Array<function(any) : boolean>} */
|
||||
this.filters = [];
|
||||
|
||||
this.shiftIsDown = false;
|
||||
this.altIsDown = false;
|
||||
this.ctrlIsDown = false;
|
||||
|
||||
this.bindToEvents();
|
||||
}
|
||||
|
||||
@ -176,27 +172,13 @@ export class InputDistributor {
|
||||
* Handles when the page got blurred
|
||||
*/
|
||||
handleBlur() {
|
||||
this.ctrlIsDown = false;
|
||||
this.shiftIsDown = false;
|
||||
this.altIsDown = false;
|
||||
this.forwardToReceiver("pageBlur", {});
|
||||
this.forwardToReceiver("shiftUp", {});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
handleKeydown(event) {
|
||||
if (event.keyCode === 16) {
|
||||
this.shiftIsDown = true;
|
||||
}
|
||||
if (event.keyCode === 17) {
|
||||
this.ctrlIsDown = true;
|
||||
}
|
||||
if (event.keyCode === 18) {
|
||||
this.altIsDown = true;
|
||||
}
|
||||
|
||||
if (
|
||||
// TAB
|
||||
event.keyCode === 9 ||
|
||||
@ -230,19 +212,6 @@ export class InputDistributor {
|
||||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
handleKeyup(event) {
|
||||
if (event.keyCode === 16) {
|
||||
this.shiftIsDown = false;
|
||||
this.forwardToReceiver("shiftUp", {});
|
||||
}
|
||||
if (event.keyCode === 17) {
|
||||
this.ctrlIsDown = false;
|
||||
this.forwardToReceiver("ctrlUp", {});
|
||||
}
|
||||
if (event.keyCode === 18) {
|
||||
this.altIsDown = false;
|
||||
this.forwardToReceiver("altUp", {});
|
||||
}
|
||||
|
||||
this.forwardToReceiver("keyup", {
|
||||
keyCode: event.keyCode,
|
||||
shift: event.shiftKey,
|
||||
|
@ -9,9 +9,6 @@ export class InputReceiver {
|
||||
this.keydown = new Signal();
|
||||
this.keyup = new Signal();
|
||||
this.pageBlur = new Signal();
|
||||
this.shiftUp = new Signal();
|
||||
this.altUp = new Signal();
|
||||
this.ctrlUp = new Signal();
|
||||
|
||||
// Dispatched on destroy
|
||||
this.destroyed = new Signal();
|
||||
|
@ -41,23 +41,6 @@ export class MetaMinerBuilding extends MetaBuilding {
|
||||
return super.getAvailableVariants(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GameRoot} root
|
||||
* @param {object} param0
|
||||
* @param {Vector} param0.origin
|
||||
* @param {number} param0.rotation
|
||||
* @param {number} param0.rotationVariant
|
||||
* @param {string} param0.variant
|
||||
*/
|
||||
performAdditionalPlacementChecks(root, { origin, rotation, rotationVariant, variant }) {
|
||||
// Make sure its placed above a resource
|
||||
const lowerLayer = root.map.getLowerLayerContentXY(origin.x, origin.y);
|
||||
if (!lowerLayer) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
|
@ -34,6 +34,7 @@ export class GameSystemWithFilter extends GameSystem {
|
||||
this.root.signals.entityQueuedForDestroy.add(this.internalPopEntityIfMatching, this);
|
||||
|
||||
this.root.signals.postLoadHook.add(this.internalPostLoadHook, this);
|
||||
this.root.signals.bulkOperationFinished.add(this.refreshCaches, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -175,7 +176,7 @@ export class GameSystemWithFilter extends GameSystem {
|
||||
internalRegisterEntity(entity) {
|
||||
this.allEntities.push(entity);
|
||||
|
||||
if (this.root.gameInitialized) {
|
||||
if (this.root.gameInitialized && !this.root.bulkOperationRunning) {
|
||||
// Sort entities by uid so behaviour is predictable
|
||||
this.allEntities.sort((a, b) => a.uid - b.uid);
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { GameRoot } from "../../root";
|
||||
import { DrawParameters } from "../../../core/draw_parameters";
|
||||
import { Loader } from "../../../core/loader";
|
||||
import { createLogger } from "../../../core/logging";
|
||||
import { Vector } from "../../../core/vector";
|
||||
import { Entity } from "../../entity";
|
||||
import { DrawParameters } from "../../../core/draw_parameters";
|
||||
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
||||
import { createLogger } from "../../../core/logging";
|
||||
import { Loader } from "../../../core/loader";
|
||||
import { GameRoot } from "../../root";
|
||||
|
||||
const logger = createLogger("blueprint");
|
||||
|
||||
@ -17,6 +16,7 @@ export class Blueprint {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new blueprint from the given entity uids
|
||||
* @param {GameRoot} root
|
||||
* @param {Array<number>} uids
|
||||
*/
|
||||
@ -48,7 +48,7 @@ export class Blueprint {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Draws the blueprint at the given origin
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
draw(parameters, tile) {
|
||||
@ -93,6 +93,31 @@ export class Blueprint {
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the blueprint clockwise
|
||||
*/
|
||||
rotateCw() {
|
||||
for (let i = 0; i < this.entities.length; ++i) {
|
||||
const entity = this.entities[i];
|
||||
const staticComp = entity.components.StaticMapEntity;
|
||||
|
||||
staticComp.rotation = (staticComp.rotation + 90) % 360;
|
||||
staticComp.originalRotation = (staticComp.originalRotation + 90) % 360;
|
||||
staticComp.origin = staticComp.origin.rotateFastMultipleOf90(90);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the blueprint counter clock wise
|
||||
*/
|
||||
rotateCcw() {
|
||||
// Well ...
|
||||
for (let i = 0; i < 3; ++i) {
|
||||
this.rotateCw();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the blueprint can be placed at the given tile
|
||||
* @param {GameRoot} root
|
||||
* @param {Vector} tile
|
||||
*/
|
||||
@ -123,10 +148,12 @@ export class Blueprint {
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to place the blueprint at the given tile
|
||||
* @param {GameRoot} root
|
||||
* @param {Vector} tile
|
||||
*/
|
||||
tryPlace(root, tile) {
|
||||
return root.logic.performBulkOperation(() => {
|
||||
let anyPlaced = false;
|
||||
for (let i = 0; i < this.entities.length; ++i) {
|
||||
let placeable = true;
|
||||
@ -172,5 +199,6 @@ export class Blueprint {
|
||||
}
|
||||
}
|
||||
return anyPlaced;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
|
||||
keyActionMapper
|
||||
.getBinding(KEYMAPPINGS.placement.abortBuildingPlacement)
|
||||
.add(this.abortPlacement, this);
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.rotateBlueprint, this);
|
||||
|
||||
this.root.camera.downPreHandler.add(this.onMouseDown, this);
|
||||
this.root.camera.movePreHandler.add(this.onMouseMove, this);
|
||||
@ -54,13 +55,13 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("down");
|
||||
const worldPos = this.root.camera.screenToWorld(pos);
|
||||
const tile = worldPos.toTileSpace();
|
||||
if (blueprint.tryPlace(this.root, tile)) {
|
||||
if (!this.root.app.inputMgr.shiftIsDown) {
|
||||
this.currentBlueprint.set(null);
|
||||
}
|
||||
// This actually feels weird
|
||||
// if (!this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placeMultiple).currentlyDown) {
|
||||
// this.currentBlueprint.set(null);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,6 +82,16 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
|
||||
this.currentBlueprint.set(Blueprint.fromUids(this.root, uids));
|
||||
}
|
||||
|
||||
rotateBlueprint() {
|
||||
if (this.currentBlueprint.get()) {
|
||||
if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateInverseModifier).currentlyDown) {
|
||||
this.currentBlueprint.get().rotateCcw();
|
||||
} else {
|
||||
this.currentBlueprint.get().rotateCw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {DrawParameters} parameters
|
||||
|
@ -161,14 +161,19 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
||||
if (
|
||||
metaBuilding &&
|
||||
metaBuilding.getRotateAutomaticallyWhilePlacing(this.currentVariant.get()) &&
|
||||
!this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placementDisableAutoOrientation).currentlyDown
|
||||
!this.root.keyMapper.getBinding(
|
||||
KEYMAPPINGS.placementModifiers.placementDisableAutoOrientation
|
||||
).currentlyDown
|
||||
) {
|
||||
const delta = newPos.sub(oldPos);
|
||||
const angleDeg = Math_degrees(delta.angle());
|
||||
this.currentBaseRotation = (Math.round(angleDeg / 90) * 90 + 360) % 360;
|
||||
|
||||
// Holding alt inverts the placement
|
||||
if (this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placeInverse).currentlyDown) {
|
||||
if (
|
||||
this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placeInverse)
|
||||
.currentlyDown
|
||||
) {
|
||||
this.currentBaseRotation = (180 + this.currentBaseRotation) % 360;
|
||||
}
|
||||
}
|
||||
@ -389,7 +394,12 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
||||
tryRotate() {
|
||||
const selectedBuilding = this.currentMetaBuilding.get();
|
||||
if (selectedBuilding) {
|
||||
if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateInverseModifier).currentlyDown) {
|
||||
this.currentBaseRotation = (this.currentBaseRotation + 270) % 360;
|
||||
} else {
|
||||
this.currentBaseRotation = (this.currentBaseRotation + 90) % 360;
|
||||
}
|
||||
|
||||
const staticComp = this.fakeEntity.components.StaticMapEntity;
|
||||
staticComp.rotation = this.currentBaseRotation;
|
||||
}
|
||||
@ -469,7 +479,9 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
||||
|
||||
if (
|
||||
metaBuilding.getFlipOrientationAfterPlacement() &&
|
||||
!this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placementDisableAutoOrientation).currentlyDown
|
||||
!this.root.keyMapper.getBinding(
|
||||
KEYMAPPINGS.placementModifiers.placementDisableAutoOrientation
|
||||
).currentlyDown
|
||||
) {
|
||||
this.currentBaseRotation = (180 + this.currentBaseRotation) % 360;
|
||||
}
|
||||
|
@ -1,24 +1,16 @@
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { getStringForKeyCode, KEYMAPPINGS } from "../../key_action_mapper";
|
||||
import { TrackedState } from "../../../core/tracked_state";
|
||||
import { queryParamOptions } from "../../../core/query_parameters";
|
||||
import { T } from "../../../translations";
|
||||
import { getStringForKeyCode, KEYMAPPINGS } from "../../key_action_mapper";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
|
||||
export class HUDKeybindingOverlay extends BaseHUDPart {
|
||||
initialize() {
|
||||
this.shiftDownTracker = new TrackedState(this.onShiftStateChanged, this);
|
||||
|
||||
this.root.hud.signals.selectedPlacementBuildingChanged.add(
|
||||
this.onSelectedBuildingForPlacementChanged,
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
onShiftStateChanged(shiftDown) {
|
||||
this.element.classList.toggle("shiftDown", shiftDown);
|
||||
}
|
||||
|
||||
createElements(parent) {
|
||||
const mapper = this.root.keyMapper;
|
||||
|
||||
@ -70,7 +62,9 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
|
||||
</div>
|
||||
|
||||
<div class="binding placementOnly">
|
||||
<code class="keybinding builtinKey shift">⇧ ${T.global.keys.shift}</code>
|
||||
<code class="keybinding builtinKey shift">⇧ ${getKeycode(
|
||||
KEYMAPPINGS.placementModifiers.placeMultiple
|
||||
)}</code>
|
||||
<label>${T.ingame.keybindingsOverlay.placeMultiple}</label>
|
||||
</div>
|
||||
`
|
||||
@ -81,7 +75,5 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
|
||||
this.element.classList.toggle("placementActive", !!selectedMetaBuilding);
|
||||
}
|
||||
|
||||
update() {
|
||||
this.shiftDownTracker.set(this.root.app.inputMgr.shiftIsDown);
|
||||
}
|
||||
update() {}
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ export const KEYMAPPINGS = {
|
||||
placement: {
|
||||
abortBuildingPlacement: { keyCode: key("Q") },
|
||||
rotateWhilePlacing: { keyCode: key("R") },
|
||||
rotateInverseModifier: { keyCode: 16 }, // SHIFT
|
||||
cycleBuildingVariants: { keyCode: key("T") },
|
||||
cycleBuildings: { keyCode: 9 }, // TAB
|
||||
},
|
||||
|
@ -3,10 +3,11 @@ import { Entity } from "./entity";
|
||||
import { Vector, enumDirectionToVector, enumDirection } from "../core/vector";
|
||||
import { MetaBuilding } from "./meta_building";
|
||||
import { StaticMapEntityComponent } from "./components/static_map_entity";
|
||||
import { Math_abs } from "../core/builtins";
|
||||
import { Math_abs, performanceNow } from "../core/builtins";
|
||||
import { createLogger } from "../core/logging";
|
||||
import { MetaBeltBaseBuilding, arrayBeltVariantToRotation } from "./buildings/belt_base";
|
||||
import { SOUNDS } from "../platform/sound";
|
||||
import { round2Digits } from "../core/utils";
|
||||
|
||||
const logger = createLogger("ingame/logic");
|
||||
|
||||
@ -132,17 +133,6 @@ export class GameLogic {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
!building.performAdditionalPlacementChecks(this.root, {
|
||||
origin,
|
||||
rotation,
|
||||
rotationVariant,
|
||||
variant,
|
||||
})
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.isAreaFreeToBuild({
|
||||
origin,
|
||||
rotation,
|
||||
@ -202,6 +192,24 @@ export class GameLogic {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a bulk operation, not updating caches in the meantime
|
||||
* @param {function} operation
|
||||
*/
|
||||
performBulkOperation(operation) {
|
||||
logger.log("Running bulk operation ...");
|
||||
assert(!this.root.bulkOperationRunning, "Can not run two bulk operations twice");
|
||||
this.root.bulkOperationRunning = true;
|
||||
const now = performanceNow();
|
||||
const returnValue = operation();
|
||||
const duration = performanceNow() - now;
|
||||
logger.log("Done in", round2Digits(duration), "ms");
|
||||
assert(this.root.bulkOperationRunning, "Bulk operation = false while bulk operation was running");
|
||||
this.root.bulkOperationRunning = false;
|
||||
this.root.signals.bulkOperationFinished.dispatch();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given building can get removed
|
||||
* @param {Entity} building
|
||||
|
@ -129,19 +129,6 @@ export class MetaBuilding {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should perform additional placement checks
|
||||
* @param {GameRoot} root
|
||||
* @param {object} param0
|
||||
* @param {Vector} param0.origin
|
||||
* @param {number} param0.rotation
|
||||
* @param {number} param0.rotationVariant
|
||||
* @param {string} param0.variant
|
||||
*/
|
||||
performAdditionalPlacementChecks(root, { origin, rotation, rotationVariant, variant }) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {object} param0
|
||||
|
@ -70,6 +70,11 @@ export class GameRoot {
|
||||
/** @type {boolean} */
|
||||
this.gameInitialized = false;
|
||||
|
||||
/**
|
||||
* Whether a bulk operation is running
|
||||
*/
|
||||
this.bulkOperationRunning = false;
|
||||
|
||||
//////// Other properties ///////
|
||||
|
||||
/** @type {Camera} */
|
||||
@ -151,6 +156,8 @@ export class GameRoot {
|
||||
|
||||
shapeDelivered: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()),
|
||||
itemProduced: /** @type {TypedSignal<[BaseItem]>} */ (new Signal()),
|
||||
|
||||
bulkOperationFinished: /** @type {TypedSignal<[]>} */ (new Signal()),
|
||||
};
|
||||
|
||||
// RNG's
|
||||
|
@ -17,9 +17,16 @@ export class MinerSystem extends GameSystemWithFilter {
|
||||
for (let i = 0; i < this.allEntities.length; ++i) {
|
||||
const entity = this.allEntities[i];
|
||||
|
||||
// Check if miner is above an actual tile
|
||||
|
||||
const minerComp = entity.components.Miner;
|
||||
const staticComp = entity.components.StaticMapEntity;
|
||||
|
||||
const tileBelow = this.root.map.getLowerLayerContentXY(staticComp.origin.x, staticComp.origin.y);
|
||||
if (!tileBelow) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// First, try to get rid of chained items
|
||||
if (minerComp.itemChainBuffer.length > 0) {
|
||||
if (this.tryPerformMinerEject(entity, minerComp.itemChainBuffer[0])) {
|
||||
|
@ -557,6 +557,8 @@ keybindings:
|
||||
|
||||
abortBuildingPlacement: Abort Placement
|
||||
rotateWhilePlacing: Rotate
|
||||
rotateInverseModifier: >-
|
||||
Modifier: Rotate CCW instead
|
||||
cycleBuildingVariants: Cycle Variants
|
||||
confirmMassDelete: Confirm Mass Delete
|
||||
cycleBuildings: Cycle Buildings
|
||||
|
Loading…
Reference in New Issue
Block a user