diff --git a/res/videos/level_1.webm b/res/videos/level_1.webm new file mode 100644 index 00000000..f5962a97 Binary files /dev/null and b/res/videos/level_1.webm differ diff --git a/res/videos/level_2.webm b/res/videos/level_2.webm new file mode 100644 index 00000000..5cf00271 Binary files /dev/null and b/res/videos/level_2.webm differ diff --git a/src/css/ingame_hud/tutorial_hints.scss b/src/css/ingame_hud/tutorial_hints.scss new file mode 100644 index 00000000..a57ac197 --- /dev/null +++ b/src/css/ingame_hud/tutorial_hints.scss @@ -0,0 +1,68 @@ +#ingame_HUD_TutorialHints { + position: absolute; + @include S(left, 10px); + @include S(bottom, 50px); + display: flex; + flex-direction: column; + background: rgba(50, 60, 70, 0); + + transition: all 0.2s ease-in-out; + pointer-events: all; + + transition-property: background-color, transform, bottom, left; + + @include S(padding, 5px); + video { + transition: all 0.2s ease-in-out; + transition-property: opacity, width; + @include S(width, 0px); + opacity: 0; + } + + .header { + @include PlainText; + color: #333438; + display: grid; + align-items: center; + @include S(grid-gap, 2px); + grid-template-columns: 1fr; + @include S(margin-bottom, 3px); + } + button.toggleHint { + .hide { + display: none; + } + } + + &.enlarged { + background: rgba(50, 60, 70, 0.9); + left: 50%; + bottom: 50%; + transform: translate(-50%, 50%); + + .header { + grid-template-columns: 1fr auto; + color: #fff; + } + + video { + @include InlineAnimation(0.2s ease-in-out) { + 0% { + opacity: 0; + @include S(width, 0px); + } + } + + opacity: 1; + @include S(width, 500px); + } + button.toggleHint { + .hide { + display: block; + } + .show { + display: none; + } + } + } +} diff --git a/src/css/main.scss b/src/css/main.scss index ea746a9f..8cb96a10 100644 --- a/src/css/main.scss +++ b/src/css/main.scss @@ -44,6 +44,7 @@ @import "ingame_hud/settings_menu"; @import "ingame_hud/debug_info"; @import "ingame_hud/entity_debugger"; +@import "ingame_hud/tutorial_hints"; // prettier-ignore $elements: @@ -57,13 +58,14 @@ ingame_HUD_PlacerVariants, // Regular hud ingame_HUD_PinnedShapes, -ingame_HUD_buildings_toolbar, ingame_HUD_GameMenu, ingame_HUD_KeybindingOverlay, ingame_HUD_Notifications, ingame_HUD_MassSelector, ingame_HUD_DebugInfo, ingame_HUD_EntityDebugger, +ingame_HUD_TutorialHints, +ingame_HUD_buildings_toolbar, // Overlays ingame_HUD_BetaOverlay, @@ -91,7 +93,8 @@ body.uiHidden { #ingame_HUD_GameMenu, #ingame_HUD_MassSelector, #ingame_HUD_PinnedShapes, - #ingame_HUD_Notifications { + #ingame_HUD_Notifications, + #ingame_HUD_TutorialHints { display: none !important; } } @@ -99,7 +102,7 @@ body.uiHidden { body.modalDialogActive, body.externalAdOpen, body.ingameDialogOpen { - > *:not(.ingameDialog):not(.modalDialogParent):not(.loadingDialog):not(.gameLoadingOverlay):not(#ingame_HUD_ModalDialogs) { + > *:not(.ingameDialog):not(.modalDialogParent):not(.loadingDialog):not(.gameLoadingOverlay):not(#ingame_HUD_ModalDialogs):not(.noBlur) { filter: blur(5px) !important; } } diff --git a/src/js/core/background_resources_loader.js b/src/js/core/background_resources_loader.js index d48f5ef4..28d414f2 100644 --- a/src/js/core/background_resources_loader.js +++ b/src/js/core/background_resources_loader.js @@ -25,13 +25,8 @@ const essentialBareGameSprites = G_ALL_UI_IMAGES; const essentialBareGameSounds = [MUSIC.theme]; const additionalGameSprites = []; -const additionalGameSounds = []; -for (const key in SOUNDS) { - additionalGameSounds.push(SOUNDS[key]); -} -for (const key in MUSIC) { - additionalGameSounds.push(MUSIC[key]); -} +// @ts-ignore +const additionalGameSounds = [...Object.values(SOUNDS), ...Object.values(MUSIC)]; export class BackgroundResourcesLoader { /** diff --git a/src/js/core/config.js b/src/js/core/config.js index a758cf48..7a43ffed 100644 --- a/src/js/core/config.js +++ b/src/js/core/config.js @@ -93,8 +93,8 @@ export const globalConfig = { // disableZoomLimits: true, // showChunkBorders: true, // rewardsInstant: true, - allBuildingsUnlocked: true, - upgradesNoCost: true, + // allBuildingsUnlocked: true, + // upgradesNoCost: true, // disableUnlockDialog: true, // disableLogicTicks: true, // testClipping: true, diff --git a/src/js/game/hud/hud.js b/src/js/game/hud/hud.js index b66c85e3..bec6c69e 100644 --- a/src/js/game/hud/hud.js +++ b/src/js/game/hud/hud.js @@ -26,6 +26,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 { HUDPartTutorialHints } from "./parts/tutorial_hints"; export class GameHUD { /** @@ -61,6 +62,8 @@ export class GameHUD { notifications: new HUDNotifications(this.root), settingsMenu: new HUDSettingsMenu(this.root), + tutorialHints: new HUDPartTutorialHints(this.root), + // betaOverlay: new HUDBetaOverlay(this.root), debugInfo: new HUDDebugInfo(this.root), diff --git a/src/js/game/hud/parts/tutorial_hints.js b/src/js/game/hud/parts/tutorial_hints.js new file mode 100644 index 00000000..2b04315f --- /dev/null +++ b/src/js/game/hud/parts/tutorial_hints.js @@ -0,0 +1,101 @@ +import { BaseHUDPart } from "../base_hud_part"; +import { makeDiv } from "../../../core/utils"; +import { cachebust } from "../../../core/cachebust"; +import { DynamicDomAttach } from "../dynamic_dom_attach"; +import { InputReceiver } from "../../../core/input_receiver"; +import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper"; +import { tutorialGoals } from "../../tutorial_goals"; +import { TrackedState } from "../../../core/tracked_state"; + +const maxTutorialVideo = 2; + +export class HUDPartTutorialHints extends BaseHUDPart { + createElements(parent) { + this.element = makeDiv( + parent, + "ingame_HUD_TutorialHints", + [], + ` +
+ No idea what to do? + +
+ + + ` + ); + + this.videoElement = this.element.querySelector("video"); + } + + shouldPauseGame() { + return this.enlarged; + } + + initialize() { + this.trackClicks(this.element.querySelector(".toggleHint"), this.toggleHintEnlarged); + + this.videoAttach = new DynamicDomAttach(this.root, this.videoElement, { + timeToKeepSeconds: 0.3, + }); + + this.videoAttach.update(false); + this.enlarged = false; + + this.inputReciever = new InputReceiver("tutorial_hints"); + this.keyActionMapper = new KeyActionMapper(this.root, this.inputReciever); + this.keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.close, this); + + this.domAttach = new DynamicDomAttach(this.root, this.element); + + this.currentShownLevel = new TrackedState(this.updateVideoUrl, this); + } + + updateVideoUrl(level) { + console.log("update video url.", level); + this.videoElement + .querySelector("source") + .setAttribute("src", cachebust("res/videos/level_" + level + ".webm")); + } + + close() { + this.enlarged = false; + document.body.classList.remove("ingameDialogOpen"); + this.element.classList.remove("enlarged", "noBlur"); + this.root.app.inputMgr.makeSureDetached(this.inputReciever); + this.update(); + } + + show() { + document.body.classList.add("ingameDialogOpen"); + this.element.classList.add("enlarged", "noBlur"); + this.enlarged = true; + this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever); + this.update(); + + this.videoElement.currentTime = 0; + this.videoElement.play(); + } + + update() { + this.videoAttach.update(this.enlarged); + + this.currentShownLevel.set(this.root.hubGoals.level); + + const tutorialVisible = this.root.hubGoals.level <= maxTutorialVideo; + this.domAttach.update(tutorialVisible); + } + + toggleHintEnlarged() { + if (this.enlarged) { + this.close(); + } else { + this.show(); + } + } +} diff --git a/src/js/platform/browser/sound.js b/src/js/platform/browser/sound.js index 7e58543b..32985bb5 100644 --- a/src/js/platform/browser/sound.js +++ b/src/js/platform/browser/sound.js @@ -104,7 +104,7 @@ class MusicInstance extends MusicInstanceInterface { }), new Promise((resolve, reject) => { this.howl = new Howl({ - src: cachebust("res/sounds/music/" + this.url), + src: cachebust("res/sounds/music/" + this.url + ".mp3"), autoplay: false, loop: true, html5: true, diff --git a/src/js/platform/sound.js b/src/js/platform/sound.js index f293ff94..dc6b073f 100644 --- a/src/js/platform/sound.js +++ b/src/js/platform/sound.js @@ -27,8 +27,8 @@ export const SOUNDS = { }; export const MUSIC = { - theme: "theme.mp3", - menu: "menu.mp3", + theme: "theme", + menu: "menu", }; export class SoundInstanceInterface {