07. Controllers

There are 2 controller ports on the NES. You can read them anytime, using ports 4016 and 4017. Behind the scenes, it is strobing the 4016 port off and on, and then reading the buttons, 1 button at a time, times 8 reads, and then shifting them into a variable.

Neslib, use this function.

pad1 = pad_poll(0) to read controller 1.

pad2 = pad_poll(1) to read controller 2.

pad_state(0) or pad_state(1) if you forgot the value, and want to get it again without re-reading the controllers.

pad_trigger() gets the newly pressed buttons. I don’t use it. If you did, the order would be pad_trigger() and then pad_state(), since trigger runs the pad_poll() function. You don’t want to poll the controllers more than once per frame. You could read the controller like this…

pad1_new = pad_trigger(0);

pad1 = pad_state(0);

I wrote a function get_pad_new(), and it returns the PAD_STATET variable, which is the same thing that pad_trigger() returned… the new button presses. You need to run pad_poll() first, and then get_pad_new(). Generally, you would want both values so you could test buttons held down (say for running left and right) and buttons newly pressed (for jumping or pausing the game). This is what I do…

pad1 = pad_poll(0);

pad1_new = get_pad_new(0);

We use pad1_new for checking the pause button. We don’t want it to continuously pause and unpause if you hold Start down. It only change modes if you let go of the Start button and press it once again.

pad1 is a char (8 bit), basically a bit field of 8 buttons. And we have to apply bit masks to get the individual button presses.

if(pad1_new & PAD_START){
	Pause();
}

.

Sprite vs. sprite collisions.

I have each sprite controlled by a different controller. When they collide, I’m changing the background color.

if (collision){
	pal_col(0,0x30); 
}

And, I wrote a funtion that can test any sprite objects to see if they are touching. But you have to pass 2 structs (or arrays) of 4 bytes each, where the byte order is (x, y, width, height). I made this function take in 2 void pointers, because I wanted to be able to use different types of structs in the future. At least, that was the plan.

Here’s the example in the code…

collision = check_collision(&BoxGuy1, &BoxGuy2);

I suppose we could have put this inside the if condition, if you like.

if(check_collision(&BoxGuy1, &BoxGuy2))

The ASM funtion is an optimized version of this code…

if((obj1_right >= obj2_left) &&

(obj2_right >= obj1_left) &&

(obj1_bottom >= obj2_top) &&

(obj2_bottom >= obj1_top)) return 1;

else return 0;

And we know it’s working, because the screen turns white when they touch. The code breaks a bit when one object is half off the edge of the screen. It’s working well enough for my needs.

08_PadsPads2b

https://github.com/nesdoug/08_Pads/blob/master/Pads.c

https://github.com/nesdoug/08_Pads

Leave a comment