Erster Commit
This commit is contained in:
@@ -0,0 +1,826 @@
|
||||
const canvas = document.getElementById("gameCanvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
canvas.width = 1280;
|
||||
canvas.height = 720;
|
||||
|
||||
const loginBox = document.getElementById("loginBox");
|
||||
const registerBox = document.getElementById("registerBox");
|
||||
|
||||
const loginUser = document.getElementById("loginUser");
|
||||
const loginPass = document.getElementById("loginPass");
|
||||
const loginBtn = document.getElementById("loginBtn");
|
||||
|
||||
const regUser = document.getElementById("regUser");
|
||||
const regPass = document.getElementById("regPass");
|
||||
const regBtn = document.getElementById("regBtn");
|
||||
|
||||
const switchToRegister = document.getElementById("switchToRegister");
|
||||
const switchToLogin = document.getElementById("switchToLogin");
|
||||
|
||||
const shopWindow = document.getElementById("shopWindow");
|
||||
const shopList = document.getElementById("shopList");
|
||||
|
||||
let ws = null;
|
||||
let maps = {};
|
||||
let tileConfig = {};
|
||||
let lastServerUpdate = 0;
|
||||
|
||||
let player = {
|
||||
id: null,
|
||||
x: 100,
|
||||
y: 100,
|
||||
world: "stadt"
|
||||
};
|
||||
player.health = 100;
|
||||
player.hunger = 100;
|
||||
player.thirst = 100;
|
||||
|
||||
player.inventory = [];
|
||||
player.money = 1000;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
let loggedIn = false;
|
||||
let otherPlayers = [];
|
||||
let keys = {};
|
||||
let shops = [];
|
||||
let atms = [];
|
||||
|
||||
let cars = [];
|
||||
let drivingCarId = null;
|
||||
|
||||
|
||||
|
||||
let objectConfig = {};
|
||||
|
||||
fetch("/objectConfig.json")
|
||||
.then(res => res.json())
|
||||
.then(data => objectConfig = data);
|
||||
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Tiles laden
|
||||
// -------------------------------------------------------------
|
||||
fetch("/tiles.json")
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
tileConfig = data;
|
||||
console.log("TileConfig geladen:", tileConfig);
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// REGISTER
|
||||
// -------------------------------------------------------------
|
||||
regBtn.onclick = async () => {
|
||||
const username = regUser.value;
|
||||
const password = regPass.value;
|
||||
|
||||
const res = await fetch("/api/register", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ username, password })
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (!data.ok) {
|
||||
alert(data.error);
|
||||
return;
|
||||
}
|
||||
|
||||
alert("Registrierung erfolgreich!");
|
||||
registerBox.style.display = "none";
|
||||
loginBox.style.display = "block";
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// LOGIN
|
||||
// -------------------------------------------------------------
|
||||
loginBtn.onclick = async () => {
|
||||
const username = loginUser.value;
|
||||
const password = loginPass.value;
|
||||
|
||||
const res = await fetch("/api/login", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ username, password })
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (!data.ok) {
|
||||
alert(data.error);
|
||||
return;
|
||||
}
|
||||
|
||||
loginBox.style.display = "none";
|
||||
canvas.style.display = "block";
|
||||
|
||||
startMultiplayer(data.token);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Hilfsfunktion: Spieler holen
|
||||
function getPlayer(playerId) {
|
||||
return playersOnline.get(playerId);
|
||||
}
|
||||
|
||||
// BANK: PIN prüfen
|
||||
async function handleBankPinCheck(playerId, data, ws) {
|
||||
const p = getPlayer(playerId);
|
||||
if (!p) return;
|
||||
|
||||
const pin = Number(data.pin) || 0;
|
||||
|
||||
const [rows] = await db.query("SELECT pin FROM players WHERE id=?", [playerId]);
|
||||
if (!rows.length) return;
|
||||
|
||||
if (rows[0].pin === pin) {
|
||||
ws.send(JSON.stringify({ type: "bank_pin_ok" }));
|
||||
} else {
|
||||
ws.send(JSON.stringify({ type: "bank_pin_fail" }));
|
||||
}
|
||||
}
|
||||
|
||||
// BANK: Fenster öffnen (Kontostand + Bargeld)
|
||||
async function handleBankOpen(playerId, ws) {
|
||||
const p = getPlayer(playerId);
|
||||
if (!p) return;
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
type: "bank_open",
|
||||
money: p.state.money,
|
||||
bank: p.state.bank
|
||||
}));
|
||||
}
|
||||
|
||||
// BANK: Einzahlen
|
||||
async function handleBankDeposit(playerId, data, ws) {
|
||||
const p = getPlayer(playerId);
|
||||
if (!p) return;
|
||||
|
||||
const amount = Number(data.amount) || 0;
|
||||
if (amount <= 0) return;
|
||||
if (p.state.money < amount) return;
|
||||
|
||||
p.state.money -= amount;
|
||||
p.state.bank += amount;
|
||||
|
||||
await db.query(
|
||||
"UPDATE players SET money=?, bank=? WHERE id=?",
|
||||
[p.state.money, p.state.bank, playerId]
|
||||
);
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
type: "bank_update",
|
||||
money: p.state.money,
|
||||
bank: p.state.bank
|
||||
}));
|
||||
}
|
||||
|
||||
// BANK: Auszahlen
|
||||
async function handleBankWithdraw(playerId, data, ws) {
|
||||
const p = getPlayer(playerId);
|
||||
if (!p) return;
|
||||
|
||||
const amount = Number(data.amount) || 0;
|
||||
if (amount <= 0) return;
|
||||
if (p.state.bank < amount) return;
|
||||
|
||||
p.state.bank -= amount;
|
||||
p.state.money += amount;
|
||||
|
||||
await db.query(
|
||||
"UPDATE players SET money=?, bank=? WHERE id=?",
|
||||
[p.state.money, p.state.bank, playerId]
|
||||
);
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
type: "bank_update",
|
||||
money: p.state.money,
|
||||
bank: p.state.bank
|
||||
}));
|
||||
}
|
||||
|
||||
// BANK: Geld an anderen Spieler senden (Bank → Bank)
|
||||
async function handleBankTransfer(playerId, data, ws) {
|
||||
const p = getPlayer(playerId);
|
||||
if (!p) return;
|
||||
|
||||
const targetId = Number(data.targetId);
|
||||
const amount = Number(data.amount) || 0;
|
||||
if (amount <= 0) return;
|
||||
|
||||
const t = getPlayer(targetId);
|
||||
if (!t) return;
|
||||
if (p.state.bank < amount) return;
|
||||
|
||||
p.state.bank -= amount;
|
||||
t.state.bank += amount;
|
||||
|
||||
await db.query("UPDATE players SET bank=? WHERE id=?", [p.state.bank, playerId]);
|
||||
await db.query("UPDATE players SET bank=? WHERE id=?", [t.state.bank, targetId]);
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
type: "bank_update",
|
||||
money: p.state.money,
|
||||
bank: p.state.bank
|
||||
}));
|
||||
|
||||
t.ws.send(JSON.stringify({
|
||||
type: "bank_update",
|
||||
money: t.state.money,
|
||||
bank: t.state.bank
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// UI SWITCH
|
||||
// -------------------------------------------------------------
|
||||
switchToRegister.onclick = () => {
|
||||
loginBox.style.display = "none";
|
||||
registerBox.style.display = "block";
|
||||
canvas.style.display = "none";
|
||||
};
|
||||
|
||||
switchToLogin.onclick = () => {
|
||||
registerBox.style.display = "none";
|
||||
loginBox.style.display = "block";
|
||||
canvas.style.display = "none";
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// MULTIPLAYER STARTEN
|
||||
// -------------------------------------------------------------
|
||||
function startMultiplayer(token) {
|
||||
ws = new WebSocket("ws://45.81.233.187:5555");
|
||||
|
||||
ws.onopen = () => {
|
||||
ws.send(JSON.stringify({ type: "auth", token }));
|
||||
};
|
||||
|
||||
ws.onmessage = ev => {
|
||||
const msg = JSON.parse(ev.data);
|
||||
|
||||
if (msg.type === "auth_ok") {
|
||||
player.id = msg.id;
|
||||
maps = msg.maps;
|
||||
document.getElementById("topMenu").style.display = "flex";
|
||||
document.getElementById("statusWindow").style.display = "block";
|
||||
document.getElementById("inventoryWindow").style.display = "block";
|
||||
|
||||
player.inventory = msg.inventory || [];
|
||||
document.getElementById("inventoryWindow").style.display = "block";
|
||||
renderInventoryWindow();
|
||||
canvas.style.display = "block";
|
||||
|
||||
console.log("MAPS GELADEN:", maps);
|
||||
|
||||
const map = maps[player.world];
|
||||
if (map && map.spawn) {
|
||||
player.x = map.spawn.x;
|
||||
player.y = map.spawn.y;
|
||||
}
|
||||
//shops=map.shops;
|
||||
loggedIn = true;
|
||||
|
||||
return;
|
||||
}
|
||||
if (msg.type === "state") {
|
||||
lastServerUpdate = Date.now();
|
||||
|
||||
const me = msg.players.find(p => p.id === player.id);
|
||||
if (me) {
|
||||
// nur setzen, wenn wir NICHT gerade bewegen
|
||||
if (!keys["w"] && !keys["a"] && !keys["s"] && !keys["d"]) {
|
||||
player.x = me.x;
|
||||
player.y = me.y;
|
||||
}
|
||||
player.world = me.world;
|
||||
player.money = me.money;
|
||||
player.bank = me.bank;
|
||||
player.health = me.health;
|
||||
player.hunger = me.hunger;
|
||||
player.thirst = me.thirst;
|
||||
player.inventory = me.inventory;
|
||||
//console.log("geld:", player.money);
|
||||
}
|
||||
|
||||
otherPlayers = msg.players.filter(p => p.id !== player.id);
|
||||
renderInventoryWindow();
|
||||
updateStatusUI();
|
||||
}
|
||||
|
||||
if (msg.type === "npc_dialog") {
|
||||
alert("NPC sagt: " + msg.text);
|
||||
}
|
||||
if (msg.type === "shop_open") {
|
||||
const shopWindow = document.getElementById("shopWindow");
|
||||
const shopList = document.getElementById("shopList");
|
||||
|
||||
shopWindow.style.display = "block";
|
||||
shopList.innerHTML = "";
|
||||
|
||||
msg.items.forEach(item => {
|
||||
const div = document.createElement("div");
|
||||
div.style.padding = "5px";
|
||||
div.style.borderBottom = "1px solid #333";
|
||||
div.innerHTML = `
|
||||
${item.name} - ${item.price}$
|
||||
<button onclick="buyItem('${item.id}')">Kaufen</button>
|
||||
`;
|
||||
shopList.appendChild(div);
|
||||
});
|
||||
}
|
||||
|
||||
if (msg.type === "shop_error") {
|
||||
alert(msg.msg);
|
||||
}
|
||||
if (msg.type === "item_used") {
|
||||
console.log(msg.hunger)
|
||||
console.log(msg.thirst)
|
||||
player.hunger = msg.hunger;
|
||||
player.thirst = msg.thirst;
|
||||
player.health = msg.health;
|
||||
player.inventory = msg.inventory;
|
||||
|
||||
updateStatusWindow();
|
||||
renderInventoryWindow();
|
||||
}
|
||||
if (msg.type === "atm_open") {
|
||||
const pin = prompt("PIN eingeben");
|
||||
ws.send(JSON.stringify({ type: "bank_pin_check", pin }));
|
||||
}
|
||||
if (msg.type === "bank_pin_ok") {
|
||||
console.log("bank_pin_ok KOMMT AN");
|
||||
ws.send(JSON.stringify({ type: "bank_open" }));
|
||||
}
|
||||
if (msg.type === "bank_pin_fail") {
|
||||
alert("Falsche PIN!");
|
||||
}
|
||||
if (msg.type === "bank_open") {
|
||||
console.log("BANK_OPEN KOMMT AN");
|
||||
openATMWindow(msg.money, msg.bank);
|
||||
}
|
||||
if (msg.type === "bank_update") {
|
||||
document.getElementById("atmMoney").innerText = msg.money;
|
||||
document.getElementById("atmBank").innerText = msg.bank;
|
||||
}
|
||||
// im ws.onmessage ergänzen:
|
||||
if (msg.type === "cars") {
|
||||
cars = msg.cars;
|
||||
const mine = cars.find(c => c.driverId === player.id);
|
||||
drivingCarId = mine ? mine.id : null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (msg.type === "object_interact") {
|
||||
if (msg.action === "loot") {
|
||||
alert("Du hast die Kiste geöffnet!");
|
||||
}
|
||||
}
|
||||
|
||||
// Map-Daten
|
||||
if (msg.type === "map_data") {
|
||||
tiles = msg.tiles;
|
||||
doors = msg.doors || [];
|
||||
objects = msg.objects || [];
|
||||
shops = msg.shops || []; // <-- WICHTIG
|
||||
atms = msg.atms || [];
|
||||
spawn = msg.spawn;
|
||||
|
||||
console.log("shops:", shops);
|
||||
console.log("atms:", atms);
|
||||
return;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
function openATMWindow(money, bank) {
|
||||
document.getElementById("atmMoney").innerText = money;
|
||||
document.getElementById("atmBank").innerText = bank;
|
||||
document.getElementById("atmBox").style.display = "block";
|
||||
}
|
||||
|
||||
function closeATM() {
|
||||
document.getElementById("atmBox").style.display = "none";
|
||||
}
|
||||
|
||||
function atmDeposit() {
|
||||
const amount = Number(document.getElementById("atmAmount").value);
|
||||
ws.send(JSON.stringify({ type: "bank_deposit", amount }));
|
||||
}
|
||||
|
||||
function atmWithdraw() {
|
||||
const amount = Number(document.getElementById("atmAmount").value);
|
||||
ws.send(JSON.stringify({ type: "bank_withdraw", amount }));
|
||||
}
|
||||
|
||||
function atmTransfer() {
|
||||
const amount = Number(document.getElementById("atmAmount").value);
|
||||
const targetId = Number(document.getElementById("atmTarget").value);
|
||||
ws.send(JSON.stringify({ type: "bank_transfer", amount, targetId }));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function updateStatusUI() {
|
||||
const hungerBar = document.getElementById("hungerValue");
|
||||
const thirstBar = document.getElementById("thirstValue");
|
||||
const moneyLabel = document.getElementById("moneyValue");
|
||||
|
||||
if (hungerBar) hungerBar.textContent = player.hunger;
|
||||
if (thirstBar) thirstBar.textContent = player.thirst;
|
||||
if (moneyLabel) moneyLabel.textContent = player.money;
|
||||
}
|
||||
|
||||
function openATM(atm) {
|
||||
ws.send(JSON.stringify({
|
||||
type: "bank_pin_check",
|
||||
pin: prompt("PIN eingeben")
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
function useItem(itemId) {
|
||||
console.log("useItem wurde ausgeführt mit:", itemId);
|
||||
ws.send(JSON.stringify({
|
||||
type: "use_item",
|
||||
itemId
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
function buyItem(itemId) {
|
||||
ws.send(JSON.stringify({
|
||||
type: "shop_buy",
|
||||
itemId
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// CAMERA (mit Zentrierung bei kleinen Maps)
|
||||
// -------------------------------------------------------------
|
||||
function getCamera() {
|
||||
const map = maps[player.world];
|
||||
if (!map || !map.tiles || map.tiles.length === 0) {
|
||||
return { x: 0, y: 0 };
|
||||
}
|
||||
|
||||
const mapWidth = map.tiles[0].length * 32;
|
||||
const mapHeight = map.tiles.length * 32;
|
||||
|
||||
let camX = player.x - canvas.width / 2;
|
||||
let camY = player.y - canvas.height / 2;
|
||||
|
||||
if (mapWidth < canvas.width) {
|
||||
camX = -(canvas.width / 2 - mapWidth / 2);
|
||||
} else {
|
||||
if (camX < 0) camX = 0;
|
||||
if (camX > mapWidth - canvas.width)
|
||||
camX = mapWidth - canvas.width;
|
||||
}
|
||||
|
||||
if (mapHeight < canvas.height) {
|
||||
camY = -(canvas.height / 2 - mapHeight / 2);
|
||||
} else {
|
||||
if (camY < 0) camY = 0;
|
||||
if (camY > mapHeight - canvas.height)
|
||||
camY = mapHeight - canvas.height;
|
||||
}
|
||||
|
||||
return { x: camX, y: camY };
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// MOVEMENT + Collision
|
||||
// -------------------------------------------------------------
|
||||
document.addEventListener("keydown", e => {
|
||||
keys[e.key] = true;
|
||||
|
||||
if (!ws) return;
|
||||
|
||||
if (e.key.toLowerCase() === "e") {
|
||||
ws.send(JSON.stringify({
|
||||
type: "interact",
|
||||
x: player.x,
|
||||
y: player.y,
|
||||
world: player.world
|
||||
}));
|
||||
}
|
||||
});
|
||||
// Shop schließen (ESC)
|
||||
document.addEventListener("keydown", e => {
|
||||
if (e.key === "Escape") {
|
||||
shopWindow.style.display = "none";
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("keyup", e => {
|
||||
keys[e.key] = false;
|
||||
});
|
||||
|
||||
function canMoveTo(nx, ny) {
|
||||
const map = maps[player.world];
|
||||
if (!map || !map.tiles) return true;
|
||||
|
||||
const tileX = Math.floor(nx / 32);
|
||||
const tileY = Math.floor(ny / 32);
|
||||
|
||||
// TILE COLLISION
|
||||
const tileId = map.tiles[tileY]?.[tileX];
|
||||
const tile = tileConfig[tileId];
|
||||
if (tile && tile.collision) return false;
|
||||
|
||||
// OBJECT COLLISION
|
||||
if (map.objects) {
|
||||
for (const obj of map.objects) {
|
||||
const cfg = objectConfig[obj.type];
|
||||
if (!cfg || !cfg.collision) continue;
|
||||
|
||||
const ox = obj.x;
|
||||
const oy = obj.y - (cfg.height - 32); // Objekt höher als Tile
|
||||
const ow = cfg.width;
|
||||
const oh = cfg.height;
|
||||
|
||||
// Spieler-Hitbox (30x30)
|
||||
const px = nx;
|
||||
const py = ny;
|
||||
const pw = 30;
|
||||
const ph = 30;
|
||||
|
||||
const hit =
|
||||
px < ox + ow &&
|
||||
px + pw > ox &&
|
||||
py < oy + oh &&
|
||||
py + ph > oy;
|
||||
|
||||
if (hit) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
function updateNeeds() {
|
||||
player.hunger -= 0.002;
|
||||
player.thirst -= 0.004;
|
||||
|
||||
if (player.hunger < 0) player.hunger = 0;
|
||||
if (player.thirst < 0) player.thirst = 0;
|
||||
|
||||
if (player.hunger === 0 || player.thirst === 0) {
|
||||
player.health -= 0.01;
|
||||
if (player.health < 0) player.health = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function updateStatusWindow() {
|
||||
const status = document.getElementById("statusWindow");
|
||||
|
||||
status.innerHTML = `
|
||||
Leben: ${Math.round(player.health)}<br>
|
||||
Hunger: ${Math.round(player.hunger)}<br>
|
||||
Durst: ${Math.round(player.thirst)}<br>
|
||||
Geld: ${player.money}$
|
||||
`;
|
||||
}
|
||||
|
||||
function updateMovement() {
|
||||
let moved = false;
|
||||
|
||||
let nx = player.x;
|
||||
let ny = player.y;
|
||||
|
||||
/*if (keys["w"]) ny -= 5;
|
||||
if (keys["s"]) ny += 5;
|
||||
if (keys["a"]) nx -= 5;
|
||||
if (keys["d"]) nx += 5;*/
|
||||
|
||||
if (keys["w"]) { ny -= 5; moved = true; }
|
||||
if (keys["s"]) { ny += 5; moved = true; }
|
||||
if (keys["a"]) { nx -= 5; moved = true; }
|
||||
if (keys["d"]) { nx += 5; moved = true; }
|
||||
|
||||
if (canMoveTo(nx, ny)) {
|
||||
player.x = nx;
|
||||
player.y = ny;
|
||||
|
||||
// FIX: nur senden, wenn WS existiert und verbunden ist
|
||||
if (ws && moved && ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(JSON.stringify({
|
||||
type: "move",
|
||||
x: nx,
|
||||
y: ny,
|
||||
//health: player.health,
|
||||
//hunger: player.hunger,
|
||||
//thirst: player.thirst
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (ws && player.id && moved) {
|
||||
ws.send(JSON.stringify({
|
||||
type: "move",
|
||||
x: player.x,
|
||||
y: player.y
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function renderInventoryWindow() {
|
||||
// console.log("renderInventoryWindow wurde ausgeführt");
|
||||
const list = document.getElementById("inventoryList");
|
||||
if (!list) return;
|
||||
|
||||
list.innerHTML = "";
|
||||
|
||||
(player.inventory || []).forEach(item => {
|
||||
const div = document.createElement("div");
|
||||
div.style.display = "flex";
|
||||
div.style.justifyContent = "space-between";
|
||||
div.style.padding = "5px";
|
||||
div.style.borderBottom = "1px solid #333";
|
||||
|
||||
div.innerHTML = `
|
||||
<span>${item.name || item.id} x${item.amount}</span>
|
||||
<button class="useItemBtn" data-id="${item.id}">Benutzen</button>
|
||||
`;
|
||||
|
||||
list.appendChild(div);
|
||||
});
|
||||
|
||||
const buttons = document.querySelectorAll(".useItemBtn");
|
||||
//console.log("Buttons gefunden:", buttons.length);
|
||||
//console.log("Buttons gefunden:", document.querySelectorAll(".useItemBtn").length);
|
||||
|
||||
document.querySelectorAll(".useItemBtn").forEach(btn => {
|
||||
btn.onclick = () => {
|
||||
//console.log("Button wurde geklickt:", btn.dataset.id);
|
||||
//console.log("Buttons gefunden:", document.querySelectorAll(".useItemBtn").length);
|
||||
|
||||
useItem(btn.dataset.id);
|
||||
};
|
||||
});
|
||||
}
|
||||
// -------------------------------------------------------------
|
||||
// RENDERING
|
||||
// -------------------------------------------------------------
|
||||
function renderMap() {
|
||||
const map = maps[player.world];
|
||||
if (!map || !map.tiles) return;
|
||||
|
||||
const cam = getCamera();
|
||||
|
||||
for (let y = 0; y < map.tiles.length; y++) {
|
||||
for (let x = 0; x < map.tiles[y].length; x++) {
|
||||
const tileId = map.tiles[y][x];
|
||||
const tile = tileConfig[tileId];
|
||||
|
||||
if (!tile) continue;
|
||||
|
||||
ctx.fillStyle = tile.color;
|
||||
|
||||
ctx.fillRect(
|
||||
x * 32 - cam.x,
|
||||
y * 32 - cam.y,
|
||||
32,
|
||||
32
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderDoors() {
|
||||
const map = maps[player.world];
|
||||
if (!map || !map.doors) return;
|
||||
|
||||
const cam = getCamera();
|
||||
|
||||
map.doors.forEach(d => {
|
||||
ctx.fillStyle = "orange";
|
||||
ctx.fillRect(
|
||||
d.x - cam.x,
|
||||
d.y - cam.y,
|
||||
30,
|
||||
30
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function renderPlayers() {
|
||||
const cam = getCamera();
|
||||
|
||||
ctx.fillStyle = "yellow";
|
||||
ctx.fillRect(
|
||||
player.x - cam.x,
|
||||
player.y - cam.y,
|
||||
20,
|
||||
20
|
||||
);
|
||||
|
||||
otherPlayers.forEach(p => {
|
||||
if (p.world === player.world) {
|
||||
ctx.fillStyle = "cyan";
|
||||
ctx.fillRect(
|
||||
p.x - cam.x,
|
||||
p.y - cam.y,
|
||||
20,
|
||||
20
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderObjects() {
|
||||
const map = maps[player.world];
|
||||
if (!map || !map.objects) return;
|
||||
|
||||
const cam = getCamera();
|
||||
|
||||
map.objects.forEach(o => {
|
||||
const cfg = objectConfig[o.type];
|
||||
if (!cfg) return;
|
||||
|
||||
ctx.fillStyle = cfg.color;
|
||||
ctx.fillRect(
|
||||
o.x - cam.x,
|
||||
o.y - (cfg.height - 32) - cam.y,
|
||||
cfg.width,
|
||||
cfg.height
|
||||
);
|
||||
});
|
||||
}
|
||||
function renderShops() {
|
||||
const cam = getCamera();
|
||||
|
||||
shops.forEach(s => {
|
||||
const px = s.x * 32 - cam.x;
|
||||
const py = s.y * 32 - cam.y;
|
||||
|
||||
ctx.fillStyle = "yellow";
|
||||
ctx.fillRect(px, py, 32, 32);
|
||||
|
||||
ctx.strokeStyle = "black";
|
||||
ctx.strokeRect(px, py, 32, 32);
|
||||
});
|
||||
}
|
||||
function renderATMs() {
|
||||
const cam = getCamera();
|
||||
atms.forEach(a => {
|
||||
const px = a.x * 32 - cam.x; // klein!
|
||||
const py = a.y * 32 - cam.y; // klein!
|
||||
|
||||
ctx.fillStyle = "blue";
|
||||
ctx.fillRect(px, py, 32, 32);
|
||||
ctx.strokeStyle = "black"; // optional, wie bei Shops
|
||||
ctx.strokeRect(px, py, 32, 32);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function render() {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
renderMap();
|
||||
renderObjects();
|
||||
renderShops();
|
||||
renderATMs();
|
||||
renderDoors();
|
||||
renderPlayers();
|
||||
|
||||
requestAnimationFrame(render);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// GAME LOOP
|
||||
// -------------------------------------------------------------
|
||||
function gameLoop() {
|
||||
updateMovement();
|
||||
setTimeout(gameLoop, 16);
|
||||
updateStatusWindow();
|
||||
//updateNeeds();
|
||||
}
|
||||
|
||||
|
||||
render();
|
||||
gameLoop();
|
||||
Reference in New Issue
Block a user