Considerazioni sulla progettazione:
Non posso raccomandare ereditare gli oggetti di gioco dalla loro rappresentazione grafica. Perché? Si consiglia di avere più rappresentazioni grafiche di un oggetto di gioco (come uno nella vista di gioco o un altro in minimappa o qualsiasi altra cosa). La relazione è "Player": una "rappresentazione grafica" e non "Player" è una "rappresentazione grafica". Una soluzione migliore è usare la composizione e non l'ereditarietà. Un altro effetto piacevole è l'incapsulamento di altri rilevamenti di collisione se non si è soddisfatti di quello fornito da Qt, disaccoppiando, ... La verità è che per il gioco semplice può essere sufficiente.
Per logica di gioco abbastanza semplice, l'ereditarietà in cui altri oggetti reagiscono all'oggetto attivo. Probabilmente troppo semplicistico per le meccaniche di gioco più complesse.
class Asteroid {
public:
virtual void CollideWithPlayer(Player&) { p.loseHealth(100); }
};
class ExplodingAsteroid: Asteroid {
public:
virtual void CollideWithPlayer(Player&) { explode(); p.loseHealth(1000); }
};
Se interazione ottiene (molti oggetti attivi comportandosi da soli) complessi potrebbe essere necessario per identificare gli oggetti:
C'è è RTTI, ma ehm è difficile raccomandare vedere: How expensive is RTTI? In Insomma: costoso, difficile da mantenere.
È possibile utilizzare la doppia spedizione. Identifica gli oggetti utilizzando due chiamate virtuali. Problemi: un po 'di sintassi, a volte difficile da mantenere (specialmente quando si aggiungono nuovi oggetti), problemi di proprietà (vedi di più). esempio Gioco da Wikipedia:
class SpaceShip {};
class GiantSpaceShip : public SpaceShip {};
class Asteroid {
public:
virtual void CollideWith(SpaceShip&) {
cout << "Asteroid hit a SpaceShip" << endl;
}
virtual void CollideWith(GiantSpaceShip&) {
cout << "Asteroid hit a GiantSpaceShip" << endl;
}
};
class ExplodingAsteroid : public Asteroid {
public:
virtual void CollideWith(SpaceShip&) {
cout << "ExplodingAsteroid hit a SpaceShip" << endl;
}
virtual void CollideWith(GiantSpaceShip&) {
cout << "ExplodingAsteroid hit a GiantSpaceShip" << endl;
}
};
funzione virtuale id
class GameObject() {
virtual getId() { return GAME_OBJECT; }
};
class Asteroid() {
virtual getId() { return ASTEROID; }
};
o come membro
class GameObject() {
ID getId() { return id; }
protected:
GameObject(ID id):id(id) {}
private:
ID id;
};
o utilizzando il modello con l'inizializzazione automatica di ID (un po 'la sintassi da capogiro, cerchiamo di ometterlo: o)
Ora per il ciclo di gioco come questo:
for each object
update by (fixed) time step
detect collisions and resolve them
si incontrano:
problemi di proprietà:
giocatore perde la salute quando viene colpita da asteroidi e asteroidi è distrutto in seguito ..
Asteorid::collideWithPlayer(Player& p) { p.loseHealth(100); this->explode(); }
Consideriamo anche
Player::collideWithAsteroid(Asteroid& a) { this->loseHealth(100); a.explode(); }
risultato: duplicazione del codice o meccaniche di gioco poco chiare
soluzione
poveri: chiamare qualcun altro per aiutarti: o)
Asteorid::collideWithPlayer(Player& p) { resolveCollision(p, *this); }
Player::collideWithAsteroid(Asteroid& a) { resolveCollision(*this, a); }
resolveCollision(Player, Asteroid) { p.loseHealth(100); a.explode(); }
+1 per tesi eccellenti. Le foto lo renderebbero migliore. ;-) –
grazie mille per la tua spiegazione. È vero che C++ non è una buona scelta per gli sviluppatori di giochi? – amirouche
C++ è una delle migliori opzioni per IMO di gioco dev. Hai più controllo sulla memoria e accesso alle chiamate di basso livello quando necessario. Ma io sono di parte perché non ho mai provato a fare un gioco in qualcosa tranne per C++ e java. –