diff --git a/.gitignore b/.gitignore index da93220..4834943 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /node_modules/ /public/build/ +/public/assets/ .DS_Store diff --git a/public/assets/images/buildings/buildings.png b/public/assets/images/buildings/buildings.png index 02c8c2b..1953901 100644 Binary files a/public/assets/images/buildings/buildings.png and b/public/assets/images/buildings/buildings.png differ diff --git a/src/App.svelte b/src/App.svelte index b8599e1..cab2516 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -1,7 +1,7 @@
@@ -80,8 +89,33 @@ {/each}

In Game Time

-

{inGameTime.days?.toString().padStart(2, '0')}.{inGameTime.months?.toString().padStart(2, '0')} of {inGameTime.years} y.

-

{inGameTime.hours?.toString().padStart(2, '0')}:{inGameTime.minutes?.toString().padStart(2, '0')}:{inGameTime.seconds?.toString().padStart(2, '0')}

+

+ {inGameTime.days?.toString().padStart(2, "0") ?? ""}.{inGameTime.months?.toString().padStart(2, "0") ?? ""} of {inGameTime.years ?? ""} y. +

+

+ {inGameTime.hours?.toString().padStart(2, "0") ?? ""}:{inGameTime.minutes?.toString().padStart(2, "0") ?? ""}:{inGameTime.seconds + ?.toString() + .padStart(2, "0") ?? ""} +

+
+

Sound

+
+

Master:

+ {UIGameSound.update((s)=>{ + s.master = Number(e.target.value) / 100; + })}}/> +
+
+

Music:

+ {UIGameSound.update((s)=>{ + s.music = Number(e.target.value) / 100; + })}}/> +
+
+

Ambient:

+ {UIGameSound.update((s)=>{ + s.ambient = Number(e.target.value) / 100; + })}}/>
@@ -101,9 +135,9 @@
-

{downloadedAssets >= 0 ? downloadedAssets:"Calculating..."}

+

{downloadedAssets >= 0 ? downloadedAssets : "Calculating..."}

/

-

{totalToDownloadAssets >= 0 ? totalToDownloadAssets:"Calculating..."}

+

{totalToDownloadAssets >= 0 ? totalToDownloadAssets : "Calculating..."}

{/if} @@ -114,11 +148,11 @@
-

FPS: {(1000.0 / frameLatency).toFixed(2)} {frameLatency.toFixed(2)}ms

+

FPS: {(1000.0 / frameLatency).toFixed(2)} {frameLatency.toFixed(2)}ms

{#each profileMessages as msg}

{msg.text}

{/each}
- \ No newline at end of file + diff --git a/src/Game/Game.js b/src/Game/Game.js index 42f4c71..0389366 100644 --- a/src/Game/Game.js +++ b/src/Game/Game.js @@ -4,7 +4,7 @@ import { UICameraInfo, UIGameProfilerPipe, UIMainPipe, UIObtainedResourcesPipe, import { getSpriteFromAtlas } from "./Utils/Sprites.utils"; import { profileFPS } from "./Profiler/Profiler"; 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 { calculateViewportFromCamera, moveHorizontally, moveVertically, screenToWorldCoordinates } from "./Camera/Camera"; @@ -22,12 +22,12 @@ import { } from "./WorldGeneration/WorldGeneration"; import { handleBuildingsIncome, incBuildingCount } from "./Buildings/Buildings"; import { handleDayNightCycle } from "./World/DayNightCycle"; +import { ambientDay, ambientMusic, ambientNight, handleSounds } from "./Sound/Sound"; export function generateWorld() { - setTimeout(()=>{ - createFirstWorldChunks(); - startGame(); - }, 0); + + createFirstWorldChunks(); + startGame(); } function setupGlobalInput() { @@ -74,6 +74,20 @@ function setupInGameSelector() { ph.zIndex = 1; BC_BUILDING_PLACEHOLDERS.push(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)=>{ for (const i of BC_BUILDING_PLACEHOLDERS) { @@ -150,6 +164,12 @@ function setupInGameSelector() { case 3: ns = getSpriteFromAtlas("assets/images/buildings/buildings.png", new PIXI.Rectangle(16, 16, 16, 16)); 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); let r = worldCoordinatesToChunkIndexesCoordinates(t.x, t.y); @@ -198,12 +218,11 @@ function setupInGameSelector() { }; } -let currentTint = 0xffffff; - export async function initGame() { const app = new PIXI.Application(); await app.init({ resizeTo: window, antialias: false }); document.body.appendChild(app.canvas); + setBC_APP(app); await loadGameAssets(); UIMainPipe.update((s) => { @@ -232,7 +251,6 @@ export async function initGame() { app.ticker.add(updateChunksVisibility); app.ticker.add(profileFPS); app.ticker.add(handleBuildingsIncome); - app.ticker.add(handleDayNightCycle); createKeyboardBinding("KeyW", "Hold", [moveVertically]); createKeyboardBinding("KeyS", "Hold", [moveVertically]); @@ -243,4 +261,9 @@ export async function initGame() { function startGame() { setupGlobalInput(); setupInGameSelector(); + BC_APP.ticker.add(handleDayNightCycle); + BC_APP.ticker.add(handleSounds); + ambientDay.play(); + ambientNight.play(); + ambientMusic.play(); } diff --git a/src/Game/GlobalVariables/GlobalVariables.js b/src/Game/GlobalVariables/GlobalVariables.js index c962bc5..8cb55ec 100644 --- a/src/Game/GlobalVariables/GlobalVariables.js +++ b/src/Game/GlobalVariables/GlobalVariables.js @@ -1,6 +1,11 @@ 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} */ diff --git a/src/Game/Sound/Sound.js b/src/Game/Sound/Sound.js new file mode 100644 index 0000000..4fd3459 --- /dev/null +++ b/src/Game/Sound/Sound.js @@ -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); +} + diff --git a/src/Game/UIPipes/UIPipes.js b/src/Game/UIPipes/UIPipes.js index 99f6bfc..c6f2f3a 100644 --- a/src/Game/UIPipes/UIPipes.js +++ b/src/Game/UIPipes/UIPipes.js @@ -38,4 +38,10 @@ export const UIObtainedResourcesPipe = new StateStorage({ export const UIGameTimePipe = new StateStorage({ gameTime: {}, gameSecondsPass: 0 +}); + +export const UIGameSound = new StateStorage({ + master: 1.0, + music: 0.3, + ambient: 1.0 }); \ No newline at end of file diff --git a/src/Game/Utils/DataTypes.utils.js b/src/Game/Utils/DataTypes.utils.js index 52961a0..39ec34e 100644 --- a/src/Game/Utils/DataTypes.utils.js +++ b/src/Game/Utils/DataTypes.utils.js @@ -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; + } + } +} diff --git a/src/Game/World/DayNightCycle.js b/src/Game/World/DayNightCycle.js index 737b481..5957703 100644 --- a/src/Game/World/DayNightCycle.js +++ b/src/Game/World/DayNightCycle.js @@ -2,10 +2,10 @@ import { BC_WORLD, PRNG } from "../GlobalVariables/GlobalVariables"; import { UIGameTimePipe } from "../UIPipes/UIPipes"; import { RGBColor, RGBCue } from "../Utils/DataTypes.utils"; -let timeElapsed = PRNG() * 8743264873; +let timeElapsed = PRNG() * 37992648739; // ex: scaling = 10; 1 game minute = 6 real seconds; -let timeScaling = 600.0; +let timeScaling = 300.0; const gameSecondsInGameMinute = 60; const gameMinutesInGameHour = 60; @@ -18,7 +18,15 @@ let dayColor = new RGBColor(255, 255, 255); let currentColor = new RGBColor(0, 0, 0); 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], "cos" ); @@ -29,12 +37,8 @@ export function handleDayNightCycle(tick) { s.gameTime = getPrettyGameTimeNow(); s.gameSecondsPass = Math.floor(timeElapsed); }); - let tt = - (Math.floor(timeElapsed) % (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay)) / - (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay); - // let t = Math.abs(Math.sin(Math.PI * tt)); - // console.log(tt); - currentColor = dayColorsCue.getColorAt(tt); + + currentColor = dayColorsCue.getColorAt(getDayPhase()); // currentColor = dayColor.multiplyByNumber(t); // console.log(((Math.floor(timeElapsed) % (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay)) / (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay))); // console.log(currentColor.toHex()); @@ -43,6 +47,13 @@ export function handleDayNightCycle(tick) { BC_WORLD.tint = currentColor.toNumber(); } +export function getDayPhase() { + return ( + (Math.floor(timeElapsed) % (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay)) / + (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay) + ); +} + export function getPrettyGameTimePassed() { let secondsPass = Math.floor(timeElapsed); let minutesPass = Math.floor(secondsPass / gameSecondsInGameMinute); diff --git a/src/UI/States/HUD/HUD.svelte b/src/UI/States/HUD/HUD.svelte index c035330..95a65bf 100644 --- a/src/UI/States/HUD/HUD.svelte +++ b/src/UI/States/HUD/HUD.svelte @@ -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 +
+ + +
{/if}