Crea un gioco ispirato a Megaman in Costrutto 2

Ti guiderò attraverso la creazione di un gioco sparatutto / platform di ispirazione Megaman. Saremo più concentrati sugli aspetti di ripresa del gameplay piuttosto che sulla piattaforma. In questo tutorial userò Construct 2 come strumento per creare il gioco, ma spiegherò la logica usando pseudocodice in modo da poter seguire questo tutorial in qualsiasi lingua o motore di tua scelta.

Post correlati
  • Costruisci un gioco da tavolo "Small Tactics" a due giocatori in Construct 2: Part 1
  • Crea un gioco ispirato ai Bomberman in Costruisci 2: Il giocatore e il livello
  • Crea un gioco Match-3 in Costrutto 2: Le basi
  • Passi comuni di nuovi arrivati ​​nella comunità di Construct 2 Gamedev

Fare clic sul gioco per focalizzarlo, quindi utilizzare i tasti freccia per spostarsi e saltare, e Z sparare.

Per concentrarmi sull'implementazione del gameplay, non spiegherò tutte le funzionalità di Construct 2; Presumo che tu conosca le basi come caricare uno sprite, una collisione di base o suonare suoni. Detto questo, iniziamo a fare il gioco.


Preparare l'opera d'arte

Per prima cosa, abbiamo bisogno di avere sprite per il nostro gioco. Per fortuna, opengameart ci ha coperti con la loro meravigliosa collezione di giochi legali. Abbiamo bisogno di quattro gruppi di sprite; un eroe, un nemico e tessere per piattaforme.

  • Hero (di Redshrike):
    http://opengameart.org/content/xeon-ultimate-smash-friends
  • Nemico (anche di Redshrike):
    http://opengameart.org/content/fighting-robot-for-ultimate-smash-friends
  • Piastrelle (per robotalità):
    http://opengameart.org/content/prototyping-2d-pixelart-tilesets

Per usarli in Costrutto 2, ritagliare gli sprite dell'eroe in singoli fotogrammi usando GIMP.


Movimento di base

Userò il comportamento della piattaforma di Construct 2 per il resto del tutorial in modo che possa concentrarmi sulla parte di ripresa e AI del gioco, che era l'obiettivo principale di questo tutorial.


Costruisci il comportamento della piattaforma 2

Spiegazione del movimento di base

Se stai lavorando in un'altra lingua o vuoi implementare il tuo movimento di base per il platform invece di usare il comportamento integrato. È necessario utilizzare il codice solo in questa sezione se non si intende utilizzare il comportamento predefinito di Construct 2.

Per iniziare, dobbiamo considerare tre modi in cui il nostro eroe può muoversi; camminare a destra, camminare a sinistra o saltare. Ogni frame, aggiorniamo la simulazione del gioco.

numero moveSpeed ​​= 50; function update () moveHero (); 

Per aggiornare il personaggio del giocatore, implementiamo movimenti di base come questo:

function moveHero () // player sta premendo questo tasto down if (keyDown (KEY_LEFT)) hero.x - = moveSpeed ​​* deltaTime; hero.animate ( "walkLeft");  if (keyDown (KEY_RIGHT)) hero.x + = moveSpeed ​​* deltaTime; hero.animate ( "walkRight");  if (keyDown (KEY_UP)) hero.jump (); hero.animate ( "salto");  // una chiave che era appena stata chiusa se (keyReleased (KEY_LEFT)) hero.animate ("standLeft");  if (keyReleased (KEY_RIGHT)) hero.animate ("standRight"); 

Io uso un'altra funzione per fare il salto perché saltare non è solo questione di cambiare il valore y ma anche calcolare la gravità. Avremo anche una funzione che ascolta se è stata appena rilasciata una chiave, per restituire l'animazione dell'eroe a un'animazione permanente.

Parliamo di come far saltare il giocatore. L'eroe dovrà sapere se sta saltando o meno, e anche se sta cadendo o meno. Quindi dichiareremo due nuove variabili: isJumping e isFalling. Per impostazione predefinita, entrambi sono falsi, il che significa che l'eroe è in piedi su una piattaforma.

Per eseguire un salto, dobbiamo prima controllare se entrambi i valori sono falsi e quindi rendere vero isjump.

Funzione jump () if (! IsJumping &&! IsFalling) isJumping = True

Perché l'eroe possa saltare, abbiamo bisogno di una variabile chiamata jumpPower e gravità. Il valore predefinito di jumpPower è -20 e la gravità è 1. La logica è di aggiungere il valore della potenza di salto alla posizione Y dell'eroe e aggiungere gravità per saltare il valore della potenza.

Facciamo questo ogni segno di spunta. Forse questa non è la fisica gravitazionale più realistica che ci sia, ma i giochi non hanno bisogno di essere realistici, hanno solo bisogno di essere credibili, ecco perché alcuni giochi hanno un super salto umano e un doppio salto. Il codice sottostante appartiene alla funzione di aggiornamento.

Se (isJumping || isFalling) hero.y + = hero.jumpPower; hero.jumpPower + = hero.gravity;  // alla fine il salto di potenza sarà maggiore di zero e ciò significa che l'eroe sta cadendo se (hero.jumpPower> = 0) isJumping = False; isFalling = True;  // per fermare l'autunno, fai qualcosa quando l'eroe si sovrappone alla piattaforma se (hero.isOverlapping (platform1)) // platform1 è la piattaforma su cui il nostro eroe può calpestare // reimposta la variabile sul loro valore predefinito isJumping = False; isFalling = False; hero.jumpPower = -20;  // e poi c'è la caduta libera, quando il giocatore cade oltre il bordo di una piattaforma se (! hero.isOverlapping (platform1) && hero.jumpPower < 0 && !isJumping)  // !hero.isOverlapping(platform1) checks whether or not our hero is standing on a platform // and if jumpPower is less than zero and the player is not currently jumping, then that means // he's falling // setting these two values like this will make the player fall. hero.jumpPower = 0; isFalling = true; 

Il comportamento della piattaforma incorporata di Costrutto 2 replica il codice di esempio precedente, a cui viene fornito solo l'aiuto di coloro che lavorano in un'altra lingua.


Attuazione dello scatto

Ora arriva la parte di ripresa del gioco. Nella serie Megaman ci sono tre tipi di colpi: colpi normali, colpi caricati e colpi di energia del boss.

I colpi normali sono auto esplicativi. I colpi caricati sono colpi che vengono caricati prima di essere rilasciati, questi colpi caricati sono di due tipi: semi caricati e completamente carichi. Questi attacchi caricati sono più forti dei colpi normali, con la carica completa diventano i più forti.

I colpi di energia del boss sono colpi con potenza che il giocatore ha acquisito dopo aver sconfitto ciascun boss. Il danno è lo stesso del normale ma hanno proprietà speciali che i colpi normali non hanno.

Ora che conosciamo il tipo di ogni sparo, iniziamo a farli. Per prima cosa vediamo la logica dietro a come usiamo ogni colpo. Qui assumiamo che il pulsante Z sulla tastiera sia usato per sparare un colpo. Implementeremo due comportamenti diversi:

  • Scatti normali: il giocatore preme z e quindi lo rilascia immediatamente (tocca il pulsante). Il proiettile verrà sparato una volta ogni tocco. L'animazione cambierà per riprendere l'animazione prima di passare immediatamente all'animazione permanente.
  • Scatti caricati: il giocatore preme Z. Viene sparato il primo proiettile normale. L'animazione cambierà per sparare prima di passare immediatamente all'animazione permanente. Se Z continua a essere premuto, verrà aggiunto un effetto di carica in cima all'animazione in riproduzione (in piedi, camminando). Se il pulsante Z viene rilasciato in meno di 5 secondi dalla prima ricarica, verrà sparato un proiettile caricato a metà. Se il pulsante Z viene rilasciato dopo 5 secondi, verrà sparato un proiettile completamente carico.
  • Colpi di energia del boss: il nostro eroe deve prima equipaggiare il proiettile che ha acquisito dopo aver sconfitto un boss. Dopo aver equipaggiato, il giocatore preme un altro pulsante per sparare a questo proiettile. Il comportamento di questo proiettile varia e deve essere codificato in modo univoco per ogni punto elenco.

Ora iniziamo a programmare. Poiché il nostro eroe può sparare a destra e sinistra, dobbiamo sapere in quale direzione si trova attualmente. Dichiariamo una nuova variabile chiamata facing che memorizza un valore stringa se l'eroe è rivolto a sinistra oa destra.

String facing = "right"; // quale direzione l'eroe sta attualmente affrontando function moveHero () // player sta premendo questo tasto down if (keyDown (KEY_LEFT)) hero.x - = moveSpeed ​​* deltaTime; hero.animate ( "walkLeft"); facing = "left";  if (keyDown (KEY_RIGHT)) hero.x + = moveSpeed ​​* deltaTime; hero.animate ( "walkRight"); facing = "right";  // ... la continuazione della funzione moveHero () va qui function update () // ... il codice di aggiornamento che abbiamo precedentemente scritto va qui ... // player premi questo tasto una volta se (keyPressed (KEY_Z)) if (facing == "right") hero.animate ("Spara"); // aggiungeremo qui la funzione di ripresa else if (facing == "left") hero.animate ("Spara"); hero.mirrorSprite (); // questa funzione ribalta lo sprite orizzontalmente if (keyReleased (KEY_Z)) if (facing == "right") hero.animate ("standRight");  else if (facing == "left") hero.animate ("standLeft"); hero.mirrorSprite (); // dobbiamo chiamarlo di nuovo perché lo sprite era speculare // se non specifichiamo di nuovo lo sprite, standLeft sarà simile a standRight

Sposta gli eventi in Costruisci 2

Prima di sparare a un proiettile, dobbiamo esaminare le proprietà del proiettile:

  • Potere: potere d'attacco del proiettile, il danno che infliggerà al nemico
  • Velocità: la velocità del proiettile
  • Angolo: l'angolo di tiro, determina in quale direzione va il proiettile.

Queste proprietà saranno diverse per ogni punto. In particolare, le proprietà di potenza saranno diverse. La proprietà angle è normalmente solo uno dei due valori; se il proiettile è sparato a destra o a sinistra, a meno che non si tratti di un proiettile di energia del boss che può sparare con un'angolazione unica.

Le variazioni dei colpi saranno discusse più tardi, quindi ora coprirò solo i colpi base. Quello che segue è il pezzo di codice che spara un proiettile.

// prima, creiamo una funzione che crea un nuovo proiettile Funzione shoot (string pathToSprite, number bulletPower, number bulletSpeed, number bulletAngle) myBullet = new Bullet (pathToSprite); myBullet.power = bulletPower; // la classe o l'oggetto del proiettile ha due variabili private che lo spostano in base al suo angolo // più spiegazione a queste due linee richiede più matematica, quindi ho scelto di non spiegare // presumo che il tuo motore di scelta abbia un modo per spostare un oggetto in base al suo angolo ySpeed ​​= Math.sin (bulletAngle) * bulletSpeed; xSpeed ​​= Math.cos (bulletAngle) * bulletSpeed;  // questa è la funzione della classe Bullet chiamata ogni frame, questo sposta il punto elenco in base alla sua funzione di angolo moveBullet () x + = xSpeed ​​* deltaTime; y + = ySpeed ​​* deltaTime;  // e questa è la modifica alla nostra funzione update () funzione update precedente () // ... il codice di aggiornamento che abbiamo precedentemente scritto va qui ... // player premi questo tasto una volta se (keyPressed (KEY_Z)) if ( di fronte == "right") hero.animate ("Spara"); hero.shoot ("path / to / sprite.png", 10, 400, 0);  else if (facing == "left") hero.animate ("Spara"); hero.mirrorSprite (); // questa funzione ribalta lo sprite orizzontalmente hero.shoot ("path / to / sprite.png", 10, 400, 180); // l'angolo è 180 in modo che il proiettile vada a sinistra // ... la continuazione del codice di aggiornamento va qui ...

Aggiunta del comportamento del proiettile agli sprite dei proiettili
Il codice di ripresa in cui generiamo un nuovo oggetto di proiettile

Scatti caricati

Alcuni proiettili possono essere più potenti di altri. Per creare un tiro carico abbiamo bisogno di una variabile chiamata ChargeTime, che aumenterà ogni secondo che il giocatore tiene premuto Z, e tornerà a zero quando il proiettile è sparato. Le modifiche al codice di aggiornamento sono le seguenti:

// player ha appena rilasciato il tasto z if (keyReleased (KEY_Z)) if (chargeTime> 0 && chargedTime <= 5)  if (facing == "right")  hero.animate("Shoot"); hero.shoot("path/to/halfChargedBullet.png", 20, 400, 0); chargedTime = 0;  else if (facing == "left")  hero.animate("Shoot"); hero.mirrorSprite(); // this function flips the sprite horizontally hero.shoot("path/to/halfChargedBullet.png", 20, 400, 180); chargedTime = 0;   else if (chargedTime > 5) if (facing == "right") hero.animate ("Spara"); hero.shoot ("path / to / fullChargedBullet.png", 40, 400, 0); chargedTime = 0;  else if (facing == "left") hero.animate ("Spara"); hero.mirrorSprite (); // questa funzione ribalta lo sprite orizzontalmente hero.shoot ("path / to / fullChargedBullet.png", 40, 400, 180); chargedTime = 0;  if (facing == "right") hero.animate ("standRight");  else if (facing == "left") hero.animate ("standLeft"); hero.mirrorSprite (); // dobbiamo chiamarlo di nuovo perché lo sprite era speculare // se non specifichiamo nuovamente lo sprite, standLeft sarà simile a standRight // player sta premendo questo tasto giù se (keyDown (KEY_Z)) // questa è la funzione che aggiunge il valore di ChargeTime ogni secondo // questo blocco di codice keyDown verrà eseguito ogni frame, che è inferiore a un secondo // il tuo motore di scelta dovrebbe avere un modo per dire se un secondo è passato o no addChargedTime (); 

Le nuove mosse del nostro eroe si spostano a sinistra, a destra e salgono secondo il nostro input, e sparano anche proiettili, sia normali, semi-caricati o completamente caricati.


Implementazione dei nemici

Ora abbiamo un eroe controllabile. Chiamiamolo Xeon per semplicità. Può eseguire alcuni movimenti di base come camminare, saltare e sparare. È fantastico! Ma a che serve la capacità di scattare senza qualcosa da sparare, giusto? Ecco perché questa volta faremo il nostro primo nemico.

Progettiamo gli attributi del nostro nemico prima di iniziare a codificarlo.

  • Salute: Quanti salute il nostro nemico ha determinato quanti colpi (e che tipo) sono necessari per distruggerlo.

  • Potere: potere d'attacco del nemico, quanto danno infligge al nostro giocatore.

  • ShotAngle: in quale direzione il nemico spara al proiettile, può essere lasciato a destra, a destra o ovunque vogliamo.

Questo è praticamente ciò di cui abbiamo bisogno per il nostro nemico, ora facciamo la classe / oggetto nemico.

La classe / oggetto nemico è praticamente uguale alla classe / oggetto del giocatore, ad eccezione del nemico che non ascolta l'input del giocatore. Per questo motivo abbiamo bisogno di sostituire le parti in cui l'eroe ascolta l'input del giocatore, l'IA / logica nemica.


Nemico AI attacco

Per i principianti, gestiamo l'IA base di tiro del nemico. Il nemico sparerà al giocatore quando vedrà il giocatore.

Per determinare se il nemico "vede" il giocatore, dovremo definire una variabile per l'oggetto nemico chiamato fronte che è una stringa che memorizza uno dei due valori, "sinistra" o "destra".

Il nemico ha anche bisogno di un certo tipo di raggio visivo, motivo per cui creeremo un'altra variabile chiamata intervallo. Se il giocatore si trova all'interno di questo intervallo, significa che il nemico "vede" il giocatore. Lo pseudocodice è il seguente:

function boolean checkSees () if (facing == "left" && hero.x> = enemy.x - range) return true;  if (facing == "right" && hero.x <= enemy.x + range)  return true;  return false; 

funzione checkSees ()

Forse hai notato qualcosa in questo pseudocodice: non considera la posizione dell'eroe, quindi il nemico continuerà a sparare all'eroe anche se sono su piattaforme con altezze diverse.

Per ora questo è sufficiente, perché fare un algoritmo di linea di vista è al di fuori dello scopo di questo tutorial. Nel tuo gioco, potresti voler aggiungere una tolleranza Y in quella funzione in alto che controllerà se la posizione y dell'eroe si trova tra due punti che definiscono l'altezza del nemico.


Spara ai nemici

Lo pseudocodice per le sparatorie nemiche è il seguente:

// può essere in update () o da qualche altra parte che viene eseguita ogni funzione di aggiornamento frame () if (checkSees ()) shoot ("path / to / bulletSprite.png", enemyPower, 400, shotAngle); 

Come puoi vedere, la funzione shoot () del nemico è simile a quella del giocatore. Prende il percorso dello sprite, la potenza di attacco, la velocità del proiettile e l'angolo di tiro come parametri.


Movimento nemico AI

Quando il nemico passa dal lato sinistro a quello destro? Per il nostro eroe, utilizziamo l'input del giocatore per cambiare la direzione che il nostro eroe deve affrontare. Per il nostro nemico abbiamo due opzioni: usa un qualche tipo di timer per cambiare direzione di fronte ogni pochi secondi mentre fai in modo che il nemico si fermi o fai in modo che il nemico cammini in un determinato punto e poi cambi direzione e poi cammini in un altro punto per cambiare di nuovo la sua direzione di fronte.

Questo secondo metodo può essere utilizzato come AI di pattugliamento. Certo, possiamo solo far camminare il nemico in una direzione e non tornare indietro.

Lo pseudocodice per il primo metodo è il seguente:

function switchingAI () // elapsedTime () è una funzione che conta quanti secondi sono passati da quando il suo valore è resettato // Presumo che il tuo motore di scelta abbia questo tipo di funzionalità se (elapsedTime ()> 4.0) if (facing == "left") facing = "right"; shotAngle = 0;  if (facing == "right") facing = "left"; shotAngle = 180;  enemy.mirrorSprite (); // capovolge anche lo sprite orizzontalmente resetTime (); // ripristina il tempo che conta in elapsedTime ()

Commutazione delle funzioni AI

Nemico che pattuglia l'IA

Per creare l'IA pattuglia, dobbiamo creare due oggetti invisibili che si trovano alla fine di entrambi i modi di pattugliamento del nemico, e fare in modo che il nemico si muova in un altro modo se si scontra con loro.


Perlustrazione dell'IA

Ora scriviamo il nostro pseudocodice per l'IA pattuglia del nemico:

function patrollingAI () if (facing == "right") walkRight (); // uguale a quello in oggetto / classe giocatore se (collidesWith (rightPatrolBorder)) facing = "left"; enemy.mirrorSprite ();  if (facing == "left") walkLeft (); if (collidesWith (leftPatrolBorder)) facing = "right"; enemy.mirrorSprite (); 

Dopo questo, il nemico pattuglia tra due punti come lo vogliamo.

Per impostare quale IA utilizza il nemico, aggiungeremo un'altra variabile con un tipo di stringa per il nostro nemico: IA nemica. Questo determinerà quale AI usare ogni fotogramma, in questo modo:

if (enemyAI == "switching") switchingAI ();  else if (enemyAI == "pattugliamento") patrollingAI (); 

Naturalmente puoi aggiungere più tipi di IA nemici se vuoi.


Shot Variation

Andiamo avanti su come possiamo fare le varianti di tiro sia per il giocatore che per il nemico. Stiamo facendo delle varianti di tiro cambiando due cose: l'angolo di tiro e il numero di proiettili.

In questo modo possiamo fare un semplice colpo di proiettile, o un colpo di proiettile a tre direzioni. Prima di fare questo, creeremo un'altra variabile per l'oggetto / classe nemico chiamato shotAI, che è una stringa. Lo useremo nei nostri checkSees () controllando se il blocco, dove spara il nemico. Le modifiche a quel blocco di codice saranno così:

// può essere in update () o da qualche altra parte che viene eseguito ogni funzione di aggiornamento frame () if (checkSees ()) if (shotAI == "simple") shoot ("percorso / a / bulletSprite.png", enemyPower , 400, shotAngle);  if (shotAI == "threeBullets") shootThreeBullets (); 

Naturalmente, il nome dell'IA e il tipo di tiro che il nemico dovrebbe sparare spetta a te, questo è solo un esempio.

Ora, approfondiamo cosa c'è dentro la funzione shootThreeBullets ().

Funzione shootThreeBullets () if (facing == "right") shoot ("percorso / a / bulletSprite.png", enemyPower, 400, 0); // questo proiettile va dritto alla ripresa giusta ("percorso / to / bulletSprite.png", enemyPower, 400, 330); // questo aumenta di 30 gradi ("path / to / bulletSprite.png", enemyPower, 400, 30); // questo scende di 30 gradi se (di fronte == "left") shoot ("path / to / bulletSprite.png", enemyPower, 400, 180); // questo proiettile va dritto a sinistra ("percorso / a / bulletSprite.png", enemyPower, 400, 210); // questo aumenta di 30 gradi ("path / to / bulletSprite.png", enemyPower, 400, 150); // questo va giù di 30 gradi

Se non sei sicuro del motivo per cui 0 va a destra e 180 a sinistra, è perché la direzione di 0 gradi va direttamente sul lato destro dello schermo, 90 gradi vanno verso il lato inferiore dello schermo, e così via fino a quando non colpisce 360 gradi. Una volta che sai quale valore va dove, puoi creare la tua variante di tiro.

Possiamo anche creare una variabile AI per il giocatore, ma preferisco chiamarla SelectedShot, perché il nostro giocatore sceglierà il proiettile anziché programmato dall'inizio. T

La logica in megaman è ogni volta che Megaman sconfigge un boss, ottiene il potere di quel boss come un nuovo colpo. Cercherò di ricreare quella logica. Per fare ciò abbiamo bisogno di un array che contenga i colpi del giocatore, inclusi i colpi normali. Lo pseudocodice è così:

var shotArr = ["normalShot", "boss1", "boss2"]; var shotIndex = 0; var selectedShot = "normalShot"; function update () // questo è il blocco di codice nella funzione di aggiornamento del giocatore dove il giocatore spara un proiettile // questa funzione cambia il proiettile sparato dal giocatore cambiaBullet (); // player premi questo tasto una volta se (keyPressed (KEY_Z)) if (facing == "right") hero.animate ("Spara"); if (selectedShot == "normalShot") hero.shoot ("path / to / sprite.png", 10, 400, 0);  else if (selectedShot == "boss1") // aggiungi codici per sparare il tipo di colpo che il giocatore ha ricevuto dopo aver sconfitto il boss 1 function changeBullet () // cambia shotIndex in base al pulsante premuto if (keyPressed (KEY_E)) shotIndex + = 1;  if (keyPressed (KEY_Q)) shotIndex - = 1;  // corregge shotIndex se è fuori dalla lunghezza dell'array if (shotIndex == shotArr.length) shotIndex = 0;  if (shotIndex < 0)  shotIndex = shotArr.length -- 1;  selectedShot = shotArr[shotIndex]; 

Dobbiamo tenere traccia di due nuove variabili:


Come aggiungere una matrice in Construct 2

Spingeremo nuovi elementi su shotArr quando il giocatore sconfiggerà un boss.


Aggiornamento dei punti elenco dei giocatori

Proprio come lo shootThreeBullet () del nemico, puoi essere creativo e creare le tue varianti di tiro. Dato che questo è il proiettile dell'eroe, diamo qualcosa di speciale.

Facciamo in modo che un tipo di tiro sia efficace contro un boss specifico, in modo che infligga più danni. Per fare ciò, creeremo una variabile per l'oggetto bullet denominato strongAgainst che è un'altra variabile di tipo stringa che contiene il nome del boss con cui questo punto elenco è efficace. Aggiungeremo questa offerta più funzionalità di danno quando discuteremo la parte principale del gioco.


Salute e morte

Questo è il punto in cui tutte le varianti di tiro che facciamo davvero iniziano ad avere importanza. Qui è dove il nostro eroe danneggia e uccide il nemico, e viceversa.

Per cominciare, creiamo una variabile per l'eroe e l'oggetto nemico, denominata salute che è un int e un'altra variabile solo per l'eroe chiamato vite. Diamo un'occhiata allo pseudocodice:

se (bullet.collidesWith (eroe)) hero.health = = bullet.power; createExplosion (); // per ora non abbiamo uno sprite dell'esplosione, quindi questo fungerà da promemoria // controlla se l'eroe è morto se (hero.health <= 0)  hero.lives -= 1; // decreases hero's total number of lives. destroyHero(); 

Faremo lo stesso pseudocodice per danneggiare i nemici, in questo modo:

se (bullet.collidesWith (nemico)) enemy.health = = bullet.power; createExplosion ();  if (enemy.health <= 0)  destroyEnemy(); 

Gestione delle collisioni tra giocatore e nemico

La GUI di Health Bar

Ora, se lo lascio a quel punto, non sarebbe interessante. Quindi creerò uno sprite rettangolare nell'angolo in alto a sinistra dello schermo che funge da barra della salute del nostro eroe.

La durata di questa barra della salute cambierà a seconda della salute attuale del nostro eroe. La formula per cambiare la lunghezza della barra della salute è questa:

// questo è nella funzione di aggiornamento healthBar.width = (hero.health / hero.maxHealth) * 100;

Abbiamo bisogno di un'altra variabile per il nostro eroe chiamata maxHealth; valore di salute pieno del nostro eroe. Per ora questo valore non può essere cambiato ma forse in futuro possiamo creare un oggetto che aumenti la quantità di maxHealth dell'eroe.


Crea il mondo di gioco

Ora che abbiamo creato le nostre varianti di eroe, nemico e tiro, dobbiamo creare più livelli e boss.

Avere più livelli significa che a un certo punto del gioco il giocatore raggiungerà uno o più checkpoint che cambieranno la partita dal livello 1-1 al livello 1-2 al livello 1-3 e così via fino a raggiungere il boss.

Quando il giocatore muore da qualche parte nel livello 1-2, non ha bisogno di ripetere il gioco dall'inizio del livello 1-1. Come faccio a fare questo? Per prima cosa creeremo il livello, non spiegherò molto sulla progettazione dei livelli, ma ecco il livello di esempio in Construct 2.


progettazione del livello di esempio

L'immagine nell'angolo in alto a sinistra è il livello HUD. Scorrerà, seguendo l'eroe quando viene giocata la partita.


Porte e posti di blocco

Uno sprite a cui dovresti prestare attenzione è lo sprite verde nella parte in alto a destra del livello. È il punto di controllo in questo livello quando l'eroe collide con esso trasferiremo il gioco al livello 1-2.

Per gestire più livelli sono necessarie tre variabili: currentLevel, levelName e nextLevel.

La variabile currentLevel viene creata nell'oggetto / classe hero. Il levelName viene creato nell'oggetto (livello) della scena di gioco per ogni livello. La variabile nextLevel viene creata nell'oggetto sprite verde.

La logica è la seguente: quando l'eroe si scontra con lo sprite verde (io lo chiamo greenDoor), cambieremo il nostro livello nella scena di gioco in cui levelName è uguale alla variabile nextLevel. Dopo aver cambiato il livello, cambieremo il valore della variabile currentLevel dell'eroe allo stesso livello di livello della scena di gioco. Ecco lo pseudocodice:

// questo è all'interno della funzione di aggiornamento del gioco se (hero.collidesWith (greenDoor)) changeLevelTo (greenDoor.nextLevel); 

Cambia i livelli quando tocchiamo la porta verde

Inizializzazione di un nuovo livello

Ecco lo pseudocodice per affrontare quando il prossimo livello è caricato e pronto per giocare.

// questa è la funzione che viene attivata quando il nuovo livello viene caricato function onStart () hero.currentLevel = scene.LevelName; hero.x = startPos.x; hero.y = startPos.y; 

Le posizioni di avvio del giocatore

Ora che siamo passati a un nuovo livello, spiegherò lo sprite arancione dietro il nostro eroe nell'immagine del livello superiore qui sopra. Quello sprite arancione è un oggetto che chiamo startPos. È usato per segnare la posizione di partenza di ogni livello.

Ci riferiamo a questo oggetto quando l'eroe ha appena cambiato livello o è morto, in modo da sapere dove generarlo.

Ecco lo pseudocodice per la gestione quando l'eroe muore:

// la funzione che viene attivata quando l'eroe viene distrutto. Funzione onDestroyed () // resuscita l'eroe se l'eroe ha ancora delle vite. If (hero.lives> 0) var newHero = new Hero (); newHero.x = startPos.x; newHero.y = startPos.y; 

Ora possiamo avere più livelli e possiamo anche rigenerare l'eroe dopo che muore.

Puoi creare tutti i livelli che vuoi, o magari persino creare due oggetti greenDoor in un livello che uno di loro ritorna al livello 1-1 se il giocatore risolve un enigma in modo sbagliato.


Boss Battles

È finalmente giunto il momento di implementare il boss stesso. Fare un livello boss è semplice come fare un altro livello che genererà un boss invece dei normali nemici.

La parte difficile è creare AI per il boss, perché ogni boss avrà un'IA unica. Quindi, per renderlo più facile da capire e duplicare per molti capi, ho intenzione di far dipendere l'intelligenza artificiale al boss dal momento in cui vengono generati. Il che significa che stanno per fare A per x secondi, quindi passare a B per y secondi, quindi fare C per z secondi prima di tornare a A. Lo pseudocodice avrà un aspetto simile al seguente:

// questo codice si trova all'interno della funzione di aggiornamento del boss, quindi viene eseguito ogni frame se (elapsedTime ()> 2.0) // questo se il blocco viene eseguito per 3 secondi, perché la differenza di tempo con il blocco if di seguito // è tre secondi. BossShot1 (); // variazione shot da eseguire questa volta else if (elapsedTime ()> 5.0) bossShot2 ();  else if (elapsedTime ()> 6.0) bossShot3 ();  if (elapsedTime ()> 7.0) // reimposta l'ora in modo che il boss esegua nuovamente la prima azione resetsTime (); 

La definizione delle funzioni boss shot è sotto. Sentiti libero di cambiarlo per adattarlo a quello che vuoi per una lotta con il boss:

function bossShot1 () // un semplice colpo dritto bossEnemy.shoot ("path / to / bullet / sprite.png", bossPower, 400, shotAngle); // shotAngle is 180 function bossShot2 () // un proiettile a tre direzioni ha sparato a bossEnemy.shoot ("path / to / bullet / sprite.png", bossPower, 400, shotAngle); bossEnemy.shoot ("path / to / bullet / sprite.png", bossPower, 400, shotAngle + 30); bossEnemy.shoot ("path / to / bullet / sprite.png", bossPower, 400, shotAngle - 30);  function bossShot3 () // per questo, ho intenzione di fare un cerchio, quindi i proiettili formeranno un cerchio per (var i = 0; i <= 9; i++)  bossEnemy.shoot("path/to/bullet/sprite.png", bossPower, 400, 36 * i); // change the shotAngle  

Spetta a te aggiungere