Création de mon premier jeu NES, Ludum Dare

Malheureusement, pour créer un jeu NES, tout doit être écrit dans l'assemblage. Quand j'étais à Georgia Tech travaille sur mon diplôme de premier cycle en informatique, j'ai eu un projet dans lequel je devais écrire le code assembleur pour un système MIPS émulé. L'émulateur a été appelé SPIM (MIPS épelé à l'envers), et on dirait qu'il est toujours disponible en téléchargement aujourd'hui. Pendant le montage écriture est pas complètement étranger à moi, il est certainement pas une de mes choses préférées à faire. Cependant, il était ma seule option pour créer un jeu NES, et ce fut une belle remise puisque je ne l'avais pas écrit de code assembleur depuis des années.







Création de mon premier jeu NES, Ludum Dare

Exécution assembleur NES pour obtenir un sprite de se déplacer sur l'écran dans l'émulateur NES

Dans le troisième tutoriel. il va dans les détails du code assembleur 6502, qui est le jeu d'instructions utilisé par l'assembleur NES. Il a tous les opérateurs standards que vous attendez, comme « charge » et « magasin » pour l'écriture des registres et de la mémoire. Le NES est un système assez simpliste, qui a seulement trois registres qui sont les Accumulator, registre X et registre Y. Le jeu d'instructions a également des fonctions mathématiques simples comme « ajouter » et « soustraire », et les opérateurs de contrôle comme « sauter » et "branche". L'exemple de cette leçon a donné assez pour commencer à changer la couleur de l'écran en fonction de la valeur de la palette sélectionnée. Je l'ai testé en changeant la couleur de l'écran à différentes combinaisons de rouge, vert et bleu en modifiant le code binaire de l'octet qui contrôle la couleur de l'écran.

Afin de rendre les sprites pour mon jeu, j'ai utilisé un programme appelé AA-CHR. Il est un autre exécutable Windows, mais il fonctionne aussi bien sous Ubuntu en utilisant Wine. La seule question que je rencontrais était que je ne pouvais pas créer un bitmap dans Gimp, puis copiez et collez-le dans YY-CHR. Par conséquent, je créé mon propre « dessiné à la main » sprite visage souriant, qui se compose de quatre 8 × 8 tuiles de pixels.

Cependant, ce n'est pas très intéressant car il toujours juste compile dans le même jeu. En tant que point de départ, j'ai créé un fichier Game.xml et défini quatre couleurs qui définissent les quatre couleurs de la palette actuelle. Dans le fichier nes_palette.rb inclus, j'ai commencé à définir des couleurs basées sur la table de tutoriel, et emmagasinés les constantes de couleur et les valeurs hexagonales correspondantes dans une table de hachage. Puis, dans un autre script qui lit le fichier en utilisant Game.xml REXML et XPath, j'emmagasinés les couleurs de la palette définies par l'utilisateur dans le tableau. Ensuite, le code de la palette semble juste ces valeurs jusqu'à la table de hachage pour obtenir les valeurs hexadécimaux correctes pour écrire des données de palette en utilisant la directive Db. Enfin, j'ai ajouté une tag pour contenir ces éléments.

Création de mon premier jeu NES, Ludum Dare

Modification des couleurs de la palette d'un sprite en utilisant des valeurs définies par l'utilisateur dans un fichier XML

Création de mon premier jeu NES, Ludum Dare

Création d'un sprite simple dans YY-CHR

Création de mon premier jeu NES, Ludum Dare

Game.xml qui définit les différentes propriétés du jeu NES

Malheureusement, lorsque la balle atteint le bord droit de l'écran, il se boucle sur le côté gauche. En outre, si le bouton A est pressé à plusieurs reprises, une balle réinitialisera à l'emplacement du vaisseau spatial. J'ai créé une variable dans le code assembleur pour maintenir le drapeau « en vie ». Lorsque le bouton A est pressé, je charge un 1 (LDA # 01 $) et le stocker dans le drapeau vivant. Dans la section UpdateBullets, je charge la balle drapeau vivant et le comparer avec 1 (CMP # 01 $) et aller à la fin de la section si elle ne correspond pas (BNE). Cela fera l'arrêt de la balle si elle n'est pas vivant. En utilisant cette référence, j'ai appris comment vérifier si une valeur est supérieure ou inférieure à un nombre en utilisant la BCC et BCS ( « branche portent clairement » et « branche carry ensemble ») des instructions. En utilisant BCC, si l'emplacement x de la balle est inférieure à 240 (# $ F0), il passera à la fin de la section, sinon il mettra le drapeau en vie à zéro. Je 240 au lieu de 255, en raison des valeurs de retour en boucle autour de zéro lorsque la valeur dépasse la limite de 255 pour un octet. Tant que la vitesse de la balle est inférieure à 15 il devrait y avoir aucun problème. Il existe des techniques pour vérifier si la valeur additionnée dépasse 255, qui est utilisé pour les numéros 16 bits, donc je vais étudier plus tard. Pour résoudre l'autre problème de réinitialisation de la position de la balle lorsque A est pressé à plusieurs reprises, après que le bouton A est lu, je simplement chargé le drapeau de balle vivant, comparé à un et a sauté à la fin si elle est égale.







Création de mon premier jeu NES, Ludum Dare

Affichage joueur navire, missile, navire ennemi, et le score sur l'écran de jeu.

L'étape suivante a consisté à obtenir un ennemi à l'écran. Je YY-CHR pour créer un nouveau sprite navire ennemi sur mon spritesheet, qui est un autre sprite quatre tuiles. J'ai ajouté un tag à mon fichier XML qui contient toutes les propriétés de l'ennemi. Dans le code Ruby, j'ai ajouté un tableau pour contenir tous les ennemis, et une classe ennemie qui contient les emplacements de mémoire de la position X et Y de l'ennemi. J'ai aussi défini une variable de drapeau « vivant » pour l'ennemi, afin que je puisse le mettre à mort quand il est détruit. À l'avenir, je pourrais aussi ajouter une valeur de la vie, si l'ennemi prend plusieurs coups à tuer. Pour obtenir le déplacement de l'ennemi, je continue simplement soustraire la valeur de la vitesse du navire à la variable d'emplacement x, donc l'ennemi garderai toujours en mouvement vers le côté gauche de l'écran. Ce n'est pas vraiment impressionnant, mais au moins il se déplace ce qui donne au jeu un peu un défi. Quand est mis à zéro (# 00 $) drapeau « vivant » du navire, le navire ennemi cesse en mouvement.

Je choisis tout le code objet dans son propre script Ruby, qui a occupé les emplacements de mémoire de toutes les tuiles pour chacun des objets. Le code de mise à jour pour chacun des objets a également été déplacé vers un autre script contenant des sous-routines de mise à jour. Dans le script de mise à jour, les emplacements des carreaux sont fixés sur la base de l'emplacement de l'objet, plus un décalage qui est ajouté basée sur la ligne et la colonne de la tuile dans l'image-objet.

Ensuite, j'ai ajouté la détection de collision entre la balle et le navire ennemi. Cela a été accompli par une série de CMP, BCS, et les déclarations BCC qui vérifient pour voir si x et la position de la balle y sont à l'image-objet ennemi. Je soustrait 4 des bornes gauche et en haut du navire ennemi, de sorte qu'une collision est détectée lorsque le bullet de x ou y est égal au du navire ennemi de x ou y, car il n'y a pas de « supérieur ou égal à » opérateur. Lorsque la balle entre en collision avec le navire ennemi, la variable balle vivante est réglée sur 00 # $. Ensuite JSR est appelé à exécuter le code pour augmenter le score du joueur. Ce code de collision vérifie juste pour voir si le x de balle, l'emplacement y est à l'intérieur du rectangle de navire ennemi pour faire les choses simples. Modification du code pour faire rectangle / rectangle compliquerait les choses trop pour ce jeu simple.

L'étape suivante a consisté à obtenir un son simple à jouer quand une balle est tirée, que je suis arrivé à travailler en suivant ce tutoriel. Celui-ci joue un simple bip, et je l'ai modifié de sorte qu'il ne joue pas en permanence en permettant le compteur de longueur et la mise à 0001.

Création de mon premier jeu NES, Ludum Dare

Deux ennemis à l'écran avec pointage à six chiffres

J'ajouté un second ennemi en ajoutant à la matrice de l'ennemi défini dans le script d'objet, et définir les valeurs d'adresses appropriées pour x, y, et les valeurs d'index de tuiles. Pour l'instant, je viens tous les dupliqué collision balle et le code de mouvement ennemi pour le second ennemi. J'ai ajouté un varaible « GameTime » qui obtient incrémenté à chaque pause NMI d'interruption. Lorsque la variable gametime est égale à FF # $, alors les deux ennemis sont mis à vie et leur position y sont fixés à une position sur l'écran. Cela donne à l'apparition de nouveaux frai des navires ennemis.

Afin d'avoir un jeu sur l'état, j'ai ajouté une nouvelle variable pour suivre la vie du joueur. Chaque fois que le vaisseau du joueur entre en collision avec un navire ennemi, un nouveau sous-programme est appelé qui soustrait un de la vie du joueur, et définir l'état de jeu « GAME OVER » si le nombre de vies sont égales à zéro.

En utilisant mon éditeur de sprite, j'ai créé un titre graphique pour le jeu. Cependant, je trouve rapidement qu'il est pas si facile de changer toutes les tuiles de fond sur l'écran à la fois. J'ai essayé quelques petites choses, mais j'avais peu de chance. Après avoir creusé autour sur certains forums, je trouve qu'il est vraiment impossible de mettre à jour l'arrière-plan entier dans une mise à jour, comme la mise à jour de l'écran dans des environnements de programmation de jeux modernes. Une affiche a dit qu'il est possible de mettre à jour 3 lignes ou des colonnes dans une mise à jour, ou le jeu va commencer à ralentir. Pour l'instant je quitte l'écran titre, mais je suis en espérant éventuellement le faire fonctionner dans le jeu.

Création de mon premier jeu NES, Ludum Dare

écran titre ... à ajouter ... je l'espère.







Articles Liés