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