mirror of
https://github.com/tobspr/shapez.io.git
synced 2026-03-02 03:39:21 +00:00
Add notifications when saving and new upgrades are available, minor improvements
This commit is contained in:
@@ -87,11 +87,6 @@ body {
|
||||
// }
|
||||
}
|
||||
|
||||
// Dirty hack
|
||||
* {
|
||||
@include TextShadow3DImpl;
|
||||
}
|
||||
|
||||
img {
|
||||
-webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */
|
||||
}
|
||||
|
||||
@@ -20,3 +20,10 @@ $upgrades: belt, miner, painting, processors;
|
||||
background-image: uiResource("res/ui/upgrades/#{$upgrade}.png") !important;
|
||||
}
|
||||
}
|
||||
|
||||
$icons: notification_saved, notification_success, notification_upgrade;
|
||||
@each $icon in $icons {
|
||||
[data-icon="icons/#{$icon}.png"] {
|
||||
background-image: uiResource("res/ui/icons/#{$icon}.png") !important;
|
||||
}
|
||||
}
|
||||
|
||||
44
src/css/ingame_hud/notifications.scss
Normal file
44
src/css/ingame_hud/notifications.scss
Normal file
@@ -0,0 +1,44 @@
|
||||
#ingame_HUD_Notifications {
|
||||
position: absolute;
|
||||
@include S(bottom, 60px);
|
||||
@include S(right, 10px);
|
||||
|
||||
.notification {
|
||||
background: rgba(#333438, 0.8);
|
||||
@include S(border-radius, 2px);
|
||||
@include S(margin-top, 3px);
|
||||
color: #fff;
|
||||
@include PlainText;
|
||||
@include S(padding, 7px, 10px);
|
||||
@include S(width, 200px);
|
||||
|
||||
&[data-icon] {
|
||||
@include S(background-position-x, 8px);
|
||||
background-position-y: center;
|
||||
@include S(padding-left, 35px);
|
||||
background-repeat: no-repeat;
|
||||
@include S(background-size, 15px);
|
||||
}
|
||||
|
||||
transform-origin: 100% 50%;
|
||||
|
||||
@include InlineAnimation(5s ease-in-out) {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
87% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
95% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: scale(0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,11 +36,13 @@
|
||||
@import "ingame_hud/vignette_overlay";
|
||||
@import "ingame_hud/statistics";
|
||||
@import "ingame_hud/pinned_shapes";
|
||||
@import "ingame_hud/notifications";
|
||||
|
||||
// Z-Index
|
||||
$elements: ingame_Canvas, ingame_VignetteOverlay, ingame_HUD_building_placer, ingame_HUD_PinnedShapes,
|
||||
ingame_HUD_buildings_toolbar, ingame_HUD_GameMenu, ingame_HUD_KeybindingOverlay, ingame_HUD_Shop,
|
||||
ingame_HUD_Statistics, ingame_HUD_BetaOverlay, ingame_HUD_MassSelector, ingame_HUD_UnlockNotification;
|
||||
ingame_HUD_buildings_toolbar, ingame_HUD_GameMenu, ingame_HUD_KeybindingOverlay, ingame_HUD_Notifications,
|
||||
ingame_HUD_Shop, ingame_HUD_Statistics, ingame_HUD_BetaOverlay, ingame_HUD_MassSelector,
|
||||
ingame_HUD_UnlockNotification;
|
||||
|
||||
$zindex: 100;
|
||||
|
||||
|
||||
@@ -253,38 +253,9 @@ button,
|
||||
}
|
||||
|
||||
@mixin TextShadow3D($color: rgb(222, 234, 238), $borderColor: #000) {
|
||||
// @if $borderColor != #000 {
|
||||
// @include TextShadow3DImpl($color: $color, $borderColor: $borderColor);
|
||||
// }
|
||||
color: $color;
|
||||
}
|
||||
|
||||
@mixin TextShadow3DImpl(
|
||||
$color: rgb(222, 234, 238),
|
||||
$scale: 1,
|
||||
$additionalShadowAlpha: 1,
|
||||
$borderColor: #222428
|
||||
) {
|
||||
// color: $text3dColor;
|
||||
|
||||
$borderColor: rgba(15, 18, 23, 0.9);
|
||||
|
||||
// $shadowColor: darken($color, 40%);
|
||||
|
||||
$border: 0.07em;
|
||||
$borderMid: $border * 1.14;
|
||||
|
||||
$drop1: $borderMid + 0.02;
|
||||
$drop2: $borderMid + 0.06em;
|
||||
|
||||
// text-shadow: #{$border} #{$border} 0 $borderColor, #{-$border} #{$border} 0 $borderColor, #{$border} #{-$border} 0 $borderColor,
|
||||
// #{-$border} #{-$border} 0 $borderColor, 0 #{$borderMid} 0 $borderColor, 0 #{-$borderMid} 0 $borderColor,
|
||||
// #{$borderMid} 0 0 $borderColor, #{-$borderMid} 0 0 $borderColor, 0 #{$drop1} 0 $borderColor, #{$borderMid} #{$drop1} 0 $borderColor,
|
||||
// #{-$borderMid} #{$drop1} 0 $borderColor, 0 #{$drop2} 0 $borderColor, #{$borderMid} #{$drop2} 0 $borderColor,
|
||||
// #{-$borderMid} #{$drop2} 0 $borderColor, -0.2em 0.13em 0 rgba(#111, 0.25); // 0px 0.07em 0px $shadowColor,
|
||||
// 0px 0.15em 0.09em rgba(#333539, $additionalShadowAlpha);;
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/* Shine animation prefab, useful for buttons etc. Adds a bright shine which moves over
|
||||
the button like a reflection. Performance heavy. */
|
||||
|
||||
@@ -19,6 +19,7 @@ import { HUDStatistics } from "./parts/statistics";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { HUDPinnedShapes } from "./parts/pinned_shapes";
|
||||
import { ShapeDefinition } from "../shape_definition";
|
||||
import { HUDNotifications, enumNotificationType } from "./parts/notifications";
|
||||
|
||||
export class GameHUD {
|
||||
/**
|
||||
@@ -51,12 +52,15 @@ export class GameHUD {
|
||||
|
||||
pinnedShapes: new HUDPinnedShapes(this.root),
|
||||
|
||||
notifications: new HUDNotifications(this.root),
|
||||
|
||||
// betaOverlay: new HUDBetaOverlay(this.root),
|
||||
};
|
||||
|
||||
this.signals = {
|
||||
selectedPlacementBuildingChanged: /** @type {TypedSignal<[MetaBuilding|null]>} */ (new Signal()),
|
||||
shapePinRequested: /** @type {TypedSignal<[ShapeDefinition, number]>} */ (new Signal()),
|
||||
notification: /** @type {TypedSignal<[string, enumNotificationType]>} */ (new Signal()),
|
||||
};
|
||||
|
||||
if (!IS_MOBILE) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { makeDiv, randomInt } from "../../../core/utils";
|
||||
import { SOUNDS } from "../../../platform/sound";
|
||||
import { enumNotificationType } from "./notifications";
|
||||
|
||||
export class HUDGameMenu extends BaseHUDPart {
|
||||
initialize() {}
|
||||
@@ -14,6 +15,10 @@ export class HUDGameMenu extends BaseHUDPart {
|
||||
handler: () => this.root.hud.parts.shop.show(),
|
||||
keybinding: "menu_open_shop",
|
||||
badge: () => this.root.hubGoals.getAvailableUpgradeCount(),
|
||||
notification: /** @type {[string, enumNotificationType]} */ ([
|
||||
"A new upgrade is available!",
|
||||
enumNotificationType.upgrade,
|
||||
]),
|
||||
},
|
||||
{
|
||||
id: "stats",
|
||||
@@ -23,10 +28,16 @@ export class HUDGameMenu extends BaseHUDPart {
|
||||
},
|
||||
];
|
||||
|
||||
/** @type {Array<{ badge: function, button: HTMLElement, badgeElement: HTMLElement, lastRenderAmount: number }>} */
|
||||
/** @type {Array<{
|
||||
* badge: function,
|
||||
* button: HTMLElement,
|
||||
* badgeElement: HTMLElement,
|
||||
* lastRenderAmount: number,
|
||||
* notification: [string, enumNotificationType]
|
||||
* }>} */
|
||||
this.badgesToUpdate = [];
|
||||
|
||||
buttons.forEach(({ id, label, handler, keybinding, badge }) => {
|
||||
buttons.forEach(({ id, label, handler, keybinding, badge, notification }) => {
|
||||
const button = document.createElement("button");
|
||||
button.setAttribute("data-button-id", id);
|
||||
this.element.appendChild(button);
|
||||
@@ -45,6 +56,7 @@ export class HUDGameMenu extends BaseHUDPart {
|
||||
lastRenderAmount: 0,
|
||||
button,
|
||||
badgeElement,
|
||||
notification,
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -68,8 +80,9 @@ export class HUDGameMenu extends BaseHUDPart {
|
||||
|
||||
update() {
|
||||
let playSound = false;
|
||||
let notifications = new Set();
|
||||
for (let i = 0; i < this.badgesToUpdate.length; ++i) {
|
||||
const { badge, button, badgeElement, lastRenderAmount } = this.badgesToUpdate[i];
|
||||
const { badge, button, badgeElement, lastRenderAmount, notification } = this.badgesToUpdate[i];
|
||||
const amount = badge();
|
||||
if (lastRenderAmount !== amount) {
|
||||
if (amount > 0) {
|
||||
@@ -78,6 +91,9 @@ export class HUDGameMenu extends BaseHUDPart {
|
||||
// Check if the badge increased
|
||||
if (amount > lastRenderAmount) {
|
||||
playSound = true;
|
||||
if (notification) {
|
||||
notifications.add(notification);
|
||||
}
|
||||
}
|
||||
this.badgesToUpdate[i].lastRenderAmount = amount;
|
||||
button.classList.toggle("hasBadge", amount > 0);
|
||||
@@ -87,6 +103,9 @@ export class HUDGameMenu extends BaseHUDPart {
|
||||
if (playSound) {
|
||||
this.root.soundProxy.playUi(SOUNDS.badgeNotification);
|
||||
}
|
||||
notifications.forEach(([notification, type]) => {
|
||||
this.root.hud.signals.notification.dispatch(notification, type);
|
||||
});
|
||||
}
|
||||
|
||||
onGameSaved() {
|
||||
|
||||
@@ -13,13 +13,18 @@ const logger = createLogger("hud/mass_selector");
|
||||
|
||||
export class HUDMassSelector extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
const removalKeybinding = this.root.gameState.keyActionMapper
|
||||
.getBinding("confirm_mass_delete")
|
||||
.getKeyCodeString();
|
||||
const abortKeybinding = this.root.gameState.keyActionMapper.getBinding("back").getKeyCodeString();
|
||||
|
||||
this.element = makeDiv(
|
||||
parent,
|
||||
"ingame_HUD_MassSelector",
|
||||
[],
|
||||
`
|
||||
Press <code class="keybinding">DEL</code> to remove selected buildings
|
||||
and <code class="keybinding">ESC</code> to cancel.
|
||||
Press <code class="keybinding">${removalKeybinding}</code> to remove selected buildings
|
||||
and <code class="keybinding">${abortKeybinding}</code> to cancel.
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
52
src/js/game/hud/parts/notifications.js
Normal file
52
src/js/game/hud/parts/notifications.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
|
||||
/** @enum {string} */
|
||||
export const enumNotificationType = {
|
||||
saved: "saved",
|
||||
upgrade: "upgrade",
|
||||
success: "success",
|
||||
};
|
||||
|
||||
export class HUDNotifications extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
this.element = makeDiv(parent, "ingame_HUD_Notifications", [], ``);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.root.hud.signals.notification.add(this.onNotification, this);
|
||||
|
||||
/** @type {Array<{ element: HTMLElement, expireAt: number}>} */
|
||||
this.notificationElements = [];
|
||||
|
||||
// Automatic notifications
|
||||
this.root.signals.gameSaved.add(() =>
|
||||
this.onNotification("Your game has been saved.", enumNotificationType.saved)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} message
|
||||
* @param {enumNotificationType} type
|
||||
*/
|
||||
onNotification(message, type) {
|
||||
const element = makeDiv(this.element, null, ["notification", "type-" + type], message);
|
||||
element.setAttribute("data-icon", "icons/notification_" + type + ".png");
|
||||
|
||||
this.notificationElements.push({
|
||||
element,
|
||||
expireAt: this.root.time.realtimeNow() + 5,
|
||||
});
|
||||
}
|
||||
|
||||
update() {
|
||||
const now = this.root.time.realtimeNow();
|
||||
for (let i = 0; i < this.notificationElements.length; ++i) {
|
||||
const handle = this.notificationElements[i];
|
||||
if (handle.expireAt <= now) {
|
||||
handle.element.remove();
|
||||
this.notificationElements.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ export const defaultKeybindings = {
|
||||
menu_open_shop: { keyCode: key("F") },
|
||||
menu_open_stats: { keyCode: key("G") },
|
||||
|
||||
confirm_mass_delete: { keyCode: 46 }, // DEL
|
||||
confirm_mass_delete: { keyCode: key("X") }, // DEL
|
||||
toggle_hud: { keyCode: 113 }, // F2
|
||||
},
|
||||
|
||||
|
||||
0
src/js/translations/en.yaml
Normal file
0
src/js/translations/en.yaml
Normal file
Reference in New Issue
Block a user