RetroChallenge, Avril 2018

Sommaire

Une paire peu probable

Une paire peu probable

Pour ma première participation au RetroChallenge, je prévois tenter le projet suivant:

  • Conçevoir un adaptateur permettant le raccord d'un NES Zapper sur un PC modèle Tandy 1000 EX.
  • Coder un clone de Duck Hunt ou un mini-jeu original si je trouve l'inspiration.
  • Utiliser le mode graphique 16 couleurs Tandy. (Il serait regrettable de ne pas le faire!)
J'aimerais aussi tenter, si le temps le permet:
  • Suporter le mode 320x200 CGA standard, et faire fonctionner le jeu sur un clone XT avec carte CGA.
  • Explorer la possibilité de faire fonctionner un Zapper sans modifications avec un écran VGA.
  • Permettre au jeu de fonctionner avec une souris (possiblement à un rythme accéléré pour maintenir la difficulté)


Introduction

À l'éopque où les ordinateurs personnels étaient un concept relativement nouveau, les écrans dédiés n'étaient pas donnés. Les PCs à cet époque étaient donc souvent pourvus de sorties vidéo composite, permettant aux utilisateur d'utiliser simplement une télévision déjà en leur possession. Tout comme les consoles de jeu quoi!

Certains ordinateurs tels que le PC d'IBM étaient offerts avec une carte CGA comportant une sortie video composite, mais les capacités graphiques (4 couleurs) étaient limités et il fallait installer une carte additionelle pour pouvoir y raccorder des joysticks. D'autres systèmes, tels que ceux de la série Tandy 1000 (depuis 1984) offrait un mode graphique 16 couleur, des ports joystick intégrés et un circuit de son amélioré. Beaucoup mieux adapté aux jeux vidéos!

La console NES a été lancée en 1985, et nous savons tous qu'elle se raccorde directement à un écran de télévision. Un pistolet nommé Zapper était fourni avec la console, permettant de viser des objets sur l'écran et fonctionnait par détection de lumière. Afin d'éviter que les sources lumineuses autres que l'écran interfère, le Zapper comporte des filtres ajustés pour un fonctionnement optimal sur écran avec rafraîchissement 60Hz vertical et environ 15 kHz horizontal.

Je pense qu'il est possible de faire fonctionner le Zapper même si la NES est remplacée par un Tandy 1000 ou un système avec carte CGA. Les fréquences de rafraîchissement sont les mêmes, ou assez près pour ne pas s'en soucier. Je crois qu'il est intéressant d'essayer, et comme l'ordinateur que je vais utiliser et les Zapper sont de la même époque, il me semble qu'il aurait été parfaitement possible à l'époque d'acheter un Zapper pour son Tandy 1000, si un adaptateur et des jeux compatibles avait existé. (Est-ce le cas et je l'ignore!?)

Pour RC2018/04, je prévois réaliser un adaptateur pour le Zapper et créer un jeu le supportant. Pour le jeu, j'utiliserai ma librairie graphique et les outils que j'ai développés pour RATillery. Mais le jeu en soi, les graphiques (et la musique s'il y en a) verront le jour entre le 1er et 30 Avril, conformément aux règles du RC2018/04.

De plus, si j'ai le temps (et à défaut de l'avoir, je le ferai ensuite) j'aimerais tester une théorie. Il parait que le Zapper ne fonctionne pas avec les écrans VGA en raison de la fréquence de rafraîchissement horizontale qui est trop élevée. J'aimerais d'abord vérifier cette affirmation. Ensuite, j'aimerais tenter de trouver une manière de faire fonctionner un Zapper non-modifié avec un écran VGA.


Mise à jour 3 Avril

J'ai commencé par jouer un peu à Duck Hunt afin de vérifier le bon fonctionnement du Zapper lui-même, et m'assurer qu'il fonctionnait avec les écrans monochromes comme celui que j'allais utiliser pour commencer. (Je compte utiliser l'énorme télé couleur plus tard). Duck Hunt a fonctionné à merveille, alors j'ai branché le Tandy 1000 EX et préparé une disquette pour le projet.

Test de Duck Hunt

Test de Duck Hunt

Préparation du Tandy 1000

Préparation du Tandy 1000



Prochain but: Fabriquer un adaptateur. Se servir du port de joystick était la solution évidente en raison de la présence d'une sortie 5 volt (pour alimenter le Zapper) et de deux entrées boutons ( une pour la gâchette, l'autre pour la détection de lumière).

J'ai déniché une rallonge NES et le boût d'un vieux câble DIN-6 dans ma boîte de pièces. Après avoir déduit le code de couleur utilisé par les deux câbles, je les ai utilisé pour fabriquer un adaptateur, selon le tableau suivant:

Port joystickZapperCommentaire(s)
5v5v
GNDGND
Button 1GâchetteTiré vers le GND lorsque le joueur fait feu
Button 2DetectContinuellement tiré vers le GND, sauf lorsque de la lumière est détectée (plus d'info là dessus sous peu)/td>
J'ai été très attentif et pris le temps de vérifier plusieurs fois, et j'ai également sondé le connecteur de joystick du Tandy 1000 EX afin d'être certain que l'alimentation était bien là où je m'y attendais.
DIN6 du bac de pièces

DIN6 du bac de pièces

Déduction du brochage

Déduction du brochage

Vérification du voltage

Vérification du voltage

Adaptateur câblé

Adaptateur câblé



L'état des deux boutons du joystick peut être surveillé en lisant le port 0x201. Les deux bits les plus significatifs en représentent l'état. J'ai écrit un petit programme BASIC affichant continuellement la valeur du port. Je me suis aussi arrangé pour qu'il y ait un rectangle blanc clignotant à l'écran afin de le viser avec le Zapper en observant l'effet.

J'ai également installé l'oscilloscope sur la sortie de détection de lumière du Zapper afin de pouvoir bien voir le comportement et le timing.

Programme de test

Programme de test

Gâchette au repos, pas de lumière

Gâchette au repos, pas de lumière

Gâchette active, pas de lumière

Gâchette active, pas de lumière

Gâchette active, lumière détectée

Gâchette active, lumière détectée



Cela fonctionnait! Mais la détection de lumière n'était pas stable. Sur l'image ci-dessus à droite (celle avec le rectangle blanc) affiche 176, mais ce nombre ne faisait qu'apparaitre momentanément.

À l'écran de l'oscilloscope, j'ai observé qu'il y avait des impulsions d'environ 2ms. Et en y réfléchissant, c'est tout à fait logique. Nos yeux ne peuvent le voir, mais la surface du rectangle n'est jamais "allumée" au complet. Le Zapper arrive à "voir" le faisceau dessiner chaque ligne, alors que la précédente est déjà éteinte. Dès que le balayage est rendu sous le rectangle, le Zapper cesse d'indiquer présence de lumière, et ce jusqu'au prochain rafraichissement vertical, ce qui a lieu à chaque 16ms (à 60 Hz)

Alors que j'écris ces lignes, je soupçonne que pointer le Zapper vers un écran complètement blanc résulterait peut-être en une impulsion beaucoup plus longe. (À essayer!)
Test avec Oscilloscope

Test avec Oscilloscope

L'impulsion

L'impulsion



Le code que j'avais utilisé jusqu'à ce point lisait le port et affichait la valeur à l'écran en boucle. Le BASIC interprété étant déjà lent, l'écriture de nombres sur l'écran en décimal entre chaque lecture du registre était évidemment bien trop lent pour détecter l'impulsion.

J'ai alors créé un nouveau programme qui surveillait le port sans afficher la valeur, attendait que la gâchette soit tirée (a très bien fonctionné) puis attendait l'impulsion indiquant de la lumière, avec une boucle dont l'échéance en indiquait l'absence, c'est à dire une cible manquée. Mais cela n'a pas suffit à obtenir une détection fiable.

Détecter une impulsion ne durant que 2ms en lisant un port en boucle en BASIC est probablement impossible sur cette machine lente. Mais c'est sans importance, je n'utilisais le langage BASIC qu'en tant qu'outil temporaire et pratique pour expérimenter rapidement. Le jeu sera évidemment écrit en assembleur. La prochaine étape sera donc de refaire l'expérience en assembleur, pour voir s'il sera possible d'obtenir un système fonctionnant bien.



Mise à jour 9 Avril

Tel que prévu, j'ai refait le test en assembleur et tout semble fonctionner très bien, bien qu'il s'agisse pour le moment d'une implémentation incomplète. En effet, en ce moment, il suffit de viser n'importe quelle zone lumineuse de l'écran pour "atteindre" sa cible. Ou pire encore, viser un écran voisin fonctionne aussi... Mais quoi qu'il en soit, la faisabilité du projet est confirmée!

Cible manquée

Cible manquée

Cible atteinte

Cible atteinte



La procédure employée est décrite ci-dessous:

  • Attends que la gâchette soit tirée
  • Une fois tirée:
    • Attends le rafraichissement vertical
    • Surveille le signal de détection de lumière pendant une trame complète
    • Si de la lumière a été détectée, considère la cible atteinte
    • Sinon, cible manquée
  • Attends que la gâchette soit relâchée
  • Retourne au début
Afin de corriger les défauts dont le paragraphe précédent fait mention, je crois qu'il suffit de faire la détection en deux phases:
  • Première phase: Les cibles sont repeintes en noir, et on voudra que le Zapper ne détecte PAS de lumière.
  • Deuxième phase: Les cibles seront repeintes en blanc, et on voudra détecter de la lumière.
Seuls les tirs répondant aux deux conditions, c'est à dire l'absence de lumière lors de la première trame suivie de présence de lumière dans la seconde, seront considérés comme réussis.

S'il faut gérer plusieurs cibles, il suffira de les repeindre en blanc à tour de rôle. Le moment exact du retour de la lumière à l'endroit visé permettra d'identifier laquelle a été touchée.

Tout ceci corresponds à peu près à ce que fait le jeu Duck Hunt. En fait, la seule différence est que dans Duck Hunt, c'est l'écran au complet qui devient noir plutôt que seulement les cibles. Est-ce pour des raisons cosmétiques ou plutôt pour une raison technique? Mes prochaines expériences me le diront. À suivre...


Mise à jour 15 Avril

Toujours pas de jeu à présenter cette semaine, mais les bases sont bien en place et je crois avoir une bonne compréhension de ce dont le Zapper est capable. Alors je devrais avoir un démo jouable sous peu!

Rejet des objets passifs

Les défauts facilitant la triche que j'ai expliqués la semaine passée sont corrigés tel que prévu. D'abord couvrir la cible de noir lors d'une première trame puis la couvrir de blanc pour la deuxième, le tout en vérifiant que le signal provenant du Zapper varie en conséquence. Le fonctionnement est démontré dans les images suivantes: Le carré au centre de l'écran n'est pas une cible (c'est un objet passif) alors que celui près du coin supérieur gauche est une cible en bonne et due forme. Les tirs visant l'objet passif n'ont aucun effet alors que ceux visant la cible près du coin sont correctement détectés. C'est ce qu'il faut pour les jeux car on ne veut pas de réaction si un tir touche le décor ou le score, par exemple.

Cible visée et touchée!

Cible visée et touchée!

Objet passif, cible manquée.

Objet passif, cible manquée.

Code de rejet des objets passifs

Code de rejet des objets passifs


Bien entendu, le désavantage de cette technique est que l'objet scintille un peu lorsqu'on tire la gâchette.

Déduction du Y par chrono

Le code de détection de lumière dont j'ai parlé la semaine passée attends le rafraîchissement vertical puis surveille ensuite le signal provenant du Zapper pendant une trame complète. Pourquoi? Car le moment exact auquel le Zapper indiquera présence de lumière n'est pas connu d'avance. Ce moment dépends de la hauteur de l'objet visé.

En y repensant cette semaine, j'ai compris que cela signifiait qu'il serait possible de déterminer la hauteur Y du tir en chronométrant le temps écoulé entre la fin de la période de rafraîchissement vertical et l'apparition de la lumière perçue par le Zapper. J'ai donc écrit un nouveau programme de test affichant une colonne sur toute la hauteur de l'écran, puis ajouté du code pour compter le nombre d'itérations avant la présence de lumière et le nombre d'itérations total pendant une trame. (Je parle d'itérations puisqu'il s'agit de compteurs dans la boucle de polling surveillant le signal du Zapper et un registre d'état la carte vidéo. Les valeurs exactes dépendent de la vitesse de l'ordinateur).

Le mode vidéo utilisé comportant 200 lignes, Y est environ équivalent à [cycles_première_lumière] * 200 / [cycles_total_trame]. Le logiciel de test calcule Y et affiche à côté de la colonne un carré rouge/rose dont la hauteur correspond. En pratique, il semble y avoir une erreur d'échelle, et je crois que ceci pourrait être causé par les 40 lignes de noir supplémentaires que la carte vidéo ajoute probablement pour générer un signal NTSC 240p. Je regarderai cela de plus près si je me sers de cette technique dans un jeu...

Au fait, je me demande s'il y a des jeux NES utilisant cette technique, n'ayant examiné de près que Duck Hunt... Quoi qu'il en soit, pour un jeu avec beaucoup de cibles non alignés verticalement, la procédure de rejet des objets passifs peut être faite d'un seul coup pour toutes les cibles, plutôt qu'une par une.

Y=162

Y=162

Y=125

Y=125

Y=78

Y=78

Y=42

Y=42



J'ai aussi profité de l'occasion pour faire un test de couleur, afin de voir comment le Zapper réagirait. Toutes les cibles colorés sont bien détectés, même à une bonne distance. Sur un fond noir, il serait probablement possible de détecter une cible sans la couvrir de blanc...

Du côté droit de l'écran, la série de traits de diverses épaisseurs était pour savoir s'il y avait un minimum pour la détection, mais il se trouve que toutes les lignes, même la plus mince, sont détectées.



Mise à jour 24 Avril

Un premier prototype de jeu

Ces derniers jours, j'ai passé du temps sur un premier concept de jeu. Il s'agit d'un mini jeu où il faut vaporiser des gouttes d'eau à l'aide du Zapper avant qu'elles ne tombent sur votre clavier. Reste encore quelques trucs à faire: Le rythme d'apparition des gouttes ainsi que la vitesse à laquelle elles tombent doit aller en augmentant. Lorsque plus que la moitié des touches sont brisées le jeu doit s'arrêter. Il faudrait aussi mémoriser et afficher le meilleur score.

J'ignore jusqu'où je me rendrai d'ici la fin de RC2018-04, mais j'aimerais au moins faire un deuxième jeu.

Voici quelques screenshots réalisés avec DOSBox:
Clavier intact, tout va bien

Clavier intact, tout va bien

Deux touches brisées

Deux touches brisées

Quatre touches brisées, ça va mal!

Quatre touches brisées, ça va mal!



Et bien entendu, le jeu fonctionne sur mon Tandy 1000 EX:



C'est tout pour l'instant, je vous quitte avec l'animation d'une touche qui se désintègre suite au court-circuit causé par la goutte d'eau...



Mise à jour 25 Avril

Zapper vs. Écran VGA

Il est bien connu que le Zapper, du moins le modèle conçu pour les télévisions NTSC, fonctionne avec une fréquence de rafraîchissement vertical de 60Hz, et horizontale de 15.75 kHz. Sur un écran VGA, il exite bien un mode à 60Hz, mais la fréquence horizontale est environ le double, soit 31.46875 kHz. Cela n'est donc pas, en théorie du moins, adéquat pour le Zapper.

À l'aide d'une petite expérience, j'ai tenté de vérifier à quelle plage de fréquence le Zapper répond. J'ai installé un LED blanc sur la sortie d'un générateur de fréquence générant une onde carrée, puis j'ai aligné un Zapper sur le LED. Un oscilloscope surveillait la sortie du générateur de fréquence et la sortie de détection de lumière du Zapper. Voici une photo de l'expérience:



J'ai pu constater que le Zapper en ma possession, lorsqu'on lui présente une onde carrée continue et un contraste très élevé (c'est bien le cas puisque ce LED est plutôt aveuglant), accepte des fréquences d'environ 1 kHz jusqu'à 74 kHz! Et à une distance plus élevée (on passe de 1m à 3m) le plafond était situé à 38 kHz.

Je regrette de ne pas avoir essayé de diminuer l'intensité du LED pour être juste au dessus du seuil détection, pour ensuite varier la fréquence. Puisque aucun écran n'est aussi brillant que le LED que j'utilisais, impossible de savoir environ quelles sont les limites en pratique à une intensité d'écran cathodique normal...



Mais comme 31.5kHz semblait être à l'intérieur de la plage de réponse du Zapper, je l'ai pointé à un écran VGA puis j'ai jeté un coup d'oeil à l'oscilloscope. Malheureusement, rien. Même en dessinant un rectangle blanc en mode 12h (VGA 640x480@60Hz).

Au cours des jours qui suivirent, j'ai eu les réflexions suivantes:
  • Bien que le Zapper ait réagit à un signal fort de plus que 3 fois la fréquence nominale de 15 kHz attendue, cela ne veut certainement pas dire qu'il soit aussi sensible aux fréquences dans les extrême qu'il l'est à 15 kHz. Il est en fait raisonnable de s'attendre à une courbe de réponse plus ou moins en forme de cloche.
  • L'écran VGA que j'ai utilisé n'émet pas beaucoup de lumière, même avec les ajustements au maximum. L'intensité lumineuse émise étant largement inférieure à celle de l'expérience avec un LED, il se pouvait simplement que cela ne suffisait pas.
Pour obtenir plus de lumière, j'ai refait une tentative avec un écran plus lumineux. Mais cela n'a pas suffit. Bon.

Mais j'avais une idée depuis le début du projet, née des réflexions suivantes:
  • Lorsque le Zapper est pointé sur un zone blanche d'un écran dont le rafraîchissement horizontal est à 31 kHz, il reçoit des impulsions espacés d'environ 32 microsecondes. Il s'agit du faisceau lumineux dans le champ de vision du zapper répété pour chaque ligne tracée.
  • Lorsqu'il s'agit d'une écran télé ou CGA, le temps qui sépare ces impulsions est le double, soit environ 63 microsecondes. Et dans ces conditions, le Zapper fonctionne bien.
« Et si, en mode VGA 640x480@60Hz, je dessinais une ligne sur deux en noir? Les Zapper ne verrait deux fois moins d'impulsions, et le temps séparant chaque impulsion doublerait: Environ 63 microsecondes!»

L'idée semblait prometteuse. À l'aide de QBasic, sélectionné le mode 12 puis dessiné 3 zones de test: Une première parfaitement blanche (contrôle), une deuxième dont une ligne sur deux est en blanc, puis une dernière où une ligne sur trois est en blanc.
QBasic! Que de souvenirs...

QBasic! Que de souvenirs...

Les 3 zones de test

Les 3 zones de test



J'ai pointé le Zapper sur chaque zone et consulté l'oscilloscope pour voir si le Zapper détectait quelque chose. Aucune réaction sur le carré blanc ni sur la zone à une ligne sur trois, mais sur celle d'une ligne sur deux, un signal est détecté! Hourra!

Zone blanche 100%. Pas d'impulsion.

Zone blanche 100%. Pas d'impulsion.

Zone une ligne sur trois. Pas d'impulsion.

Zone une ligne sur trois. Pas d'impulsion.

Zone une ligne sur deux. Ça fonctionne!

Zone une ligne sur deux. Ça fonctionne!



Conclusion: Il semble que le Zapper peut fonctionner avec un écran VGA lorsqu'une ligne sur deux est en noir. Je vais fabriquer un adaptateur Zapper à joystick DB15 et faire un test complet! Mais tout d'abord, il me faut ajouter le support du mode VGA 12h à 16 couleurs à ma librairie graphique maison...


Mise à jour 27 Avril

Suite au test concluant avec un écran VGA il y a deux jours, j'ai fabriqué un adaptateur Zapper à port joystick DB15 afin de tester la boucle complète (Zapper + PC + Écran VGA cathodique).

Schéma

Schéma

Les pièces

Les pièces

Assemblage...

Assemblage...

Terminé!

Terminé!



Après avoir mis du temps sur ma librairie graphique pour gérer le mode VGA 16 couleurs en 640x480, j'ai modifié un des tests précédents (voir section du 15 Avril). J'ai installé l'adaptateur et j'ai lancé le test.

Rappel: Le carré au centre de l'écran n'est pas une cible (c'est un objet passif) alors que celui près du coin supérieur gauche est une cible en bonne et due forme. Lorsque le test détecte que la cible a été touchée, le mot "detected" s'affiche dans le coin. Sinon, c'est le mot "miss".

Installation de l'adaptateur

Installation de l'adaptateur

Écran de test

Écran de test



Cela fonctionne parfaitement à bout portant et jusqu'à une distance d'environ 1.5m. Plus loin, il devient difficile de toucher la cible. Soit qu'elle est trop petite, soit que l'écran n'est pas assez lumineux, et sans doute une combinaison des deux.

À bout portant sur la cible

À bout portant sur la cible

À bout portant sur l'objet passif

À bout portant sur l'objet passif

D'un peu plus loin: Sur la cible

D'un peu plus loin: Sur la cible

D'un peu plus loin: Sur l'objet passif

D'un peu plus loin: Sur l'objet passif



Note: Ce petit programme de test fera parti du release final avec code source que je rendrai disponible à la fin du projet.

Bon, assez dévié du but pour le moment, j'ai un jeu à terminer!


Mise à jour 29 Avril

Je continue d'apporter des touches finales au mini-jeu de vaporisation de gouttes d'eau. Tout d'abord l'élément le plus visible, l'écran titre.

Un ami a tracé l'esquisse suivante, qui représente de manière un peu humoristique la situation du jeu:

J'ai réduit la taille de l'image et soigneusement retracé les countours. Afin que l'image soit la plus belle possible sur un écran de télévision, j'ai évité les traits minces d'un seul pixel qui génèrent des artefacts de couleur.

J'ai coloré l'intérieur des différentes zones. J'ai bien apprécié avoir 16 couleurs, ce qui est bien moins contraignant que les 4 couleurs que procure CGA. Toutefois j'aurais bien aimé avoir une couleur « peau »... Tant pis, j'ai fait comme dans Commande Keen et utilisé du blanc. Voici le résultat:



Pas mal! Mais lorsque j'ai essayé sur la télé:



Oh? Qu'est-ce qui arrive à mon jaune? Et le vert des pantalons est bien pâle? J'ignore s'il s'agit d'un problème avec mon Tandy 1000 EX ou si la sortie vidéo NTSC donne toujours ce genre de résultats. Évidemment l'idéal serait d'utiliser un écran CGA, mais je n'en ai pas.

Afin d'obtenir la couleur jaune recherchée, j'ai utilisé du brun (ce qui corresponds généralement à du jaune foncé sur certains écrans). Pour le petit problème de vert, j'ai simplement utilisé du vert foncé.

Sur un écran CGA (et dans DOSBox) cela donne ceci, qui n'est pas trop mal (pour le clavier, pas certain, mais bon...):


La même image sur la télé, le résultat est bon:



Outre l'écran titre, j'ai corrigé de petits détails tels que le score qui n'était pas visible sur un écran de télé puisqu'il était trop prés du bord, l'augmentation graduelle de la vitesse et de la difficulté, l'affichage du meilleur score à date (gardé en mémoire RAM seulement) et l'ajout d'une banière affichée lors du retour au DOS. J'ai aussi ajouté un écran « Game over ».

Game over

Game over

Bannière à la sortie

Bannière à la sortie

Nouveau record

Nouveau record


J'ai une version VGA en cours de mise au point qui permet au choix de jouer avec une souris ou avec un Zapper. Les dimensions de la zone de jeu s'adaptent automatiquement à la plus haute résolution! Reste à voir si ce sera utilisable avec le Zapper ou si les cibles seront trop petites. Si c'est le cas, soit j'augmenterai la taille des grapiques, soit je dessinerai un rectangle plus gros que la cible lors de la détection.



Les versions VGA et CGA (pas encore commencé) seront disponibles quelques jours ou semaines après la fin de RC2018/04 puisqu'il ne reste que quelques heurs pour finir la version Tandy du jeu (objectif principal).


Mise à jour 30 Avril (finale)

Encore quelques heures, car si j'ai bien compris RC2018/04 prends fin à minuit! Heureusement, car j'avais encore quelques trucs à faire avant la fin:
  • Afficher des instructions en bas de l'écran d'accueil, telles que « Tirer la gâchette pour commencer » et « Appuyez sur ESC pour quitter ». Du plus, si un pilote de souris est présent: « Cliquez pour comencer ».
  • Active le mode souris ou le mode Zapper en fonction de l'action à l'écran d'accueil.
  • Permettre de sortir de l'écran « Game Over » en tirant la gâchette. Évite au joueur d'aller au clavier pour rejouer.
  • Faire un release.
J'ai eu un souci sur le Tandy 1000 EX. Lorsque je faisais appel à l'interruption 33h (pilote souris) l'écran se remplissait progressivement de caractères et le système plantait! J'ai examiné le vecteur d'interuption avec la commande DEBUG.COM de DOS et j'ai constaté que le vecteur 33h est initialisé à 0000:0000... Comme je n'ai pas de pilote souris (ni de souris) sur cette machine, c'est sans doute le BIOS (ou DOS 2.11) qui l'initialize ainsi. J'ai ajouté du code pour détecter cette situation et éviter un plantage.

Ah les surprises de dernière minute!
Le problème

Le problème

Examen de la mémoire

Examen de la mémoire



Une fois ce petit problème corrigé, les deux écrans, avec et sans souris, fonctionnent:
Avec souris

Avec souris

Sans souris

Sans souris




À propos du release

Les fichiers faisant partie du premier release sont les suivants:
  • rain.com (28K) : Le jeu « Rain Zapper » présenté ci-dessus.
  • zapdemo1.com (14K) : Le test du 9 Avril qui affiche deux carrés. Pratique pour tester votre adaptateur si vous en fabriquez un.
  • zapdemo2.com (14K) : Le test de chrono. pour calculer le Y. Pratique aussi pour tester la performance du Zapper avec différentes couleurs et épaisseurs de traits.
IMPORTANT: Ces logiciels ne fonctionnent que sur les ordinateur avec carte video Tandy, tel qu'intégrée dans le Tandy 1000 EX. Sous DOSBox, il faut utiliser 'machine=tandy'. Note: Avec la vieille version de DOSBox incluses dans Linux Debian, la fonction souris de DOSBox dans ce mode vidéo ne fonctionne pas correctement. Le pointeur efface le contenu de l'écran et les valeurs X rapportées sont incorrecte (semblent être divisées par deux).

Oui mais, et CGA, EGA et VGA alors!?

C'est à venir d'ici quelques jours! Au début CGA n'était qu'un objectif secondaire, et pour VGA je ne savais même pas encore que c'était possible. C'est prêt! Voir ci-dessous.

Prêt à essayer le jeu?

Le jeu Rain Zapper est disponible ci-dessous. Si le code source vous intéresse, visitez le projet GitHub (ci-dessous également).
Version 2
27 mai 2018 (Dimanche)
Version 2, maintenant pour Tandy, CGA et VGA!
  • Ajout d'une version VGA
  • Ajout d'une version CGA
Fichier(s):
rainzap2.zip (57.2 KB)
Afficher les versions précédentes
Version 1
30 avril 2018 (Lundi)
Première version. Tandy seulement.
Fichier(s):
rainzap1.zip (24 KB)
Ce projet est aussi disponible sur GitHub!
Pour suggérer de nouvelles fonctionnalités, signaler un problème ou contribuer au projet, vous pouvez m'écrire ou utiliser le dépôt GitHub:
https://github.com/raphnet/rc201804


Conclusion

Commentaires et réflection sur le projet

C'était ma première participation au RetroChallenge, et pour résumer: J'ai adoré. Ce concours était la parfaite excuse pour jouer avec du vieux matériel: Utiliser un écran CRT couleur ambre, manipuler des disquettes 5.25", coder en assembleur 8088, utiliser un peu GW-Basic et QBasic... Mais aussi pour apprendre de nouveaux trucs: Comprendre à fond le fonctionnement du Zapper, utiliser nasm un peu mieux qu'avant en me servant de STRUC, concevoir des macros nasm pour gérer facilement des listes d'objets (les gouttes d'eau dans le jeu), découvrir et entrevoir la puissance de la programmation VGA, utiliser le pilote de souris via int 33h...

Vais-je reparticiper au Retro Challenge? Si je peux, c'est certain!

Est-ce que j'ai atteint mes buts?

En résumé: Oui!

Mes objectifs principaux étaient:
  • Conçevoir un adaptateur permettant le raccord d'un NES Zapper sur un PC modèle Tandy 1000 EX.
    Oui! C'était l'élément essentiel, je m'en suis chargé dès la première semaine.
  • Coder un clone de Duck Hunt ou un mini-jeu original si je trouve l'inspiration.
    Oui! Finalement j'ai réalisé un mini-jeu original: Vaporiser les gouttes d'eau avant qu'elles n'atteigne et n'endommage un clavier au bas de l'écran.
  • Utiliser le mode graphique 16 couleurs Tandy.
    Oui! Ce n'était pas trop difficile puisque ce n'était pas la première fois que j'utilsais ce mode video. J'ai en fait réutilisé du code de RATillery.

Objectifs secondaires, à réaliser si le temps le permet:
  • Suporter le mode 320x200 CGA standard, et faire fonctionner le jeu sur un clone XT avec carte CGA.
    Non. Je n'ai pas eu le temps de réaliser une version CGA. Mais ce sera fait d'ici quelques jours. Toutefois pour le test sur XT, ce sera difficile puisque je n'ai pas de port de jeu. Mais je pourrais peut-être utiliser le port parallèle...
  • Explorer la possibilité de faire fonctionner un Zapper sans modifications avec un écran VGA.
    Oui!. J'ai fait quelques expériences qui m'ont permit de vérifier que c'était faisable. On parle bien ici d'un écran VGA Cathodique bien sûr. L'objectif était « explorer la possibilité », mais j'ai fait un peu plus: Une version VGA du jeu est en cours de réalisation!
  • Permettre au jeu de fonctionner avec une souris.
    Oui!. Le jeu comporte un mode souris, parfait pour jouer dans DOSBox ou sur un PC qui n'est pas doté d'un adaptateur pour Zapper.


Epilogue - 27 Mai

RC2018/04 a pris fin le 30 Avril sans que j'aie eu le temps de réaliser les versions CGA et VGA pour permettre d'utiliser un Zapper sur des systèmes non-Tandy. J'y ai travaillé pendant ces dernières semaines et ces deux nouvelles versions du jeu sont maintenant disponibles!

Version CGA

J'ai modifié chaque dessin pour n'utiliser que 4 couleurs. L'écran titre m'a posé quelques difficultés, mais cela m'a permit d'appendre des techniques intéressantes telles que l'utilisation de doubles contours à certains endroits, notamment sur le clavier, sans quoi les bras noirs seraient invisibles sur ce fond noir.

Côté code, je n'ai ensuite eu qu'à utiliser ma librairie graphique CGA (celle que j'avais créée pour RATillery) et recompiler.
J'ai choisi d'utiliser la palette CGA Cyan/Magenta/Blanc/Noir car il me fallait absolument une couleur évoquant de l'eau (le cyan). En ce moment, c'est la version faible intensité de cette palette qui est mise en oeuvre. Sur un écran sombre, il se peut donc que le Zapper ne recoive pas assez de lumière mais je n'ai pas eu ce problème. Une solution serait d'activer la version haute intensité pour le temps de détection seulement, ce qui ferait aussi un effect de flash..



Version VGA

Cette version m'a pris plus de temps car la programmation VGA était pour moi une nouveauté. J'utilise le mode 12h (640x480, 16 couleurs), un mode planaire, ce qui est complètement différent des modes CGA et Tandy. Heureusement le livre Graphics Programming Black Book était là pour tout expliquer.

Côté graphiques, VGA offre par défaut les mêmes 16 couleurs que Tandy. J'ai choisi de les conserver, ce qui devait me permettre de réutiliser les graphiques de la version Tandy.

J'avais publié un screenshot du prototype de la version VGA le 29 Avril (voir plus haut) où je montrais un jeu avec le double des touches à protéger au bas de l'écran (Le double, car on passe de 320 pixels à 640 pixels). Mais je formulais également mes craintes à propos de la taille des cibles, craintes qui se sont avérés fondées: Les cibles était trop difficiles à atteindre autrement qu'à boût portant.

Pour palier à ce problème, j'ai simplement doublé la taille de tous les éléments graphiques. Les touches qui faisaient 32x32 font 64x64, les gouttes qui faisaient 16x16 font désormais 32x32, et ainsi de suite. Comme je tenais à profiter de la résolution plus haute, j'ai passé beaucoup de temps à retoucher les images en ajoutant manuellement des points pour adoucir les courbes, arrondir certaines zones ou augmenter les détails. Pour l'écran titre, j'y ai passé quelques heures!



Cette version fonctionne parfaitement bien sur mon 386SX (l'ordinateur le plus lent doté d'une carte VGA que je possède) avec l'adaptateur Zapper à DB15. Toutefois en mode souris, le pointeur disparait lorsqu'il est près du haut de l'écran. C'est que le jeu cache le pointeur pendant qu'il dessine les objets qui se sont déplacés. Lorsque le pointeur est affiché à nouveau, le balayage de l'écran a déjà commencé et si le faisceau est rendu plus bas que l'endroit où le pointeur doit apparaître, ce dernier est invisible.

Il faudrait que j'accélère mon code de dessin, ce qui est encore possible! Car en ce moment les gouttes sont dessinées en copiant des données de la mémoire vive vers la mémoire vidéo. Il faudrait que les gouttes d'eau soient stockées en mémoire vidéo, ce qui permettrait d'utiliser des techniques de copie plus rapide (VGA permet de copier 4 octets d'un coup via la lecture puis l'écritude d'un seul octet). Autre piste d'optimisation: Le jeu pourrait gérer l'affichage du curseur lui-même, plutôt que de faire des appels répétés à int 33h. Cela permettrait de stocker le pointeur en mémoire vidéo également. Le pilote de souris pourrait le faire, mais ce n'est vraiment pas certain.

Téléchargement

Voir la section de téléchargement ci-dessus.


Références



Avertissement

Je compte publier les schémas pour l'adaptateur, ainsi que le code source des jeux l'utilisant. L'avertissement ci-dessous s'appliquera.
Je ne saurais être tenu responsable pour les dommages que l'utilisation des informations ou la mise en œuvre des instructions présentées sur cette page pourrait causer à votre équipement, à vous-même ou à autrui. Aussi, je ne donne aucune garantie quant à l'exactitude des informations et à leur fonctionnement.