mapa
This commit is contained in:
44
src/utils/Compression.js
Normal file
44
src/utils/Compression.js
Normal file
@@ -0,0 +1,44 @@
|
||||
// Utility class for string compression (LZW algorithm)
|
||||
// Used to reduce save file size in localStorage
|
||||
class Compression {
|
||||
static compress(s) {
|
||||
if (s == null) return "";
|
||||
var dict = {}, data = (s + "").split(""), out = [], currChar, phrase = data[0], code = 256;
|
||||
for (var i = 1; i < data.length; i++) {
|
||||
currChar = data[i];
|
||||
if (dict[phrase + currChar] != null) {
|
||||
phrase += currChar;
|
||||
} else {
|
||||
out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0));
|
||||
dict[phrase + currChar] = code;
|
||||
code++;
|
||||
phrase = currChar;
|
||||
}
|
||||
}
|
||||
out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0));
|
||||
for (var i = 0; i < out.length; i++) {
|
||||
out[i] = String.fromCharCode(out[i]);
|
||||
}
|
||||
return out.join("");
|
||||
}
|
||||
|
||||
static decompress(s) {
|
||||
if (s == null) return "";
|
||||
if (s == "") return null;
|
||||
var dict = {}, data = (s + "").split(""), currChar = data[0], oldPhrase = currChar, out = [currChar], code = 256, phrase;
|
||||
for (var i = 1; i < data.length; i++) {
|
||||
var currCode = data[i].charCodeAt(0);
|
||||
if (currCode < 256) {
|
||||
phrase = data[i];
|
||||
} else {
|
||||
phrase = dict[currCode] ? dict[currCode] : (oldPhrase + oldPhrase.charAt(0));
|
||||
}
|
||||
out.push(phrase);
|
||||
currChar = phrase.charAt(0);
|
||||
dict[code] = oldPhrase + currChar;
|
||||
code++;
|
||||
oldPhrase = phrase;
|
||||
}
|
||||
return out.join("");
|
||||
}
|
||||
}
|
||||
99
src/utils/Pathfinding.js
Normal file
99
src/utils/Pathfinding.js
Normal file
@@ -0,0 +1,99 @@
|
||||
class Pathfinding {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
// Offsets for 4 directions (Isometric grid)
|
||||
this.dirs = [
|
||||
{ x: 0, y: -1 }, // Up
|
||||
{ x: 0, y: 1 }, // Down
|
||||
{ x: -1, y: 0 }, // Left
|
||||
{ x: 1, y: 0 } // Right
|
||||
];
|
||||
}
|
||||
|
||||
findPath(startX, startY, endX, endY, limit = 50) {
|
||||
// Simple A* implementation
|
||||
const startNode = { x: startX, y: startY, g: 0, h: 0, f: 0, parent: null };
|
||||
const openList = [startNode];
|
||||
const closedSet = new Set();
|
||||
|
||||
let count = 0;
|
||||
|
||||
while (openList.length > 0 && count < limit) {
|
||||
count++;
|
||||
|
||||
// Sort by F cost (can be optimized with PriorityQueue)
|
||||
openList.sort((a, b) => a.f - b.f);
|
||||
const currentNode = openList.shift();
|
||||
|
||||
// Reached destination? (or close enough)
|
||||
if (currentNode.x === endX && currentNode.y === endY) {
|
||||
return this.reconstructPath(currentNode);
|
||||
}
|
||||
|
||||
const key = `${currentNode.x},${currentNode.y}`;
|
||||
closedSet.add(key);
|
||||
|
||||
// Explore neighbors
|
||||
for (const dir of this.dirs) {
|
||||
const neighborX = currentNode.x + dir.x;
|
||||
const neighborY = currentNode.y + dir.y;
|
||||
|
||||
if (closedSet.has(`${neighborX},${neighborY}`)) continue;
|
||||
|
||||
// Check collision
|
||||
if (!this.isValidMove(neighborX, neighborY)) continue;
|
||||
|
||||
const gScore = currentNode.g + 1;
|
||||
const hScore = Math.abs(neighborX - endX) + Math.abs(neighborY - endY);
|
||||
const fScore = gScore + hScore;
|
||||
|
||||
// Check if already in openList with lower G
|
||||
const existing = openList.find(n => n.x === neighborX && n.y === neighborY);
|
||||
if (existing) {
|
||||
if (gScore < existing.g) {
|
||||
existing.g = gScore;
|
||||
existing.f = fScore;
|
||||
existing.parent = currentNode;
|
||||
}
|
||||
} else {
|
||||
openList.push({ x: neighborX, y: neighborY, g: gScore, h: hScore, f: fScore, parent: currentNode });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Limit reached or no path - return simplified direction if possible
|
||||
return null;
|
||||
}
|
||||
|
||||
reconstructPath(node) {
|
||||
const path = [];
|
||||
let curr = node;
|
||||
while (curr.parent) {
|
||||
path.unshift({ x: curr.x, y: curr.y });
|
||||
curr = curr.parent;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
isValidMove(x, y) {
|
||||
const terrain = this.scene.terrainSystem;
|
||||
if (!terrain) return true;
|
||||
|
||||
// Bounds
|
||||
if (x < 0 || y < 0 || x >= terrain.width || y >= terrain.height) return false;
|
||||
|
||||
// Tile Type
|
||||
const tile = terrain.tiles[y][x];
|
||||
if (tile.type.name === 'water') return false;
|
||||
|
||||
// Decorations collision
|
||||
const key = `${x},${y}`;
|
||||
if (terrain.decorationsMap.has(key)) {
|
||||
const decor = terrain.decorationsMap.get(key);
|
||||
const solidTypes = ['tree', 'stone', 'bush', 'wall', 'ruin', 'fence', 'house', 'gravestone'];
|
||||
if (solidTypes.includes(decor.type)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -268,18 +268,43 @@ class TextureGenerator {
|
||||
x.fillStyle = 'gray'; x.fillRect(8, 12, 16, 4);
|
||||
c.refresh();
|
||||
}
|
||||
if (!scene.textures.exists('item_hoe')) {
|
||||
const c = scene.textures.createCanvas('item_hoe', 32, 32);
|
||||
const x = c.getContext();
|
||||
x.fillStyle = 'brown'; x.fillRect(14, 10, 4, 18); // Ročaj
|
||||
x.fillStyle = 'gray';
|
||||
x.fillRect(10, 8, 12, 4); // Rezilo motike
|
||||
c.refresh();
|
||||
}
|
||||
if (!scene.textures.exists('item_sword')) {
|
||||
const c = scene.textures.createCanvas('item_sword', 32, 32);
|
||||
const x = c.getContext();
|
||||
x.fillStyle = 'brown'; x.fillRect(14, 10, 4, 14); // Ročaj
|
||||
x.fillStyle = 'gray';
|
||||
x.fillRect(12, 8, 8, 12); // Rezilo meča
|
||||
x.fillStyle = 'gold'; x.fillRect(14, 21, 4, 2); // Guard
|
||||
c.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
static createItemSprites(scene) {
|
||||
// Placeholder item generation
|
||||
const items = ['wood', 'stone', 'seed', 'item_bone']; // Ensure item_bone is here
|
||||
items.forEach(it => {
|
||||
const items = [
|
||||
{ name: 'wood', color: '#8B4513' }, // Rjava
|
||||
{ name: 'stone', color: '#808080' }, // Siva
|
||||
{ name: 'seeds', color: '#90EE90' }, // Svetlo zelena
|
||||
{ name: 'wheat', color: '#FFD700' }, // Zlata
|
||||
{ name: 'item_bone', color: '#F5F5DC' } // Beige
|
||||
];
|
||||
items.forEach(item => {
|
||||
const it = typeof item === 'string' ? item : item.name;
|
||||
const color = typeof item === 'string' ? 'gold' : item.color;
|
||||
const k = (it.startsWith('item_')) ? it : 'item_' + it;
|
||||
if (!scene.textures.exists(k)) {
|
||||
const c = scene.textures.createCanvas(k, 32, 32);
|
||||
const x = c.getContext();
|
||||
x.clearRect(0, 0, 32, 32);
|
||||
x.fillStyle = 'gold';
|
||||
x.fillStyle = color;
|
||||
x.beginPath(); x.arc(16, 16, 10, 0, Math.PI * 2); x.fill();
|
||||
c.refresh();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user