FAZA 1: Terrain generation with Perlin noise and isometric view - Ready for testing
This commit is contained in:
62
src/utils/IsometricUtils.js
Normal file
62
src/utils/IsometricUtils.js
Normal file
@@ -0,0 +1,62 @@
|
||||
// Isometric Utilities
|
||||
// Konverzija med kartezičnimi in izometričnimi koordinatami
|
||||
class IsometricUtils {
|
||||
constructor(tileWidth = 48, tileHeight = 24) {
|
||||
this.tileWidth = tileWidth;
|
||||
this.tileHeight = tileHeight;
|
||||
}
|
||||
|
||||
// Kartezične (grid) koordinate -> Isometrične (screen) koordinate
|
||||
toScreen(gridX, gridY) {
|
||||
const screenX = (gridX - gridY) * (this.tileWidth / 2);
|
||||
const screenY = (gridX + gridY) * (this.tileHeight / 2);
|
||||
return { x: screenX, y: screenY };
|
||||
}
|
||||
|
||||
// Isometrične (screen) koordinate -> Kartezične (grid) koordinate
|
||||
toGrid(screenX, screenY) {
|
||||
const gridX = (screenX / (this.tileWidth / 2) + screenY / (this.tileHeight / 2)) / 2;
|
||||
const gridY = (screenY / (this.tileHeight / 2) - screenX / (this.tileWidth / 2)) / 2;
|
||||
return { x: Math.floor(gridX), y: Math.floor(gridY) };
|
||||
}
|
||||
|
||||
// Izračun depth (z-index) za pravilno sortiranje
|
||||
getDepth(gridX, gridY) {
|
||||
return gridX + gridY;
|
||||
}
|
||||
|
||||
// Izračun centerja tile-a
|
||||
getTileCenter(gridX, gridY) {
|
||||
const screen = this.toScreen(gridX, gridY);
|
||||
return {
|
||||
x: screen.x,
|
||||
y: screen.y + this.tileHeight / 2
|
||||
};
|
||||
}
|
||||
|
||||
// Preveri ali je grid koordinata znotraj meja
|
||||
isInBounds(gridX, gridY, mapWidth, mapHeight) {
|
||||
return gridX >= 0 && gridX < mapWidth && gridY >= 0 && gridY < mapHeight;
|
||||
}
|
||||
|
||||
// Dobi sosednje tile-e (NSEW)
|
||||
getNeighbors(gridX, gridY, mapWidth, mapHeight) {
|
||||
const neighbors = [];
|
||||
const directions = [
|
||||
{ x: 0, y: -1 }, // North
|
||||
{ x: 1, y: 0 }, // East
|
||||
{ x: 0, y: 1 }, // South
|
||||
{ x: -1, y: 0 } // West
|
||||
];
|
||||
|
||||
for (const dir of directions) {
|
||||
const nx = gridX + dir.x;
|
||||
const ny = gridY + dir.y;
|
||||
if (this.isInBounds(nx, ny, mapWidth, mapHeight)) {
|
||||
neighbors.push({ x: nx, y: ny });
|
||||
}
|
||||
}
|
||||
|
||||
return neighbors;
|
||||
}
|
||||
}
|
||||
88
src/utils/PerlinNoise.js
Normal file
88
src/utils/PerlinNoise.js
Normal file
@@ -0,0 +1,88 @@
|
||||
// Perlin Noise Generator
|
||||
// Implementacija za proceduralno generacijo terena
|
||||
class PerlinNoise {
|
||||
constructor(seed = Math.random()) {
|
||||
this.seed = seed;
|
||||
this.permutation = this.generatePermutation();
|
||||
}
|
||||
|
||||
generatePermutation() {
|
||||
const p = [];
|
||||
for (let i = 0; i < 256; i++) {
|
||||
p[i] = i;
|
||||
}
|
||||
|
||||
// Fisher-Yates shuffle z seed-om
|
||||
let random = this.seed;
|
||||
for (let i = 255; i > 0; i--) {
|
||||
random = (random * 9301 + 49297) % 233280;
|
||||
const j = Math.floor((random / 233280) * (i + 1));
|
||||
[p[i], p[j]] = [p[j], p[i]];
|
||||
}
|
||||
|
||||
// Podvoji permutacijo
|
||||
return [...p, ...p];
|
||||
}
|
||||
|
||||
fade(t) {
|
||||
return t * t * t * (t * (t * 6 - 15) + 10);
|
||||
}
|
||||
|
||||
lerp(t, a, b) {
|
||||
return a + t * (b - a);
|
||||
}
|
||||
|
||||
grad(hash, x, y) {
|
||||
const h = hash & 3;
|
||||
const u = h < 2 ? x : y;
|
||||
const v = h < 2 ? y : x;
|
||||
return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v);
|
||||
}
|
||||
|
||||
noise(x, y) {
|
||||
const X = Math.floor(x) & 255;
|
||||
const Y = Math.floor(y) & 255;
|
||||
|
||||
x -= Math.floor(x);
|
||||
y -= Math.floor(y);
|
||||
|
||||
const u = this.fade(x);
|
||||
const v = this.fade(y);
|
||||
|
||||
const p = this.permutation;
|
||||
const a = p[X] + Y;
|
||||
const aa = p[a];
|
||||
const ab = p[a + 1];
|
||||
const b = p[X + 1] + Y;
|
||||
const ba = p[b];
|
||||
const bb = p[b + 1];
|
||||
|
||||
return this.lerp(v,
|
||||
this.lerp(u, this.grad(p[aa], x, y), this.grad(p[ba], x - 1, y)),
|
||||
this.lerp(u, this.grad(p[ab], x, y - 1), this.grad(p[bb], x - 1, y - 1))
|
||||
);
|
||||
}
|
||||
|
||||
// Octave noise za bolj kompleksne terene
|
||||
octaveNoise(x, y, octaves = 4, persistence = 0.5) {
|
||||
let total = 0;
|
||||
let frequency = 1;
|
||||
let amplitude = 1;
|
||||
let maxValue = 0;
|
||||
|
||||
for (let i = 0; i < octaves; i++) {
|
||||
total += this.noise(x * frequency, y * frequency) * amplitude;
|
||||
maxValue += amplitude;
|
||||
amplitude *= persistence;
|
||||
frequency *= 2;
|
||||
}
|
||||
|
||||
return total / maxValue;
|
||||
}
|
||||
|
||||
// Generira normalizirano vrednost med 0 in 1
|
||||
getNormalized(x, y, scale = 0.1, octaves = 4) {
|
||||
const value = this.octaveNoise(x * scale, y * scale, octaves);
|
||||
return (value + 1) / 2; // Normalizacija iz [-1, 1] v [0, 1]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user