added day-night cycle

This commit is contained in:
TorgaW 2024-04-10 11:49:15 +03:00
parent aab9708ba8
commit c6dc0b42a0
8 changed files with 269 additions and 31 deletions

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, UIMainPipe, UISelectionInfo } from './Game/UIPipes/UIPipes'; import { UIAssetsLoaderInfoPipe, UICameraInfo, UIGameProfilerPipe, UIGameTimePipe, UIMainPipe, UISelectionInfo } from './Game/UIPipes/UIPipes';
import { UIGlobalPipe } from "./UI/GlobalNamespace/GlobalNamespace"; import { UIGlobalPipe } from "./UI/GlobalNamespace/GlobalNamespace";
initGame(); initGame();
@ -51,11 +51,25 @@
UIStateComponent = s.currentStateComponent; UIStateComponent = s.currentStateComponent;
}); });
let inGameTime = {
seconds: 0,
minutes: 0,
hours: 0,
days: 0,
weeks: 0,
months: 0,
years: 0
};
UIGameTimePipe.subscribe((s)=>{
inGameTime = s.gameTime;
});
</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">
{#if !loadingAssets} {#if !loadingAssets}
<div class="w-[500px] h-[500px] flex flex-col gap-4 text-xl absolute left-8 top-8"> <div class="w-[500px] flex flex-col gap-4 text-xl absolute left-8 top-8">
<div class="bg-indigo-800 bg-opacity-90 flex flex-col p-4 w-[400px] rounded-xl"> <div class="bg-indigo-800 bg-opacity-90 flex flex-col p-4 w-[400px] rounded-xl">
<h2 class="font-semibold">Camera info</h2> <h2 class="font-semibold">Camera info</h2>
<p>Position: {cameraInfo.position.x.toFixed(1)} {cameraInfo.position.y.toFixed(1)}</p> <p>Position: {cameraInfo.position.x.toFixed(1)} {cameraInfo.position.y.toFixed(1)}</p>
@ -64,6 +78,11 @@
{#each selectedTypes as selection} {#each selectedTypes as selection}
<p>Selected cell type: {selection}</p> <p>Selected cell type: {selection}</p>
{/each} {/each}
<h2 class="font-semibold mt-2">In Game Time</h2>
<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>{inGameTime.hours?.toString().padStart(2, '0')}:{inGameTime.minutes?.toString().padStart(2, '0')}:{inGameTime.seconds?.toString().padStart(2, '0')}</p>
</div>
</div> </div>
</div> </div>
<svelte:component this={UIStateComponent} /> <svelte:component this={UIStateComponent} />

View File

@ -1,5 +1,19 @@
import { BC_CAMERA, BC_VIEWPORT } from "../GlobalVariables/GlobalVariables"; 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() { export function calculateViewportFromCamera() {
// BC_VIEWPORT.pivot.set(0.5, 0.5); // BC_VIEWPORT.pivot.set(0.5, 0.5);

View File

@ -1,18 +1,13 @@
// import { dot } from "mathjs";
import * as PIXI from "../pixi/pixi.mjs"; import * as PIXI from "../pixi/pixi.mjs";
// import { loadPixelAsset } from "./Utils/Assets.utils";
// import { Howl } from "howler";
import { loadGameAssets } from "./AssetsLoader/AssetsLoader"; import { loadGameAssets } from "./AssetsLoader/AssetsLoader";
import { UICameraInfo, UIGameProfilerPipe, UIMainPipe, UIObtainedResourcesPipe, UISelectionInfo } from "./UIPipes/UIPipes"; import { UICameraInfo, UIGameProfilerPipe, UIMainPipe, UIObtainedResourcesPipe, UISelectionInfo } from "./UIPipes/UIPipes";
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_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 { clampNumber, interpolate, } from "./Utils/Math.utils";
// import { addToTerrain, addToVegetation, addToViewport } from "./Utils/World.utils"; import { calculateViewportFromCamera, moveHorizontally, moveVertically, screenToWorldCoordinates } from "./Camera/Camera";
import { calculateViewportFromCamera, screenToWorldCoordinates } from "./Camera/Camera";
// import { Noise } from "noisejs";
// import { createWorldChunk } from "./WorldChunk/WorldChunk";
import { import {
addToBuildings, addToBuildings,
createFirstWorldChunks, createFirstWorldChunks,
@ -26,20 +21,7 @@ import {
worldCoordinatesToChunkLocalCoordinates, worldCoordinatesToChunkLocalCoordinates,
} from "./WorldGeneration/WorldGeneration"; } from "./WorldGeneration/WorldGeneration";
import { handleBuildingsIncome, incBuildingCount } from "./Buildings/Buildings"; import { handleBuildingsIncome, incBuildingCount } from "./Buildings/Buildings";
import { handleDayNightCycle } from "./World/DayNightCycle";
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;
});
}
export function generateWorld() { export function generateWorld() {
setTimeout(()=>{ setTimeout(()=>{
@ -145,7 +127,7 @@ function setupInGameSelector() {
let terrainObject = getObjectFromTerrainLayer(t.x, t.y); let terrainObject = getObjectFromTerrainLayer(t.x, t.y);
let vegetationObject = getObjectFromVegetationLayer(t.x, t.y); let vegetationObject = getObjectFromVegetationLayer(t.x, t.y);
let buildingObject = getObjectFromBuildingsLayer(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(UIMainPipe.get().building && terrainObject.type !== "ter_water" && !vegetationObject && !buildingObject)
{ {
if(UIObtainedResourcesPipe.get().gold >= 50) if(UIObtainedResourcesPipe.get().gold >= 50)
@ -216,6 +198,8 @@ 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 });
@ -233,6 +217,7 @@ export async function initGame() {
setBC_WORLD(world); setBC_WORLD(world);
viewport.isRenderGroup = true; viewport.isRenderGroup = true;
app.stage.addChild(world); app.stage.addChild(world);
// world.tint = 0x00ffff;
BC_CAMERA.position.x = Math.floor(PRNG() * 3242 - 372); BC_CAMERA.position.x = Math.floor(PRNG() * 3242 - 372);
BC_CAMERA.position.y = Math.floor(PRNG() * 1285 - 255); BC_CAMERA.position.y = Math.floor(PRNG() * 1285 - 255);
@ -247,6 +232,7 @@ 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]);

View File

@ -33,4 +33,9 @@ export const UIObtainedResourcesPipe = new StateStorage({
gold: 0, gold: 0,
goldPerSec: 0, goldPerSec: 0,
score: 0 score: 0
});
export const UIGameTimePipe = new StateStorage({
gameTime: {},
gameSecondsPass: 0
}); });

View File

@ -1,3 +1,5 @@
import { clampNumber, interpolateWith, mapRange } from "./Math.utils";
/** /**
* map representation * map representation
*/ */
@ -33,17 +35,19 @@ export class Vault {
/** /**
* remove key from storage * remove key from storage
* @param {String} key * @param {String} key
* @returns true/false * @returns true/false
*/ */
this.del = (key) => { this.del = (key) => {
return delete this.storage[key]; return delete this.storage[key];
} };
/** /**
* clears storage * 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)' * run 'for' loop through all storage and call 'fn(storage_element)'
* @param {Function} fn * @param {Function} fn
*/ */
this.forAll = (fn) => { this.forAll = (fn) => {
let keys = Object.keys(this.storage); let keys = Object.keys(this.storage);
@ -69,4 +73,98 @@ export class Vault {
} }
}; };
} }
} }
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;
}
}
};

View File

@ -75,6 +75,42 @@ export function interpolate(x, y, a) {
return x * (1 - a) + 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). * Returns a random integer between min (inclusive) and max (inclusive).
* The value is no lower than min (or the next integer greater than min * The value is no lower than min (or the next integer greater than min

View File

@ -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;
}

View File

@ -218,7 +218,7 @@ export function addToVegetation(chunk, object, props, ceiledX, ceiledY) {
* @param {Number} ceiledX * @param {Number} ceiledX
* @param {Number} ceiledY * @param {Number} ceiledY
*/ */
export function addToBuildings(chunk, object, props = {}, ceiledX, ceiledY) { export function addToBuildings(chunk, object, props, ceiledX, ceiledY) {
chunk.buildingsLayer.addChild(object); chunk.buildingsLayer.addChild(object);
chunk.buildingsObjectsVault.set(ceiledX + "_" + ceiledY, new BuildingsObjectProps(object, { ...props })); chunk.buildingsObjectsVault.set(ceiledX + "_" + ceiledY, new BuildingsObjectProps(object, { ...props }));
} }