diff --git a/src/App.svelte b/src/App.svelte index 43b27ed..b8599e1 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -1,7 +1,7 @@
{#if !loadingAssets} -
+

Camera info

Position: {cameraInfo.position.x.toFixed(1)} {cameraInfo.position.y.toFixed(1)}

@@ -64,6 +78,11 @@ {#each selectedTypes as selection}

Selected cell type: {selection}

{/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')}

+
diff --git a/src/Game/Camera/Camera.js b/src/Game/Camera/Camera.js index ef3c60b..14766f0 100644 --- a/src/Game/Camera/Camera.js +++ b/src/Game/Camera/Camera.js @@ -1,5 +1,19 @@ import { BC_CAMERA, BC_VIEWPORT } from "../GlobalVariables/GlobalVariables"; +import { UICameraInfo } from "../UIPipes/UIPipes"; +export function moveVertically(tick, keyCode) { + BC_CAMERA.position.y += (tick.deltaMS / 1000) * 800 * (keyCode === "KeyS" ? 1 : -1); + UICameraInfo.update((s) => { + s.position.y = BC_CAMERA.position.y; + }); +} + +export function moveHorizontally(tick, keyCode) { + BC_CAMERA.position.x += (tick.deltaMS / 1000) * 800 * (keyCode === "KeyD" ? 1 : -1); + UICameraInfo.update((s) => { + s.position.x = BC_CAMERA.position.x; + }); +} export function calculateViewportFromCamera() { // BC_VIEWPORT.pivot.set(0.5, 0.5); diff --git a/src/Game/Game.js b/src/Game/Game.js index 4a36277..42f4c71 100644 --- a/src/Game/Game.js +++ b/src/Game/Game.js @@ -1,18 +1,13 @@ -// import { dot } from "mathjs"; import * as PIXI from "../pixi/pixi.mjs"; -// import { loadPixelAsset } from "./Utils/Assets.utils"; -// import { Howl } from "howler"; import { loadGameAssets } from "./AssetsLoader/AssetsLoader"; import { UICameraInfo, UIGameProfilerPipe, UIMainPipe, UIObtainedResourcesPipe, UISelectionInfo } from "./UIPipes/UIPipes"; 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 { clampNumber, } from "./Utils/Math.utils"; -// import { addToTerrain, addToVegetation, addToViewport } from "./Utils/World.utils"; -import { calculateViewportFromCamera, screenToWorldCoordinates } from "./Camera/Camera"; -// import { Noise } from "noisejs"; -// import { createWorldChunk } from "./WorldChunk/WorldChunk"; +import { clampNumber, interpolate, } from "./Utils/Math.utils"; +import { calculateViewportFromCamera, moveHorizontally, moveVertically, screenToWorldCoordinates } from "./Camera/Camera"; + import { addToBuildings, createFirstWorldChunks, @@ -26,20 +21,7 @@ import { worldCoordinatesToChunkLocalCoordinates, } from "./WorldGeneration/WorldGeneration"; import { handleBuildingsIncome, incBuildingCount } from "./Buildings/Buildings"; - -function moveVertically(tick, keyCode) { - BC_CAMERA.position.y += (tick.deltaMS / 1000) * 800 * (keyCode === "KeyS" ? 1 : -1); - UICameraInfo.update((s) => { - s.position.y = BC_CAMERA.position.y; - }); -} - -function moveHorizontally(tick, keyCode) { - BC_CAMERA.position.x += (tick.deltaMS / 1000) * 800 * (keyCode === "KeyD" ? 1 : -1); - UICameraInfo.update((s) => { - s.position.x = BC_CAMERA.position.x; - }); -} +import { handleDayNightCycle } from "./World/DayNightCycle"; export function generateWorld() { setTimeout(()=>{ @@ -145,7 +127,7 @@ function setupInGameSelector() { let terrainObject = getObjectFromTerrainLayer(t.x, t.y); let vegetationObject = getObjectFromVegetationLayer(t.x, t.y); let buildingObject = getObjectFromBuildingsLayer(t.x, t.y); - console.log(vegetationObject); + // console.log(vegetationObject); if(UIMainPipe.get().building && terrainObject.type !== "ter_water" && !vegetationObject && !buildingObject) { if(UIObtainedResourcesPipe.get().gold >= 50) @@ -216,6 +198,8 @@ function setupInGameSelector() { }; } +let currentTint = 0xffffff; + export async function initGame() { const app = new PIXI.Application(); await app.init({ resizeTo: window, antialias: false }); @@ -233,6 +217,7 @@ export async function initGame() { setBC_WORLD(world); viewport.isRenderGroup = true; app.stage.addChild(world); + // world.tint = 0x00ffff; BC_CAMERA.position.x = Math.floor(PRNG() * 3242 - 372); BC_CAMERA.position.y = Math.floor(PRNG() * 1285 - 255); @@ -247,6 +232,7 @@ 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]); diff --git a/src/Game/UIPipes/UIPipes.js b/src/Game/UIPipes/UIPipes.js index 1a60e2d..99f6bfc 100644 --- a/src/Game/UIPipes/UIPipes.js +++ b/src/Game/UIPipes/UIPipes.js @@ -33,4 +33,9 @@ export const UIObtainedResourcesPipe = new StateStorage({ gold: 0, goldPerSec: 0, score: 0 +}); + +export const UIGameTimePipe = new StateStorage({ + gameTime: {}, + gameSecondsPass: 0 }); \ No newline at end of file diff --git a/src/Game/Utils/DataTypes.utils.js b/src/Game/Utils/DataTypes.utils.js index baf16a2..52961a0 100644 --- a/src/Game/Utils/DataTypes.utils.js +++ b/src/Game/Utils/DataTypes.utils.js @@ -1,3 +1,5 @@ +import { clampNumber, interpolateWith, mapRange } from "./Math.utils"; + /** * map representation */ @@ -33,17 +35,19 @@ export class Vault { /** * remove key from storage - * @param {String} key + * @param {String} key * @returns true/false */ this.del = (key) => { return delete this.storage[key]; - } + }; /** * clears storage */ - this.clear = () => {this.storage = {}} + this.clear = () => { + this.storage = {}; + }; /** * @@ -60,7 +64,7 @@ export class Vault { /** * run 'for' loop through all storage and call 'fn(storage_element)' - * @param {Function} fn + * @param {Function} fn */ this.forAll = (fn) => { let keys = Object.keys(this.storage); @@ -69,4 +73,98 @@ export class Vault { } }; } -} \ No newline at end of file +} + +export class RGBColor { + /** + * + * @param {Number} r + * @param {Number} g + * @param {Number} b + */ + constructor(r, g, b) { + this.r = r; + this.g = g; + this.b = b; + + /** + * + * @returns hex string + */ + this.toHex = () => { + return ((r << 16) + (g << 8) + b).toString(16).padStart(6, "0"); + }; + + /** + * converts color to Number + * @returns Number + */ + this.toNumber = () => { + return Number("0x" + this.toHex()); + }; + + /** + * + * @param {Number} num + */ + this.multiplyByNumber = (num) => { + return new RGBColor( + clampNumber(Math.floor(num * this.r), 0, 255), + clampNumber(Math.floor(num * this.g), 0, 255), + clampNumber(Math.floor(num * this.b), 0, 255) + ); + }; + } + + /** + * + * @param {RGBColor} colorA + * @param {RGBColor} colorB + * @param {Number} t + * @param {String} f interpolation type. default 'lin' + * @returns + */ + static interpolateColor(colorA, colorB, t, f = 'lin') { + return new RGBColor( + Math.floor(interpolateWith(colorA.r, colorB.r, t, f)), + Math.floor(interpolateWith(colorA.g, colorB.g, t, f)), + Math.floor(interpolateWith(colorA.b, colorB.b, t, f)) + ); + } +}; + +export class RGBCue { + /** + * + * @param {[RGBColor]} colors + * @param {[Number]} midpoints points in range [0, 1] + * @param {String} f interpolation type. default 'lin' + */ + constructor(colors, midpoints, f = 'lin') + { + this.colors = colors; + this.midpoints = midpoints; + this.interpolationFunction = f; + } + + /** + * + * @param {Number} point + */ + getColorAt(point) + { + let idx = this.#getPointIndex(point); + return RGBColor.interpolateColor(this.colors[idx-1], this.colors[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/Utils/Math.utils.js b/src/Game/Utils/Math.utils.js index aca2de8..907732e 100644 --- a/src/Game/Utils/Math.utils.js +++ b/src/Game/Utils/Math.utils.js @@ -75,6 +75,42 @@ export function interpolate(x, y, a) { return x * (1 - a) + y * a; } +export function interpolateCos(x, y, a) { + let m = (1-Math.cos(a*Math.PI))/2; + return (x*(1-m)+y*m); +} + +/** + * 'lin', 'cos' + * @param {Number} x + * @param {Number} y + * @param {Number} a + * @param {String} f + */ +export function interpolateWith(x, y, a, f) { + switch (f) { + case 'lin': + return interpolate(x, y, a); + case 'cos': + return interpolateCos(x, y, a); + default: + return interpolate(x, y, a); + } +} + +/** + * + * @param {Number} x value between a and b + * @param {Number} a minRange + * @param {Number} b maxRange + * @param {Number} c desiredMaxRange + * @param {Number} d desiredMinRange + * @returns + */ +export function mapRange(x, a, b, c, d) { + return (x-a)/(b-a) * (d-c) + c; +} + /** * Returns a random integer between min (inclusive) and max (inclusive). * The value is no lower than min (or the next integer greater than min diff --git a/src/Game/World/DayNightCycle.js b/src/Game/World/DayNightCycle.js new file mode 100644 index 0000000..737b481 --- /dev/null +++ b/src/Game/World/DayNightCycle.js @@ -0,0 +1,80 @@ +import { BC_WORLD, PRNG } from "../GlobalVariables/GlobalVariables"; +import { UIGameTimePipe } from "../UIPipes/UIPipes"; +import { RGBColor, RGBCue } from "../Utils/DataTypes.utils"; + +let timeElapsed = PRNG() * 8743264873; + +// ex: scaling = 10; 1 game minute = 6 real seconds; +let timeScaling = 600.0; + +const gameSecondsInGameMinute = 60; +const gameMinutesInGameHour = 60; +const gameHoursInGameDay = 24; +const gameDaysInGameWeek = 7; +const gameWeeksInGameMonth = 4; +const gameMonthsInGameYear = 12; + +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)], + [0.0, 0.15, 0.4, 0.75, 0.8, 0.9, 1.0], + "cos" +); + +export function handleDayNightCycle(tick) { + timeElapsed += (tick.deltaMS / 1000) * timeScaling; + UIGameTimePipe.update((s) => { + 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 = dayColor.multiplyByNumber(t); + // console.log(((Math.floor(timeElapsed) % (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay)) / (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay))); + // console.log(currentColor.toHex()); + // console.log(((Math.floor(timeElapsed) % (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay)) / (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay))); + // currentColor.multiplyByNumber(((Math.floor(timeElapsed) % (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay)) / (gameSecondsInGameMinute * gameMinutesInGameHour * gameHoursInGameDay))); + BC_WORLD.tint = currentColor.toNumber(); +} + +export function getPrettyGameTimePassed() { + let secondsPass = Math.floor(timeElapsed); + let minutesPass = Math.floor(secondsPass / gameSecondsInGameMinute); + let hoursPass = Math.floor(minutesPass / gameMinutesInGameHour); + let daysPass = Math.floor(hoursPass / gameHoursInGameDay); + let weeksPass = Math.floor(daysPass / gameDaysInGameWeek); + let monthsPass = Math.floor(weeksPass / gameWeeksInGameMonth); + let yearsPass = Math.floor(monthsPass / gameMonthsInGameYear); + return { + seconds: secondsPass, + minutes: minutesPass, + hours: hoursPass, + days: daysPass, + weeks: weeksPass, + months: monthsPass, + years: yearsPass, + }; +} + +export function getPrettyGameTimeNow() { + let passed = getPrettyGameTimePassed(); + return { + seconds: passed.seconds % gameSecondsInGameMinute, + minutes: passed.minutes % gameMinutesInGameHour, + hours: passed.hours % gameHoursInGameDay, + days: passed.days % gameDaysInGameWeek, + weeks: passed.weeks % gameWeeksInGameMonth, + months: passed.months % gameMonthsInGameYear, + years: passed.years, + }; +} + +export function getGameTimeElapsed() { + return timeElapsed; +} diff --git a/src/Game/WorldGeneration/WorldGeneration.js b/src/Game/WorldGeneration/WorldGeneration.js index e44a3a9..3350b09 100644 --- a/src/Game/WorldGeneration/WorldGeneration.js +++ b/src/Game/WorldGeneration/WorldGeneration.js @@ -218,7 +218,7 @@ export function addToVegetation(chunk, object, props, ceiledX, ceiledY) { * @param {Number} ceiledX * @param {Number} ceiledY */ -export function addToBuildings(chunk, object, props = {}, ceiledX, ceiledY) { +export function addToBuildings(chunk, object, props, ceiledX, ceiledY) { chunk.buildingsLayer.addChild(object); chunk.buildingsObjectsVault.set(ceiledX + "_" + ceiledY, new BuildingsObjectProps(object, { ...props })); }