From 0e0639bbb7a688143baad18260ec4015d8205294 Mon Sep 17 00:00:00 2001 From: TorgaW Date: Mon, 15 Apr 2024 00:58:17 +0300 Subject: [PATCH] fixed naming and complete terrain tiles generation with object system --- src/Game/Game.js | 14 +- .../Scene.js => GameScene/GameScene.js} | 4 +- src/Game/GlobalVariables/GlobalVariables.js | 15 +- src/Game/SceneObjects/SceneObject.js | 5 + .../WorldChunk/WorldGenChunk.js | 57 +++++ src/Game/WorldGeneration/WorldGen.js | 241 ++++++++++++++++++ .../WorldObjects/TerrainTile/TerrainTile.js | 52 ++++ 7 files changed, 381 insertions(+), 7 deletions(-) rename src/Game/{Scene/Scene.js => GameScene/GameScene.js} (95%) create mode 100644 src/Game/WorldGeneration/WorldChunk/WorldGenChunk.js create mode 100644 src/Game/WorldGeneration/WorldGen.js create mode 100644 src/Game/WorldGeneration/WorldObjects/TerrainTile/TerrainTile.js diff --git a/src/Game/Game.js b/src/Game/Game.js index 9723d61..5fa7e07 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_APP, BC_BUILDING_PLACEHOLDERS, BC_CAMERA, BC_SPRITES_SETTINGS, BC_VIEWPORT, BC_WORLD, PRNG, setBC_APP, setBC_NPC_LAYER, setBC_SELECTION, setBC_VIEWPORT, setBC_WORLD } from "./GlobalVariables/GlobalVariables"; +import { BC_APP, BC_BUILDING_PLACEHOLDERS, BC_CAMERA, BC_CURRENT_SCENE, BC_SPRITES_SETTINGS, BC_VIEWPORT, BC_WORLD, PRNG, setBC_APP, setBC_CURRENT_SCENE, setBC_NPC_LAYER, setBC_SELECTION, setBC_VIEWPORT, setBC_WORLD } from "./GlobalVariables/GlobalVariables"; import { clampNumber, interpolate, } from "./Utils/Math.utils"; import { calculateViewportFromCamera, moveHorizontally, moveVertically, screenToWorldCoordinates } from "./Camera/Camera"; @@ -27,10 +27,12 @@ import { handleChunkFilling } from "./WorldGeneration/ChunkFillQueue"; import { addNPCToWorld } from "./NPC/NPC"; import { gameStateObjectsCleaner } from "./GameState/GameState"; import { tickHandler } from "./TickHandler/TickHandler"; +import { GameScene } from "./GameScene/GameScene"; +import { createChunks } from "./WorldGeneration/WorldGen"; export function generateWorld() { - createFirstWorldChunks(); + // createFirstWorldChunks(); startGame(); } @@ -249,6 +251,8 @@ export async function initGame() { app.stage.addChild(viewport); // world.tint = 0x00ffff; + setBC_CURRENT_SCENE(new GameScene()); + BC_CAMERA.position.x = Math.floor(PRNG() * 3242 - 372); BC_CAMERA.position.y = Math.floor(PRNG() * 1285 - 255); @@ -259,8 +263,8 @@ export async function initGame() { app.ticker.add(inputControllerTick); app.ticker.add(calculateViewportFromCamera); - app.ticker.add(updateChunksVisibility); - app.ticker.add(handleChunkFilling); + // app.ticker.add(updateChunksVisibility); + // app.ticker.add(handleChunkFilling); app.ticker.add(profileFPS); app.ticker.add(handleBuildingsIncome); @@ -281,4 +285,6 @@ function startGame() { // addNPCToWorld(BC_CAMERA.position.x, BC_CAMERA.position.y, {type: "slave"}); BC_APP.ticker.add(gameStateObjectsCleaner); BC_APP.ticker.add(tickHandler); + + createChunks(); } diff --git a/src/Game/Scene/Scene.js b/src/Game/GameScene/GameScene.js similarity index 95% rename from src/Game/Scene/Scene.js rename to src/Game/GameScene/GameScene.js index c15d606..12aa5c5 100644 --- a/src/Game/Scene/Scene.js +++ b/src/Game/GameScene/GameScene.js @@ -2,7 +2,7 @@ import { addGameObjectToGameState } from "../GameState/GameState"; import { BC_VIEWPORT } from "../GlobalVariables/GlobalVariables"; import { SceneObject } from "../SceneObjects/SceneObject"; -export class Scene { +export class GameScene { /** * @type Map */ @@ -22,7 +22,7 @@ export class Scene { }; /** - * Uninitialized SceneObject + * For uninitialized SceneObjects * @param {SceneObject} sceneObject */ addObjectToSceneWithInitialization(sceneObject) { diff --git a/src/Game/GlobalVariables/GlobalVariables.js b/src/Game/GlobalVariables/GlobalVariables.js index 2aed9de..cb8123f 100644 --- a/src/Game/GlobalVariables/GlobalVariables.js +++ b/src/Game/GlobalVariables/GlobalVariables.js @@ -1,5 +1,6 @@ import Alea from "alea"; import { Container } from "../../pixi/pixi.mjs"; +import { GameScene } from "../GameScene/GameScene"; export let BC_APP; @@ -81,4 +82,16 @@ export function setNewPRNG(prng) { PRNG = prng; }; -export const BC_BUILDING_PLACEHOLDERS = []; \ No newline at end of file +export const BC_BUILDING_PLACEHOLDERS = []; + +/** + * @type GameScene + */ +export let BC_CURRENT_SCENE; +/** + * + * @param {GameScene} scene new scene + */ +export function setBC_CURRENT_SCENE(scene) { + BC_CURRENT_SCENE = scene; +}; \ No newline at end of file diff --git a/src/Game/SceneObjects/SceneObject.js b/src/Game/SceneObjects/SceneObject.js index c26b674..2d37e49 100644 --- a/src/Game/SceneObjects/SceneObject.js +++ b/src/Game/SceneObjects/SceneObject.js @@ -8,6 +8,11 @@ export class SceneObject extends GameObject { */ drawObject = new Container(); + /** + * Props for scene object. Defined in children classes + */ + props = {}; + /** * Instantly* kills drawObject (by PIXI) and after several ticks kills SceneObject * diff --git a/src/Game/WorldGeneration/WorldChunk/WorldGenChunk.js b/src/Game/WorldGeneration/WorldChunk/WorldGenChunk.js new file mode 100644 index 0000000..0e555c9 --- /dev/null +++ b/src/Game/WorldGeneration/WorldChunk/WorldGenChunk.js @@ -0,0 +1,57 @@ +import { Container } from "../../../pixi/pixi.mjs"; +import { SceneObject } from "../../SceneObjects/SceneObject"; +import { TerrainTile } from "../WorldObjects/TerrainTile/TerrainTile"; + +export class ChunkStorageTypes +{ + static TYPE_TERRAIN = 0; + static TYPE_VEGETATION = 1; + static TYPE_BUILDINGS = 2; + static TYPE_NPC = 3; +}; + +export class WorldChunk extends SceneObject +{ + /** + * @type Map + */ + terrainStorage = new Map(); + + /** + * + * @param {SceneObject} object + * @param {ChunkStorageTypes} storageType + * @param {String} objectId + */ + addToChunk(object, storageType, objectId) + { + switch (storageType) { + case 0: + this.terrainStorage.set(objectId, object); + break; + + default: + break; + } + this.drawObject.addChild(object.drawObject); + } + + /** + * + * @param {SceneObject} object + * @param {ChunkStorageTypes} storageType + * @param {String} objectId + */ + removeFromChunk(object, storageType, objectId) + { + switch (storageType) { + case 0: + this.terrainStorage.delete(objectId); + break; + + default: + break; + } + this.drawObject.removeChild(object); + } +}; \ No newline at end of file diff --git a/src/Game/WorldGeneration/WorldGen.js b/src/Game/WorldGeneration/WorldGen.js new file mode 100644 index 0000000..2d6947d --- /dev/null +++ b/src/Game/WorldGeneration/WorldGen.js @@ -0,0 +1,241 @@ +import {Noise} from "noisejs"; +import { Rectangle } from "../../pixi/pixi.mjs"; +import { BC_CAMERA, BC_CHUNKS_SETTINGS, BC_CURRENT_SCENE, BC_SPRITES_SETTINGS, BC_TERRAIN_SETTINGS, PRNG } from "../GlobalVariables/GlobalVariables"; +import { NumberCue, RGBColor } from "../Utils/DataTypes.utils"; +import { ChunkStorageTypes, WorldChunk } from "./WorldChunk/WorldGenChunk"; +import { TerrainTile, TerrainTileProps } from "./WorldObjects/TerrainTile/TerrainTile"; +import { clampNumber } from "../Utils/Math.utils"; +import { addGameObjectToGameState } from "../GameState/GameState"; + +/** + * @type Map + */ +const WorldChunksStorage = new Map(); + + +/* #### REWRITE PART START ####*/ +const terrainSpriteList = { + 0: { x: 21, y: 21 }, //water + 1: { x: 2, y: 21 }, //sand + 2: { x: 2, y: 2 }, //grass + 3: { x: 21, y: 2 }, //stone +}; +const terrainTypeList = { + 0: "ter_water", //water + 1: "ter_sand", //sand + 2: "ter_grass", //grass + 3: "ter_stone", //stone +}; +const grassVegetationSpriteList = { + 0: { x: 10, y: 11 }, + 1: { x: 11, y: 11 }, + 2: { x: 12, y: 11 }, + 3: { x: 13, y: 11 }, + 4: { x: 14, y: 11 }, + 5: { x: 15, y: 11 }, + 6: { x: 16, y: 11 }, + 7: { x: 17, y: 11 }, + 8: { x: 18, y: 11 }, + 9: { x: 19, y: 11 }, + 10: { x: 0, y: 12 }, + 11: { x: 1, y: 12 }, + 12: { x: 2, y: 12 }, + 13: { x: 3, y: 12 }, + 14: { x: 7, y: 13 }, + 15: { x: 7, y: 12 }, + 16: { x: 8, y: 12 }, + 17: { x: 9, y: 12 }, +}; +const sandVegetationSpriteList = { + 0: { x: 14, y: 10 }, + 1: { x: 7, y: 13 }, + 2: { x: 6, y: 13 }, + 3: { x: 5, y: 13 }, + 4: { x: 4, y: 13 }, + 5: { x: 3, y: 13 }, +}; +const stoneVegetationSpriteList = { + 0: { x: 5, y: 13 }, + 1: { x: 4, y: 13 }, + 2: { x: 3, y: 13 }, +}; +const grassVegResourcesList = { + 0: { type: "grass", num: 10 / 5 }, + 1: { type: "grass", num: 9 / 5 }, + 2: { type: "grass", num: 8 / 5 }, + 3: { type: "grass", num: 7 / 5 }, + 4: { type: "grass", num: 4 / 5 }, + 5: { type: "grass", num: 4 / 5 }, + 6: { type: "grass", num: 5 / 5 }, + 7: { type: "grass", num: 3 / 5 }, + 8: { type: "grass", num: 2 / 5 }, + 9: { type: "grass", num: 1 / 5 }, + 10: { type: "grass", num: 2 / 5 }, + 11: { type: "grass", num: 2 / 5 }, + 12: { type: "grass", num: 2 / 5 }, + 13: { type: "grass", num: 2 / 5 }, + 14: { type: "stone", num: 1 / 5 }, + 15: { type: "wood", num: 2 / 5 }, + 16: { type: "wood", num: 2 / 5 }, + 17: { type: "wood", num: 2 / 5 }, +}; + +const sandVegResourcesList = { + 0: { type: "grass", num: 4 / 5 }, + 1: { type: "stone", num: 1 / 5 }, + 2: { type: "stone", num: 3 / 5 }, + 3: { type: "stone", num: 4 / 5 }, + 4: { type: "stone", num: 5 / 5 }, + 5: { type: "stone", num: 5 / 5 }, +}; + +const stoneVegResourcesList = { + 0: { type: "stone", num: 4 / 5 }, + 1: { type: "stone", num: 5 / 5 }, + 2: { type: "stone", num: 5 / 5 }, +}; + +let noise = new Noise(Math.floor(PRNG() * 188822321)); +let noiseErosion = new Noise(Math.floor(PRNG() * 327749029)); +let noiseBiomes = new Noise(Math.floor(PRNG() * 927472011)); + +let terrainCue = new NumberCue([0, 1, 2, 3, 3], [0.0, 0.45, 0.5, 0.9, 1.0]); +let terrainTintCue = new NumberCue([0.9, 1, 1, 0.95, 0.9, 1, 0.93, 1], [0.0, 0.45, 0.45, 0.5, 0.5, 0.9, 0.9, 1.0]); + +/** + * + * @param {WorldChunk} chunk chunk to fill + * @param {Number} x ceiled coordinates of left-upper corner + * @param {Number} y ceiled coordinates of left-upper corner + */ +export function fillWorldGenChunk(chunk, x, y) { + let ii = 0; + let jj = 0; + for (let i = BC_CHUNKS_SETTINGS.width * x; i < BC_CHUNKS_SETTINGS.width * (x + 1); i++) { + jj = 0; + for (let j = BC_CHUNKS_SETTINGS.height * y; j < BC_CHUNKS_SETTINGS.height * (y + 1); j++) { + let res = (noise.simplex2(i * 0.025, j * 0.025) + 1) / 2; + let resR = (noiseErosion.simplex2(i * 0.3, j * 0.3) + 1) / 2; + let resB = (noiseBiomes.simplex2(i * 0.01, j * 0.01) + 1) / 2; + if (resB > 0.7) { + res = clampNumber(res - resR / 4, 0.0, 0.99); + } + if (resB > 0.5 && res < 0.9 && res >= 0.5) { + res = clampNumber(res + resR / 4, 0.0, 0.99); + } + + let sTint = new RGBColor(255, 255, 255).multiplyByNumber(terrainTintCue.getValueAt(res)).toNumber(); + res = Math.floor(terrainCue.getValueAt(res)); + + let terrainTile = new TerrainTile(); + terrainTile.spriteSheetPath = "assets/images/world/world_terrain_atlas.png"; + terrainTile.frame = new Rectangle(terrainSpriteList[res].x, terrainSpriteList[res].y, 16, 16); + terrainTile.props = new TerrainTileProps(terrainTypeList[res], res*5); + addGameObjectToGameState(terrainTile); + + terrainTile.drawObject.tint = sTint; + terrainTile.drawObject.position.set(16 * BC_SPRITES_SETTINGS.scale * ii, 16 * BC_SPRITES_SETTINGS.scale * jj); + terrainTile.drawObject.scale.set(BC_SPRITES_SETTINGS.scale, BC_SPRITES_SETTINGS.scale); + + chunk.addToChunk(terrainTile, ChunkStorageTypes.TYPE_TERRAIN, i+"_"+j); + // let sprite = getSpriteFromAtlas( + // "assets/images/world/world_terrain_atlas.png", + // new PIXI.Rectangle(terrainSpriteList[res].x, terrainSpriteList[res].y, 16, 16) + // ); + // sprite.position.set(16 * BC_SPRITES_SETTINGS.scale * ii, 16 * BC_SPRITES_SETTINGS.scale * jj); + // sprite.scale.set(BC_SPRITES_SETTINGS.scale, BC_SPRITES_SETTINGS.scale); + // sprite.tint = sTint; + // addToTerrain(chunk, sprite, { type: terrainTypeList[res] }, i, j); + // console.log(ii, jj); + // addToTerrain(sprite, {x: i, y: j}, {type: terrainTypeList[res]}); + // if (res === 2 && PRNG() > 0.9) { + // let rv = Math.floor(PRNG() * 18); + + // let veg = getSpriteFromAtlas( + // "assets/images/world/vegetation_ts.png", + // new PIXI.Rectangle(16 * grassVegetationSpriteList[rv].x, 16 * grassVegetationSpriteList[rv].y, 16, 16) + // ); + // veg.position.set(16 * BC_SPRITES_SETTINGS.scale * ii, 16 * BC_SPRITES_SETTINGS.scale * jj); + // veg.scale.set(BC_SPRITES_SETTINGS.scale, BC_SPRITES_SETTINGS.scale); + // veg.tint = sTint; + // addToVegetation(chunk, veg, { ...grassVegResourcesList[rv] }, i, j); + // jj++; + // continue; + // } + // if (res === 1 && PRNG() > 0.99) { + // let rv = Math.floor(PRNG() * 6); + + // let veg = getSpriteFromAtlas( + // "assets/images/world/vegetation_ts.png", + // new PIXI.Rectangle(16 * sandVegetationSpriteList[rv].x, 16 * sandVegetationSpriteList[rv].y, 16, 16) + // ); + // veg.position.set(16 * BC_SPRITES_SETTINGS.scale * ii, 16 * BC_SPRITES_SETTINGS.scale * jj); + // veg.scale.set(BC_SPRITES_SETTINGS.scale, BC_SPRITES_SETTINGS.scale); + // veg.tint = sTint; + // addToVegetation(chunk, veg, { ...sandVegResourcesList[rv] }, i, j); + // jj++; + // continue; + // } + // if (res === 3 && PRNG() > 0.9) { + // let rv = Math.floor(PRNG() * 3); + + // let veg = getSpriteFromAtlas( + // "assets/images/world/vegetation_ts.png", + // new PIXI.Rectangle(16 * stoneVegetationSpriteList[rv].x, 16 * stoneVegetationSpriteList[rv].y, 16, 16) + // ); + // veg.position.set(16 * BC_SPRITES_SETTINGS.scale * ii, 16 * BC_SPRITES_SETTINGS.scale * jj); + // veg.scale.set(BC_SPRITES_SETTINGS.scale, BC_SPRITES_SETTINGS.scale); + // veg.tint = sTint; + // addToVegetation(chunk, veg, { ...stoneVegResourcesList[rv] }, i, j); + // jj++; + // continue; + // } + jj++; + } + ii++; + } +} + +export function createChunks() { + let w = BC_CHUNKS_SETTINGS.width * BC_TERRAIN_SETTINGS.tileSize * BC_TERRAIN_SETTINGS.scale; + let h = BC_CHUNKS_SETTINGS.height * BC_TERRAIN_SETTINGS.tileSize * BC_TERRAIN_SETTINGS.scale; + for (let i = -1; i < 2; i++) { + for (let j = -1; j < 2; j++) { + let chunkXCeiled = Math.floor((BC_CAMERA.position.x + w * i) / w); + let chunkYCeiled = Math.floor((BC_CAMERA.position.y + h * j) / h); + let chunkId = chunkXCeiled + "_" + chunkYCeiled; + + let chunk = new WorldChunk(false); + chunk.drawObject.position.set(w * chunkXCeiled, h * chunkYCeiled); + + BC_CURRENT_SCENE.addObjectToSceneWithInitialization(chunk); + + fillWorldGenChunk(chunk, chunkXCeiled, chunkYCeiled); + WorldChunksStorage.set(chunkId, chunk); + // console.log(chunkId); + // let chunkRef = createWorldChunkContainer(); + // chunkRef.isRenderGroup = true; + // chunkRef.position.set(w * chunkXCeiled, h * chunkYCeiled); + // console.log(w * chunkXCeiled, h * chunkYCeiled); + // let chunk0 = new WorldChunk( + // chunkRef, + // chunkRef.getChildAt(0), + // chunkRef.getChildAt(1), + // chunkRef.getChildAt(2), + // // chunkRef.getChildAt(3), + // new Vault("terrain"), + // new Vault("vegetation"), + // new Vault("buildings") + // ); + + // fillChunk(chunk0, chunkXCeiled, chunkYCeiled); + // WORLD_CHUNKS.set(chunkId, chunk0); + // chunkRef.visible = false; + // addToViewport(chunkRef); + // console.log(WORLD_CHUNKS) + // console.log(chunkXCeiled, chunkYCeiled); + } + } +} + +/* #### REWRITE PART END ####*/ \ No newline at end of file diff --git a/src/Game/WorldGeneration/WorldObjects/TerrainTile/TerrainTile.js b/src/Game/WorldGeneration/WorldObjects/TerrainTile/TerrainTile.js new file mode 100644 index 0000000..1f03f78 --- /dev/null +++ b/src/Game/WorldGeneration/WorldObjects/TerrainTile/TerrainTile.js @@ -0,0 +1,52 @@ +import { Rectangle } from "../../../../pixi/pixi.mjs"; +import { SceneObject } from "../../../SceneObjects/SceneObject"; +import { getSpriteFromAtlas } from "../../../Utils/Sprites.utils"; + +export class TerrainTileProps +{ + /** + * @type String + */ + type; + /** + * @type Number + */ + temperature; + + /** + * + * @param {String} type + * @param {Number} temperature + */ + constructor(type = "", temperature = 0) + { + this.type = type; + this.temperature = temperature; + }; + + +} + +export class TerrainTile extends SceneObject +{ + props = new TerrainTileProps(); + spriteSheetPath = ""; + frame = new Rectangle(); + + #printed = false; + + onInit() + { + super.onInit(); + this.drawObject = getSpriteFromAtlas(this.spriteSheetPath, this.frame); + }; + + tick(ticker) + { + if(!this.#printed) + { + console.log(this.props); + this.#printed = true; + } + } +}; \ No newline at end of file