🎮ArcadeLab

Attack on Titan Ultimate Survivor

by BlazeGamer18
579 lines10.8 KB
▶ Play
ATTACK ON TITAN: ULTIMATE SURVIVOR — index.html

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Attack on Titan Ultimate Survivor</title>

<style>
*{box-sizing:border-box}
body{
 margin:0;
 overflow:hidden;
 background:#111b25;
 font-family:Arial;
 color:white;
 touch-action:none;
}
canvas{
 display:block;
 width:100vw;
 height:100vh;
}
#hud{
 position:absolute;
 top:12px;
 left:12px;
 background:#101820cc;
 padding:12px;
 border-radius:12px;
 line-height:1.7;
 font-size:14px;
}
#controls{
 position:absolute;
 bottom:15px;
 width:100%;
 display:flex;
 justify-content:space-between;
 padding:0 15px;
 align-items:end;
}
.group{display:flex;gap:8px}
button{
 background:#243e52dd;
 border:2px solid #d5e5ed;
 color:white;
 border-radius:12px;
 padding:15px;
 font-weight:bold;
 font-size:17px;
}
button:active{background:#a64b32}
#menu{
 position:absolute;
 inset:0;
 background:linear-gradient(#162b3beF,#111820f5);
 display:flex;
 flex-direction:column;
 justify-content:center;
 align-items:center;
 text-align:center;
 padding:20px;
}
h1{color:#e7c28a;font-size:30px}
#menu button{margin:6px}
#message{
 position:absolute;
 top:45%;
 width:100%;
 text-align:center;
 font-size:30px;
 font-weight:bold;
 pointer-events:none;
}
.hidden{display:none!important}
</style>
</head>

<body>

<canvas id="game"></canvas>

<div id="hud">
 ❤️ HP: <span id="hp">100</span><br>
 ⚡ Энергия: <span id="energy">100</span><br>
 ⚔️ Убийства: <span id="score">0</span><br>
 🗺️ Уровень: <span id="level">1</span><br>
 👑 Враг: <span id="enemy">Обычный титан</span>
</div>

<div id="message"></div>

<div id="controls">
 <div class="group">
  <button id="left">◀</button>
  <button id="right">▶</button>
 </div>
 <div class="group">
  <button id="gear">⚙️ ODM</button>
  <button id="jump">⬆</button>
  <button id="attack">⚔️</button>
 </div>
</div>

<div id="menu">
 <h1>ATTACK ON TITAN</h1>
 <h2>ULTIMATE SURVIVOR</h2>
 <p>Выбери своего персонажа:</p>
 <div>
  <button onclick="selectCharacter('Эрен')">Эрен</button>
  <button onclick="selectCharacter('Леви')">Леви</button>
  <button onclick="selectCharacter('Микаса')">Микаса</button>
 </div>
 <p id="selected">Персонаж: Эрен</p>
 <button onclick="startGame()" style="background:#a43e2e">
  НАЧАТЬ ИГРУ
 </button>
 <p>Уничтожай титанов и проходи уровни!</p>
</div>

<script>
const canvas=document.getElementById("game");
const ctx=canvas.getContext("2d");

let W,H;

function resize(){
 W=canvas.width=innerWidth;
 H=canvas.height=innerHeight;
}
resize();
addEventListener("resize",resize);

let running=false;
let character="Эрен";
let score=0;
let level=1;
let kills=0;
let gameTime=0;

let keys={left:false,right:false};

const player={
 x:200,
 y:0,
 hp:100,
 energy:100,
 jump:0,
 speed:4,
 gear:false,
 attack:false,
 facing:1,
 color:"#344d67"
};

let titans=[];
let buildings=[];
let particles=[];

function selectCharacter(name){
 character=name;
 document.getElementById("selected").textContent=
 "Персонаж: "+name;

 if(name==="Леви")player.speed=5.5;
 if(name==="Микаса")player.speed=4.8;
 if(name==="Эрен")player.speed=4;
}

function makeBuildings(){
 buildings=[];
 for(let i=0;i<20;i++){
  buildings.push({
   x:i*180,
   h:100+Math.random()*180,
   w:100+Math.random()*45,
   color:["#71675c","#897967","#6a7471"][i%3]
  });
 }
}

function spawnTitan(boss=false){
 titans.push({
  x:W+Math.random()*200,
  y:H-75,
  size:boss?160:65+Math.random()*40,
  hp:boss?15:3,
  maxHp:boss?15:3,
  speed:boss?0.5:0.7+Math.random(),
  boss:boss,
  attackTimer:0,
  color:boss?"#a85d48":"#c58c76"
 });
}

function startGame(){
 document.getElementById("menu").classList.add("hidden");
 player.hp=100;
 player.energy=100;
 player.x=W/2;
 player.y=H-75;
 score=0;
 kills=0;
 level=1;
 gameTime=0;
 titans=[];
 particles=[];
 makeBuildings();

 for(let i=0;i<4;i++)spawnTitan();

 running=true;
 requestAnimationFrame(loop);
}

function drawBackground(){
 let sky=ctx.createLinearGradient(0,0,0,H);
 sky.addColorStop(0,"#70a5bd");
 sky.addColorStop(1,"#d5c59b");
 ctx.fillStyle=sky;
 ctx.fillRect(0,0,W,H);

 // Sun
 ctx.fillStyle="#f4dca1";
 ctx.beginPath();
 ctx.arc(W-100,90,40,0,Math.PI*2);
 ctx.fill();

 // Distant city
 buildings.forEach((b)=>{
  let x=(b.x-gameTime*0.5)%(buildings.length*180);
  if(x< -200)x+=buildings.length*180;

  ctx.fillStyle=b.color;
  ctx.fillRect(x,H-70-b.h,b.w,b.h+70);

  ctx.fillStyle="#e8c99b";
  for(let j=0;j<4;j++){
   ctx.fillRect(x+12+j*22,H-55-b.h+25,10,18);
  }
 });

 ctx.fillStyle="#596c43";
 ctx.fillRect(0,H-70,W,70);
}

function drawPlayer(){
 let x=player.x;
 let y=player.y-player.jump;

 // Shadow
 ctx.fillStyle="#3337";
 ctx.beginPath();
 ctx.ellipse(x,player.y,20,6,0,0,Math.PI*2);
 ctx.fill();

 // Legs
 ctx.fillStyle="#28394c";
 ctx.fillRect(x-12,y-35,10,35);
 ctx.fillRect(x+3,y-35,10,35);

 // Jacket
 ctx.fillStyle=player.color;
 ctx.fillRect(x-14,y-70,28,38);

 // Face
 ctx.fillStyle="#e9b99b";
 ctx.beginPath();
 ctx.arc(x,y-80,12,0,Math.PI*2);
 ctx.fill();

 // Hair
 ctx.fillStyle=character==="Леви"?"#303038":
 character==="Микаса"?"#36252a":"#75482e";
 ctx.beginPath();
 ctx.arc(x,y-86,12,Math.PI,Math.PI*2);
 ctx.fill();

 // Scarf for Mikasa
 if(character==="Микаса"){
  ctx.fillStyle="#a32f30";
  ctx.fillRect(x-13,y-70,26,6);
 }

 // Swords
 ctx.fillStyle="#dce8ed";
 ctx.save();
 ctx.translate(x,y-55);
 ctx.rotate(player.facing*0.5);
 ctx.fillRect(15,-3,35,4);
 ctx.restore();

 // ODM cables
 if(player.gear){
  ctx.strokeStyle="#dce4e9";
  ctx.lineWidth=2;
  ctx.beginPath();
  ctx.moveTo(x-7,y-50);
  ctx.lineTo(x-90,y-130);
  ctx.moveTo(x+7,y-50);
  ctx.lineTo(x+90,y-130);
  ctx.stroke();
 }
}

function drawTitan(t){
 let s=t.size;
 let x=t.x;
 let y=t.y;

 // Shadow
 ctx.fillStyle="#3335";
 ctx.beginPath();
 ctx.ellipse(x,y, s*.4,7,0,0,Math.PI*2);
 ctx.fill();

 // Body
 ctx.fillStyle=t.color;
 ctx.fillRect(x-s*.22,y-s*.85,s*.44,s*.85);

 // Head
 ctx.beginPath();
 ctx.arc(x,y-s*.96,s*.29,0,Math.PI*2);
 ctx.fill();

 // Arms
 ctx.fillStyle=t.color;
 ctx.fillRect(x-s*.43,y-s*.72,s*.18,s*.55);
 ctx.fillRect(x+s*.25,y-s*.72,s*.18,s*.55);

 // Legs
 ctx.fillStyle="#895e50";
 ctx.fillRect(x-s*.2,y-s*.3,s*.15,s*.3);
 ctx.fillRect(x+s*.05,y-s*.3,s*.15,s*.3);

 // Eyes
 ctx.fillStyle="#fff";
 ctx.fillRect(x-s*.17,y-s*.99,9,7);
 ctx.fillRect(x+s*.08,y-s*.99,9,7);

 ctx.fillStyle="#e33";
 ctx.fillRect(x-s*.25,y-s*1.18,s*.5,5);
 ctx.fillStyle="#7cff75";
 ctx.fillRect(x-s*.25,y-s*1.18,
  s*.5*(t.hp/t.maxHp),5);

 if(t.boss){
  ctx.fillStyle="#ffcf6b";
  ctx.font="bold 16px Arial";
  ctx.textAlign="center";
  ctx.fillText("BOSS TITAN",x,y-s*1.28);
 }
}

function addParticles(x,y){
 for(let i=0;i<10;i++){
  particles.push({
   x:x,
   y:y,
   vx:(Math.random()-.5)*5,
   vy:(Math.random()-.5)*5,
   life:25
  });
 }
}

function drawParticles(){
 particles.forEach(p=>{
  p.x+=p.vx;
  p.y+=p.vy;
  p.life--;
  ctx.fillStyle="#e5c59a";
  ctx.fillRect(p.x,p.y,4,4);
 });
 particles=particles.filter(p=>p.life>0);
}

function attack(){
 if(!running)return;

 player.attack=true;

 let hit=false;

 titans.forEach(t=>{
  let distance=Math.abs(t.x-player.x);
  if(distance<player.size || distance<120){
   if(player.gear && player.energy>5){
    t.hp-=character==="Леви"?3:2;
    player.energy-=5;
   }else{
    t.hp--;
   }
   hit=true;
   addParticles(t.x,t.y-t.size/2);

   if(t.hp<=0){
    score++;
    kills++;
   }
  }
 });

 if(!hit){
  // Attack animation without a hit
 }

 setTimeout(()=>player.attack=false,250);
}

function useGear(){
 if(!running||player.energy<10)return;

 player.gear=!player.gear;
 if(player.gear){
  player.energy-=10;
  player.jump=150;
  player.speed=9;
 }else{
  player.speed=character==="Леви"?5.5:
   character==="Микаса"?4.8:4;
 }
}

function jump(){
 if(running&&player.jump===0){
  player.jump=110;
 }
}

function update(){
 gameTime++;

 if(keys.left){
  player.x-=player.speed;
  player.facing=-1;
 }

 if(keys.right){
  player.x+=player.speed;
  player.facing=1;
 }

 player.x=Math.max(20,Math.min(W-20,player.x));

 if(player.jump>0)player.jump-=3.5;

 if(player.energy<100 && !player.gear){
  player.energy+=0.12;
 }

 titans.forEach(t=>{
  if(t.x>player.x+35){
   t.x-=t.speed;
  }else if(t.x<player.x-35){
   t.x+=t.speed;
  }

  t.attackTimer++;

  if(Math.abs(t.x-player.x)<45&&t.attackTimer>100){
   player.hp-=t.boss?12:5;
   t.attackTimer=0;
  }
 });

 titans=titans.filter(t=>t.hp>0);

 if(titans.length===0){
  level++;
  if(level%3===0){
   spawnTitan(true);
   showMessage("BOSS LEVEL!");
  }else{
   for(let i=0;i<Math.min(3+level,8);i++){
    spawnTitan();
   }
   showMessage("LEVEL "+level);
  }
 }

 if(player.hp<=0){
  endGame();
 }
}

function drawAttack(){
 if(player.attack){
  ctx.strokeStyle="#fff";
  ctx.lineWidth=5;
  ctx.beginPath();
  ctx.arc(player.x+player.facing*30,
   player.y-player.jump-55,
   45,-1,1);
  ctx.stroke();
 }
}

let messageTimer;

function showMessage(text){
 const el=document.getElementById("message");
 el.textContent=text;
 clearTimeout(messageTimer);
 messageTimer=setTimeout(()=>el.textContent="",1500);
}

function endGame(){
 running=false;
 document.getElementById("message").innerHTML=
 "GAME OVER<br><small>Уничтожено титанов: "+score+
 "<br><button onclick='location.reload()'>ЗАНОВО</button></small>";
}

function loop(){
 if(!running)return;

 update();
 drawBackground();

 titans.forEach(drawTitan);
 drawPlayer();
 drawAttack();
 drawParticles();

 document.getElementById("hp").textContent=
 Math.max(0,Math.floor(player.hp));

 document.getElementById("energy").textContent=
 Math.floor(player.energy);

 document.getElementById("score").textContent=score;
 document.getElementById("level").textContent=level;

 document.getElementById("enemy").textContent=
 titans.some(t=>t.boss)?"БОСС":"Обычный титан";

 requestAnimationFrame(loop);
}

// Mobile controls
function bindHold(id,key){
 const el=document.getElementById(id);
 el.addEventListener("pointerdown",e=>{
  e.preventDefault();
  keys[key]=true;
 });
 ["pointerup","pointercancel","pointerleave"].forEach(event=>{
  el.addEventListener(event,()=>keys[key]=false);
 });
}

bindHold("left","left");
bindHold("right","right");

document.getElementById("attack").onclick=attack;
document.getElementById("jump").onclick=jump;
document.getElementById("gear").onclick=useGear;

// Keyboard
document.addEventListener("keydown",e=>{
 if(e.key==="ArrowLeft"||e.key==="a")keys.left=true;
 if(e.key==="ArrowRight"||e.key==="d")keys.right=true;
 if(e.key===" ")jump();
 if(e.key==="x")attack();
 if(e.key==="z")useGear();
});

document.addEventListener("keyup",e=>{
 if(e.key==="ArrowLeft"||e.key==="a")keys.left=false;
 if(e.key==="ArrowRight"||e.key==="d")keys.right=false;
});

makeBuildings();
</script>
</body>
</html>

Game Source: Attack on Titan Ultimate Survivor

Creator: BlazeGamer18

Libraries: none

Complexity: complex (579 lines, 10.8 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: attack-on-titan-ultimate-survivor-blazegamer18" to link back to the original. Then publish at arcadelab.ai/publish.