Täiendame ja parandame varem loodud mängu Aliens Attack. Mäng on huvitavam, kui vaenlasi on mitmesuguseid - uuel tasemel ilmuvad uued animeeritud vaenlased
Tasemed
Lisame mängu initsialiseerimisel mõned uued muutujad:
nExplosions = 40; nEnemies = 30; var level = 0; var maxLevels = 3; //tasemete arv
Animeeritud vaenlased
Tasemetel 1 ja 2 tulevad juba animeeritud vaenlased, s.t. loodud konstruktorfunktsiooniga animated; vastavad spriidilehed tuleb laadida koos teiste piltidega mängu algul. Kuna selle funktsiooni eelnev versioon oli plahvatuste, seega ühekordse animatsiooni mängimiseks - kui animatsioon jõudis lõppuni this.activeFrame == this.coords.length, seati this.state = "hidden";. Vaenlaste animatsioone tuleb mängida korduvalt, sellepärast lisame funktisoonile animated veel ühe formaalse parameetri repeat (animatsiooni mängimise kordused: 0 - uuesti, 1 - lõpetab)ja täiendame funktsiooni animated alamfunktsiooni draw:
if (this.repeat == 1){ this.state = "hidden"; //end animation
Et kontruktorfunktsioon enemy saaks spriidi vastavalt tasemele (tase 0: animeerimata pilt, tasemetel 2,3 - animeeritud), lisame funktsiooni, mis loob vastava spriidid:
var enemySprite = function() { switch(level) { case 0: return images.enemy; break; case 1: return new animated(images.enemy1,[[0,0],[32,0]],32,32,"active",8,0); break; case 2: return new animated(images.enemy2,[[0,0],[38,0],[76,0]],38,48,"active",8,0); break; default: //announce("Victory!"); //clearInterval(int); break; } }
Funktsioonis enemy määratakse spriit ja joonistamine käskudega
this.sprite = enemySprite(); //images.enemy; this.width = this.sprite.width; //32; this.height = this.sprite.height; //32; this.y = - this.height; this.state = "hidden"; this.draw = function() { if (this.state =="active") { if(level == 0) ctx.drawImage(this.sprite, this.x, this.y); else { this.sprite.x = this.x; this.sprite.y = this.y; this.sprite.draw(); } }
Vaenlased muutuvad tigedamaks, kui neid tapetakse - lisame parameetri, mis suurendab nende allalangemise kiirust:
this.increase = 0.1; this.vy = 2 + player.kills * this.increase;
Kõrgematel tasemetel parameetrit increase suurendatakse.
Vaenlaste säästlik kasutamine
Kui vaenlase spriit on animatsioon, on otstarbekaks mälu kasutamiseks parem ka vaenlasi käsitleda nagu plahvatusi - mitte luua uusi, vaid taaskasutada.
Hakkame ka vaenlasi taaskasutama, s.t. kui vaenlane ei ole aktiivne, siis teda ei uuendata (liigutata), s.t. lisame vaenlaste konstruktorfunktsioonile parameetri state; vaenlase loomisel konstruktorfunktsioonis enemy
this.state = "hidden";
Vaenlasi uuendandatakse (update) ja joonistatakse vaid siis, kui nad on aktiivsed, s.t. lisame vastavatesse funktsioonidesse kontrollid
this.update = function() { if (this.state =="active") {...
Vaenlasi luuakse mängu funktsioonis update vajaduse korral (muidu ilmuvad nad kõik peaaegu samas reas); massiivis activeEnemies on vaenlased, kes on parajasti ekraanil, ülejäänud on massiivis enemies; sellest massiivist otsitakse 'mittemängivaid', s.t. mis pole aktiivsed analoogiliselt sellega, kuidas otsitakse mittemängivaid plahvatusi:
activeEnemies = enemies.filter(function(e) { return e.state = "active"; }); if((activeEnemies.length < nEnemies/2) && (Math.random() < 0.1) ) { var x1 = w0/4 + Math.random()*w0/2; var y1 = 0; if (find_free(enemies, x1, y1) == -1); { //aktiveerime juhuslikult vaenlasi kuni < 20 var bad = new enemy(); enemies.push(bad); } }
Kuulidega tabamist tuleb kontrollida vaid aktiivsete vaenlaste jaoks:
activeEnemies = enemies.filter(function(e) { return e.state=="active"; }); bullets.forEach(function(bullet) { activeEnemies.forEach(function(enemy) { if(collision(bullet, enemy)) { enemy.explode(); player.kills++; bullet.active = false; } }); });
Et nii plahvatuste kui ka vaenlaste massivist vaba (mittemängiva) leidmiseks saaks kasutada sama funktsiooni, on funktsioonile find_free lisatud veel üks parameeter objects - see on massiiv, millest peab otsima:
function find_free(objects,x,y) { var i = 0; while(i < objects.length && objects[i].state == "active"){ i++; } if (i < objects.length) { //õnnestus! objects[i].x = x; objects[i].y = y; objects[i].state = "active"; objects[i].draw(); return 0; } else return -1; //ei leitud }
Kui vaenlast tabab kuul, vaenlane plahvatab ja muutub passiivseks (osa konstruktorfunktsioonist enemy):
this.explode = function() { explosion_snd.cloneNode(true).play(); find_free(explosions,this.x,this.y); this.y = -this.sprite.height; //peidame ylemise ääre taha this.state = "hidden"; };
Tasemete vahetamine
if (player.health > 0) { if (player.kills > nEnemies) { level++ ; if (level <= maxLevels) { enemies.forEach(function(e) { e.sprite = enemySprite(); }); //uus spriit vastavalt uuele tasemele enemy.increase += 0.1; player.kills = 0; //igal tasemel peab tapma nEnemies vaenlast! } else { announce("Victory!"); stopGame(); } } } else { announce('You are dead...');//loose game stopGame(); //clearInterval(gm); } }
Mängu lõpetamine
Mäng käivitatakse korduva taimeriga:
var gm = setInterval(gameLoop,FT);
Funktsioon stopGame eemaldab sündmuste kuulajad ja vaenlased; plahvatused mängivad lõpuni:
function stopGame(){ removeDown(); removeUp(); enemies.forEach(function(enemy) { enemy.explode(); }); enemies.length = 0; bullets.length = 0; }
Funktsioonid removeDown, removeUp on kirjeldatud veidi modifitseeritud utiliidis keys.js, kus varemkasutatud anonüümsetele funktsioonidele on antud nimed, muidu ei saa sündmuste kuulajaid eemaldada:
var keysDown = []; window.addEventListener("keydown", downKey,false); function downKey(e) { keysDown[e.keyCode] = true; } function removeDown() { window.removeEventListener("keydown", downKey,false); keysDown.length = 0; } window.addEventListener("keyup", upKey,false); function upKey(e) { keysDown[e.keyCode] = false; } function removeUp() { window.removeEventListener("keyup", upKey,false); keysDown.length = 0; }
Ja ongi kõik... Mängija on võitnud, kui ta tapab nEnemies vaenlast (rohkem pole isegi Talibanidel kusagilt võtta)
Ülesandeid.
1. Kangelasel on mõlemas käes relv - pane ta kahe käega ( vaheldumisi) tulistama; kuulid peaks välja lendama enam-vähem) käes oleva toru otsast selle suunas !
2.Lisa mängija edukuse (kui palju vaenlasi on tapetud) ja tervise arvestus - kui vaenlane põrkab mängijaga kokku, peab selle tervis vähenema 10% ja kui tervis on 0, on mängija kaotanud; tervis näidatakse punase kriipsuga mängu vasakus nurgas
3. Kui vaenlasi tapetakse, muutuvad nad tigedamaks ja hakkavad kiiremini allapoole liikuma - täienda ! Allalangemise kiirusega saab määrata ka mängu raskusastme.
© Jaak Henno