+
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 }));
}