Jump to content
IGNORED

Simple Joystick Reading


Hornpipe2

Recommended Posts

My joystick checking routines span pages and pages. Has anyone got an efficient technique for polling joysticks? The best I can do is a series of:

 

CheckP1Up
   LDA #%00000001
   BIT SWCHA
   BNE CheckP1Down
   (do something)
CheckP1Down
   LDA #%00000010
   BIT SWCHA
   BNE CheckP1Right
   (do something)

...

 

It may be that what I'm really looking for is a good solution to: (decrement a counter, but only if it's above 0) or (decrement a counter, but if it goes below 0, reset it to N)

Link to comment
Share on other sites

  LDA SWCHA
 ROR
 BCS CheckP1Down
 (do P1 up)

CheckP1Down:
 ROR
 BCS CheckP1Left
 (do P1 down)

CheckP1Left:
 ROR
 BCS CheckP1Right
 (do P1 left)

CheckP1Right:
 ROR
 BCS CheckP0Up
 (do P1 right)

CheckP0Up:
etc

 

Only issue is you need to preserve A in the (do xxxx) sections. Can do something like: PHA (do something) PLA if you have the stack free, TAX (do something) TXA if you're routine isn't using X or TAY (do something) TYA if your routine isn't using Y

Link to comment
Share on other sites

You could also use a table approach:

 

	LDA  SWCHA
	
BIT  JOY_UP
BEQ  JoystickUp		
BIT  JOY_DOWN
BEQ  JoystickDown
BIT  JOY_LEFT
BEQ  JoystickLeft		
BIT  JOY_RIGHT
BEQ  JoystickRight

  ;=== No input

JMP  JoystickEnd

JoystickUp
...
JMP  JoystickEnd

JoystickDown
...
JMP  JoystickEnd

JoystickLeft
...
JMP  JoystickEnd

JoystickRight
...
JMP  JoystickEnd
  
;----------------------------------------
;Table. Has to be memory for BIT command	
;----------------------------------------

JOY_UP	 .byte #%00010000   ;Up bit
JOY_DOWN   .byte #%00100000   ;Down bit
JOY_LEFT   .byte #%01000000   ;Left bit
JOY_RIGHT  .byte #%10000000   ;Right bit

JoystickEnd

Link to comment
Share on other sites

My joystick checking routines span pages and pages. Has anyone got an efficient technique for polling joysticks? The best I can do is a series of:

 

CheckP1Up
   LDA #%00000001
   BIT SWCHA
   BNE CheckP1Down
   (do something)
CheckP1Down
   LDA #%00000010
   BIT SWCHA
   BNE CheckP1Right
   (do something)

...

It will depend on what you want to happen when the stick is moved one way or another, but the most efficient method I can think of is to read the joystick and store it all at once in a variable, then use that variable as an index into two tables-- an x motion table, and a y motion table. The following code is in batari Basic, but can be easily converted into assembly:

 

   dim joy0 = temp6

  joy0 = SWCHA / 16 : rem * for joy1, use joy1 = SWCHA

  player0x = player0x + xmotion[joy0] : rem * 0, 1, or 255 (i.e., -1)
  player0y = player0y + ymotion[joy0] : rem * 0, 1, or 255 (i.e., -1)

  rem * etc.

  data xmotion
  0,0,0,0,1,1,1,1,255,255,255,255,0,0,0,0
end

  data ymotion
  0,1,255,0,0,1,255,0,0,1,255,0,0,1,255,0
end

 

It may be that what I'm really looking for is a good solution to: (decrement a counter, but only if it's above 0) or (decrement a counter, but if it goes below 0, reset it to N)

I'm not sure what you're getting at here, or what it has to do with polling a joystick-- unless you're wanting to implement some kind of "debounce" logic? I think that for a joystick, you might want to use two debounce flags/counters-- one for x (left/right), and one for y (up/down).

 

Michael

Link to comment
Share on other sites

My joystick checking routines span pages and pages. Has anyone got an efficient technique for polling joysticks? The best I can do is a series of:

 

CheckP1Up
LDA #%00000001
BIT SWCHA
BNE CheckP1Down
(do something)
CheckP1Down
LDA #%00000010
BIT SWCHA
BNE CheckP1Right
(do something)
...

 

It may be that what I'm really looking for is a good solution to: (decrement a counter, but only if it's above 0) or (decrement a counter, but if it goes below 0, reset it to N)

Be careful when reading SWCHA. It's generally better to load SWCHA into a register or a temp variable at the start of your joystick routine. Don't do multiple checks directly against SWCHA in one frame. The danger is that the user will happen to press the joystick in the middle of the joystick checking routine, which would cause SWCHA to change state in the middle of the logic. This caused a nasty transitional logic bug in Master of Arcturus.

 

I generally use a technique similar to Supercat, except I store the register in a temp var so I don't have to worry about preservation. However, I really like Michael's lookup technique. It's very elegant, definitely faster, and may even be less ROM. I may try this out in Stellar Fortress.

Edited by TROGDOR
Link to comment
Share on other sites

You could also use a table approach:

 

Nice idea for BIT usage, but there's no advantage over the standard bit-shifting approach Darrel posted, which is not only a lot more efficient, but will also handle diagonal movement automatically.

 

You can even just loop it back to the first shift and do the second joystick with the same code, if you hold a player index (0 or 1) in the X or Y register, executing stuff like INC xPos,X in the branches.

Link to comment
Share on other sites

Here's what Michael's routine would look like in assembly:

 

	LDA SWCHA
LSR
LSR
LSR
LSR
TAY			; Store for later use.

LSR
LSR			; A now holds D7 and D6 from SWCHA in bits 1 and 0.

TAX
LDA JoyDeltaTable,X

CLC
ADC Xloc
STA Xloc

TYA
AND #%00000011

TAX
LDA JoyDeltaTable,X
EOR #$FF

SEC			; 2s Compliment from the above EOR.
ADC Yloc
STA Yloc


JoyDeltaTable
.byte #0
.byte #1
.byte #255
.byte #0

Note that by adding two more LSRs in the X delta check, and using a 2s compliment on the Y delta, you can reduce the 32 byte ROM table down to just 4 bytes. I haven't tested this code, but it looks like it should work.

Edited by TROGDOR
Link to comment
Share on other sites

Here's what Michael's routine would look like in assembly:

 

It does neither look faster, nor smaller than the bit-shifting code. Add in the need for boundry checks and you'll realize that with this approach you actually don't even know where you're going ;)

Details. Details.

 

I was having so much fun optimizing the look-up code, I didn't go back and byte/cycle count the bit-shifting code. You burst my bubble. :(

 

Bit shifting is definitely the way to go. But without the 2s complement, it's not nearly as sexy. :P

Link to comment
Share on other sites

Details. Details.

 

I was having so much fun optimizing the look-up code, I didn't go back and byte/cycle count the bit-shifting code. You burst my bubble. :(

 

Bit shifting is definitely the way to go. But without the 2s complement, it's not nearly as sexy. :P

 

Well, the bit-shifting code is just 4 times this:

ROR; or any other shifter
BCS NotMe
INC/DEC pos

 

That is 20 bytes and 31/32 cycles depending on wether the stick is pushed straight or diagonal.

Link to comment
Share on other sites

Here's what Michael's routine would look like in assembly:

 

It does neither look faster, nor smaller than the bit-shifting code. Add in the need for boundry checks and you'll realize that with this approach you actually don't even know where you're going ;)

Details. Details.

 

I was having so much fun optimizing the look-up code, I didn't go back and byte/cycle count the bit-shifting code. You burst my bubble. :(

 

Bit shifting is definitely the way to go. But without the 2s complement, it's not nearly as sexy. :P

I admit that my example wasn't as compact (smaller/faster) as the bit-shifting approach, but using the joystick bits as an index into a 16-byte table can still be useful. As I said, it really depends on what you want to have happen when the stick is pushed in a given direction. For example, you could identify all nine directions separately (the ninth direction being the center), so that "up-left" could be detected all at once without having to check for "up" and then check for "left" as well.

 

Also, in my "xmotion" and "ymotion" tables, I took contradictory readings into account, such as "up-left-down," which would amount to just "left," since "up" and "down" would cancel each other out. True, you can't (or aren't supposed to be able to) push the stick in opposite directions at the same time-- but I've read that some games had Easter eggs that required the player to push the stick in all four directions at once, and you could detect that sort of situation very easily if you treat all 4 bits as a single value ranging from 0 to 15. On the other hand, if you had one of those funky "up-left-down" situations with the bit-shift approach, you would end up moving up, then moving left, then moving down, so you would waste time moving up and then down when you could have just ignored those two motions (since they cancel each other out).

 

Additionally, the table could be expanded to 32 bytes-- 2 bytes per index value-- to get 16 JMP vectors, if for some reason you wanted to have a different routine for each possible direction, including the "contradictory" directions. For instance, you could have one Easter egg triggered by "up-down," a different Easter egg triggered by "up-left-down," etc.

 

Michael

Link to comment
Share on other sites

but using the joystick bits as an index into a 16-byte table can still be useful.

 

I usually use that direction table coming from the other side, i.e. I pick a random value, look up the direction bits from the table and voilà: AI joystick input! :)

 

As you are already mentioning, usually 13 bytes are good enough, since 1100 is the highest combo a joystick can do. You can use the 7 unused bit patterns to put an emphasis on (a) certain direction(s) for the AI though.

Link to comment
Share on other sites

  • 1 month later...

One simple optimization if you're going with the bit-shifting code:

CheckP0Right
  LDA SWCHA
  BMI CheckLeft
  ...
CheckP0Left
  ROL
  BMI CheckDown
  ...
CheckP0Down
  ROL
  BMI CheckUp
  ...
CheckP0Up
  ROL
  BMI CheckP1Right
  ...
CheckP1Right
...

 

Using BMI and ROL shaves off that initial rotate to set Carry Bit, saving a byte and 2 cycles : )

Edited by Hornpipe2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...