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

Waypoints - Step 1

This commit is contained in:
dengr1065 2020-05-23 11:24:16 +03:00
parent 5bda1ee8a5
commit 7390fa350a
8 changed files with 346 additions and 0 deletions

View File

@ -0,0 +1,95 @@
#ingame_HUD_Waypoints {
.content {
@include S(width, 500px);
}
.wizardWrap {
display: grid;
grid-template-columns: 1fr auto;
@include S(column-gap, 5px);
}
.content {
@include S(margin-top, 10px);
@include S(height, 350px);
overflow-y: scroll;
display: flex;
flex-direction: column;
justify-content: flex-start;
@include S(padding-right, 4px);
> .noWaypoints {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
@include PlainText;
color: #aaa;
}
> div {
background: #f4f4f4;
@include S(border-radius, $globalBorderRadius);
@include S(margin-bottom, 4px);
display: grid;
@include DarkThemeOverride {
background: #222428;
color: #efefef;
}
grid-template-columns: 1fr auto;
@include S(padding, 5px);
@include S(padding-left, 10px);
&:last-child {
margin-bottom: 0;
}
.title {
@include Text;
@include S(padding-top, 10px);
}
.position {
@include PlainText;
opacity: 0.7;
}
button {
@include S(margin, 4px);
}
.removeButton {
background: #df3f3d;
}
.teleportButton {
background: #804db1;
}
}
}
.dialogInner {
&[data-displaymode="detailed"] .content.hasEntries {
> div {
@include S(padding, 10px);
@include S(height, 40px);
grid-template-columns: auto 1fr auto;
@include S(grid-column-gap, 15px);
.counter {
grid-column: 3 / 4;
grid-row: 1 / 2;
@include Heading;
align-self: center;
text-align: right;
color: #55595a;
}
}
}
}
}

View File

@ -39,6 +39,7 @@
@import "ingame_hud/vignette_overlay";
@import "ingame_hud/statistics";
@import "ingame_hud/pinned_shapes";
@import "ingame_hud/waypoints";
@import "ingame_hud/notifications";
@import "ingame_hud/settings_menu";
@import "ingame_hud/debug_info";
@ -71,6 +72,7 @@ ingame_HUD_BetaOverlay,
ingame_HUD_UnlockNotification,
ingame_HUD_Shop,
ingame_HUD_Statistics,
ingame_HUD_Waypoints,
ingame_HUD_SettingsMenu,
ingame_HUD_ModalDialogs;

View File

@ -56,6 +56,9 @@ export class Camera extends BasicSerializableObject {
/** @type {Vector} */
this.center = new Vector(0, 0);
/** @type {{ name: string, pos: Vector }[]} */
this.waypoints = [];
// Input handling
this.currentlyMoving = false;
this.lastMovingPosition = null;
@ -117,6 +120,12 @@ export class Camera extends BasicSerializableObject {
return {
zoomLevel: types.float,
center: types.vector,
waypoints: types.array(
types.structured({
name: types.string,
pos: types.vector,
})
),
};
}

View File

@ -18,6 +18,7 @@ import { HUDVignetteOverlay } from "./parts/vignette_overlay";
import { HUDStatistics } from "./parts/statistics";
import { MetaBuilding } from "../meta_building";
import { HUDPinnedShapes } from "./parts/pinned_shapes";
import { HUDWaypoints } from "./parts/waypoints";
import { ShapeDefinition } from "../shape_definition";
import { HUDNotifications, enumNotificationType } from "./parts/notifications";
import { HUDSettingsMenu } from "./parts/settings_menu";
@ -26,6 +27,7 @@ import { HUDEntityDebugger } from "./parts/entity_debugger";
import { KEYMAPPINGS } from "../key_action_mapper";
import { HUDWatermark } from "./parts/watermark";
import { HUDModalDialogs } from "./parts/modal_dialogs";
import { Vector } from "../../core/vector";
export class GameHUD {
/**
@ -53,6 +55,7 @@ export class GameHUD {
shop: new HUDShop(this.root),
statistics: new HUDStatistics(this.root),
waypoints: new HUDWaypoints(this.root),
vignetteOverlay: new HUDVignetteOverlay(this.root),

View File

@ -29,6 +29,12 @@ export class HUDGameMenu extends BaseHUDPart {
handler: () => this.root.hud.parts.statistics.show(),
keybinding: KEYMAPPINGS.ingame.menuOpenStats,
},
{
id: "waypoints",
label: "Waypoints",
handler: () => this.root.hud.parts.waypoints.show(),
keybinding: KEYMAPPINGS.ingame.menuOpenWaypoints,
},
];
/** @type {Array<{

View File

@ -0,0 +1,215 @@
import { BaseHUDPart } from "../base_hud_part";
import { DrawParameters } from "../../../core/draw_parameters";
import { makeDiv, removeAllChildren, makeButton } from "../../../core/utils";
import { T } from "../../../translations";
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { InputReceiver } from "../../../core/input_receiver";
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
import { createLogger } from "../../../core/logging";
const logger = createLogger("waypoints");
export class HUDWaypoints extends BaseHUDPart {
createElements(parent) {
this.background = makeDiv(parent, "ingame_HUD_Waypoints", ["ingameDialog"]);
// DIALOG Inner / Wrapper
this.dialogInner = makeDiv(this.background, null, ["dialogInner"]);
this.title = makeDiv(this.dialogInner, null, ["title"], T.ingame.waypoints.title);
this.closeButton = makeDiv(this.title, null, ["closeButton"]);
this.trackClicks(this.closeButton, this.close);
this.wizardWrap = makeDiv(this.dialogInner, null, ["wizardWrap"]);
// FIXME: Make use of built-in methods
this.nameInput = document.createElement("input");
this.nameInput.classList.add("findOrCreate");
this.nameInput.placeholder = T.ingame.waypoints.findOrCreate;
this.nameInput.addEventListener("focus", () => {
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.textInputReciever);
});
this.nameInput.addEventListener("blur", () => {
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
});
this.nameInput.addEventListener("keyup", ev => {
if (ev.keyCode == 13) {
ev.preventDefault();
if (!this.newWaypoint()) {
return;
}
this.nameInput.blur();
return;
}
this.rerenderFull();
});
this.wizardWrap.appendChild(this.nameInput);
this.newButton = makeButton(this.wizardWrap, ["newButton"], T.ingame.waypoints.buttonNew);
this.trackClicks(this.newButton, this.newWaypoint);
this.contentDiv = makeDiv(this.dialogInner, null, ["content"]);
}
initialize() {
this.domAttach = new DynamicDomAttach(this.root, this.background, {
attachClass: "visible",
});
this.textInputReciever = new InputReceiver("waypoints_text");
this.inputReciever = new InputReceiver("waypoints");
this.keyActionMapper = new KeyActionMapper(this.root, this.inputReciever);
this.keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.close, this);
this.keyActionMapper.getBinding(KEYMAPPINGS.ingame.menuOpenWaypoints).add(this.close, this);
this.close();
this.rerenderFull();
}
getNextWaypointName() {
const inputName = this.nameInput.value.trim().substr(0, 32);
if (inputName !== "") return inputName;
let counter = 0;
let autoName = "The BEST name for a WAYPOINT!";
do {
counter++;
autoName = T.ingame.waypoints.defaultName.replace("<num>", counter.toString());
} while (this.waypoints.find(w => w.name == autoName));
return autoName;
}
newWaypoint() {
const vector = this.root.camera.center.round();
if (this.waypoints.find(w => w.pos.distance(vector) < 2)) {
return false;
}
this.waypoints.push({
name: this.getNextWaypointName(),
pos: vector,
});
this.nameInput.value = "";
this.rerenderFull();
return true;
}
cleanup() {
document.body.classList.remove("ingameDialogOpen");
}
show() {
this.visible = true;
document.body.classList.add("ingameDialogOpen");
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
this.rerenderFull();
this.update();
}
close() {
this.nameInput.value = "";
this.visible = false;
document.body.classList.remove("ingameDialogOpen");
this.root.app.inputMgr.makeSureDetached(this.inputReciever);
this.root.app.inputMgr.makeSureDetached(this.textInputReciever);
this.update();
}
update() {
this.domAttach.update(this.visible);
}
/**
* @param {number} index
*/
removeWaypoint(index) {
if (this.waypoints[index] === undefined) {
logger.warn("Attempt to remove nonexisting waypoint", index);
return;
}
this.waypoints.splice(index, 1);
this.rerenderFull();
}
/**
* @param {number} index
*/
waypointTeleport(index) {
if (this.waypoints[index] === undefined) {
logger.warn("Attempt to teleport to nonexisting waypoint", index);
return;
}
this.close();
this.root.camera.setDesiredCenter(this.waypoints[index].pos);
}
rerenderFull() {
this.waypoints = this.root.camera.waypoints;
removeAllChildren(this.contentDiv);
if (this.waypoints.length == 0) {
return (this.contentDiv.innerHTML = `
<strong class="noWaypoints">
${T.ingame.waypoints.noWaypoints.replace("<buttonNew>", T.ingame.waypoints.buttonNew)}
</strong>
`);
}
this.waypoints.forEach(waypoint => {
const term = this.nameInput.value.replaceAll(" ", "");
if (term !== "") {
const simpleName = waypoint.name.toLowerCase().replaceAll(" ", "");
if (!simpleName.includes(term.toLowerCase())) {
return;
}
}
const tilePos = waypoint.pos.toTileSpace();
const wpContainer = makeDiv(this.contentDiv, null, ["waypoint"]);
const positionStr = T.ingame.waypoints.position
.replace("<xpos>", tilePos.x)
.replace("<ypos>", tilePos.y);
const index = this.waypoints.indexOf(waypoint);
// Waypoint name
makeDiv(wpContainer, null, ["title"], waypoint.name);
// Remove button
const buttonRemove = makeButton(wpContainer, ["removeButton"], T.ingame.waypoints.buttonRemove);
this.trackClicks(buttonRemove, this.removeWaypoint.bind(this, index));
// Waypoint coords
makeDiv(wpContainer, null, ["position"], positionStr);
// Teleport button
const buttonTeleport = makeButton(
wpContainer,
["teleportButton"],
T.ingame.waypoints.buttonTeleport
);
this.trackClicks(buttonTeleport, this.waypointTeleport.bind(this, index));
});
}
/**
* @param {DrawParameters} parameters
*/
drawOverlays(parameters) {
// TODO: Draw tile overlays on existing waypoints
}
}

View File

@ -29,6 +29,7 @@ export const KEYMAPPINGS = {
menuOpenShop: { keyCode: key("F") },
menuOpenStats: { keyCode: key("G") },
menuOpenWaypoints: { keyCode: key("H") },
toggleHud: { keyCode: 113 }, // F2
toggleFPSInfo: { keyCode: 115 }, // F1

View File

@ -239,6 +239,21 @@ ingame:
# Displays the shapes per minute, e.g. '523 / m'
shapesPerMinute: <shapes> / m
# The "Waypoints" window
waypoints:
title: Waypoints
position: "X: <xpos>; Y: <ypos>"
findOrCreate: Find or create...
buttonNew: Add Waypoint
buttonTeleport: Teleport
buttonRemove: Remove
# When a new waypoint is created, this name is used.
defaultName: Waypoint <num>
noWaypoints: >-
There are no waypoints. Click "<buttonNew>" to create a new waypoint.
# Settings menu, when you press "ESC"
settingsMenu:
playtime: Playtime