In questa lezione vediamo come implemenrtare un semplice nemico volante che alla collisione con un blocco cambi direzione. Poi ci dedicheremo alli effetti sonori e alla gestione degli spari.
Creare un GameObj per i nemici
Iniziamo con i nemici caricando come al solito lo sprite animato:
this.sprUmbrella = rh.LoadSprite("img/umbrella.png",4);
Definiamo poi l'oggetto Umbrella
, che colpisce e ferisce il Player quando entra in collisione con esso:
function Umbrella(x,y) {
GameObj.call(this, x, y);
// imposta lo sprite e l'evento draw
this.SetSprite(game.sprUmbrella);
this.hSpeed = 1;
this.life = 5;
this.animSpeed = 0.25;
this.bbox = new BoundingBox(this.x, this.y, this.sprite.w, this.sprite.height);
this.Update = function() {
// se collide con un blocco, cambia direzione
if(this.GetCollision(game.blocks, this.hSpeed/2, 0)) {
this.hSpeed = - this.hSpeed;
}
this.x += this.hSpeed;
this.bbox.Move(this.x, this.y);
// se il player non è in status "colpito/invulnerabile"
if(!game.player.hit) {
// se entra in collisione con il Player
if(this.bbox.Collides(game.player.bbox)) {
// colpisci il player
game.player.Hit();
}
}
}
// inserisco l'istanza nell'array dei nemici
game.enemies.push(this);
//quando viene distrutto, cancella dall'array dei nemici
this.OnDestroy = function() {
game.enemies.splice(game.enemies.indexOf(this), 1);
}
}
//eredita da GameObj
Inherit(Umbrella);
Aggiungiamo l'array enemies
in ResetLevel
:
this.ResetLevel = function() {
// ...
this.enemies = [];
}
Nella mappa che abbiamo importato, ci sono già alcuni oggetti, possiamo caricarli aggiungendo a LoadLevel
il seguente codice, appena sotto il caricamento delle collisioni:
// dati sui blocchi di collisione
// ...
// dati sugli oggetti
var objects = levels[lev][3];
for(var i = 0; i < objects.length; i++){
var object = null;
var x = objects[i][0]*this.cellSize;
var y = objects[i][1]*this.cellSize;
switch(objects[i][2]) {
case "umbrella":
new Umbrella(x, y);
break;
}
}
Avviare Sound Effects
Definiamo la funzione AudioPlay in Utils.js, aggiungendo il seguente codice, che ci permetterà di avviare un suono più volte facendolo ripartire dall'inizio (dall'istante zero).
function AudioPlay(source) {
// se il browser è internet explorer
if(window.ActiveXObject != undefined) {
source.pause();
source.currentTime = 0;
} else {
source.load();
}
// avvia il suono
source.play();
}
Purtroppo ci sono tantissime incongruenze tra i vari browser e l'istruzione currentTime = 0
non funziona ovunque come dovrebbe, perciò bisogna usare la funzione load()
che inizializza nuovamente il suono dalla cache, facendolo ripartire dall'inizio.
Questo non sarà necessario su Internet Explorer, che almeno stavolta è uno dei pochi che funziona come dovrebbe.
Proiettili
Per rendere il gioco più vivo, diamo al nostro personaggio la possibilità di sparare. Come al solito carichiamo gli sprite necessari:
this.sprBullet = rh.LoadSprite("img/bullet.png",1);
this.sprBulletHit = rh.LoadSprite("img/bullethit.png",3);
Creiamo quindi l' oggetto Bullet, che rappresenterà la pallottola.
function Bullet(x,y,hspeed) {
//constructor di GameObj
GameObj.call(this, x, y);
//imposta sprite e metodo Draw
this.SetSprite(game.sprBullet);
this.hSpeed = hspeed;
//centra l'offset dello sprite
this.OffsetCenter();
//crea il bounding box
this.bbox = new BoundingBox(x-this.xOffset, y-this.yOffset, this.sprite.w, this.sprite.height);
this.Update = function() {
// se collide con un blocco, si distrugge
if(this.GetCollision(game.blocks, this.hSpeed/2, 0)) {
this.Destroy();
}
//se collide con un nemico, gli riduce la vita
//e il proiettile viene distrutto
if(inst = this.GetCollision(game.enemies, this.hSpeed/2, 0)) {
inst.life--;
this.Destroy();
}
this.x += this.hSpeed;
this.bbox.Move(this.x-game.sprBullet.width/2, this.y-game.sprBullet.height/2);
//se il proiettile esce dalla visuale, viene distrutto
if(this.x < 0 || this.x > game.AreaW * game.cellSize) {
this.Destroy();
}
}
//quando viene distrutto
this.OnDestroy = function() {
//viene cancellato dall'array bullets
game.bullets.splice(game.bullets.indexOf(this), 1);
//crea una piccola esplosione
new BulletExplosion(this.x, this.y);
}
game.bullets.push(this);
}
//eredita da GameObj
Inherit(Bullet);
Inizializziamo l'array bullets all'interno di ResetLevel
//...
this.bullets = [];
//...
Definiamo anche BulletExplosion
, una semplice animazione che avviene quando il proiettile si distrugge:
function BulletExplosion(x,y) {
//constructor
GameObj.call(this, x, y);
//avvia un suono
AudioPlay(game.sndHit);
//imposta sprite e funzione di draw
this.SetSprite(game.sprBulletHit);
//imposta l'offset al centro
this.OffsetCenter();
//velocità di animazione
this.animSpeed = 0.25;
//distruggi al termine dell'animazione
this.OnAnimationEnd = function(){
this.Destroy();
}
}
//eredita da gameobject
Inherit(BulletExplosion);
Prima di andare avanti, dobbiamo caricare un paio di suoni, tra cui sndHit
, utilizzato nel codice precedente:
this.sndHit = rh.LoadSound("audio/hit",["ogg", "mp3"]);
this.sndHit.volume = 0.03;
this.sndShot = rh.LoadSound("audio/shot",["ogg", "mp3"]);
this.sndShot.volume = 0.03;
Possiamo quindi far sparare il nostro player quando viene premuto il tasto X. In fondo al metodo Update del Player, aggiungiamo un po' di codice:
// ...
//se è possibile sparare
if(this.canShot){
if(Inputs.GetKeyPress("X")) {
var bullet = new Bullet(this.x + 10*this.scaling, this.y-this.height/2, this.scaling * 8);
//avvia il suono di sparo
AudioPlay(game.sndShot);
//imposta una pausa di qualche frazione di secondo,
//prima di poter sparare un altro colpo
this.canShot = false;
this.shotTime = 10;
}
} else {
//timer di attesa per sparare il prossimo colpo
this.shotTime --;
if(this.shotTime <= 0){
this.canShot = true;
}
//cambia sprite in base allo status corrente
//se salta, imposta lo sprite di sparo durante il salto
//se è fermo, imposta lo sprite fermo in modalità sparo
//ecc..
switch(this.sprite){
case game.sprPlayerRun:
this.sprite = game.sprPlayerIdleShot;
this.curFrame = 0;
break;
case game.sprPlayerIdle:
this.sprite = game.sprPlayerIdleShot;
this.curFrame = 0;
break;
case game.sprPlayerFall:
this.sprite = game.sprPlayerFallShot;
break;
case game.sprPlayerJump:
this.sprite = game.sprPlayerJumpShot;
break;
}
}