Port 2 Controller Input (buttons always registered as "pressed")
Moderator: Moderators
- mechadendrite
- Posts: 10
- Joined: Tue May 17, 2022 9:00 pm
- Location: North America
Port 2 Controller Input (buttons always registered as "pressed")
Hello! I'll get right into it. I'm working on making a Pong game for a tutorial (Nerdy Nights, of course), but I've run into a bit of a snag I don't understand. For some reason, the "down" button on controller 2 is always active, sending the second player's paddle sliding down the screen.
I thought maybe there was an issue in my code, but there wasn't anything major I could see that would tell the program that the second player's controller was sending "down" constantly. My ReadController2 subroutine is basically the exact same as my ReadController1 subroutine, except it's reading from $4017 instead of $4016. I checked the other buttons, and they seem to function correctly without any issues, I can try and send the paddle back up no problem (although, if I set the carry flag before doing the arithmetic for decreasing the paddle's y position, pushing up just stops it in place. Leaving the flag clear allows it to slowly inch back up the screen).
I then checked Mesen's debugger to see what my program was loading from my second controller, hoping it'd shed some light. As I recall, it always recieved the down button as "pressed". I checked it again after tinkering with it today just before making this post, and I see that it loads a value of $FF after reading from the second controller, meaning that every button is considered "pressed". This is perplexing, because 1) I'm not pressing any buttons for controller 2, and 2) Controller 1 receives a value of $00 when I'm not inputting anything on it. If I'm not inputting anything on controller 2, and the code for reading it is the same as the code for reading controller 1, which behaves correctly, then why is controller 2 constantly inputting all buttons?
By the by, if any code excerpts are required to give sound advice, just ask and I'll post up the relevant/requested sections.
I thought maybe there was an issue in my code, but there wasn't anything major I could see that would tell the program that the second player's controller was sending "down" constantly. My ReadController2 subroutine is basically the exact same as my ReadController1 subroutine, except it's reading from $4017 instead of $4016. I checked the other buttons, and they seem to function correctly without any issues, I can try and send the paddle back up no problem (although, if I set the carry flag before doing the arithmetic for decreasing the paddle's y position, pushing up just stops it in place. Leaving the flag clear allows it to slowly inch back up the screen).
I then checked Mesen's debugger to see what my program was loading from my second controller, hoping it'd shed some light. As I recall, it always recieved the down button as "pressed". I checked it again after tinkering with it today just before making this post, and I see that it loads a value of $FF after reading from the second controller, meaning that every button is considered "pressed". This is perplexing, because 1) I'm not pressing any buttons for controller 2, and 2) Controller 1 receives a value of $00 when I'm not inputting anything on it. If I'm not inputting anything on controller 2, and the code for reading it is the same as the code for reading controller 1, which behaves correctly, then why is controller 2 constantly inputting all buttons?
By the by, if any code excerpts are required to give sound advice, just ask and I'll post up the relevant/requested sections.
What a horrible night to have a curse.
Re: Port 2 Controller Input (buttons always registered as "pressed")
It sounds like a simple miss somewhere in the code but it's not something I can make good guesses without at at least seeing the code.
Could you share the input reading code (where you check what buttons are pressed and stores the states in RAM) as well as the input handling code (where the input states are actually used in the code)? In Nerdy Nights they might have both those merged together (I forgot), in that case just post the whole controller code.
You may also wanna check if you have setup some joystick or something on your computer to the second controller for the emulator that is misbehaving.
Could you share the input reading code (where you check what buttons are pressed and stores the states in RAM) as well as the input handling code (where the input states are actually used in the code)? In Nerdy Nights they might have both those merged together (I forgot), in that case just post the whole controller code.
You may also wanna check if you have setup some joystick or something on your computer to the second controller for the emulator that is misbehaving.
- mechadendrite
- Posts: 10
- Joined: Tue May 17, 2022 9:00 pm
- Location: North America
Re: Port 2 Controller Input (buttons always registered as "pressed")
Sure thing! First up is the input reading:Pokun wrote: ↑Sun May 22, 2022 1:15 pm It sounds like a simple miss somewhere in the code but it's not something I can make good guesses without at at least seeing the code.
Could you share the input reading code (where you check what buttons are pressed and stores the states in RAM) as well as the input handling code (where the input states are actually used in the code)? In Nerdy Nights they might have both those merged together (I forgot), in that case just post the whole controller code.
You may also wanna check if you have setup some joystick or something on your computer to the second controller for the emulator that is misbehaving.
Code: Select all
ReadController1:
LDA #$01
STA $4016 ; polling input for controller 1
LDA #$00
STA $4016
LDX #$08 ; setting up loop counter
:
LDA $4016
LSR A ; send controller status bit into carry
ROL buttons1 ; send status bit from carry into buttons1 (a variable elsewhere in code)
DEX
BNE :- ; this loop runs 8 times, once for each button
RTS
ReadController2:
LDA #$01
STA $4017 ; polling input for controller 2
LDA #$00
STA $4017
LDX #$08 ; loop counter
:
LDA $4017
LSR A ; controller status bit into carry
ROL buttons2 ; carry into buttons2 (also a variable)
DEX
BNE :- ; this loop runs 8 times, once for each button
RTS
Code: Select all
MovePaddle1Up:
JSR ReadController1
LDA buttons1
AND #%00001000 ; is "up" being pressed?
BEQ MovePaddle1UpDone ; if not, skip everything
LDA paddle1ytop
CMP #TOPWALL ; is the top of the paddle colliding with the upper bound of the screen?
BCC MovePaddle1UpDone ; only continue if it is not
SBC paddlespeed ; 1, in this case
STA paddle1ytop
CLC
ADC #$08 ; offset to render the bottom sprite of the paddle properly
STA paddle1ybottom
MovePaddle1UpDone:
MovePaddle1Down:
JSR ReadController1
LDA buttons1
AND #%00000100 ; is "down" being pressed?
BEQ MovePaddle1DownDone
LDA paddle1ybottom
CMP #BOTTOMWALL ; is the bottom of the paddle colliding with the lower bound of the screen?
BCS MovePaddle1DownDone ; BCS here because paddle1ybottom would have to be greater than/equal to BOTTOMWALL to be colliding
ADC paddlespeed
STA paddle1ybottom
SEC
SBC #$08 ; offset to render top paddle sprite properly
STA paddle1ytop
MovePaddle1DownDone:
Code: Select all
MovePaddle2Up:
JSR ReadController2
LDA buttons2
AND #%00001000 ; is "up" being pressed?
BEQ MovePaddle2UpDone
LDA paddle2ytop
CMP #TOPWALL ; is the top of the paddle colliding with the upper bound?
BCC MovePaddle2UpDone
SBC paddlespeed
STA paddle2ytop
CLC
ADC #$08 ; sprite offset
STA paddle2ybottom
MovePaddle2UpDone:
MovePaddle2Down:
JSR ReadController2
LDA buttons2
AND #%00000100 ; is "down" being pressed?
BEQ MovePaddle2DownDone
LDA paddle2ybottom
CMP #BOTTOMWALL ; is the bottom sprite colliding with the lower bound?
BCS MovePaddle2DownDone
ADC paddlespeed
STA paddle2ybottom
SEC
SBC #$08 ; sprite offset
STA paddle2ytop
MovePaddle2DownDone:
What a horrible night to have a curse.
Re: Port 2 Controller Input (buttons always registered as "pressed")
Change $4017 to $4016.mechadendrite wrote: ↑Sun May 22, 2022 1:28 pmCode: Select all
ReadController2: LDA #$01 STA $4017 ; polling input for controller 2 LDA #$00 STA $4017
Suggested: One controller reading routine that reads both. No need to call it again when a button press doesn't match, just read the controllers once per frame.
Re: Port 2 Controller Input (buttons always registered as "pressed")
To explain further, while each joypad has its own register for reading, there is only a single shared write register for them. When you write 1 and then 0 to $4016, both controllers see that and latch their current button state. Writing to $4017 is actually an entirely unrelated register called the frame counter.
And indeed, a controller-reading function is normally only called once per frame; there's generally no reason to read more often than that, and it may lead to undesirable behavior to do so (allowing opposite directions to be pressed in a single frame of game logic, which causes problems in a lot of games). You might also want to learn about using the X register avoid repeating all this code; you can index with X equal to 0 for player 1, and then do it again with X equal to 1 for player 2, and your player variables would need to be placed one after the other (buttons1 followed immediately by buttons2) so you can use X as an index to get the appropriate variable per player. Maybe that's something coming up in the tutorial, though; I'm not sure.
And indeed, a controller-reading function is normally only called once per frame; there's generally no reason to read more often than that, and it may lead to undesirable behavior to do so (allowing opposite directions to be pressed in a single frame of game logic, which causes problems in a lot of games). You might also want to learn about using the X register avoid repeating all this code; you can index with X equal to 0 for player 1, and then do it again with X equal to 1 for player 2, and your player variables would need to be placed one after the other (buttons1 followed immediately by buttons2) so you can use X as an index to get the appropriate variable per player. Maybe that's something coming up in the tutorial, though; I'm not sure.
Re: Port 2 Controller Input (buttons always registered as "pressed")
Ah yes that is probably the problem. $4016 is the output register used to latch all controllers (including expansion port controllers) so it must be written to both times. Writing to $4017 does not latch any controllers.
I'm not sure what Fiskbit meant by using the X register. I think Mechadendrite is already doing that isn't he? But yes you would normally just read both controllers in the same routine, that way you only need to write to $4016 once. But that is just a small optimization and not important for making it work.
This is how my controller reading routine looks like (asm6 syntax):
This code also reads the two Famicom expansion port controllers (con III and IV) by shifting both bit 0 and bit 1 of $4016/$4017 into RAM registers. It then merges them with con I and II using ORA. This is a good habit for any game that uses one or two controllers, and most commercial games do this too. It means that people with Famicoms (like me) can use any controller we want with your game instead of just the two hardwired ones. Nerdy Nights doesn't teach this so consider this a bonus lesson.
As Movax and Fiskbit both said you should only call this controller reading routine once per frame, typically the first thing in your main loop. This makes sure that all logic uses the same "snapshot" of your controllers' states, avoiding any inconsistencies which can be the cause of bugs.
Another bonus lesson you won't learn in Nerdy Nights is to use metasprites.
Instead of moving both the top and bottom parts of the paddle, just decide one of them to be the "parent" sprite and the other the "child" sprite, and only move the parent in your input handler. Then somewhere after that in your code you have a separate routine that updates the X- and Y-positions of all child sprites to a certain relative of their respective parent sprites. This way you only have to move one hardware sprite per "metasprite" (paddle). You are almost doing this, but you update the child sprite (bottom paddle part) inside the input handler which is wasteful since you need to do it both for when moving up and when moving down, and would also make the code longer if you decide to make the paddle longer by adding more child sprites to it.
About any other game more complex than Pong that uses more hardware sprites for each metasprite and also have more complex movement than just up and down will benefit from this much more.
I'm not sure what Fiskbit meant by using the X register. I think Mechadendrite is already doing that isn't he? But yes you would normally just read both controllers in the same routine, that way you only need to write to $4016 once. But that is just a small optimization and not important for making it work.
This is how my controller reading routine looks like (asm6 syntax):
Code: Select all
con_read:
;Reads current controller button states.
lda #$01
sta $4016 ;set $4016.0
lsr a
sta $4016 ;clear $4016.0, controllers latched
ldx #$08 ;loop counter for 8 buttons
@loop:
lda $4016 ;get button data from D0 (con I) and D1 (con III)
lsr a ;shift button data from D0 into carry
rol con_state+0 ;rotate carry into a RAM register (con I buttons)
lsr a ;shift button data from D1 into carry
rol temp+0 ;rotate carry into a RAM register (con III buttons)
lda $4017 ;get button data from D0 (con II) and D1 (con IV)
lsr a ;shift button data from D0 into carry
rol con_state+1 ;rotate carry into a RAM register (con II buttons)
lsr a ;shift button data from D1 into carry
rol temp+1 ;rotate carry into a RAM register (con IV buttons)
dex
bne @loop
@merge: ;merge controller I with III and II with IV using OR
lda temp+0
ora con_state+0
sta con_state+0 ;OR con III with con I
lda temp+1
ora con_state+1
sta con_state+1 ;OR con IV with con II
rts
As Movax and Fiskbit both said you should only call this controller reading routine once per frame, typically the first thing in your main loop. This makes sure that all logic uses the same "snapshot" of your controllers' states, avoiding any inconsistencies which can be the cause of bugs.
Another bonus lesson you won't learn in Nerdy Nights is to use metasprites.
Instead of moving both the top and bottom parts of the paddle, just decide one of them to be the "parent" sprite and the other the "child" sprite, and only move the parent in your input handler. Then somewhere after that in your code you have a separate routine that updates the X- and Y-positions of all child sprites to a certain relative of their respective parent sprites. This way you only have to move one hardware sprite per "metasprite" (paddle). You are almost doing this, but you update the child sprite (bottom paddle part) inside the input handler which is wasteful since you need to do it both for when moving up and when moving down, and would also make the code longer if you decide to make the paddle longer by adding more child sprites to it.
About any other game more complex than Pong that uses more hardware sprites for each metasprite and also have more complex movement than just up and down will benefit from this much more.
Re: Port 2 Controller Input (buttons always registered as "pressed")
Using a temporary variable for reading expansion port controllers is not necessary... Most games do it in a significantly faster way:
One reason to keep the amount of time spent reading controllers down is to reduce the chances of corrupted reads caused by DPCM samples that might be playing. The longer the controller-reading code takes, the higher the chances that it'll be interrupted by a DPCM fetch. If a high-frequency sample is playing and the controller-reading code is too slow, the chances of it getting interrupted could be 100%, meaning it'll be very hard for you to get an accurate read.
Code: Select all
lda $4016
and #%00000011 ;keeps only the relevant bits
cmp #$01 ;sets the carry if bits 0 or 1 are set
rol con_state+0
Re: Port 2 Controller Input (buttons always registered as "pressed")
I had meant using an index register (usually X) to avoid all of this code repetition. You don't need two duplicate copies of all of this code for each joypad or for each player; you can do $4016,index or buttons,index. Avoiding code duplication leads to code that is cleaner, easier to understand, and easier to maintain such that they don't begin to diverge and develop bugs.
- mechadendrite
- Posts: 10
- Joined: Tue May 17, 2022 9:00 pm
- Location: North America
Re: Port 2 Controller Input (buttons always registered as "pressed")
Ahhhh, now that makes much more sense. I'll have to get in the habit of consulting the NesDev wiki pages for the more important memory locations more frequently! That controller routine is a hot tip, also. The Nerdy Nights tutorial seems to separate the controller input code, but this is a lot more convenient, I'll definitely be doing it this way in the future. Also very glad that I've made things more accessible for people with other controllers, that's pretty awesome!Pokun wrote: ↑Sun May 22, 2022 3:43 pm Ah yes that is probably the problem. $4016 is the output register used to latch all controllers (including expansion port controllers) so it must be written to both times. Writing to $4017 does not latch any controllers.
I'm not sure what Fiskbit meant by using the X register. I think Mechadendrite is already doing that isn't he? But yes you would normally just read both controllers in the same routine, that way you only need to write to $4016 once. But that is just a small optimization and not important for making it work.
This is how my controller reading routine looks like (asm6 syntax):This code also reads the two Famicom expansion port controllers (con III and IV) by shifting both bit 0 and bit 1 of $4016/$4017 into RAM registers. It then merges them with con I and II using ORA. This is a good habit for any game that uses one or two controllers, and most commercial games do this too. It means that people with Famicoms (like me) can use any controller we want with your game instead of just the two hardwired ones. Nerdy Nights doesn't teach this so consider this a bonus lesson.Code: Select all
con_read: ;Reads current controller button states. lda #$01 sta $4016 ;set $4016.0 lsr a sta $4016 ;clear $4016.0, controllers latched ldx #$08 ;loop counter for 8 buttons @loop: lda $4016 ;get button data from D0 (con I) and D1 (con III) lsr a ;shift button data from D0 into carry rol con_state+0 ;rotate carry into a RAM register (con I buttons) lsr a ;shift button data from D1 into carry rol temp+0 ;rotate carry into a RAM register (con III buttons) lda $4017 ;get button data from D0 (con II) and D1 (con IV) lsr a ;shift button data from D0 into carry rol con_state+1 ;rotate carry into a RAM register (con II buttons) lsr a ;shift button data from D1 into carry rol temp+1 ;rotate carry into a RAM register (con IV buttons) dex bne @loop @merge: ;merge controller I with III and II with IV using OR lda temp+0 ora con_state+0 sta con_state+0 ;OR con III with con I lda temp+1 ora con_state+1 sta con_state+1 ;OR con IV with con II rts
As Movax and Fiskbit both said you should only call this controller reading routine once per frame, typically the first thing in your main loop. This makes sure that all logic uses the same "snapshot" of your controllers' states, avoiding any inconsistencies which can be the cause of bugs.
Ooh, now this also makes a lot of sense. I was starting to get a little annoyed with having to write the same lengthy code for sprite handling over and over again! One thing I'm immediately curious about is how one handles collision with metasprites, though. I can update my sprite-updating subroutine easily enough, changing it so it only uses the variable for the paddle top and simply offsetting the sprites for the paddle bottoms by 8 pixels, but the system I'm tinkering with for this Nerdy Nights example has collision code that looks like this:Pokun wrote: ↑Sun May 22, 2022 3:43 pm Another bonus lesson you won't learn in Nerdy Nights is to use metasprites.
Instead of moving both the top and bottom parts of the paddle, just decide one of them to be the "parent" sprite and the other the "child" sprite, and only move the parent in your input handler. Then somewhere after that in your code you have a separate routine that updates the X- and Y-positions of all child sprites to a certain relative of their respective parent sprites. This way you only have to move one hardware sprite per "metasprite" (paddle). You are almost doing this, but you update the child sprite (bottom paddle part) inside the input handler which is wasteful since you need to do it both for when moving up and when moving down, and would also make the code longer if you decide to make the paddle longer by adding more child sprites to it.
About any other game more complex than Pong that uses more hardware sprites for each metasprite and also have more complex movement than just up and down will benefit from this much more.
Code: Select all
CheckPaddle1Collision:
LDA ballx
CMP #PADDLE1X
BCS CheckPaddle1CollisionDone ; is ballx < paddlex?
LDA bally
CMP paddle1ytop
BCC CheckPaddle1CollisionDone ; is bally > paddle1ytop?
CMP paddle1ybottom
BCS CheckPaddle1CollisionDone ; is bally < paddle1ybottom?
LDA #$00
STA ballleft ; ball is not moving left anymore
LDA #$01
STA ballright ; bounce
CheckPaddle1CollisionDone:
What a horrible night to have a curse.
- mechadendrite
- Posts: 10
- Joined: Tue May 17, 2022 9:00 pm
- Location: North America
Re: Port 2 Controller Input (buttons always registered as "pressed")
I'll have to keep that bit about conflict with the audio samples in mind for later. I think I understand what's happening here re: code, doing the CMP here sets the carry whether it's bit 0 or bit 1 that's set, so it effectively merges the input from both into one, which is then stored in the controller input variable. What happens if input comes in from both controller 1 and controller 3, though? Which is prioritized?tokumaru wrote: ↑Sun May 22, 2022 4:10 pm Using a temporary variable for reading expansion port controllers is not necessary... Most games do it in a significantly faster way:
One reason to keep the amount of time spent reading controllers down is to reduce the chances of corrupted reads caused by DPCM samples that might be playing. The longer the controller-reading code takes, the higher the chances that it'll be interrupted by a DPCM fetch. If a high-frequency sample is playing and the controller-reading code is too slow, the chances of it getting interrupted could be 100%, meaning it'll be very hard for you to get an accurate read.Code: Select all
lda $4016 and #%00000011 ;keeps only the relevant bits cmp #$01 ;sets the carry if bits 0 or 1 are set rol con_state+0
What a horrible night to have a curse.
- mechadendrite
- Posts: 10
- Joined: Tue May 17, 2022 9:00 pm
- Location: North America
Re: Port 2 Controller Input (buttons always registered as "pressed")
I'm not sure I follow you here, but code duplication is bad, that much I understand all too well. If you'd like to elaborate further about how to use the X index register to track player input instead of 2 separate variables, I'd love to hear more.Fiskbit wrote: ↑Sun May 22, 2022 4:18 pm I had meant using an index register (usually X) to avoid all of this code repetition. You don't need two duplicate copies of all of this code for each joypad or for each player; you can do $4016,index or buttons,index. Avoiding code duplication leads to code that is cleaner, easier to understand, and easier to maintain such that they don't begin to diverge and develop bugs.
What a horrible night to have a curse.
Re: Port 2 Controller Input (buttons always registered as "pressed")
Here's a conversion of your paddle moving code into a single generic function that can handle either player 1 or player 2, and code that calls it for each player. This is pretty quick-and-dirty, but hopefully illustrates what I mean.
Code: Select all
buttons: .res 2
kButtonRight = %00000001
kButtonLeft = %00000010
kButtonDown = %00000100
kButtonUp = %00001000
kButtonStart = %00010000
kButtonSelect = %00100000
kButtonB = %01000000
kButtonA = %10000000
paddle_y_top: .res 2
paddle_y_bottom: .res 2
paddle_speed: .res 1
; ...
JSR con_read
; Move paddles for players 1 and 2.
LDX #$00
JSR MovePaddle
INX
JSR MovePaddle
; ...
MovePaddle:
MovePaddle_Down:
LDA buttons,X
AND #kButtonUp
BEQ MovePaddle_UpDone ; if not, skip everything
LDA paddle_y_top,X
CMP #TOPWALL ; is the top of the paddle colliding with the upper bound of the screen?
BCC MovePaddle_UpDone ; only continue if it is not
; SEC
SBC paddle_speed ; 1, in this case
STA paddle_y_top,X
CLC
ADC #$08 ; offset to render the bottom sprite of the paddle properly
STA paddle_y_bottom,X
MovePaddle_UpDone:
MovePaddle_Down:
LDA buttons,X
AND #kButtonDown
BEQ MovePaddle_DownDone
LDA paddle_y_bottom,X
CMP #BOTTOMWALL ; is the bottom of the paddle colliding with the lower bound of the screen?
BCS MovePaddle_DownDone ; BCS here because paddle1ybottom would have to be greater than/equal to BOTTOMWALL to be colliding
; CLC
ADC paddle_speed
STA paddle_y_bottom,X
SEC
SBC #$08 ; offset to render top paddle sprite properly
STA paddle_y_top,X
MovePaddle1DownDone:
RTS
Re: Port 2 Controller Input (buttons always registered as "pressed")
If you plan on using DPCM samples, fortifying your controller-reading code is a must. You can either keep reading until two consecutive reads match, or reuse last frame's input if the second read doesn't match.mechadendrite wrote: ↑Sun May 22, 2022 5:01 pmI'll have to keep that bit about conflict with the audio samples in mind for later.
Yup.I think I understand what's happening here re: code, doing the CMP here sets the carry whether it's bit 0 or bit 1 that's set, so it effectively merges the input from both into one, which is then stored in the controller input variable.
Any value equal to or larger than 1 will cause the carry to be set after the CMP instruction (1 = button on controller 1, 2 = button on controller 3, 3 = button on both controllers), so the result is effectively the same as ORing the bits from both controllers, which means that pressed buttons always win over non-pressed buttons, no matter the controller.What happens if input comes in from both controller 1 and controller 3, though? Which is prioritized?
Re: Port 2 Controller Input (buttons always registered as "pressed")
Treat the metasprite as a single object and do your collision box relative from a single hot-spot. Naturally that might be the position of the parent sprite (top-left pixel of top paddle), but many game designers make up an arbitrary hot-spot in the middle of the metasprite, and in platform games it is common to use the middle pixel of the bottom row of pixels in the metasprite to simplify platform jumping logic.mechadendrite wrote: ↑Sun May 22, 2022 4:57 pm Ooh, now this also makes a lot of sense. I was starting to get a little annoyed with having to write the same lengthy code for sprite handling over and over again! One thing I'm immediately curious about is how one handles collision with metasprites, though. I can update my sprite-updating subroutine easily enough, changing it so it only uses the variable for the paddle top and simply offsetting the sprites for the paddle bottoms by 8 pixels, but the system I'm tinkering with for this Nerdy Nights example has collision code that looks like this:With similar code for paddle 2. If I'm to change this to better resemble the metasprites system, all of a sudden the variable for paddle1ybottom and paddle2ybottom seem like dead weight, even though things like this code and the movement handling use it to a large extent. I feel like I'm missing something here, maybe I should put it out of my mind for now and focus on completely finishing the Pong example. Either way, it's something I'll be studying more soon, I'll warrant. Thanks for the tips!Code: Select all
CheckPaddle1Collision: LDA ballx CMP #PADDLE1X BCS CheckPaddle1CollisionDone ; is ballx < paddlex? LDA bally CMP paddle1ytop BCC CheckPaddle1CollisionDone ; is bally > paddle1ytop? CMP paddle1ybottom BCS CheckPaddle1CollisionDone ; is bally < paddle1ybottom? LDA #$00 STA ballleft ; ball is not moving left anymore LDA #$01 STA ballright ; bounce CheckPaddle1CollisionDone:
But the simplest is to just use the top left pixel which is already used for sprite position. You need to know the height and width of your metasprite in pixels, then when you test for bottom collision you just add the height of the metasprite and for collision on the right side of the paddle you add the width.
You can use constants for your height and width to avoid magic numbers, or use RAM registers to store them if they are variable.
You never need to test collisions with the child sprites. They are just there for looks.
- mechadendrite
- Posts: 10
- Joined: Tue May 17, 2022 9:00 pm
- Location: North America
Re: Port 2 Controller Input (buttons always registered as "pressed")
Ahhh, I think I understand now. I've been too stuck on treating each individual sprite tile as if it were an object itself, I need to kind of "zoom out" and consider what I want the final metasprite object to look/act like and then code accordingly. Thanks for the clarification!Pokun wrote: ↑Mon May 23, 2022 11:30 am Treat the metasprite as a single object and do your collision box relative from a single hot-spot. Naturally that might be the position of the parent sprite (top-left pixel of top paddle), but many game designers make up an arbitrary hot-spot in the middle of the metasprite, and in platform games it is common to use the middle pixel of the bottom row of pixels in the metasprite to simplify platform jumping logic.
But the simplest is to just use the top left pixel which is already used for sprite position. You need to know the height and width of your metasprite in pixels, then when you test for bottom collision you just add the height of the metasprite and for collision on the right side of the paddle you add the width.
You can use constants for your height and width to avoid magic numbers, or use RAM registers to store them if they are variable.
What a horrible night to have a curse.