Shinobi Rising: Ultimate Ninja Combat
by BlazeKoala991047 lines47.2 KB
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Shinobi Rising: Ultimate Ninja Combat</title>
<style>
:root {
--bg-grad-top: #09090b;
--bg-grad-mid: #121019;
--bg-grad-bottom: #1c1924;
--accent-orange: #ff6b00;
--accent-cyan: #00f0ff;
--accent-purple: #a855f7;
--accent-red: #ef4444;
--panel-bg: rgba(18, 16, 25, 0.88);
--text-color: #f4f4f5;
--border-glow: rgba(255, 107, 0, 0.3);
}
body {
margin: 0;
padding: 0;
font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
overflow: hidden;
background: #09090b;
user-select: none;
-webkit-user-select: none;
color: var(--text-color);
}
body::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 100vw;
height: 100vh;
transform: translate(-50%, -50%);
background: radial-gradient(circle, rgba(255, 107, 0, 0.08) 0%, rgba(0, 0, 0, 0) 70%);
pointer-events: none;
z-index: 1;
}
.screen {
position: absolute;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 100;
transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
background: rgba(9, 9, 11, 0.85);
}
.hidden {
opacity: 0 !important;
pointer-events: none !important;
transform: scale(0.95);
display: none !important;
}
.glass-panel {
background: var(--panel-bg);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 28px;
padding: 24px;
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.8), 0 0 20px var(--border-glow);
text-align: center;
max-width: 500px;
width: 92%;
box-sizing: border-box;
max-height: 90vh;
overflow-y: auto;
position: relative;
z-index: 2;
}
h1 {
font-size: 2.2rem;
font-weight: 900;
background: linear-gradient(135deg, #ff6b00, #ffa800);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 2px;
text-transform: uppercase;
letter-spacing: 2px;
margin-top: 0;
filter: drop-shadow(0 0 12px rgba(255, 107, 0, 0.4));
}
.rank-badge {
font-size: 11px;
font-weight: 800;
color: #eab308;
background: rgba(234, 179, 8, 0.15);
padding: 4px 12px;
border-radius: 12px;
border: 1px solid rgba(234, 179, 8, 0.3);
display: inline-block;
margin-bottom: 12px;
text-transform: uppercase;
letter-spacing: 1px;
}
h2 { font-size: 1.5rem; margin-top: 0; margin-bottom: 15px; font-weight: 800; letter-spacing: 1px; }
.btn {
padding: 12px 18px;
font-size: 13px;
font-weight: 800;
border: none;
border-radius: 14px;
color: white;
cursor: pointer;
transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
text-transform: uppercase;
letter-spacing: 1px;
width: 100%;
box-sizing: border-box;
margin-bottom: 8px;
position: relative;
overflow: hidden;
}
.btn:hover { transform: translateY(-2px); filter: brightness(1.15); }
.btn:active { transform: translateY(1px) scale(0.98); }
.btn-primary { background: linear-gradient(135deg, #ff6b00, #e65100); box-shadow: 0 8px 25px rgba(255, 107, 0, 0.4); }
.btn-secondary { background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.12); }
.btn-secondary:hover { background: rgba(255, 255, 255, 0.12); }
.btn-gold { background: linear-gradient(135deg, #eab308, #ca8a04); box-shadow: 0 8px 20px rgba(234, 179, 8, 0.3); color: #000; }
.btn-green { background: linear-gradient(135deg, #10b981, #059669); box-shadow: 0 8px 20px rgba(16, 185, 129, 0.3); }
#loadingScreen { background: #09090b; z-index: 500; display: flex; }
.loader-container { width: 80%; max-width: 280px; background: rgba(255, 255, 255, 0.08); height: 10px; border-radius: 20px; overflow: hidden; margin-top: 25px; padding: 2px; }
.loader-bar { width: 0%; height: 100%; background: linear-gradient(90deg, #ff6b00, #00f0ff); border-radius: 20px; transition: width 0.1s linear; box-shadow: 0 0 12px var(--accent-orange); }
#gameContainer {
position: relative;
width: 100vw;
height: 100vh;
background: linear-gradient(to bottom, var(--bg-grad-top), var(--bg-grad-mid), var(--bg-grad-bottom));
}
#gameCanvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 5; }
#hud {
position: absolute;
top: max(15px, env(safe-area-inset-top));
left: 15px; right: 15px;
display: flex;
justify-content: space-between;
pointer-events: none;
z-index: 50;
}
.hud-card {
background: rgba(18, 16, 25, 0.75);
padding: 8px 16px;
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.1);
font-weight: 800;
font-size: 0.85rem;
backdrop-filter: blur(10px);
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
letter-spacing: 0.5px;
}
.stat-val { color: var(--accent-orange); font-weight: 900; }
.shop-tabs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-bottom: 12px; }
.tab-btn { background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.08); color: #a1a1aa; padding: 8px 2px; border-radius: 10px; cursor: pointer; font-weight: 700; font-size: 10px; text-align: center; transition: 0.2s; }
.tab-btn.active { background: var(--accent-orange); color: #000; font-weight: 900; border-color: var(--accent-orange); box-shadow: 0 4px 15px rgba(255, 107, 0, 0.3); }
.shop-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; max-height: 260px; overflow-y: auto; padding-right: 4px; margin-bottom: 12px;}
.shop-item { background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 16px; padding: 10px; display: flex; flex-direction: column; align-items: center; justify-content: space-between; transition: 0.2s; }
.shop-item:hover { border-color: rgba(255, 255, 255, 0.2); background: rgba(255, 255, 255, 0.05); }
.shop-avatar-placeholder { width: 48px; height: 48px; border-radius: 50%; border: 3px solid #3f3f46; margin-bottom: 6px; background: #27272a; box-shadow: 0 4px 10px rgba(0,0,0,0.3); display: flex; align-items: center; justify-content: center; font-size: 20px;}
.shop-item.equipped { border-color: var(--accent-orange); background: rgba(255, 107, 0, 0.08); box-shadow: 0 0 15px rgba(255, 107, 0, 0.2); }
.shop-item.locked-skin { opacity: 0.6; }
.shop-item small { font-size: 10px; margin-bottom: 4px; color: #a1a1aa; }
.shop-item .item-title { font-weight: 800; font-size: 12px; margin-bottom: 2px; }
.quest-list { max-height: 280px; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; text-align: left; padding-right: 4px; margin-bottom: 12px; }
.quest-item { background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.08); padding: 10px 14px; border-radius: 14px; display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.quest-item.ready { border-color: #eab308; background: rgba(234, 179, 8, 0.1); }
.quest-item.claimed { border-color: #10b981; background: rgba(16, 185, 129, 0.05); opacity: 0.6; }
.quest-reward-tag { font-size: 11px; color: #eab308; font-weight: 800; white-space: nowrap; background: rgba(234, 179, 8, 0.15); padding: 4px 8px; border-radius: 8px;}
.quest-info { display: flex; flex-direction: column; }
.quest-label { font-weight: 700; font-size: 12px; }
.quest-progress { font-size: 11px; color: #a1a1aa; margin-top: 2px; }
.char-select-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin: 12px 0; width: 100%; max-height: 220px; overflow-y: auto; padding-right: 2px;}
.char-card { background: rgba(255, 255, 255, 0.03); border: 2px solid rgba(255, 255, 255, 0.08); border-radius: 16px; padding: 10px 6px; cursor: pointer; transition: all 0.2s ease; text-align: center; position: relative;}
.char-card:hover { transform: translateY(-2px); border-color: rgba(255, 255, 255, 0.2); }
.char-card.active { border-color: var(--accent-orange); background: rgba(255, 107, 0, 0.1); box-shadow: 0 0 15px rgba(255, 107, 0, 0.25); }
.char-card.locked { opacity: 0.4; border-style: dashed; }
.char-card h3 { margin: 6px 0 2px 0; font-size: 0.85rem; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.char-card p { margin: 0; font-size: 0.65rem; color: #a1a1aa; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.char-avatar { width: 40px; height: 40px; border-radius: 50%; background: #27272a; display: inline-flex; align-items: center; justify-content: center; font-size: 18px; border: 2px solid #52525b; box-shadow: 0 4px 10px rgba(0,0,0,0.4); }
.char-card.active .char-avatar { border-color: var(--accent-orange); }
.locked-badge { position: absolute; top: 4px; right: 4px; font-size: 8px; background: #ef4444; color: white; padding: 2px 4px; border-radius: 4px; font-weight: 800; }
.powerup-box { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.08); border-radius: 16px; padding: 10px; margin-bottom: 12px; }
.powerup-item { text-align: left; display: flex; flex-direction: column; justify-content: space-between; }
.powerup-item span { font-size: 10px; color: #a1a1aa; font-weight: 700; text-transform: uppercase; }
#combatOverlay {
position: absolute;
bottom: 25px; left: 0; width: 100%;
display: flex; justify-content: center; align-items: center; gap: 15px;
z-index: 40; padding: 0 15px; box-sizing: border-box;
}
.action-circle-btn {
width: 70px; height: 70px; border-radius: 50%;
border: 2px solid rgba(255, 255, 255, 0.2);
background: rgba(18, 16, 25, 0.85); color: white;
font-weight: 800; font-size: 10px;
display: flex; flex-direction: column; justify-content: center; align-items: center;
cursor: pointer; backdrop-filter: blur(8px);
box-shadow: 0 8px 20px rgba(0,0,0,0.6);
text-transform: uppercase; transition: all 0.15s;
position: relative;
}
.action-circle-btn:active { transform: scale(0.9); background: var(--accent-orange); color: #000; border-color: white;}
#jutsuBtn { border-color: var(--accent-orange); width: 85px; height: 85px; background: rgba(255, 107, 0, 0.15); box-shadow: 0 0 20px rgba(255, 107, 0, 0.3); }
.cooldown-overlay {
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.8); border-radius: 50%;
display: flex; justify-content: center; align-items: center;
font-size: 20px; color: #ef4444; font-weight: 900;
opacity: 0; pointer-events: none; transition: opacity 0.2s;
}
.cooldown-overlay.active { opacity: 1; }
#healthBarsContainer {
position: absolute;
top: max(65px, env(safe-area-inset-top) + 40px);
left: 15px; right: 15px;
display: flex; justify-content: space-between;
z-index: 50; pointer-events: none;
}
.hp-panel {
background: rgba(18, 16, 25, 0.8);
padding: 8px 12px; border-radius: 14px;
width: 45%; border: 1px solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(8px); box-shadow: 0 8px 20px rgba(0,0,0,0.4);
}
.hp-name { font-size: 11px; font-weight: 800; margin-bottom: 4px; display: flex; justify-content: space-between; text-transform: uppercase; letter-spacing: 0.5px; }
.hp-bg { width: 100%; height: 8px; background: #27272a; border-radius: 4px; overflow: hidden; }
.hp-fill { width: 100%; height: 100%; background: linear-gradient(90deg, #10b981, #34d399); transition: width 0.2s ease-out; box-shadow: 0 0 8px rgba(16, 185, 129, 0.5); }
.hp-fill.enemy { background: linear-gradient(90deg, #ef4444, #f87171); box-shadow: 0 0 8px rgba(239, 68, 68, 0.5); }
#endGamePanel {
position: absolute; bottom: 120px; left: 50%; transform: translateX(-50%);
width: 80%; max-width: 300px; z-index: 60; display: none;
}
#toast-container { position: absolute; top: 20px; left: 50%; transform: translateX(-50%); z-index: 200; width: 80%; max-width: 300px; pointer-events: none; }
.toast { background: rgba(16, 185, 129, 0.95); color: white; padding: 10px 16px; border-radius: 12px; text-align: center; font-weight: 800; box-shadow: 0 10px 30px rgba(0,0,0,0.5); margin-bottom: 6px; backdrop-filter: blur(4px); font-size: 12px; }
.toast.error { background: rgba(239, 68, 68, 0.95); }
#quest-notifier {
position: absolute; bottom: 20px; left: 50%;
transform: translateX(-50%) translateY(100px);
background: rgba(18, 16, 25, 0.95); border: 1px solid #eab308;
border-radius: 12px; padding: 8px 16px; display: flex;
align-items: center; gap: 8px; font-size: 12px; font-weight: 800;
box-shadow: 0 10px 30px rgba(0,0,0,0.8), 0 0 15px rgba(234, 179, 8, 0.3);
z-index: 150; pointer-events: none; transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
#quest-notifier.show { transform: translateX(-50%) translateY(0); }
.combo-counter {
position: absolute;
top: 30%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
font-size: 2.5rem;
font-weight: 900;
color: #ff6b00;
text-shadow: 0 0 20px #ff6b00, 0 0 40px #eab308;
pointer-events: none;
z-index: 45;
transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.combo-counter.show { transform: translate(-50%, -50%) scale(1.2); }
</style>
</head>
<body>
<div id="loadingScreen" class="screen">
<h1>Shinobi Rising</h1>
<p style="color: #a1a1aa; font-size: 12px; font-weight: 600;">Chakra wird gesammelt...</p>
<div class="loader-container">
<div id="loaderBar" class="loader-bar"></div>
</div>
</div>
<div id="mainMenu" class="screen hidden">
<div class="glass-panel">
<h1>Shinobi Rising</h1>
<div id="playerRank" class="rank-badge">Anfänger-Ninja</div>
<div style="display: flex; justify-content: space-around; margin-bottom: 10px;">
<div class="hud-card">LVL: <span id="menuLevel" class="stat-val">1</span></div>
<div class="hud-card"><span id="menuTotalCoins" class="stat-val">0</span> 🪙</div>
</div>
<div class="powerup-box">
<div class="powerup-item">
<span>HP Bonus: +<span id="statHpBonus">0</span></span>
<button class="btn btn-green" style="padding: 6px; font-size: 10px; margin-top: 4px; margin-bottom: 0;" onclick="buyUpgrade('hp')">HP +15 (<span id="costHp">200</span>🪙)</button>
</div>
<div class="powerup-item">
<span>ATK Bonus: +<span id="statAtkBonus">0</span></span>
<button class="btn btn-green" style="padding: 6px; font-size: 10px; margin-top: 4px; margin-bottom: 0;" onclick="buyUpgrade('atk')">ATK +3 (<span id="costAtk">200</span>🪙)</button>
</div>
</div>
<h3 style="margin: 5px 0; font-size: 12px; text-transform: uppercase; color: #a1a1aa;">Wähle deinen Ninja</h3>
<div id="charSelectContainer" class="char-select-container"></div>
<button class="btn btn-primary" onclick="startBotFight()">Kampf Starten ⚔️</button>
<div style="display: flex; gap: 8px;">
<button class="btn btn-secondary" onclick="openScreen('shopScreen')">Shop 🛒</button>
<button class="btn btn-secondary" onclick="openScreen('questScreen')">Quests 📜</button>
</div>
</div>
</div>
<div id="shopScreen" class="screen hidden">
<div class="glass-panel">
<h2>Shinobi Shop</h2>
<p style="margin-top: -8px; color: #a1a1aa; margin-bottom: 12px; font-size: 12px;">Deine Coins: <span id="shopCoins" class="stat-val">0</span> 🪙</p>
<div id="shopTabsContainer" class="shop-tabs"></div>
<div id="shopGrid" class="shop-grid"></div>
<button class="btn btn-secondary" onclick="openScreen('mainMenu')">Zurück</button>
</div>
</div>
<div id="questScreen" class="screen hidden">
<div class="glass-panel">
<h2>Missions-Zentrale</h2>
<p style="margin-top: -8px; color: #a1a1aa; margin-bottom: 12px; font-size: 12px;">Erfülle Missionen für fette Belohnungen</p>
<div id="questList" class="quest-list"></div>
<button class="btn btn-secondary" onclick="openScreen('mainMenu')">Zurück</button>
</div>
</div>
<div id="gameContainer" style="display: none;">
<canvas id="gameCanvas"></canvas>
<div id="hud">
<div class="hud-card">Gegner: <span id="hudEnemyName" style="color: #ef4444;">Gegner</span></div>
<div class="hud-card"><span id="hudCoins">0</span> 🪙</div>
</div>
<div id="healthBarsContainer">
<div class="hp-panel">
<div class="hp-name"><span>Du</span><span id="playerHpTxt">100/100</span></div>
<div class="hp-bg"><div id="playerHpBar" class="hp-fill"></div></div>
</div>
<div class="hp-panel">
<div class="hp-name"><span id="enemyHpName">Gegner</span><span id="enemyHpTxt">100/100</span></div>
<div class="hp-bg"><div id="enemyHpBar" class="hp-fill enemy"></div></div>
</div>
</div>
<div id="comboCounter" class="combo-counter">CRITICAL!</div>
<div id="endGamePanel">
<button class="btn btn-gold" onclick="goToHome()">🏠 Hauptmenü</button>
</div>
<div id="combatOverlay">
<button id="atkBtn" class="action-circle-btn" onclick="playerAction('attack')">⚔️<br>Angriff</button>
<button id="jutsuBtn" class="action-circle-btn" onclick="playerAction('jutsu')">
🔥<br>Jutsu
<div id="jutsuCDOverlay" class="cooldown-overlay">3</div>
</button>
<button id="fleeBtn" class="action-circle-btn" onclick="playerAction('flee')">💨<br>Flucht</button>
</div>
</div>
<div id="toast-container"></div>
<div id="quest-notifier">🏆 <span id="quest-notifier-text">Quest Abgeschlossen!</span></div>
<script>
// State Management
const state = {
coins: 100,
level: 1,
xp: 0,
selectedCharacter: 'naruto',
upgrades: { hp: 0, atk: 0 },
equippedSkins: {
naruto: 'skin_naruto_base',
sasuke: 'skin_sasuke_base',
kakashi: 'skin_kakashi_base',
itachi: 'skin_itachi_base',
madara: 'skin_madara_base',
pain: 'skin_pain_base',
minato: 'skin_minato_base',
gaara: 'skin_gaara_base',
jiraiya: 'skin_jiraiya_base'
},
unlockedSkins: ['skin_naruto_base'],
quests: [
{ id: 'q1', type: 'bot_kills', label: 'Besiege 3 Gegner', progress: 0, target: 3, reward: 100, claimed: false },
{ id: 'q2', type: 'jutsu_uses', label: 'Setze 5 Spezial-Jutsus ein', progress: 0, target: 5, reward: 75, claimed: false },
{ id: 'q3', type: 'perfect_win', label: 'Gewinne 2 Kämpfe', progress: 0, target: 2, reward: 120, claimed: false },
{ id: 'q4', type: 'earn_coins', label: 'Sammle 200 Coins', progress: 0, target: 200, reward: 150, claimed: false },
{ id: 'q5', type: 'upgrades_made', label: 'Kaufe 3 Upgrades', progress: 0, target: 3, reward: 200, claimed: false },
{ id: 'q6', type: 'boss_fight', label: 'Besiege einen Boss', progress: 0, target: 1, reward: 300, claimed: false }
]
};
const skinsData = {
naruto: [
{ id: 'skin_naruto_base', name: 'Naruto (Genin)', cost: 0, color: '#ff6b00', secondary: '#00f0ff', jutsu: 'Rasengan', icon: '🍥', power: 1.0 },
{ id: 'skin_naruto_shippuden', name: 'Naruto (Shippuden)', cost: 800, color: '#ea580c', secondary: '#18181b', jutsu: 'Oodama Rasengan', icon: '🌀', power: 1.4 },
{ id: 'skin_naruto_hokage', name: 'Hokage Naruto', cost: 2500, color: '#fef08a', secondary: '#ffffff', jutsu: 'Rasen-Shuriken', icon: '🦊', power: 2.0 }
],
sasuke: [
{ id: 'skin_sasuke_base', name: 'Sasuke (Genin)', cost: 500, color: '#312e81', secondary: '#818cf8', jutsu: 'Chidori', icon: '⚡', power: 1.2 },
{ id: 'skin_sasuke_hebi', name: 'Sasuke (Hebi)', cost: 1500, color: '#1e1b4b', secondary: '#a855f7', jutsu: 'Kirin', icon: '🐉', power: 1.6 }
],
kakashi: [
{ id: 'skin_kakashi_base', name: 'Kakashi Hatake', cost: 1200, color: '#64748b', secondary: '#00f0ff', jutsu: 'Raikiri', icon: '⚡', power: 1.5 },
{ id: 'skin_kakashi_hokage', name: 'Hokage Kakashi', cost: 3000, color: '#334155', secondary: '#eab308', jutsu: 'Kamui Lightning', icon: '👁️', power: 2.2 }
],
itachi: [
{ id: 'skin_itachi_base', name: 'Itachi Uchiha', cost: 2000, color: '#ef4444', secondary: '#000000', jutsu: 'Tsukuyomi', icon: '👁️', power: 1.8 },
{ id: 'skin_itachi_susanoo', name: 'Itachi (Susanoo)', cost: 4500, color: '#991b1b', secondary: '#f87171', jutsu: 'Amaterasu & Susanoo', icon: '🔥', power: 2.5 }
],
madara: [
{ id: 'skin_madara_base', name: 'Madara Uchiha', cost: 3500, color: '#7f1d1d', secondary: '#a855f7', jutsu: 'Tengai Shinsei', icon: '☄️', power: 2.3 }
],
pain: [
{ id: 'skin_pain_base', name: 'Pain (Tendo)', cost: 2800, color: '#f97316', secondary: '#3f3f46', jutsu: 'Shinra Tensei', icon: '💥', power: 2.1 }
],
minato: [
{ id: 'skin_minato_base', name: 'Minato Namikaze', cost: 2200, color: '#eab308', secondary: '#ffffff', jutsu: 'Fliegender Raijin', icon: '⚡', power: 1.9 }
],
gaara: [
{ id: 'skin_gaara_base', name: 'Gaara', cost: 1000, color: '#b45309', secondary: '#ef4444', jutsu: 'Sand-Sarg', icon: '⏳', power: 1.4 }
],
jiraiya: [
{ id: 'skin_jiraiya_base', name: 'Jiraiya (Eremit)', cost: 1800, color: '#15803d', secondary: '#ffffff', jutsu: 'Kröten-Sumpf', icon: '🐸', power: 1.7 }
]
};
const botsData = [
{ name: 'Übungs-Klon', hp: 70, atk: 5, color: '#94a3b8', xp: 30, coins: 15, isBoss: false },
{ name: 'Sound Ninja', hp: 100, atk: 8, color: '#10b981', xp: 50, coins: 25, isBoss: false },
{ name: 'Akatsuki Spion', hp: 140, atk: 12, color: '#ef4444', xp: 80, coins: 45, isBoss: false },
{ name: 'Orochimaru', hp: 200, atk: 16, color: '#8b5cf6', xp: 140, coins: 80, isBoss: true },
{ name: 'Madara Uchiha (Boss)', hp: 300, atk: 22, color: '#dc2626', xp: 250, coins: 150, isBoss: true }
];
let canvas, ctx;
let currentScreen = 'mainMenu';
let activeShopTab = 'naruto';
let combat = {
active: false,
playerHP: 100, playerMaxHP: 100,
enemyHP: 100, enemyMaxHP: 100,
enemyData: null,
jutsuCD: 0,
particles: [],
visualEffects: [],
shake: 0,
timer: 0,
playerAnim: { x: 0, y: 0, attack: 0 },
enemyAnim: { x: 0, y: 0, attack: 0 }
};
window.addEventListener('DOMContentLoaded', () => {
canvas = document.getElementById('gameCanvas');
ctx = canvas.getContext('2d');
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
loadSavedData();
updateUI();
let prog = 0;
const loader = setInterval(() => {
prog += 15;
document.getElementById('loaderBar').style.width = prog + '%';
if(prog >= 100) {
clearInterval(loader);
document.getElementById('loadingScreen').classList.add('hidden');
document.getElementById('mainMenu').classList.remove('hidden');
requestAnimationFrame(gameLoop);
}
}, 40);
});
function resizeCanvas() {
if(canvas) {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
}
function saveData() { localStorage.setItem('shinobi_save', JSON.stringify(state)); }
function loadSavedData() {
const saved = localStorage.getItem('shinobi_save');
if(saved) {
try { Object.assign(state, JSON.parse(saved)); } catch(e){}
}
}
function getRankName(lvl) {
if(lvl < 3) return "Anfänger-Ninja (Genin)";
if(lvl < 7) return "Missions-Chunin";
if(lvl < 12) return "Anbu-Spezialeinheit";
if(lvl < 20) return "S-Rang Jounin";
return "Legendärer Hokage";
}
function updateUI() {
document.getElementById('menuLevel').innerText = state.level;
document.getElementById('menuTotalCoins').innerText = state.coins;
document.getElementById('shopCoins').innerText = state.coins;
document.getElementById('hudCoins').innerText = state.coins;
document.getElementById('playerRank').innerText = getRankName(state.level);
document.getElementById('statHpBonus').innerText = state.upgrades.hp * 15;
document.getElementById('statAtkBonus').innerText = state.upgrades.atk * 3;
document.getElementById('costHp').innerText = (state.upgrades.hp + 1) * 200;
document.getElementById('costAtk').innerText = (state.upgrades.atk + 1) * 200;
renderCharSelect();
}
function renderCharSelect() {
const container = document.getElementById('charSelectContainer');
container.innerHTML = '';
Object.keys(skinsData).forEach(charKey => {
const baseSkin = skinsData[charKey][0];
const isUnlocked = state.unlockedSkins.includes(baseSkin.id) || charKey === 'naruto';
const card = document.createElement('div');
card.className = `char-card ${state.selectedCharacter === charKey ? 'active' : ''} ${!isUnlocked ? 'locked' : ''}`;
card.onclick = () => selectCharacter(charKey);
card.innerHTML = `
${!isUnlocked ? '<div class="locked-badge">🔒 Shop</div>' : ''}
<div class="char-avatar" style="border-color: ${baseSkin.color}; color: white;">${baseSkin.icon}</div>
<h3>${charKey.toUpperCase()}</h3>
<p>${baseSkin.jutsu}</p>
`;
container.appendChild(card);
});
}
function buyUpgrade(type) {
const cost = (state.upgrades[type] + 1) * 200;
if (state.coins >= cost) {
state.coins -= cost;
state.upgrades[type]++;
showToast("Erfolgreich geupgradet!");
triggerQuestProgress('upgrades_made', 1);
updateUI();
saveData();
} else {
showToast("Nicht genug Coins!", true);
}
}
function openScreen(screenId) {
document.getElementById('mainMenu').classList.add('hidden');
document.getElementById('shopScreen').classList.add('hidden');
document.getElementById('questScreen').classList.add('hidden');
document.getElementById('gameContainer').style.display = 'none';
if (screenId === 'game') {
document.getElementById('gameContainer').style.display = 'block';
currentScreen = 'game';
} else {
document.getElementById(screenId).classList.remove('hidden');
currentScreen = screenId;
}
if(screenId === 'shopScreen') {
renderShopTabs();
renderShop();
}
if(screenId === 'questScreen') renderQuests();
if(screenId === 'mainMenu') updateUI();
}
function selectCharacter(char) {
const baseSkinId = skinsData[char][0].id;
if (char !== 'naruto' && !state.unlockedSkins.includes(baseSkinId)) {
showToast("Schalte diesen Ninja im Shop frei!", true);
return;
}
state.selectedCharacter = char;
renderCharSelect();
saveData();
}
function renderShopTabs() {
const container = document.getElementById('shopTabsContainer');
container.innerHTML = '';
Object.keys(skinsData).forEach(charKey => {
const btn = document.createElement('button');
btn.className = `tab-btn ${activeShopTab === charKey ? 'active' : ''}`;
btn.innerText = charKey.toUpperCase();
btn.onclick = () => switchShopTab(charKey);
container.appendChild(btn);
});
}
function switchShopTab(tab) {
activeShopTab = tab;
renderShopTabs();
renderShop();
}
function getCurrentSkin(charKey) {
const equippedId = state.equippedSkins[charKey];
const list = skinsData[charKey] || [];
return list.find(s => s.id === equippedId) || list[0];
}
function renderShop() {
const grid = document.getElementById('shopGrid');
grid.innerHTML = '';
const skins = skinsData[activeShopTab] || [];
skins.forEach(skin => {
const isUnlocked = state.unlockedSkins.includes(skin.id) || skin.cost === 0;
const isEquipped = state.equippedSkins[activeShopTab] === skin.id;
const card = document.createElement('div');
card.className = `shop-item ${isEquipped ? 'equipped' : ''} ${!isUnlocked ? 'locked-skin' : ''}`;
let btnHtml = '';
if (isEquipped) {
btnHtml = `<button class="btn btn-gold" disabled style="padding: 6px; font-size: 10px; margin: 0;">Ausrüstet</button>`;
} else if (isUnlocked) {
btnHtml = `<button class="btn btn-green" onclick="equipSkin('${activeShopTab}', '${skin.id}')" style="padding: 6px; font-size: 10px; margin: 0;">Ausrüsten</button>`;
} else {
btnHtml = `<button class="btn btn-primary" onclick="buySkin('${skin.id}', ${skin.cost})" style="padding: 6px; font-size: 10px; margin: 0;">Kaufen (${skin.cost}🪙)</button>`;
}
card.innerHTML = `
<div class="shop-avatar-placeholder" style="border-color: ${skin.color};">${skin.icon}</div>
<div class="item-title">${skin.name}</div>
<small>Power: x${skin.power.toFixed(1)} | ${skin.jutsu}</small>
${btnHtml}
`;
grid.appendChild(card);
});
}
function buySkin(skinId, cost) {
if (state.coins >= cost) {
state.coins -= cost;
state.unlockedSkins.push(skinId);
showToast("Skin freigeschaltet!");
// Automatisches Ausrüsten beim Kauf
state.equippedSkins[activeShopTab] = skinId;
if (!state.unlockedSkins.includes(skinsData[activeShopTab][0].id)) {
state.unlockedSkins.push(skinsData[activeShopTab][0].id);
}
updateUI();
renderShop();
saveData();
} else {
showToast("Nicht genug Coins!", true);
}
}
function equipSkin(charKey, skinId) {
state.equippedSkins[charKey] = skinId;
showToast("Skin ausgerüstet!");
renderShop();
saveData();
}
function renderQuests() {
const list = document.getElementById('questList');
list.innerHTML = '';
state.quests.forEach(q => {
const item = document.createElement('div');
const isReady = q.progress >= q.target && !q.claimed;
item.className = `quest-item ${isReady ? 'ready' : ''} ${q.claimed ? 'claimed' : ''}`;
let btn = '';
if (q.claimed) {
btn = `<span style="font-size: 10px; color: #10b981; font-weight: 800;">Abgeholt ✓</span>`;
} else if (isReady) {
btn = `<button class="btn btn-gold" onclick="claimQuest('${q.id}')" style="padding: 6px 12px; font-size: 10px; margin: 0; width: auto;">Einlösen</button>`;
} else {
btn = `<span class="quest-reward-tag">+${q.reward} 🪙</span>`;
}
item.innerHTML = `
<div class="quest-info">
<span class="quest-label">${q.label}</span>
<span class="quest-progress">${Math.min(q.progress, q.target)} / ${q.target}</span>
</div>
${btn}
`;
list.appendChild(item);
});
}
function triggerQuestProgress(type, amount = 1) {
state.quests.forEach(q => {
if (q.type === type && !q.claimed) {
q.progress += amount;
if (q.progress >= q.target) {
showQuestNotification(q.label);
}
}
});
saveData();
}
function claimQuest(id) {
const q = state.quests.find(x => x.id === id);
if (q && q.progress >= q.target && !q.claimed) {
q.claimed = true;
state.coins += q.reward;
showToast(`+${q.reward} Coins erhalten!`);
updateUI();
renderQuests();
saveData();
}
}
function showQuestNotification(text) {
const notif = document.getElementById('quest-notifier');
document.getElementById('quest-notifier-text').innerText = text;
notif.classList.add('show');
setTimeout(() => notif.classList.remove('show'), 3000);
}
function showToast(text, isError = false) {
const container = document.getElementById('toast-container');
const toast = document.createElement('div');
toast.className = `toast ${isError ? 'error' : ''}`;
toast.innerText = text;
container.appendChild(toast);
setTimeout(() => toast.remove(), 2500);
}
// KAMPF SYSTEM
function startBotFight() {
const currentSkin = getCurrentSkin(state.selectedCharacter);
// Zufälliger Gegner passend zum Level
let botIndex = Math.min(Math.floor(Math.random() * (state.level + 1)), botsData.length - 1);
let bot = { ...botsData[botIndex] };
combat.active = true;
combat.playerMaxHP = 100 + (state.upgrades.hp * 15);
combat.playerHP = combat.playerMaxHP;
combat.enemyData = bot;
combat.enemyMaxHP = bot.hp;
combat.enemyHP = bot.hp;
combat.jutsuCD = 0;
combat.particles = [];
combat.visualEffects = [];
document.getElementById('hudEnemyName').innerText = bot.name;
document.getElementById('enemyHpName').innerText = bot.name;
document.getElementById('endGamePanel').style.display = 'none';
document.getElementById('combatOverlay').style.display = 'flex';
updateCombatHP();
openScreen('game');
}
function updateCombatHP() {
const pPct = Math.max(0, (combat.playerHP / combat.playerMaxHP) * 100);
const ePct = Math.max(0, (combat.enemyHP / combat.enemyMaxHP) * 100);
document.getElementById('playerHpBar').style.width = pPct + '%';
document.getElementById('enemyHpBar').style.width = ePct + '%';
document.getElementById('playerHpTxt').innerText = `${Math.ceil(combat.playerHP)}/${combat.playerMaxHP}`;
document.getElementById('enemyHpTxt').innerText = `${Math.ceil(combat.enemyHP)}/${combat.enemyMaxHP}`;
}
function playerAction(type) {
if (!combat.active || combat.playerHP <= 0 || combat.enemyHP <= 0) return;
const skin = getCurrentSkin(state.selectedCharacter);
let baseAtk = 12 + (state.upgrades.atk * 3);
if (type === 'attack') {
let damage = Math.round((baseAtk * skin.power) * (0.8 + Math.random() * 0.4));
combat.enemyHP -= damage;
combat.playerAnim.attack = 10;
combat.shake = 5;
spawnParticles(canvas.width * 0.7, canvas.height * 0.5, skin.color, 15);
spawnDamageText(canvas.width * 0.7, canvas.height * 0.4, damage, '#ffffff');
if (combat.jutsuCD > 0) combat.jutsuCD--;
}
else if (type === 'jutsu') {
if (combat.jutsuCD > 0) {
showToast("Jutsu lädt noch auf!", true);
return;
}
let damage = Math.round((baseAtk * skin.power * 2.2) * (0.9 + Math.random() * 0.3));
combat.enemyHP -= damage;
combat.jutsuCD = 3;
combat.playerAnim.attack = 20;
combat.shake = 15;
spawnParticles(canvas.width * 0.7, canvas.height * 0.5, skin.secondary, 35);
spawnDamageText(canvas.width * 0.7, canvas.height * 0.35, `${skin.jutsu}! -${damage}`, skin.secondary);
triggerQuestProgress('jutsu_uses', 1);
}
else if (type === 'flee') {
showToast("Geflohen!");
goToHome();
return;
}
// Cooldown Overlay Update
const cdOverlay = document.getElementById('jutsuCDOverlay');
if (combat.jutsuCD > 0) {
cdOverlay.classList.add('active');
cdOverlay.innerText = combat.jutsuCD;
} else {
cdOverlay.classList.remove('active');
}
updateCombatHP();
// Prüfen ob Gegner besiegt
if (combat.enemyHP <= 0) {
winBattle();
return;
}
// Gegner schlägt zurück
setTimeout(enemyTurn, 600);
}
function enemyTurn() {
if (!combat.active || combat.enemyHP <= 0) return;
let damage = Math.round(combat.enemyData.atk * (0.8 + Math.random() * 0.4));
combat.playerHP -= damage;
combat.enemyAnim.attack = 10;
combat.shake = 8;
spawnParticles(canvas.width * 0.3, canvas.height * 0.5, combat.enemyData.color, 15);
spawnDamageText(canvas.width * 0.3, canvas.height * 0.4, damage, '#ef4444');
updateCombatHP();
if (combat.playerHP <= 0) {
loseBattle();
}
}
function winBattle() {
combat.active = false;
const rewardCoins = combat.enemyData.coins;
const rewardXp = combat.enemyData.xp;
state.coins += rewardCoins;
state.xp += rewardXp;
// Level Up Berechnung
if (state.xp >= state.level * 100) {
state.level++;
showToast(`LEVEL UP! Du bist jetzt Level ${state.level}!`);
}
triggerQuestProgress('bot_kills', 1);
triggerQuestProgress('earn_coins', rewardCoins);
triggerQuestProgress('perfect_win', 1);
if (combat.enemyData.isBoss) triggerQuestProgress('boss_fight', 1);
showToast(`Sieg! +${rewardCoins} Coins | +${rewardXp} XP`);
document.getElementById('endGamePanel').style.display = 'block';
document.getElementById('combatOverlay').style.display = 'none';
saveData();
}
function loseBattle() {
combat.active = false;
showToast("Niederlage! Trainiere weiter.", true);
document.getElementById('endGamePanel').style.display = 'block';
document.getElementById('combatOverlay').style.display = 'none';
}
function goToHome() {
combat.active = false;
openScreen('mainMenu');
}
function spawnParticles(x, y, color, amount) {
for (let i = 0; i < amount; i++) {
combat.particles.push({
x: x, y: y,
vx: (Math.random() - 0.5) * 12,
vy: (Math.random() - 0.5) * 12,
size: Math.random() * 6 + 2,
color: color,
life: 1.0
});
}
}
function spawnDamageText(x, y, text, color) {
combat.visualEffects.push({
x: x, y: y,
text: text,
color: color,
life: 1.0,
vy: -2
});
}
// MAIN GAME LOOP (RENDER & ANIMATIONS)
function gameLoop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (currentScreen === 'game') {
combat.timer += 0.05;
// Screen Shake Anwenden
ctx.save();
if (combat.shake > 0) {
let rx = (Math.random() - 0.5) * combat.shake;
let ry = (Math.random() - 0.5) * combat.shake;
ctx.translate(rx, ry);
combat.shake *= 0.85;
if (combat.shake < 0.5) combat.shake = 0;
}
// Kampf-Arena Hintergrund zeichnen
let grad = ctx.createLinearGradient(0, 0, 0, canvas.height);
grad.addColorStop(0, '#09090b');
grad.addColorStop(0.7, '#1a102f');
grad.addColorStop(1, '#050508');
ctx.fillStyle = grad;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Arena-Boden
ctx.fillStyle = 'rgba(255,255,255,0.03)';
ctx.beginPath();
ctx.ellipse(canvas.width/2, canvas.height * 0.7, canvas.width * 0.4, 80, 0, 0, Math.PI * 2);
ctx.fill();
// ANIMATION POSITIONEN
let pSkin = getCurrentSkin(state.selectedCharacter);
let px = canvas.width * 0.25 + (combat.playerAnim.attack > 0 ? 30 : 0);
let py = canvas.height * 0.65 + Math.sin(combat.timer * 2) * 5;
let ex = canvas.width * 0.75 - (combat.enemyAnim.attack > 0 ? 30 : 0);
let ey = canvas.height * 0.65 + Math.sin(combat.timer * 2 + 1) * 5;
if (combat.playerAnim.attack > 0) combat.playerAnim.attack--;
if (combat.enemyAnim.attack > 0) combat.enemyAnim.attack--;
// SPIELER ZEICHNEN
ctx.shadowBlur = 20;
ctx.shadowColor = pSkin.color;
ctx.fillStyle = pSkin.color;
ctx.beginPath();
ctx.arc(px, py, 35, 0, Math.PI * 2);
ctx.fill();
// Aura / Innenschicht
ctx.fillStyle = pSkin.secondary;
ctx.beginPath();
ctx.arc(px, py, 15, 0, Math.PI * 2);
ctx.fill();
// GEGNER ZEICHNEN
if (combat.enemyData) {
ctx.shadowColor = combat.enemyData.color;
ctx.fillStyle = combat.enemyData.color;
ctx.beginPath();
ctx.arc(ex, ey, 35, 0, Math.PI * 2);
ctx.fill();
}
ctx.shadowBlur = 0;
// PARTIKEL RENDERN
for (let i = combat.particles.length - 1; i >= 0; i--) {
let p = combat.particles[i];
p.x += p.vx;
p.y += p.vy;
p.life -= 0.03;
if (p.life <= 0) {
combat.particles.splice(i, 1);
continue;
}
ctx.fillStyle = p.color;
ctx.globalAlpha = p.life;
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
ctx.fill();
ctx.globalAlpha = 1.0;
}
// SCHADENS-TEXTE RENDERN
for (let i = combat.visualEffects.length - 1; i >= 0; i--) {
let fx = combat.visualEffects[i];
fx.y += fx.vy;
fx.life -= 0.02;
if (fx.life <= 0) {
combat.visualEffects.splice(i, 1);
continue;
}
ctx.font = '900 20px Segoe UI, sans-serif';
ctx.fillStyle = fx.color;
ctx.globalAlpha = fx.life;
ctx.textAlign = 'center';
ctx.fillText(fx.text, fx.x, fx.y);
ctx.globalAlpha = 1.0;
}
ctx.restore();
}
requestAnimationFrame(gameLoop);
}
</script>
</body>
</html>Game Source: Shinobi Rising: Ultimate Ninja Combat
Creator: BlazeKoala99
Libraries: none
Complexity: complex (1047 lines, 47.2 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: naruto-shinobi-rising-blazekoala99" to link back to the original. Then publish at arcadelab.ai/publish.