added sounds

This commit is contained in:
TorgaW 2024-04-10 14:22:12 +03:00
parent 03eb586a9d
commit 24fa4203bc
10 changed files with 234 additions and 37 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
/node_modules/ /node_modules/
/public/build/ /public/build/
/public/assets/
.DS_Store .DS_Store

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1013 B

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,7 +1,7 @@
<script> <script>
import {initGame} from "./Game/Game"; import { initGame } from "./Game/Game";
import TailwindCss from "./TailwindCss.svelte"; import TailwindCss from "./TailwindCss.svelte";
import { UIAssetsLoaderInfoPipe, UICameraInfo, UIGameProfilerPipe, UIGameTimePipe, UIMainPipe, UISelectionInfo } from './Game/UIPipes/UIPipes'; import { UIAssetsLoaderInfoPipe, UICameraInfo, UIGameProfilerPipe, UIGameSound, UIGameTimePipe, UIMainPipe, UISelectionInfo } from "./Game/UIPipes/UIPipes";
import { UIGlobalPipe } from "./UI/GlobalNamespace/GlobalNamespace"; import { UIGlobalPipe } from "./UI/GlobalNamespace/GlobalNamespace";
initGame(); initGame();
@ -14,12 +14,12 @@
let totalToDownloadAssets = -1; let totalToDownloadAssets = -1;
let assetsFinished = false; let assetsFinished = false;
UIMainPipe.subscribe((s)=>{ UIMainPipe.subscribe((s) => {
amogusCount = s.amogusCount; amogusCount = s.amogusCount;
loadingAssets = s.loadingAssets; loadingAssets = s.loadingAssets;
}); });
UIAssetsLoaderInfoPipe.subscribe((s)=>{ UIAssetsLoaderInfoPipe.subscribe((s) => {
totalToDownloadAssets = s.totalToDownload; totalToDownloadAssets = s.totalToDownload;
downloadedAssets = s.downloaded; downloadedAssets = s.downloaded;
assetsFinished = s.finished; assetsFinished = s.finished;
@ -27,27 +27,27 @@
let frameLatency = 0; let frameLatency = 0;
let profileMessages = []; let profileMessages = [];
UIGameProfilerPipe.subscribe((s)=>{ UIGameProfilerPipe.subscribe((s) => {
frameLatency = s.frameLatency; frameLatency = s.frameLatency;
profileMessages = s.profileMessages; profileMessages = s.profileMessages;
}); });
let selectedTypes = []; let selectedTypes = [];
UISelectionInfo.subscribe((s)=>{ UISelectionInfo.subscribe((s) => {
selectedTypes = s.types; selectedTypes = s.types;
}); });
let cameraInfo = { let cameraInfo = {
position: {x: 0, y: 0}, position: { x: 0, y: 0 },
zoom: 1 zoom: 1,
}; };
UICameraInfo.subscribe((s)=>{ UICameraInfo.subscribe((s) => {
cameraInfo.position = s.position; cameraInfo.position = s.position;
cameraInfo.zoom = s.zoom; cameraInfo.zoom = s.zoom;
}); });
let UIStateComponent = null; let UIStateComponent = null;
UIGlobalPipe.subscribe((s)=>{ UIGlobalPipe.subscribe((s) => {
UIStateComponent = s.currentStateComponent; UIStateComponent = s.currentStateComponent;
}); });
@ -58,13 +58,22 @@
days: 0, days: 0,
weeks: 0, weeks: 0,
months: 0, months: 0,
years: 0 years: 0,
}; };
UIGameTimePipe.subscribe((s)=>{ UIGameTimePipe.subscribe((s) => {
inGameTime = s.gameTime; inGameTime = s.gameTime;
}); });
let masterSound = 1.0;
let ambientSound = 1.0;
let musicSound = 0.3;
UIGameSound.subscribe((s) => {
masterSound = s.master;
ambientSound = s.ambient;
musicSound = s.music;
});
</script> </script>
<div id="game-ui" class="absolute inset-0 flex items-center justify-center text-white select-none tracking-widest font-pixel pointer-events-none"> <div id="game-ui" class="absolute inset-0 flex items-center justify-center text-white select-none tracking-widest font-pixel pointer-events-none">
@ -80,8 +89,33 @@
{/each} {/each}
<h2 class="font-semibold mt-2">In Game Time</h2> <h2 class="font-semibold mt-2">In Game Time</h2>
<div class="w-full flex gap-2"> <div class="w-full flex gap-2">
<p>{inGameTime.days?.toString().padStart(2, '0')}.{inGameTime.months?.toString().padStart(2, '0')} of {inGameTime.years} y.</p> <p>
<p>{inGameTime.hours?.toString().padStart(2, '0')}:{inGameTime.minutes?.toString().padStart(2, '0')}:{inGameTime.seconds?.toString().padStart(2, '0')}</p> {inGameTime.days?.toString().padStart(2, "0") ?? ""}.{inGameTime.months?.toString().padStart(2, "0") ?? ""} of {inGameTime.years ?? ""} y.
</p>
<p>
{inGameTime.hours?.toString().padStart(2, "0") ?? ""}:{inGameTime.minutes?.toString().padStart(2, "0") ?? ""}:{inGameTime.seconds
?.toString()
.padStart(2, "0") ?? ""}
</p>
</div>
<h2 class="font-semibold mt-2">Sound</h2>
<div class="flex gap-2 items-center pointer-events-auto">
<p>Master:</p>
<input type="range" min="0" max="100" value="100" on:input={(e)=>{UIGameSound.update((s)=>{
s.master = Number(e.target.value) / 100;
})}}/>
</div>
<div class="flex gap-2 items-center pointer-events-auto">
<p>Music:</p>
<input type="range" min="0" max="100" value="30" on:input={(e)=>{UIGameSound.update((s)=>{
s.music = Number(e.target.value) / 100;
})}}/>
</div>
<div class="flex gap-2 items-center pointer-events-auto">
<p>Ambient:</p>
<input type="range" min="0" max="100" value="100" on:input={(e)=>{UIGameSound.update((s)=>{
s.ambient = Number(e.target.value) / 100;
})}}/>
</div> </div>
</div> </div>
</div> </div>
@ -101,9 +135,9 @@
</svg> </svg>
</div> </div>
<div class="flex justify-center items-center gap-1 text-2xl opacity-60"> <div class="flex justify-center items-center gap-1 text-2xl opacity-60">
<p>{downloadedAssets >= 0 ? downloadedAssets:"Calculating..."}</p> <p>{downloadedAssets >= 0 ? downloadedAssets : "Calculating..."}</p>
<p>/</p> <p>/</p>
<p>{totalToDownloadAssets >= 0 ? totalToDownloadAssets:"Calculating..."}</p> <p>{totalToDownloadAssets >= 0 ? totalToDownloadAssets : "Calculating..."}</p>
</div> </div>
</div> </div>
{/if} {/if}
@ -114,7 +148,7 @@
<div id="game-profiler" class="absolute inset-0 flex text-yellow-500 select-none pointer-events-none font-pixel tracking-widest"> <div id="game-profiler" class="absolute inset-0 flex text-yellow-500 select-none pointer-events-none font-pixel tracking-widest">
<div class="w-full h-full flex flex-col text-lg px-2"> <div class="w-full h-full flex flex-col text-lg px-2">
<p class="bg-black bg-opacity-50">FPS: {(1000.0 / frameLatency).toFixed(2)} {frameLatency.toFixed(2)}ms </p> <p class="bg-black bg-opacity-50">FPS: {(1000.0 / frameLatency).toFixed(2)} {frameLatency.toFixed(2)}ms</p>
{#each profileMessages as msg} {#each profileMessages as msg}
<p class="bg-black bg-opacity-50">{msg.text}</p> <p class="bg-black bg-opacity-50">{msg.text}</p>
{/each} {/each}

View File

@ -4,7 +4,7 @@ import { UICameraInfo, UIGameProfilerPipe, UIMainPipe, UIObtainedResourcesPipe,
import { getSpriteFromAtlas } from "./Utils/Sprites.utils"; import { getSpriteFromAtlas } from "./Utils/Sprites.utils";
import { profileFPS } from "./Profiler/Profiler"; import { profileFPS } from "./Profiler/Profiler";
import { createKeyboardBinding, inputControllerTick } from "./InputController/InputController"; import { createKeyboardBinding, inputControllerTick } from "./InputController/InputController";
import { BC_BUILDING_PLACEHOLDERS, BC_CAMERA, BC_SPRITES_SETTINGS, BC_VIEWPORT, BC_WORLD, PRNG, setBC_SELECTION, setBC_VIEWPORT, setBC_WORLD } from "./GlobalVariables/GlobalVariables"; import { BC_APP, BC_BUILDING_PLACEHOLDERS, BC_CAMERA, BC_SPRITES_SETTINGS, BC_VIEWPORT, BC_WORLD, PRNG, setBC_APP, setBC_SELECTION, setBC_VIEWPORT, setBC_WORLD } from "./GlobalVariables/GlobalVariables";
import { clampNumber, interpolate, } from "./Utils/Math.utils"; import { clampNumber, interpolate, } from "./Utils/Math.utils";
import { calculateViewportFromCamera, moveHorizontally, moveVertically, screenToWorldCoordinates } from "./Camera/Camera"; import { calculateViewportFromCamera, moveHorizontally, moveVertically, screenToWorldCoordinates } from "./Camera/Camera";
@ -22,12 +22,12 @@ import {
} from "./WorldGeneration/WorldGeneration"; } from "./WorldGeneration/WorldGeneration";
import { handleBuildingsIncome, incBuildingCount } from "./Buildings/Buildings"; import { handleBuildingsIncome, incBuildingCount } from "./Buildings/Buildings";
import { handleDayNightCycle } from "./World/DayNightCycle"; import { handleDayNightCycle } from "./World/DayNightCycle";
import { ambientDay, ambientMusic, ambientNight, handleSounds } from "./Sound/Sound";
export function generateWorld() { export function generateWorld() {
setTimeout(()=>{
createFirstWorldChunks(); createFirstWorldChunks();
startGame(); startGame();
}, 0);
} }
function setupGlobalInput() { function setupGlobalInput() {
@ -74,6 +74,20 @@ function setupInGameSelector() {
ph.zIndex = 1; ph.zIndex = 1;
BC_BUILDING_PLACEHOLDERS.push(ph); BC_BUILDING_PLACEHOLDERS.push(ph);
BC_VIEWPORT.addChild(ph); BC_VIEWPORT.addChild(ph);
ph = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(0, 32, 16, 16));
ph.scale.set(BC_SPRITES_SETTINGS.scale);
ph.alpha = 0.5;
ph.visible = false;
ph.zIndex = 1;
BC_BUILDING_PLACEHOLDERS.push(ph);
BC_VIEWPORT.addChild(ph);
ph = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(16, 32, 16, 16));
ph.scale.set(BC_SPRITES_SETTINGS.scale);
ph.alpha = 0.5;
ph.visible = false;
ph.zIndex = 1;
BC_BUILDING_PLACEHOLDERS.push(ph);
BC_VIEWPORT.addChild(ph);
UIMainPipe.subscribe((s)=>{ UIMainPipe.subscribe((s)=>{
for (const i of BC_BUILDING_PLACEHOLDERS) { for (const i of BC_BUILDING_PLACEHOLDERS) {
@ -150,6 +164,12 @@ function setupInGameSelector() {
case 3: case 3:
ns = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(16, 16, 16, 16)); ns = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(16, 16, 16, 16));
break; break;
case 4:
ns = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(0, 32, 16, 16));
break;
case 5:
ns = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(16, 32, 16, 16));
break;
} }
ns.scale.set(BC_SPRITES_SETTINGS.scale, BC_SPRITES_SETTINGS.scale); ns.scale.set(BC_SPRITES_SETTINGS.scale, BC_SPRITES_SETTINGS.scale);
let r = worldCoordinatesToChunkIndexesCoordinates(t.x, t.y); let r = worldCoordinatesToChunkIndexesCoordinates(t.x, t.y);
@ -198,12 +218,11 @@ function setupInGameSelector() {
}; };
} }
let currentTint = 0xffffff;
export async function initGame() { export async function initGame() {
const app = new PIXI.Application(); const app = new PIXI.Application();
await app.init({ resizeTo: window, antialias: false }); await app.init({ resizeTo: window, antialias: false });
document.body.appendChild(app.canvas); document.body.appendChild(app.canvas);
setBC_APP(app);
await loadGameAssets(); await loadGameAssets();
UIMainPipe.update((s) => { UIMainPipe.update((s) => {
@ -232,7 +251,6 @@ export async function initGame() {
app.ticker.add(updateChunksVisibility); app.ticker.add(updateChunksVisibility);
app.ticker.add(profileFPS); app.ticker.add(profileFPS);
app.ticker.add(handleBuildingsIncome); app.ticker.add(handleBuildingsIncome);
app.ticker.add(handleDayNightCycle);
createKeyboardBinding("KeyW", "Hold", [moveVertically]); createKeyboardBinding("KeyW", "Hold", [moveVertically]);
createKeyboardBinding("KeyS", "Hold", [moveVertically]); createKeyboardBinding("KeyS", "Hold", [moveVertically]);
@ -243,4 +261,9 @@ export async function initGame() {
function startGame() { function startGame() {
setupGlobalInput(); setupGlobalInput();
setupInGameSelector(); setupInGameSelector();
BC_APP.ticker.add(handleDayNightCycle);
BC_APP.ticker.add(handleSounds);
ambientDay.play();
ambientNight.play();
ambientMusic.play();
} }

View File

@ -1,6 +1,11 @@
import Alea from "alea"; import Alea from "alea";
import * as PIXI from "../../pixi/pixi.mjs";
import { getSpriteFromAtlas } from "../Utils/Sprites.utils";
export let BC_APP;
export function setBC_APP(app) {
BC_APP = app;
};
/** /**
* {PIXI.Container} * {PIXI.Container}
*/ */

69
src/Game/Sound/Sound.js Normal file
View File

@ -0,0 +1,69 @@
import { Howl } from "howler";
import { getDayPhase } from "../World/DayNightCycle";
import { clampNumber, mapRange } from "../Utils/Math.utils";
import { NumberCue } from "../Utils/DataTypes.utils";
import { UIGameSound } from "../UIPipes/UIPipes";
export let globalSoundVolume = 1.0;
export let musicSoundVolume = 0.3;
export let ambientSoundVolume = 1.0;
UIGameSound.subscribe((s)=>{
globalSoundVolume = s.master;
musicSoundVolume = s.music;
ambientSoundVolume = s.ambient;
});
export let ambientNight = new Howl({
src: ['assets/sound/night_ambient.mp3'],
loop: true,
volume: globalSoundVolume * ambientSoundVolume
});
export let ambientDay = new Howl({
src: ['assets/sound/day_ambient.mp3'],
loop: true,
volume: globalSoundVolume * ambientSoundVolume
});
export let ambientMusic = new Howl({
src: ['assets/sound/df_music/df_espagnole.mp3'],
loop: true,
volume: globalSoundVolume * musicSoundVolume
});
let dayAmbientSoundCue = new NumberCue(
[
0,
0,
1.0,
1.0,
0.8,
0.1,
0,
],
[0.0, 0.15, 0.4, 0.75, 0.8, 0.9, 1.0],
"cos"
);
let nightAmbientSoundCue = new NumberCue(
[
1.0,
1.0,
0.0,
0.0,
0.2,
0.9,
1.0,
],
[0.0, 0.15, 0.4, 0.75, 0.8, 0.9, 1.0],
"cos"
);
export function handleSounds(tick) {
let p = getDayPhase();
ambientDay.volume(dayAmbientSoundCue.getValueAt(p) * globalSoundVolume * ambientSoundVolume * 0.6);
ambientNight.volume(nightAmbientSoundCue.getValueAt(p) * globalSoundVolume * ambientSoundVolume * 0.6);
ambientMusic.volume(globalSoundVolume * musicSoundVolume);
}

View File

@ -39,3 +39,9 @@ export const UIGameTimePipe = new StateStorage({
gameTime: {}, gameTime: {},
gameSecondsPass: 0 gameSecondsPass: 0
}); });
export const UIGameSound = new StateStorage({
master: 1.0,
music: 0.3,
ambient: 1.0
});

View File

@ -168,3 +168,39 @@ export class RGBCue {
} }
} }
}; };
export class NumberCue {
/**
*
* @param {[Number]} numbers
* @param {[Number]} midpoints points in range [0, 1]
* @param {String} f interpolation type. default 'lin'
*/
constructor(numbers, midpoints, f = 'lin')
{
this.numbers = numbers;
this.midpoints = midpoints;
this.interpolationFunction = f;
}
/**
*
* @param {Number} point
*/
getValueAt(point)
{
let idx = this.#getPointIndex(point);
return interpolateWith(this.numbers[idx-1], this.numbers[idx], mapRange(point, this.midpoints[idx-1], this.midpoints[idx], 0.0, 1.0), this.interpolationFunction);
}
/**
*
* @param {Number} point
*/
#getPointIndex(point)
{
for (let i = 0; i < this.midpoints.length; i++) {
if(point < this.midpoints[i]) return i;
}
}
}

View File

@ -2,10 +2,10 @@ import { BC_WORLD, PRNG } from "../GlobalVariables/GlobalVariables";
import { UIGameTimePipe } from "../UIPipes/UIPipes"; import { UIGameTimePipe } from "../UIPipes/UIPipes";
import { RGBColor, RGBCue } from "../Utils/DataTypes.utils"; import { RGBColor, RGBCue } from "../Utils/DataTypes.utils";
let timeElapsed = PRNG() * 8743264873; let timeElapsed = PRNG() * 37992648739;
// ex: scaling = 10; 1 game minute = 6 real seconds; // ex: scaling = 10; 1 game minute = 6 real seconds;
let timeScaling = 600.0; let timeScaling = 300.0;
const gameSecondsInGameMinute = 60; const gameSecondsInGameMinute = 60;
const gameMinutesInGameHour = 60; const gameMinutesInGameHour = 60;
@ -18,7 +18,15 @@ let dayColor = new RGBColor(255, 255, 255);
let currentColor = new RGBColor(0, 0, 0); let currentColor = new RGBColor(0, 0, 0);
let dayColorsCue = new RGBCue( let dayColorsCue = new RGBCue(
[new RGBColor(1, 22, 46), new RGBColor(1, 66, 109), new RGBColor(255, 255, 255), new RGBColor(255, 255, 192), new RGBColor(136, 99, 77), new RGBColor(1, 66, 109), new RGBColor(1, 22, 46)], [
new RGBColor(1, 22, 46),
new RGBColor(1, 66, 109),
new RGBColor(255, 255, 255),
new RGBColor(255, 255, 192),
new RGBColor(136, 99, 77),
new RGBColor(1, 66, 109),
new RGBColor(1, 22, 46),
],
[0.0, 0.15, 0.4, 0.75, 0.8, 0.9, 1.0], [0.0, 0.15, 0.4, 0.75, 0.8, 0.9, 1.0],
"cos" "cos"
); );
@ -29,12 +37,8 @@ export function handleDayNightCycle(tick) {
s.gameTime = getPrettyGameTimeNow(); s.gameTime = getPrettyGameTimeNow();
s.gameSecondsPass = Math.floor(timeElapsed); s.gameSecondsPass = Math.floor(timeElapsed);
}); });
let tt =
(Math.floor(timeElapsed) % (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay)) / currentColor = dayColorsCue.getColorAt(getDayPhase());
(gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay);
// let t = Math.abs(Math.sin(Math.PI * tt));
// console.log(tt);
currentColor = dayColorsCue.getColorAt(tt);
// currentColor = dayColor.multiplyByNumber(t); // currentColor = dayColor.multiplyByNumber(t);
// console.log(((Math.floor(timeElapsed) % (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay)) / (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay))); // console.log(((Math.floor(timeElapsed) % (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay)) / (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay)));
// console.log(currentColor.toHex()); // console.log(currentColor.toHex());
@ -43,6 +47,13 @@ export function handleDayNightCycle(tick) {
BC_WORLD.tint = currentColor.toNumber(); BC_WORLD.tint = currentColor.toNumber();
} }
export function getDayPhase() {
return (
(Math.floor(timeElapsed) % (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay)) /
(gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay)
);
}
export function getPrettyGameTimePassed() { export function getPrettyGameTimePassed() {
let secondsPass = Math.floor(timeElapsed); let secondsPass = Math.floor(timeElapsed);
let minutesPass = Math.floor(secondsPass / gameSecondsInGameMinute); let minutesPass = Math.floor(secondsPass / gameSecondsInGameMinute);

View File

@ -78,6 +78,18 @@
}) })
}} class={"w-full focus:outline-none mt-4 bg-slate-800 hover:bg-slate-800 p-4 text-2xl border-2 hover:border-amber-600 " + (selectedBuilding === 3 ? "border-amber-600":"border-slate-700")}>House #4</button> }} class={"w-full focus:outline-none mt-4 bg-slate-800 hover:bg-slate-800 p-4 text-2xl border-2 hover:border-amber-600 " + (selectedBuilding === 3 ? "border-amber-600":"border-slate-700")}>House #4</button>
</div> </div>
<div class="flex flex-col items-center gap-2 w-full">
<button on:click={()=>{
UIMainPipe.update((s)=>{
s.selectedBuilding = 4;
})
}} class={"w-full focus:outline-none mt-4 bg-slate-800 hover:bg-slate-800 p-4 text-2xl border-2 hover:border-amber-600 " + (selectedBuilding === 4 ? "border-amber-600":"border-slate-700")}>House #5</button>
<button on:click={()=>{
UIMainPipe.update((s)=>{
s.selectedBuilding = 5;
})
}} class={"w-full focus:outline-none mt-4 bg-slate-800 hover:bg-slate-800 p-4 text-2xl border-2 hover:border-amber-600 " + (selectedBuilding === 5 ? "border-amber-600":"border-slate-700")}>House #6</button>
</div>
</div> </div>
{/if} {/if}
</div> </div>