The Essence of the 8-bit 6502 programming for NES (Nintendo Entertainment System) should be the Sprites. So, what is a Sprite? A Sprite is a moving object in the game, e.g. Super Mario, plane, bullet.
Almost in every 8-bit NES games, there are spirits. There are at most 64 Sprites supported, which has the index from 0 to 63 inclusive. You can control the spirits and let them move in the screen.
There are two sizes/dimensions that can be defined for Sprites, either 8×8 (Single tile) or 8×16 pixels (Double tile). Every Sprite takes four byte to define, so 64 spirits takes up 256 bytes, in the SPRAM (Spirit RAM), which is independent from VRAM and RAM.
The way to access (read or write) SPRAM is quite similar to VRAM except that it only takes 1 byte (8 bit) to specify the address and every time when the data is written to SPRAM, the pointer/address is automatically incremented by 1 byte. So if you have some continuous data, you just have to set the address once.
The CPU mapping address is 0x2003 for SPRAM and the data address is 0x2004. For example, if you want to write 1 and 2 to the 7-th and 8-th byte of the SPRAM, you can do this:
1 2 3 4 | #define address(add) (*(u8 *)(add)) // macro to access the memory address(0x2003) = 7; // set the location to 7 address(0x2004) = 1; // write value 1 to 7-th address(0x2004) = 2; // write value 2 to 8-th (pointer address increments one) |
#define address(add) (*(u8 *)(add)) // macro to access the memory address(0x2003) = 7; // set the location to 7 address(0x2004) = 1; // write value 1 to 7-th address(0x2004) = 2; // write value 2 to 8-th (pointer address increments one)
The 256 bytes represent 64 spirits. The byte offset 0 to 3 denotes the first Sprite, the byte offset 4 to 7 denotes the second Sprite and this goes on to the 63 Sprite which is represented by byte offset 0xfc-0xff.
For each Sprite, the first byte is the y coordinate in pixel and the fourth byte is the x coordinate in pixel. The second byte is the tile number (known as index number of the pattern). The third number is the attribute for the Sprite (we will cover that in the future tutorial).
We can then have a macro to set the specified Sprite.
1 2 3 4 5 6 | #define address(add) (*(u8 *)(add)) // macro to access the memory #define putSP(n, x, y, t, a) address(0x2003)=n*4;\ address(0x2004)=y;\ address(0x2004)=t;\ address(0x2004)=a;\ address(0x2004)=x |
#define address(add) (*(u8 *)(add)) // macro to access the memory #define putSP(n, x, y, t, a) address(0x2003)=n*4;\ address(0x2004)=y;\ address(0x2004)=t;\ address(0x2004)=a;\ address(0x2004)=x
Now, we are going to show a tiny example that controls the spirit using joystick. [This tutorial] covers the details of using joysticks in 8-bit NES.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | #include "conio.h" #include "nes.h" #include "stdio.h" #include "stdlib.h" #include "string.h" typedef unsigned char u8; #define address(add) (*(u8 *)(add)) #define button_A 0x80 #define button_B 0x40 #define button_SELECT 0x20 #define button_START 0x10 #define button_UP 0x08 #define button_DOWN 0x04 #define button_LEFT 0x02 #define button_RIGHT 0x01 #define presskey(k) (key & (k)) #define iskey(k) (key == (k)) #define downkey(k) (okey!=key && (k)&key) #define upkey(k) (okey!=key && (k)&okey) #define putSP(n, x, y, t, a) address(0x2003)=n*4;\ address(0x2004)=y;\ address(0x2004)=t;\ address(0x2004)=a;\ address(0x2004)=x u8 read_joystick_1() { u8 n = 8, joy_state = 0; address(0x4016) = 01; address(0x4016) = 00; while(n){ joy_state = (joy_state<<1) | address(0x4016) & 1; --n; } return joy_state; } void main() { u8 key,x=100,y=60; address(0x2000) = 0x80; address(0x2001) = 0x1e; while(1){ key = read_joystick_1(); if(presskey(button_UP)) --y; if(presskey(button_DOWN)) ++y; if(presskey(button_LEFT)) --x; if(presskey(button_RIGHT)) ++x; waitvblank(); putSP(0,x,y,'*',0); gotoxy(0,0); cprintf("x:%-3d y:%-3d", x, y); } } |
#include "conio.h" #include "nes.h" #include "stdio.h" #include "stdlib.h" #include "string.h" typedef unsigned char u8; #define address(add) (*(u8 *)(add)) #define button_A 0x80 #define button_B 0x40 #define button_SELECT 0x20 #define button_START 0x10 #define button_UP 0x08 #define button_DOWN 0x04 #define button_LEFT 0x02 #define button_RIGHT 0x01 #define presskey(k) (key & (k)) #define iskey(k) (key == (k)) #define downkey(k) (okey!=key && (k)&key) #define upkey(k) (okey!=key && (k)&okey) #define putSP(n, x, y, t, a) address(0x2003)=n*4;\ address(0x2004)=y;\ address(0x2004)=t;\ address(0x2004)=a;\ address(0x2004)=x u8 read_joystick_1() { u8 n = 8, joy_state = 0; address(0x4016) = 01; address(0x4016) = 00; while(n){ joy_state = (joy_state<<1) | address(0x4016) & 1; --n; } return joy_state; } void main() { u8 key,x=100,y=60; address(0x2000) = 0x80; address(0x2001) = 0x1e; while(1){ key = read_joystick_1(); if(presskey(button_UP)) --y; if(presskey(button_DOWN)) ++y; if(presskey(button_LEFT)) --x; if(presskey(button_RIGHT)) ++x; waitvblank(); putSP(0,x,y,'*',0); gotoxy(0,0); cprintf("x:%-3d y:%-3d", x, y); } }
To compile the above example, use command cl65 -t nes -o sp.nes sp.c assumed the source C file is sp.c. You can then use any NES emulator (e.g. Virtual NES) to run the example.
The above example reads from joystick and control the Sprite which is the star and prints out the coordinates on the top-left corner of the screen.
The pre-compiled NES can be downloaded here.
–EOF (The Ultimate Computing & Technology Blog) —
loading...
Last Post: Bouncing Balls Animation Made in Processing Programming Language
Next Post: How to Revive Old Posts using PHP and Crontab
Hi, great tutorials, but I can figure out how to display more than 2 sprite on screen at the same time. If I display 3 differents, only the 2 lasts appear, they are not even flickering, any idea ?
Thanks
Do you have source code?
I believe the 8-bit FC maximum supports up to 15 spirits at a time, however, only 2 can be controlled by joysticks.
Thanks for your quick answer 😀
Yea here is the download link for my source code and the nes file :
https://mega.nz/#F!MUFVAAJY!hlXjrTt2Z1nMjhL3r2eyHA
putSP(0,x,28*8,10,0);
putSP(1,x+8,28*8,10,0);
putSP(2,x+16,28*8,10,0);
putSP(80,ball_x,ball_y,’*’,0);
All sprite numbers are differents, there are less than 8 sprite per line, I don’t understand x) .
Thanks
Hi ! I found the solution, you don’t need to put anything in 2003 address. I made this function : if you had the same problem as me, try it 🙂
void putSP(char x, char y, char t, char a){
address(0x2004)=y;
address(0x2004)=t;
address(0x2004)=a;
address(0x2004)=x;
}
Thanks for sharing!
Hey dude how would you do that with chr files for your character?
As in put your chr file on screen
Great Tutorial. More please.
Sure. glad you like it.
Thank you very much for all these tutorials. This was very interesting and help me get my feet wet in nes programming.
my pleasure.
How do you display more than
one sprite on the screen
I hope the tutorial can go on。It lets me go into the NES programing world.
Hello,
I have been thoroughly enjoying these tutorials on C programming in 6502. Thank you for this because i was having such a hard time trying to figure out how to set up 6502 assembly to be able to program for the NES. I was curious if there are going to be more tutorials past part 8? If not, should i learn more C and then try to apply it to what i have learned in these tutorials? I have learned C++ somewhat, but not any C. Some stuff i recognize, but a lot i do not.
Thanks,
EWS
Glad you like it..
yes, i will write more.. but too busy at the moment.