1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2024-10-27 20:34:29 +00:00

Initial support for themes, sound improvements

This commit is contained in:
tobspr 2020-05-16 09:49:00 +02:00
parent 236859baa1
commit 7870f011b8
20 changed files with 137 additions and 41 deletions

View File

@ -9,7 +9,7 @@ function gulptasksSounds($, gulp, buildFolder) {
return gulp.src(builtSoundsDir).pipe($.clean({ force: true })); return gulp.src(builtSoundsDir).pipe($.clean({ force: true }));
}); });
const filters = ["loudnorm", "volume=0.2"]; const filters = ["volume=0.2"];
const fileCache = new $.cache.Cache({ const fileCache = new $.cache.Cache({
cacheDirName: "shapezio-precompiled-sounds", cacheDirName: "shapezio-precompiled-sounds",
@ -27,8 +27,8 @@ function gulptasksSounds($, gulp, buildFolder) {
.audioBitrate(48) .audioBitrate(48)
.audioChannels(1) .audioChannels(1)
.audioFrequency(22050) .audioFrequency(22050)
.audioCodec("libmp3lame"); .audioCodec("libmp3lame")
// .audioFilters(["volume=0.25"]) .audioFilters(["volume=0.3"]);
}), }),
{ {
name: "music", name: "music",

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:dba7e859fb98713943890281a543e209d57c6633496090bd70d23dc58bed4405
size 743136

View File

@ -37,7 +37,7 @@ export const globalConfig = {
// Belt speeds // Belt speeds
// NOTICE: Update webpack.production.config too! // NOTICE: Update webpack.production.config too!
beltSpeedItemsPerSecond: 1, beltSpeedItemsPerSecond: 10,
itemSpacingOnBelts: 0.63, itemSpacingOnBelts: 0.63,
minerSpeedItemsPerSecond: 0, // COMPUTED minerSpeedItemsPerSecond: 0, // COMPUTED
@ -71,7 +71,7 @@ export const globalConfig = {
debug: { debug: {
/* dev:start */ /* dev:start */
// fastGameEnter: true, fastGameEnter: true,
noArtificialDelays: true, noArtificialDelays: true,
// disableSavegameWrite: true, // disableSavegameWrite: true,
showEntityBounds: false, showEntityBounds: false,

View File

@ -252,7 +252,7 @@ export class GameState {
* @returns {string|null} * @returns {string|null}
*/ */
getThemeMusic() { getThemeMusic() {
return null; return MUSIC.menu;
} }
//////////////////// ////////////////////

View File

@ -1,5 +1,6 @@
import { DrawParameters } from "../core/draw_parameters"; import { DrawParameters } from "../core/draw_parameters";
import { BasicSerializableObject, types } from "../savegame/serialization"; import { BasicSerializableObject, types } from "../savegame/serialization";
import { THEME } from "./theme";
/** /**
* Class for items on belts etc. Not an entity for performance reasons * Class for items on belts etc. Not an entity for performance reasons
@ -28,6 +29,6 @@ export class BaseItem extends BasicSerializableObject {
draw(x, y, parameters, size) {} draw(x, y, parameters, size) {}
getBackgroundColorAsResource() { getBackgroundColorAsResource() {
return "#eaebec"; abstract;
} }
} }

View File

@ -1,5 +1,6 @@
import { BaseHUDPart } from "../base_hud_part"; import { BaseHUDPart } from "../base_hud_part";
import { makeDiv, randomInt } from "../../../core/utils"; import { makeDiv, randomInt } from "../../../core/utils";
import { SOUNDS } from "../../../platform/sound";
export class HUDGameMenu extends BaseHUDPart { export class HUDGameMenu extends BaseHUDPart {
initialize() {} initialize() {}
@ -60,12 +61,13 @@ export class HUDGameMenu extends BaseHUDPart {
this.trackClicks(this.saveButton, this.startSave); this.trackClicks(this.saveButton, this.startSave);
this.musicButton.classList.toggle("muted", this.root.app.settings.getAllSettings().musicMuted); this.musicButton.classList.toggle("muted", this.root.app.settings.getAllSettings().musicMuted);
this.sfxButton.classList.toggle("muted", this.root.app.settings.getAllSettings().musicMuted); this.sfxButton.classList.toggle("muted", this.root.app.settings.getAllSettings().soundsMuted);
this.root.signals.gameSaved.add(this.onGameSaved, this); this.root.signals.gameSaved.add(this.onGameSaved, this);
} }
update() { update() {
let playSound = false;
for (let i = 0; i < this.badgesToUpdate.length; ++i) { for (let i = 0; i < this.badgesToUpdate.length; ++i) {
const { badge, button, badgeElement, lastRenderAmount } = this.badgesToUpdate[i]; const { badge, button, badgeElement, lastRenderAmount } = this.badgesToUpdate[i];
const amount = badge(); const amount = badge();
@ -73,10 +75,18 @@ export class HUDGameMenu extends BaseHUDPart {
if (amount > 0) { if (amount > 0) {
badgeElement.innerText = amount; badgeElement.innerText = amount;
} }
// Check if the badge increased
if (amount > lastRenderAmount) {
playSound = true;
}
this.badgesToUpdate[i].lastRenderAmount = amount; this.badgesToUpdate[i].lastRenderAmount = amount;
button.classList.toggle("hasBadge", amount > 0); button.classList.toggle("hasBadge", amount > 0);
} }
} }
if (playSound) {
this.root.soundProxy.playUi(SOUNDS.badgeNotification);
}
} }
onGameSaved() { onGameSaved() {

View File

@ -4,13 +4,7 @@ import { DrawParameters } from "../../core/draw_parameters";
import { types } from "../../savegame/serialization"; import { types } from "../../savegame/serialization";
import { BaseItem } from "../base_item"; import { BaseItem } from "../base_item";
import { enumColors, enumColorsToHexCode } from "../colors"; import { enumColors, enumColorsToHexCode } from "../colors";
import { THEME } from "../theme";
/** @enum {string} */
const enumColorToMapBackground = {
[enumColors.red]: "#ffbfc1",
[enumColors.green]: "#cbffc4",
[enumColors.blue]: "#bfdaff",
};
export class ColorItem extends BaseItem { export class ColorItem extends BaseItem {
static getId() { static getId() {
@ -39,7 +33,7 @@ export class ColorItem extends BaseItem {
} }
getBackgroundColorAsResource() { getBackgroundColorAsResource() {
return enumColorToMapBackground[this.color]; return THEME.map.resources[this.color];
} }
/** /**
@ -75,8 +69,8 @@ export class ColorItem extends BaseItem {
context.scale((dpi * w) / 12, (dpi * h) / 12); context.scale((dpi * w) / 12, (dpi * h) / 12);
context.fillStyle = enumColorsToHexCode[this.color]; context.fillStyle = enumColorsToHexCode[this.color];
context.strokeStyle = "rgba(100,102, 110, 1)"; context.strokeStyle = THEME.items.outline;
context.lineWidth = 2; context.lineWidth = 2 * THEME.items.outlineWidth;
context.beginCircle(2, -1, 3); context.beginCircle(2, -1, 3);
context.stroke(); context.stroke();
context.fill(); context.fill();

View File

@ -2,6 +2,7 @@ import { DrawParameters } from "../../core/draw_parameters";
import { types } from "../../savegame/serialization"; import { types } from "../../savegame/serialization";
import { BaseItem } from "../base_item"; import { BaseItem } from "../base_item";
import { ShapeDefinition } from "../shape_definition"; import { ShapeDefinition } from "../shape_definition";
import { THEME } from "../theme";
export class ShapeItem extends BaseItem { export class ShapeItem extends BaseItem {
static getId() { static getId() {
@ -33,6 +34,10 @@ export class ShapeItem extends BaseItem {
this.definition = definition; this.definition = definition;
} }
getBackgroundColorAsResource() {
return THEME.map.resources.shape;
}
/** /**
* @param {number} x * @param {number} x
* @param {number} y * @param {number} y

View File

@ -4,6 +4,7 @@ import { DrawParameters } from "../core/draw_parameters";
import { BaseMap } from "./map"; import { BaseMap } from "./map";
import { freeCanvas, makeOffscreenBuffer } from "../core/buffer_utils"; import { freeCanvas, makeOffscreenBuffer } from "../core/buffer_utils";
import { Entity } from "./entity"; import { Entity } from "./entity";
import { THEME } from "./theme";
/** /**
* This is the view of the map, it extends the map which is the raw model and allows * This is the view of the map, it extends the map which is the raw model and allows
@ -16,7 +17,7 @@ export class MapView extends BaseMap {
/** /**
* DPI of the background cache images, required in some places * DPI of the background cache images, required in some places
*/ */
this.backgroundCacheDPI = 4; this.backgroundCacheDPI = 2;
/** /**
* The cached background sprite, containing the flat background * The cached background sprite, containing the flat background
@ -109,14 +110,16 @@ export class MapView extends BaseMap {
}); });
context.scale(dpi, dpi); context.scale(dpi, dpi);
context.fillStyle = "#fff"; context.fillStyle = THEME.map.background;
context.fillRect(0, 0, dims, dims); context.fillRect(0, 0, dims, dims);
context.fillStyle = "#fafafa"; const borderWidth = THEME.map.gridLineWidth;
context.fillRect(0, 0, dims, 1); context.fillStyle = THEME.map.grid;
context.fillRect(0, 0, 1, dims); context.fillRect(0, 0, dims, borderWidth);
context.fillRect(dims - 1, 0, 1, dims); context.fillRect(0, borderWidth, borderWidth, dims);
context.fillRect(0, dims - 1, dims, 1);
context.fillRect(dims - borderWidth, borderWidth, borderWidth, dims - 2 * borderWidth);
context.fillRect(borderWidth, dims - borderWidth, dims, borderWidth);
this.cachedBackgroundCanvas = canvas; this.cachedBackgroundCanvas = canvas;
this.cachedBackgroundContext = context; this.cachedBackgroundContext = context;

View File

@ -7,6 +7,7 @@ import { createLogger } from "../core/logging";
import { Vector } from "../core/vector"; import { Vector } from "../core/vector";
import { BasicSerializableObject, types } from "../savegame/serialization"; import { BasicSerializableObject, types } from "../savegame/serialization";
import { enumColors, enumColorsToHexCode, enumColorToShortcode, enumShortcodeToColor } from "./colors"; import { enumColors, enumColorsToHexCode, enumColorToShortcode, enumShortcodeToColor } from "./colors";
import { THEME } from "./theme";
const rusha = require("rusha"); const rusha = require("rusha");
@ -274,8 +275,8 @@ export class ShapeDefinition extends BasicSerializableObject {
context.rotate(rotation); context.rotate(rotation);
context.fillStyle = enumColorsToHexCode[color]; context.fillStyle = enumColorsToHexCode[color];
context.strokeStyle = "#555"; context.strokeStyle = THEME.items.outline;
context.lineWidth = 1; context.lineWidth = THEME.items.outlineWidth;
const insetPadding = 0.0; const insetPadding = 0.0;

7
src/js/game/theme.js Normal file
View File

@ -0,0 +1,7 @@
export const THEMES = {
dark: require("./themes/dark.json"),
light: require("./themes/light.json"),
};
// TODO: Make themes customizable
export const THEME = THEMES.light;

View File

@ -0,0 +1,20 @@
{
"uiStyle": "dark",
"map": {
"background": "#2e2f37",
"grid": "rgba(255, 255, 255, 0.02)",
"gridLineWidth": 0.5,
"resources": {
"shape": "#3d3f4a",
"red": "#4a3d3f",
"green": "#3e4a3d",
"blue": "#35384a"
}
},
"items": {
"outline": "#111418",
"outlineWidth": 0.75
}
}

View File

@ -0,0 +1,20 @@
{
"uiStyle": "light",
"map": {
"background": "#fff",
"grid": "#fafafa",
"gridLineWidth": 1,
"resources": {
"shape": "#eaebec",
"red": "#ffbfc1",
"green": "#cbffc4",
"blue": "#bfdaff"
}
},
"items": {
"outline": "#55575a",
"outlineWidth": 0.75
}
}

View File

@ -74,10 +74,17 @@ class MusicInstance extends MusicInstanceInterface {
autoplay: false, autoplay: false,
loop: true, loop: true,
html5: true, html5: true,
volume: 0.3, volume: 1,
preload: true, preload: true,
pool: 2, pool: 2,
onunlock: () => {
if (this.playing) {
logger.log("Playing music after manual unlock");
this.play();
}
},
onload: () => { onload: () => {
resolve(); resolve();
}, },

View File

@ -18,6 +18,7 @@ export const SOUNDS = {
dialogOk: "ui/dialog_ok.mp3", dialogOk: "ui/dialog_ok.mp3",
swishHide: "ui/ui_swish_hide.mp3", swishHide: "ui/ui_swish_hide.mp3",
swishShow: "ui/ui_swish_show.mp3", swishShow: "ui/ui_swish_show.mp3",
badgeNotification: "ui/badge_notification.mp3",
levelComplete: "ui/level_complete.mp3", levelComplete: "ui/level_complete.mp3",
@ -27,6 +28,7 @@ export const SOUNDS = {
export const MUSIC = { export const MUSIC = {
theme: "theme.mp3", theme: "theme.mp3",
menu: "menu.mp3",
}; };
export class SoundInstanceInterface { export class SoundInstanceInterface {

View File

@ -6,6 +6,7 @@ import { ReadWriteProxy } from "../core/read_write_proxy";
import { BoolSetting, EnumSetting, BaseSetting } from "./setting_types"; import { BoolSetting, EnumSetting, BaseSetting } from "./setting_types";
import { createLogger } from "../core/logging"; import { createLogger } from "../core/logging";
import { ExplainedResult } from "../core/explained_result"; import { ExplainedResult } from "../core/explained_result";
import { THEMES } from "../game/theme";
const logger = createLogger("application_settings"); const logger = createLogger("application_settings");
@ -67,6 +68,18 @@ export const allApplicationSettings = [
}, },
G_IS_STANDALONE G_IS_STANDALONE
), ),
new EnumSetting("theme", {
options: Object.keys(THEMES),
valueGetter: theme => theme,
textGetter: theme => theme.substr(0, 1).toUpperCase() + theme.substr(1),
category: categoryApp,
restartRequired: false,
changeCb:
/**
* @param {Application} app
*/
(app, id) => document.body.setAttribute("data-theme", id),
}),
new BoolSetting( new BoolSetting(
"soundsMuted", "soundsMuted",
categoryApp, categoryApp,
@ -100,6 +113,7 @@ class SettingsStorage {
this.soundsMuted = false; this.soundsMuted = false;
this.musicMuted = false; this.musicMuted = false;
this.theme = "light";
} }
} }
@ -110,7 +124,17 @@ export class ApplicationSettings extends ReadWriteProxy {
initialize() { initialize() {
// Read and directly write latest data back // Read and directly write latest data back
return this.readAsync().then(() => this.writeAsync()); return this.readAsync()
.then(() => {
// Apply default setting callbacks
const settings = this.getAllSettings();
for (let i = 0; i < allApplicationSettings.length; ++i) {
const handle = allApplicationSettings[i];
handle.apply(this.app, settings[handle.id]);
}
})
.then(() => this.writeAsync());
} }
save() { save() {
@ -208,7 +232,7 @@ export class ApplicationSettings extends ReadWriteProxy {
} }
getCurrentVersion() { getCurrentVersion() {
return 2; return 3;
} }
migrate(data) { migrate(data) {

View File

@ -27,6 +27,16 @@ export class BaseSetting {
this.dialogs = null; this.dialogs = null;
} }
/**
* @param {Application} app
* @param {any} value
*/
apply(app, value) {
if (this.changeCb) {
this.changeCb(app, value);
}
}
/** /**
* @param {Application} app * @param {Application} app
* @param {Element} element * @param {Element} element

View File

@ -99,17 +99,6 @@ export class PreloadState extends GameState {
.then(() => { .then(() => {
return this.app.settings.initialize(); return this.app.settings.initialize();
}) })
.then(() => {
// Make sure the app pickups the right size
this.app.updateAfterUiScaleChanged();
})
.then(() => {
// Initialize fullscreen
if (this.app.platformWrapper.getSupportsFullscreen()) {
this.app.platformWrapper.setFullscreen(this.app.settings.getIsFullScreen());
}
})
.then(() => this.setStatus("Initializing sounds")) .then(() => this.setStatus("Initializing sounds"))
.then(() => { .then(() => {