In this part we will put it all together and make a simple scrolling shooter on a space theme: the ship flies and shoots enemies with lasers
We need to implement the following game modes:
The code should be organized like this:
And still need to draw all the necessary graphics and write music.
Let's start with the splash screen, then make the game screen. For show of lives and points we use Sprite 0. Scrolling will be vertical. Here is the layout:
Some of the texts will also be implemented by sprites, such as "Pause" and "End of the game." This will simplify development.
The first logically coherent piece of the game is the splash screen, the game screen and the pause screen. The transition between them will be on the Start button.
Screensaver is the easiest to draw in Photoshop. Arial Black looks good in the name of the game, especially after adding a small perspective and a couple of filters. Compress up to 128 pixels wide, 4 colors, and translate to YY-CHR.
The ship and the stars for the background can be made immediately in YY-CHR. Stars randomly scribble, and the NES Screen Tool perfectly packs them into the RLE .h file. The text is saved in the table of names.
You can immediately make the victory screen, temporarily hanging it on the select. I also import music at this stage, the effects can be switched by arrows. Then I'll delete it all. In general, it is more correct to add music at the very end - the same track very quickly begins to irritate during debugging.
Now you can realize the ship and the logic of its movement by arrows. He continues to move with a small inertia a few frames after releasing the button - a slight hint at the laws of motion in space. In principle, it can be disabled on the basis of tests.
Next comes the score counter, updated every frame. It is made in another table of names, their substitution in the middle of the frame is implemented through a zero sprite. This technique is described in detail in one of the articles .
Vert_scroll2 = ((Vert_scroll & 0xF8) << 2); Sprite_Zero(); // PPU_ADDRESS = 0; SCROLL = Vert_scroll; SCROLL = 0; PPU_ADDRESS = Vert_scroll2;
There were difficulties: in a few seconds everything was leaving. In the FCEUX debugger, you can set breakpoints to write to the registers, put them on the scroll control registers - $ 2000, $ 2005, $ 2006. The values ​​were recorded correctly, but the installation of the top coordinates of the screen should be in V-blank, but in reality it was obtained on the 40th line. This happened because of the music, the procedures of which did not fit in V-blank. I moved them to the very end of the line, everything began to work normally.
Now you can do different game modes.
void main (void){ while (1) { // while (GameMode == TITLE_MODE){ // } while (GameMode == RUN_GAME_MODE){ // } while (GameMode == PAUSE_MODE){ // } while (GameMode == GAME_OVER_MODE){ // } while (GameMode == VICTORY_MODE){ // } } }
Sprite objects are better implemented by structures:
struct ENEMY { unsigned char anime; // unsigned char dir; // - 0, unsigned char Y; // unsigned char X; // unsigned char delay; // unsigned char type; // unsigned char move; // unsigned char count; // };
Enemies will accumulate in waves, so that its type will be established before its start.
Dropbox
Github
Separate structure for shells:
struct BULLET { unsigned char Y; // y = 0 - , unsigned char Y_sub; unsigned char tile; unsigned char attrib; unsigned char X; unsigned char X_sub; unsigned char Y_speed; // , - unsigned char X_speed; };
Sprites need to be implemented slightly differently - dynamically draw them every frame. The sprites are in the OAM buffer, the addresses in the memory are $ 200- $ 2FF, and first they are behind the screen — the vertical coordinate is greater than 0xF0. Then I draw a zero sprite, and after that I place each active sprite in the buffer. The order in which the sprites are placed in the buffer changes every frame, so the sprites flicker.
Larger metasprite should be prepared in the NES Screen Tool. I did not like the code from the Shiru example, I had to rewrite it. In particular, when the meta-list goes beyond the border of the screen, it does not appear on the opposite side, but is simply lost sight of. It does not fit the logic of the game, although it works faster. In addition, there were difficulties with the reflections of sprites. I had to write a script on Python, which converts ready-made meta data into a format convenient for importing into code. This slightly accelerated the process.
At this stage, the Down button adds shells, Select - adds enemies. Mirroring works for some of them. Collision handling is rewritten in Assembler and allows to increase the number of objects.
And now you need to rewrite everything again. Zero sprite handling and scrolling control occur in the NMI handler. Each frame there are about the following actions:
We need to think of a way to beautifully place enemy ships at the beginning of each wave. They do not appear at the same time either. Every enemy is active and moves until it gets hit, or until it leaves the screen. When all enemies from the wave disappear in one way or another, the Master_Delay timer is activated, counting frames to the next wave. When the waves end, the Boss mode begins.
Boss has a list of possible moves and hit points, which are removed on hits. When they are reset, simple sound effects and screen shake are included. After that, the game goes into Victory mode. From it you can start anew, with the preservation of lives and points.
The rest I propose to look at the game code. Use it as is, or as a basis for your project. Thanks for attention!
I want to thank everyone who helped me learn programming for NES, especially the forum.nesdev.com forum participants .
I learned a lot from the cc65 code examples that Shiru wrote. Some of these examples are used in this tutorial. He is the author of Famitone2 and the NES Screen Tool. His site with games and examples: one and two .
His two games are sold at GreetingCarts (Retroscribe) (site is dead - approx. Transl.)
I want to thank THEFOX for his help when I first started learning cc65. And for the examples that were previously on his site .
But you can still play his game, Streemerz.
Rainwarrior made a Coltrane demo, and gave a good example of working with sound.
And he has a game Lizard Game .
Thanks to all!
And now I have to do the same, but for the SNES console ...
Source: https://habr.com/ru/post/350426/
All Articles