Clash Royale - Deluxe Edition
by NovaGalaxy88623 lines24.1 KB
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Clash Royale - Deluxe Edition</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #2c3e50;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
font-family: 'Arial', sans-serif;
color: white;
overflow: hidden;
user-select: none;
}
canvas {
background-color: #228B22;
border: 4px solid #34495e;
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
display: block;
cursor: pointer;
}
</style>
</head>
<body>
<canvas id="gameCanvas" width="450" height="700"></canvas>
<script>
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
// --- GLOBALE STATS (bleiben permanent erhalten) ---
const FPS = 60;
const SCREEN_WIDTH = 450;
const SCREEN_HEIGHT = 700;
let currentLevel = 1;
const MAX_LEVEL = 25;
let trophies = 1000;
let gold = 500;
// Menü-Navigation: "menu", "game", "shop", "quests", "emotes"
let currentScreen = "menu";
// --- ENTITÄTEN-KLASSEN (KAMPF) ---
class Tower {
constructor(x, y, team, isKing = false, aiLevel = 1) {
this.x = x;
this.y = y;
this.team = team;
this.isKing = isKing;
this.radius = isKing ? 25 : 18;
// Level 1 viel leichter machen für die KI (0.6x HP)
let hpMultiplier = 1;
let dmgMultiplier = 1;
if (team === "red") {
if (aiLevel === 1) {
hpMultiplier = 0.6;
dmgMultiplier = 0.6;
} else {
hpMultiplier = 1 + (aiLevel - 1) * 0.1;
dmgMultiplier = 1 + (aiLevel - 1) * 0.05;
}
}
this.maxHp = (isKing ? 3000 : 1500) * hpMultiplier;
this.hp = this.maxHp;
this.range = 120;
this.damage = (isKing ? 50 : 35) * dmgMultiplier;
this.attackCooldown = 0;
this.laserTarget = null;
this.laserTimer = 0;
}
draw() {
if (this.hp <= 0) return;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.team === "blue" ? "#0000FF" : "#FF0000";
ctx.fill();
ctx.lineWidth = 3;
ctx.strokeStyle = "#323232";
ctx.stroke();
const barWidth = this.radius * 2;
const hpPct = Math.max(0, this.hp / this.maxHp);
ctx.fillStyle = "#FF0000";
ctx.fillRect(this.x - this.radius, this.y - this.radius - 10, barWidth, 5);
ctx.fillStyle = "#00FF00";
ctx.fillRect(this.x - this.radius, this.y - this.radius - 10, barWidth * hpPct, 5);
if (this.laserTimer > 0 && this.laserTarget && this.laserTarget.hp > 0) {
ctx.beginPath();
ctx.moveTo(this.x, this.y);
ctx.lineTo(this.laserTarget.x, this.laserTarget.y);
ctx.strokeStyle = "#FFD700";
ctx.lineWidth = 3;
ctx.stroke();
this.laserTimer--;
}
}
update(enemies) {
if (this.hp <= 0) return;
if (this.attackCooldown > 0) this.attackCooldown--;
if (this.attackCooldown === 0) {
let target = null;
let minDist = this.range;
for (let enemy of enemies) {
let dist = Math.hypot(enemy.x - this.x, enemy.y - this.y);
if (dist < minDist) { minDist = dist; target = enemy; }
}
if (target) {
target.hp -= this.damage;
this.attackCooldown = 50;
this.laserTarget = target;
this.laserTimer = 8;
}
}
}
}
class Unit {
constructor(x, y, team, unitType, aiLevel = 1) {
this.x = x;
this.y = y;
this.team = team;
this.type = unitType;
this.laserTarget = null;
this.laserTimer = 0;
this.attackCooldown = 0;
let baseHp = 0, baseDmg = 0;
if (unitType === "Knight") { baseHp = 600; baseDmg = 40; this.range = 20; this.speed = 1.2; this.radius = 10; }
else if (unitType === "Archer") { baseHp = 250; baseDmg = 25; this.range = 90; this.speed = 1.5; this.radius = 7; }
else if (unitType === "Giant") { baseHp = 2000; baseDmg = 50; this.range = 20; this.speed = 0.7; this.radius = 14; }
else if (unitType === "Goblins") { baseHp = 120; baseDmg = 30; this.range = 20; this.speed = 2.2; this.radius = 6; }
let hpMultiplier = 1;
let dmgMultiplier = 1;
if (team === "red") {
if (aiLevel === 1) {
hpMultiplier = 0.5; // Level 1 Einheiten der KI haben nur halbes Leben
dmgMultiplier = 0.6;
} else {
hpMultiplier = 1 + (aiLevel - 1) * 0.08;
dmgMultiplier = 1 + (aiLevel - 1) * 0.05;
}
}
this.hp = this.maxHp = baseHp * hpMultiplier;
this.damage = baseDmg * dmgMultiplier;
}
draw() {
if (this.hp <= 0) return;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.team === "blue" ? "#0000FF" : "#FF0000";
ctx.fill();
if (this.type === "Archer") {
ctx.beginPath(); ctx.arc(this.x, this.y, this.radius - 3, 0, Math.PI * 2);
ctx.fillStyle = "#FFFFFF"; ctx.fill();
} else if (this.type === "Giant") {
ctx.beginPath(); ctx.arc(this.x, this.y, this.radius - 4, 0, Math.PI * 2);
ctx.fillStyle = "#FFD700"; ctx.fill();
} else if (this.type === "Goblins") {
ctx.beginPath(); ctx.arc(this.x, this.y, this.radius - 2, 0, Math.PI * 2);
ctx.fillStyle = "#32C832"; ctx.fill();
}
const hpPct = Math.max(0, this.hp / this.maxHp);
ctx.fillStyle = "#FF0000";
ctx.fillRect(this.x - 10, this.y - this.radius - 6, 20, 3);
ctx.fillStyle = "#00FF00";
ctx.fillRect(this.x - 10, this.y - this.radius - 6, 20 * hpPct, 3);
if (this.laserTimer > 0 && this.laserTarget && this.laserTarget.hp > 0) {
ctx.beginPath(); ctx.moveTo(this.x, this.y); ctx.lineTo(this.laserTarget.x, this.laserTarget.y);
ctx.strokeStyle = "#FFFFFF"; ctx.lineWidth = 2; ctx.stroke();
this.laserTimer--;
}
}
moveAndAttack(enemies, enemyTowers) {
if (this.hp <= 0) return;
if (this.attackCooldown > 0) this.attackCooldown--;
let target = null;
let targetDist = 999990;
if (this.type === "Giant") {
for (let tower of enemyTowers) {
if (tower.hp > 0) {
let dist = Math.hypot(tower.x - this.x, tower.y - this.y);
if (dist < targetDist) { targetDist = dist; target = tower; }
}
}
} else {
for (let enemy of enemies) {
let dist = Math.hypot(enemy.x - this.x, enemy.y - this.y);
if (dist < targetDist) { targetDist = dist; target = enemy; }
}
if (!target) {
for (let tower of enemyTowers) {
if (tower.hp > 0) {
let dist = Math.hypot(tower.x - this.x, tower.y - this.y);
if (dist < targetDist) { targetDist = dist; target = tower; }
}
}
}
}
if (!target) return;
if (targetDist <= this.range) {
if (this.attackCooldown === 0) {
target.hp -= this.damage;
this.attackCooldown = 40;
if (this.type === "Archer") { this.laserTarget = target; this.laserTimer = 5; }
}
} else {
let targetX = target.x;
let targetY = target.y;
if (this.team === "blue" && this.y > 340 && targetY < 340) {
let bridgeX = this.x < SCREEN_WIDTH / 2 ? 100 : 350;
if (Math.abs(this.y - 350) > 10) { targetX = bridgeX; targetY = 350; }
} else if (this.team === "red" && this.y < 340 && targetY > 340) {
let bridgeX = this.x < SCREEN_WIDTH / 2 ? 100 : 350;
if (Math.abs(this.y - 350) > 10) { targetX = bridgeX; targetY = 350; }
}
let dx = targetX - this.x;
let dy = targetY - this.y;
let dist = Math.hypot(dx, dy);
if (dist > 0) {
this.x += (dx / dist) * this.speed;
this.y += (dy / dist) * this.speed;
}
}
}
}
// --- GAME STATE ENGINE ---
class Game {
constructor(level) {
this.level = level;
this.towers = [
new Tower(SCREEN_WIDTH / 2, 590, "blue", true, level),
new Tower(120, 520, "blue", false, level),
new Tower(330, 520, "blue", false, level),
new Tower(SCREEN_WIDTH / 2, 70, "red", true, level),
new Tower(120, 140, "red", false, level),
new Tower(330, 140, "red", false, level)
];
this.units = [];
this.blueElixir = 5.0;
this.redElixir = 5.0;
this.allCards = ["Knight", "Archer", "Giant", "Goblins"];
this.cardCosts = {"Knight": 3, "Archer": 2, "Giant": 5, "Goblins": 2};
this.deck = ["Knight", "Archer", "Giant", "Goblins"];
this.selectedIndex = 0;
this.cardButtons = [
{x: 180, y: 615, w: 55, h: 70},
{x: 245, y: 615, w: 55, h: 70},
{x: 310, y: 615, w: 55, h: 70},
{x: 375, y: 615, w: 55, h: 70}
];
// Emote-System Variablen
this.emoteMenuOpen = false;
this.activeEmote = null;
this.activeEmoteTimer = 0;
this.spawnCooldown = 0;
this.timeLeft = 180 * FPS;
this.gameOver = false;
this.endMessage = "";
this.levelChangedText = "";
}
getSelectedCard() { return this.deck[this.selectedIndex]; }
rotateCard() { let played = this.deck.splice(this.selectedIndex, 1)[0]; this.deck.push(played); }
spawnUnit(x, y, team, unitType) {
let cost = this.cardCosts[unitType];
if (team === "blue") {
if (y < 340 || y > 600 || this.blueElixir < cost) return false;
this.blueElixir -= cost;
this.rotateCard();
} else {
if (this.redElixir < cost) return false;
this.redElixir -= cost;
}
if (unitType === "Goblins") {
for (let i = 0; i < 3; i++) {
this.units.push(new Unit(x + (Math.random()*30-15), y + (Math.random()*30-15), team, unitType, this.level));
}
} else {
this.units.push(new Unit(x, y, team, unitType, this.level));
}
return true;
}
update() {
if (this.gameOver) return;
if (this.timeLeft > 0) this.timeLeft--;
else this.checkTiebreaker();
// Elixier-Generierung (In Level 1 lädt die KI extrem langsam!)
if (this.blueElixir < 10) this.blueElixir += 0.015;
let aiElixirSpeed = this.level === 1 ? 0.008 : 0.015 + (this.level - 1) * 0.002;
if (this.redElixir < 10) this.redElixir += aiElixirSpeed;
let blueUnits = this.units.filter(u => u.team === "blue" && u.hp > 0);
let redUnits = this.units.filter(u => u.team === "red" && u.hp > 0);
let blueTowers = this.towers.filter(t => t.team === "blue" && t.hp > 0);
let redTowers = this.towers.filter(t => t.team === "red" && t.hp > 0);
this.units = blueUnits.concat(redUnits);
// Bot Spawn-Verhalten
this.spawnCooldown++;
let aiSpawnRate = this.level === 1 ? 160 : Math.max(50, 120 - (this.level * 2));
if (this.spawnCooldown > aiSpawnRate) {
if (this.redElixir >= 4) {
let randCard = this.allCards[Math.floor(Math.random() * this.allCards.length)];
let spawnX = [120, 330, SCREEN_WIDTH / 2][Math.floor(Math.random() * 3)];
let spawnY = [100, 120][Math.floor(Math.random() * 2)];
this.spawnUnit(spawnX, spawnY, "red", randCard);
this.spawnCooldown = 0;
}
}
for (let tower of this.towers) tower.update(tower.team === "blue" ? redUnits : blueUnits);
for (let unit of this.units) {
if (unit.team === "blue") unit.moveAndAttack(redUnits, redTowers);
else unit.moveAndAttack(blueUnits, blueTowers);
}
if (this.activeEmoteTimer > 0) this.activeEmoteTimer--;
if (this.towers[0].hp <= 0) this.endGame(false);
else if (this.towers[3].hp <= 0) this.endGame(true);
}
checkTiebreaker() {
let blueAlive = this.towers.filter(t => t.team === "blue" && t.hp > 0).length;
let redAlive = this.towers.filter(t => t.team === "red" && t.hp > 0).length;
if (blueAlive > redAlive) this.endGame(true);
else if (redAlive > blueAlive) this.endGame(false);
else { this.gameOver = true; this.endMessage = "UNENTSCHIEDEN!"; }
}
endGame(playerWon) {
this.gameOver = true;
if (playerWon) {
trophies += 30; gold += 150;
this.endMessage = "SIEG! (+30 🏆 / +150 💰)";
if (currentLevel < MAX_LEVEL) { currentLevel++; }
} else {
trophies = Math.max(0, trophies - 20);
this.endMessage = "NIEDERLAGE! (-20 🏆)";
if (currentLevel > 1) { currentLevel--; }
}
}
drawMap() {
ctx.fillStyle = "#228B22"; ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
ctx.fillStyle = "#1E90FF"; ctx.fillRect(0, 340, SCREEN_WIDTH, 20);
ctx.fillStyle = "#8B4513"; ctx.fillRect(80, 335, 40, 30); ctx.fillRect(330, 335, 40, 30);
}
drawUi() {
// UI Leiste unten
ctx.fillStyle = "#2c3e50"; ctx.fillRect(0, 600, SCREEN_WIDTH, 100);
// Elixier
ctx.fillStyle = "#323232"; ctx.fillRect(20, 615, 140, 20);
ctx.fillStyle = "#FF00FF"; ctx.fillRect(20, 615, (this.blueElixir / 10) * 140, 20);
ctx.fillStyle = "#FFFFFF"; ctx.font = "bold 12px Arial"; ctx.fillText(`Punkte: ${Math.floor(this.blueElixir)}/10`, 35, 629);
// Emote Button (☺) unten links
ctx.fillStyle = "#f39c12"; ctx.fillRect(20, 645, 40, 40);
ctx.strokeStyle = "#FFFFFF"; ctx.strokeRect(20, 645, 40, 40);
ctx.fillStyle = "#FFFFFF"; ctx.font = "20px Arial"; ctx.fillText("☺", 33, 672);
// Deck Boxen
this.deck.forEach((card, i) => {
let btn = this.cardButtons[i];
ctx.fillStyle = "#34495e"; ctx.fillRect(btn.x, btn.y, btn.w, btn.h);
ctx.strokeStyle = (i === this.selectedIndex) ? "#FFD700" : "#7f8c8d";
ctx.lineWidth = (i === this.selectedIndex) ? 3 : 1;
ctx.strokeRect(btn.x, btn.y, btn.w, btn.h);
ctx.fillStyle = (i === this.selectedIndex) ? "#FFD700" : "#FFFFFF";
ctx.font = "bold 10px Arial"; ctx.fillText(card, btn.x + 4, btn.y + 25);
ctx.fillStyle = "#FF00FF"; ctx.beginPath(); ctx.arc(btn.x + btn.w - 12, btn.y + btn.h - 12, 8, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = "#FFFFFF"; ctx.fillText(this.cardCosts[card], btn.x + btn.w - 15, btn.y + btn.h - 9);
});
// Topbar
let totalSecs = Math.floor(this.timeLeft / FPS), mins = Math.floor(totalSecs / 60), secs = totalSecs % 60;
ctx.fillStyle = "#FFFFFF"; ctx.font = "bold 16px Arial"; ctx.fillText(`Zeit: ${mins}:${secs < 10 ? '0' : ''}${secs}`, 20, 25);
ctx.textAlign = "center"; ctx.fillText(`Level ${this.level} / 25`, SCREEN_WIDTH/2, 25); ctx.textAlign = "left";
// Aktives Emote auf dem Feld anzeigen
if (this.activeEmoteTimer > 0 && this.activeEmote) {
ctx.font = "40px Arial";
ctx.fillText(this.activeEmote, SCREEN_WIDTH / 2 - 20, 450);
}
// Emote Menü Popup
if (this.emoteMenuOpen) {
ctx.fillStyle = "rgba(0,0,0,0.8)"; ctx.fillRect(20, 480, 150, 110);
ctx.fillStyle = "#FFFFFF"; ctx.font = "12px Arial"; ctx.fillText("Wähle ein Emote:", 30, 500);
ctx.font = "24px Arial";
ctx.fillText("😂", 35, 535); ctx.fillText("😡", 75, 535); ctx.fillText("👍", 115, 535);
ctx.fillText("😭", 35, 575); ctx.fillText("👑", 75, 575); ctx.fillText("⚔", 115, 575);
}
if (this.gameOver) {
ctx.fillStyle = "rgba(0, 0, 0, 0.85)"; ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
ctx.fillStyle = "#FFFFFF"; ctx.font = "bold 26px Arial"; ctx.textAlign = "center";
ctx.fillText(this.endMessage, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 - 20);
ctx.fillStyle = "#FFD700"; ctx.font = "14px Arial"; ctx.fillText("Drücke LEERTASTE für das Hauptmenü", SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 + 30);
ctx.textAlign = "left";
}
}
}
// --- MENÜ INTERFACES DRAWER ---
function drawMenuScreens() {
// Oberer Balken (Ressourcen immer sichtbar)
ctx.fillStyle = "#1a252f"; ctx.fillRect(0, 0, SCREEN_WIDTH, 60);
ctx.fillStyle = "#FFD700"; ctx.font = "bold 16px Arial"; ctx.fillText(`🏆 ${trophies}`, 30, 38);
ctx.fillStyle = "#f1c40f"; ctx.fillText(`💰 ${gold} Gold`, SCREEN_WIDTH - 120, 38);
// Untere Tab-Leiste
ctx.fillStyle = "#1a252f"; ctx.fillRect(0, 630, SCREEN_WIDTH, 70);
const tabs = ["Shop", "Quests", "Kampf", "Emotes"];
tabs.forEach((tab, i) => {
let x = i * (SCREEN_WIDTH / 4);
ctx.fillStyle = (currentScreen === tab.toLowerCase() || (currentScreen === "menu" && tab === "Kampf")) ? "#34495e" : "#1a252f";
ctx.fillRect(x, 630, SCREEN_WIDTH / 4, 70);
ctx.strokeStyle = "#2c3e50"; ctx.strokeRect(x, 630, SCREEN_WIDTH / 4, 70);
ctx.fillStyle = "#FFFFFF"; ctx.font = "bold 14px Arial"; ctx.fillText(tab, x + 20, 670);
});
// Content je nach gewähltem Screen
ctx.fillStyle = "#2c3e50"; ctx.fillRect(0, 60, SCREEN_WIDTH, 570);
if (currentScreen === "menu") {
ctx.fillStyle = "#FFFFFF"; ctx.font = "bold 28px Arial"; ctx.fillText("ARENA STUFE", 125, 150);
ctx.fillStyle = "#f39c12"; ctx.font = "bold 36px Arial"; ctx.fillText(`LEVEL ${currentLevel}`, 145, 210);
// Großer Kampfbutton
ctx.fillStyle = "#e67e22"; ctx.fillRect(125, 300, 200, 80);
ctx.strokeStyle = "#FFFFFF"; ctx.lineWidth = 3; ctx.strokeRect(125, 300, 200, 80);
ctx.fillStyle = "#FFFFFF"; ctx.font = "bold 28px Arial"; ctx.fillText("KAMPF", 175, 350);
}
else if (currentScreen === "shop") {
ctx.fillStyle = "#FFFFFF"; ctx.font = "bold 24px Arial"; ctx.fillText("KARTEN SHOP", 30, 110);
// Gratis Truhe
ctx.fillStyle = "#34495e"; ctx.fillRect(40, 160, 160, 150);
ctx.fillStyle = "#FFFFFF"; ctx.font = "14px Arial"; ctx.fillText("Gratis Truhe", 50, 190);
ctx.fillStyle = "#2ecc71"; ctx.fillRect(60, 250, 120, 35);
ctx.fillStyle = "#FFFFFF"; ctx.fillText("ÖFFNEN (0g)", 75, 272);
// Magietruhe
ctx.fillStyle = "#34495e"; ctx.fillRect(240, 160, 160, 150);
ctx.fillStyle = "#9b59b6"; ctx.fillText("Magietruhe", 250, 190);
ctx.fillStyle = "#e74c3c"; ctx.fillRect(260, 250, 120, 35);
ctx.fillStyle = "#FFFFFF"; ctx.fillText("250 Gold", 290, 272);
}
else if (currentScreen === "quests") {
ctx.fillStyle = "#FFFFFF"; ctx.font = "bold 24px Arial"; ctx.fillText("DAILY QUESTS", 30, 110);
ctx.font = "14px Arial";
ctx.fillText("1. Gewinne 3 Kämpfe in Arena 1 (Belohnung: 200g)", 40, 170);
ctx.fillText("2. Setze 10 Riesen auf das Feld (Belohnung: 100g)", 40, 220);
ctx.fillText("3. Zerstöre einen Königsturm (Belohnung: 300g)", 40, 270);
}
else if (currentScreen === "emotes") {
ctx.fillStyle = "#FFFFFF"; ctx.font = "bold 24px Arial"; ctx.fillText("DEINE EMOTES", 30, 110);
ctx.font = "40px Arial";
ctx.fillText("😂 😡 👍 😭 👑 ⚔", 40, 180);
ctx.font = "14px Arial"; ctx.fillText("Diese Emojis kannst du aktiv im Kampf benutzen!", 40, 240);
}
}
// --- INTERACTION LOGIC ---
let combatInstance = null;
window.addEventListener("keydown", (e) => {
if (currentScreen === "game" && combatInstance) {
if (e.key === "1") combatInstance.selectedIndex = 0;
if (e.key === "2") combatInstance.selectedIndex = 1;
if (e.key === "3") combatInstance.selectedIndex = 2;
if (e.key === "4") combatInstance.selectedIndex = 3;
if (combatInstance.gameOver && e.key === " ") {
combatInstance = null;
currentScreen = "menu"; // Zurück zum Menü
}
}
});
canvas.addEventListener("mousedown", (e) => {
const rect = canvas.getBoundingClientRect();
const mx = e.clientX - rect.left;
const my = e.clientY - rect.top;
// --- KLICK LOGIK FÜR DAS MENÜ ---
if (currentScreen !== "game") {
// Tab-Bar Wechsel am unteren Rand
if (my >= 630) {
let tabIdx = Math.floor(mx / (SCREEN_WIDTH / 4));
if (tabIdx === 0) currentScreen = "shop";
if (tabIdx === 1) currentScreen = "quests";
if (tabIdx === 2) currentScreen = "menu";
if (tabIdx === 3) currentScreen = "emotes";
return;
}
// Kampf starten im Hauptmenü
if (currentScreen === "menu" && mx >= 125 && mx <= 325 && my >= 300 && my <= 380) {
combatInstance = new Game(currentLevel);
currentScreen = "game";
return;
}
// Shop Kisten öffnen
if (currentScreen === "shop") {
// Gratis Truhe öffnen
if (mx >= 60 && mx <= 180 && my >= 250 && my <= 285) {
let loot = Math.floor(Math.random() * 50) + 20; gold += loot;
alert(`Du hast eine Gratis Truhe geöffnet und ${loot} Gold erhalten!`);
}
// Magietruhe öffnen
if (mx >= 260 && mx <= 380 && my >= 250 && my <= 285) {
if (gold >= 250) {
gold -= 250;
alert("Du hast eine Magietruhe geöffnet! Epische Karten freigeschaltet!");
} else { alert("Nicht genug Gold!"); }
}
}
return;
}
// --- KLICK LOGIK FÜR DAS LAUFENDE SPIEL ---
if (currentScreen === "game" && combatInstance) {
if (combatInstance.gameOver) return;
// Wenn das Emote Menü offen ist, Klicks prüfen
if (combatInstance.emoteMenuOpen) {
if (mx >= 20 && mx <= 170 && my >= 480 && my <= 590) {
// Emote auswählen anhand Raster-Klick
let emX = Math.floor((mx - 20) / 50);
let emY = Math.floor((my - 510) / 40);
let emotesArr = [["😂","😡","👍"],["😭","👑","⚔"]];
if(emotesArr[emY] && emotesArr[emY][emX]) {
combatInstance.activeEmote = emotesArr[emY][emX];
combatInstance.activeEmoteTimer = 90; // Bleibt 1.5s
}
combatInstance.emoteMenuOpen = false;
return;
}
}
// Emote Button anklicken
if (mx >= 20 && mx <= 60 && my >= 645 && my <= 685) {
combatInstance.emoteMenuOpen = !combatInstance.emoteMenuOpen;
return;
}
// Deck-Auswahl per Klick
for (let i = 0; i < combatInstance.cardButtons.length; i++) {
let btn = combatInstance.cardButtons[i];
if (mx >= btn.x && mx <= btn.x + btn.w && my >= btn.y && my <= btn.y + btn.h) {
combatInstance.selectedIndex = i;
return;
}
}
// Truppen spawnen auf dem Feld
let activeCard = combatInstance.getSelectedCard();
combatInstance.spawnUnit(mx, my, "blue", activeCard);
}
});
// --- ENGINE MAIN LOOP ---
function gameLoop() {
if (currentScreen === "game" && combatInstance) {
combatInstance.update();
combatInstance.drawMap();
for (let tower of combatInstance.towers) tower.draw();
for (let unit of combatInstance.units) unit.draw();
combatInstance.drawUi();
} else {
drawMenuScreens();
}
requestAnimationFrame(gameLoop);
}
gameLoop();
</script>
</body>
</html>Game Source: Clash Royale - Deluxe Edition
Creator: NovaGalaxy88
Libraries: none
Complexity: complex (623 lines, 24.1 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: mini-clash-royale-html5-prototyp-novagalaxy88" to link back to the original. Then publish at arcadelab.ai/publish.