Emulateur Space Invaders

Blast from the past

a marqué ce sujet comme résolu.

Bonjour à tous :)

Je vous présente mon premier vrai projet en c++, un émulateur du Space Invaders original de Taito de 1978, codé en c++11 approximatif et avec Qt en UI.

J'ai entièrement implémenté le CPU (Intel 8080A) avec des timings corrects et testés, ainsi que le son (mais partiellement, pas émulé la puce sonore). Il n'est pas optimisé mais tourne quand même bien, même sur un PC du troisième âge (2007 ça fait quand même 9 ans ! Et toujours pas d'Half-life 3 à l'horizon :'( )

C'est ma première tentative approximative en multithreading, mais ça marche ! Sûrement mal, mais ça marche !

Le code est sur github : https://github.com/Stellaris-code/SpaceInvadersEmu

Pas encore de binaires pour windows, j'y travaille (pas de machine windaube sous la main, donc cross-compilation) Seule dépendance : Qt (core/widgets/multimedia)

J'attends vos retours sur le code et sur le programme en lui-même avec impatience ! :)

+1 -0

Je suis sous Windows, donc pour tester … c'est mort. Mais sinon ça à l'air sympa. Comment tu fait pour faire un émulateur, j'ai jamais compris ? Il te faut le code du jeu original, non ?

Et si un memebre du staff passe par là, je pense que le forum Présentation de vos projets serait plus adapté, il faudrait peut-être déplacer ?

Merci :) Pour ce qui est de la partie Présentation de vos projets, je ne l'ai pas posté là bas car c'est un projet court et de toute façon je l'ai fini (bien sûr je peux toujours l'améliorer :) )

Et pour ce qui est d'un tuto émulation basique, c'est une très bonne idée ! Je m'y pencherais dès que j'aurais le temps et l'expérience (je m'essaie à l'émulation d'une Gameboy, palier entre Space Invaders et la NES niveau complexité)

+1 -0

Lu'!

Très sympa comme projet (même si j'ai la flemme de le compiler).

Quelques commentaires par rapport à ton code :

  • Ta classe CPU (pareil : IOManager, MemoryManager) est copiable/affectable. C'est voulu ? Etant (à mon sens, peut être pas au tien), une classe à sémantique d'entité, ce ne devrait pas être le cas,
  • Pour Motherboard c'est certain car elle a un destructeur virtuel,
  • Préférer "using" à "typedef",
  • Tu as quelques includes qui traînent dans des headers alors qu'ils n'y servent pas,
  • Dans IOManager, ton 256 est fixé en dur, tu y accèdes par l'intermédiaire de port de type "byte", pour la maintenance, on aurait bien envie que ce 256 soit calculé par rapport au type byte (je sais que ça ne changera pas, mais quand même ;) ),
  • Pour les différentes positions (RAM, VRAM, ROM …) dans "MemoryManager" on aurait bien envie de renvoyer des array_views (probablement C++17, mais facile à implémenter) pour intégrer un contrôle de bornes facile,
  • (Les tailles des patterns pour les OP-codes pourraient être fixée au compile-time puis accédés par au runtime par string_view),
  • Il y a une raison particulière pour que tu traites les op-codes invalides par exception plutôt que par assertion dans le constructeur de OpDefinition ?

Sinon le code est très bien foutu :) .

Par contre, ça manque de documentation (moi, j'dis ça hein … :P ) et de tests (ou des preuves ?? plein de preuves !).

Merci pour les retours :)

Pour ce qui est des classes CPU/IOManager/Motherboard… qui devraient être non-copyable, c'est un gros oubli de ma part ^^

Pour la taille du string pour les Opcodes, oui, elle devrait être gérée avec une assertion… Encore un oubli (en fait j'utilisais une exception car à la base je voulais faire en sorte que les définitions des opcodes soient chargés au runtime dans un fichier script style lua, mais trop de travail au bout du compte). Hop, corrigé !

Je vais me pencher au niveau des array_view et string_view, je n'en avais pas entendu parler :) C'est une sorte de référence constante mais en mieux pour les arrays ?

Et pour un string de taille constante à la compilation, faut obligatoirement passer par un std::array<char, 10> ?

Et encore merci pour ces conseils !

+0 -0

Encore un oubli (en fait j'utilisais une exception car à la base je voulais faire en sorte que les définitions des opcodes soient chargés au runtime dans un fichier script style lua, mais trop de travail au bout du compte).

Stellaris

Cela ne change rien en fait. Ce n'est pas à cet étape que le contrôle doit se trouver dans ce genre de cas mais avant. Par exemple, tu pourrais avoir une fonction "build_if_parsed" qui commence par vérifier que l'OpCode est correct, renvoie une exception si ce n'est pas le cas, sinon produit l'objet valide. Le contrôle de valeur au runtime est bien sorti du constructeur qui ne garde qu'une unique responsabilité : construire.

Je vais me pencher au niveau des array_view et string_view, je n'en avais pas entendu parler :) C'est une sorte de référence constante mais en mieux pour les arrays ?

Stellaris

http://guillaume.belz.free.fr/doku.php?id=c_1y_-_les_tableaux#la_gestion_des_vues

Et pour un string de taille constante à la compilation, faut obligatoirement passer par un std::array<char, 10> ?

Stellaris

En fait, faute de mieux, ce serait char const [FIXED_SIZE], puis string_view pour la manipulation. A voir si on peut faire mieux en jouant avec les traits de basic_string, mais j'ai jamais poussé le concept.

Merci pour les conseils :)

Je viens de voir l'article de gbdivers sur les tableaus en c++1y, la vache j'ai appris des trucs oO Et franchement, vivement le support complet du c++17 ! ^^

+0 -0

Salut,

C'est un bien chouette projet ça. Seul problème : le dossier roms et data ne sont visiblement pas présents dans ton dépôt.

J'ai tout de même pris la peine de compiler sous Windows avec quelques ressources que j'ai pu trouver sur Internet. Le jeu est très lent, mais il marche. :)

Améliorations possibles :

  • ne pas fermer le jeu si les roms sont introuvables (il faudrait au moins une boîte de message indiquant l'erreur) ;
  • afficher la liste des commandes de jeu ;
  • permettre à l'utilisateur de modifier ces commandes (pour ma part, n'ayant pas un clavier AZERTY, ce n'est pas hyper agréable pour jouer).

Pour ceux qui veulent tester sous Windows : SpaceInvadersEmu-win32.zip (7,21 Mo)

J'ai poussé les dossiers rom et data dans le dépôt, ça devrait être bon :) Et ouais, je vais signaler les exceptions par une boîte de dialogue ! Pour ce qui est des touches, je vais balancer la configuration dans un fichier ini

EDIT : Ok, c'est poussé, j'ai amélioré le code grâces aux conseils de Ksass' Peuk et j'ai ajouté un message d'erreur lors du lancer d'une exception fatale :)

Sinon les touches c'est :

c pour insert coin

t pour tilt (si un taré alcoolique secoue la borne d'arcade)

P1:

s pour start

z pour tirer

q pour gauche

d pour droite

P2:

k pour start

i pour tirer

j pour gauche

l pour droite

Et pour ce qui est des performances, tu peux me dire à combien d'IPS (en bas à droite de la fenêtre) en moyenne tu es ? Avec mon PC antédéluvien j'ai ~160 000 ips en tournant

<troll> en même temps môa j'utilise un vrai OS :P </troll>

+1 -1

Visiblement, tu as du pousser le mauvais dossier data, car à part invadersOverlay.png, tous les autres fichiers sont manquants (notamment les effets sonores).

Maintenant que tu as ajouté des boîtes de messages, j'ai simplement un crash plutôt qu'une runtime error lorsqu'une ROM est introuvable, ce qui n'est pas beaucoup mieux. On dirait que visiblement les QMessageBox ne peuvent pas être crées tant que l'application n'est pas exécutée. C'est peut-être spécifique à Windows, je sais pas. Ça fonctionne sur ton OS ?

Quand je joue, j'ai environ 60'000-70'000 IPS. Je sais pas trop ce que ça signifie, mais c'est pratiquement injouable pour ma part (bon, mon PC n'est pas extraordinaire non plus). Je pense qu'il y a principalement un manque d'optimisation, car faire tourner cette même ROM avec un autre émulateur (en l’occurrence MAME) donne un résultat parfaitement fluide.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte