Jump to content
Mike Harris

8 direction Z80 Routine?

Recommended Posts

Any ideas?

 

I know that the Coleco Poller returns 4 directions and from what I know about Coleco physical hardware is that the original J-Sticks have only up, down, left and right.

The SAC controllers actually have physical contacts for the connects to inputs at one time yet it is still only up, down, left and right.

As far as a routine all I can come up with is still check one bit at a time.

 

0 for north 1 for west, 2 for south and 4 for east.

 

 

Any thoughts, recommendations, code???

Edited by Mike Harris

Share this post


Link to post
Share on other sites

you can use the bit opcode to check the bits and call the code, for up/down/left/right, thats the way i usely do, quite easy actually.

Share this post


Link to post
Share on other sites

These are combinations of the bits. NW is both N and W set to zero. You need to make your own table manually for values 0-15 (AND $0F) and index the controller value into the table.

Share this post


Link to post
Share on other sites

Yep, multiple directions at once. Yes, the SAC has an 8-direction contactor, but the diagonals just activate 2 directions at once. So SW activates both S and W. They probably just used the 8-way contactor because the 4-way one with their "real joystick" design wasn't working as well as the standard controller did on the diagonals.

 

So just check the bits and allow for multiple "on" bits.

Share this post


Link to post
Share on other sites

These are combinations of the bits. NW is both N and W set to zero. You need to make your own table manually for values 0-15 (AND $0F) and index the controller value into the table.

Do you have a quick and dirty example?

 

So far I have been checking one bit at a time then jump to an action such as move in that direction.

Share this post


Link to post
Share on other sites

Well, if you used a table with a nibble for the x and for the y direction, it might look like this:

 

 

BITS2DIR table based on lower nibble of joystick:
             00  ; 0000 All directions at once... not happening
             00  ; 0001 All directions except N... also not happening
             00  ; 0010 All directions except S... Also 
             00  ; 0011 East and west...You guessed it
             00  ; 0100 All directions except W
             11  ; 0101 Southeast
             1F  ; 0110 Northeast
             10  ; 0111 East
             00  ; 1000 All directions except E
             F1  ; 1001 Southwest
             FF  ; 1010 Northwest
             F0  ; 1011 West
             00  ; 1100 North and south...nah
             01  ; 1101 South
             0F  ; 1110 North
             00  ; 1111 No direction
Now just separate and sign-extend the nibbles, and add them to your x and y. Edited by ChildOfCv

Share this post


Link to post
Share on other sites

It's also the case that a fall-through would accomplish the same result. Pseudo-code:

Bit test 0
Jump nonzero to South
dec Y

South:
Bit test 1
Jump nonzero to West
inc Y

West:
Bit test 2
Jump nonzero to East
dec X

East:
Bit test 3
Jump nonzero to Done
inc X

Done: 

Since it does not restrict itself to one direction, it handles any combination correctly.

Share this post


Link to post
Share on other sites

Here is the routine in Z80 I created to give you the Joystick Values for your Coleco Games.

Mind you this uses subroutines and definitions from the Electric Adventure Megablast Game.

I did not post those routines because they don't belong to me.

You can pick them up at http://www.electricadventures.net/

 

 

TEST_JOYSTICS:
CALL POLLER
LD A,(CONTROLLER_BUFFER+3)

CP 00
CALL Z, PRINT_ZERO
CP 01
CALL Z, PRINT_ONE
CP 02
CALL Z, PRINT_TWO
CP 03
CALL Z, PRINT_THREE
CP 04
CALL Z, PRINT_FOUR
CP 05
CALL Z, PRINT_FIVE
CP 06
CALL Z, PRINT_SIX
CP 07
CALL Z, PRINT_SEVEN
CP 08
CALL Z, PRINT_EIGHT
CP 09
CALL Z, PRINT_NINE

JP TEST_JOYSTICS:

PRINT_ZERO:
LD HL,VRAM_NAME+460
LD DE, ZERO_PAT
LD BC, 1
CALL LDIRVM
RET

 

PRINT_ONE:
LD HL,VRAM_NAME+460
LD DE, ONE_PAT
LD BC, 1
CALL LDIRVM
RET

 

PRINT_TWO:
LD HL,VRAM_NAME+460
LD DE, TWO_PAT
LD BC, 1
CALL LDIRVM
RET

 

PRINT_THREE:
LD HL,VRAM_NAME+460
LD DE, THREE_PAT
LD BC, 1
CALL LDIRVM
RET

 

PRINT_FOUR:
LD HL,VRAM_NAME+460
LD DE, FOUR_PAT
LD BC, 1
CALL LDIRVM
RET

 

PRINT_FIVE:
LD HL,VRAM_NAME+460
LD DE, FIVE_PAT
LD BC, 1
CALL LDIRVM
RET

 

PRINT_SIX:
LD HL,VRAM_NAME+460
LD DE, SIX_PAT
LD BC, 1
CALL LDIRVM
RET

 

PRINT_SEVEN:
LD HL,VRAM_NAME+460
LD DE, SEVEN_PAT
LD BC, 1
CALL LDIRVM
RET

 

PRINT_EIGHT:
LD HL,VRAM_NAME+460
LD DE, EIGHT_PAT
LD BC, 1
CALL LDIRVM
RET

 

PRINT_NINE:
LD HL,VRAM_NAME+460
LD DE, NINE_PAT
LD BC, 1
CALL LDIRVM
RET

 

ZERO_PAT:
DB 010
ONE_PAT:
DB 001
TWO_PAT:
DB 002
THREE_PAT:
DB 003
FOUR_PAT:
DB 004
FIVE_PAT:
DB 005
SIX_PAT:
DB 006
SEVEN_PAT:
DB 007
EIGHT_PAT:
DB 008
NINE_PAT:
DB 009

 

Pattern Numbers would correspond to your pattern number representing whatever you decide to represent the number.

You could put Klingon Symbols if you wanted.

 

This was just a quick routine to give numbers and may have errors but the numbers are sound.

It was never meant to be optimized or professional.

 

So for all those out there that can not find the info you need then here you are.

 

You have 12 bytes in the buffer to check against so you can do all kinds of things with this routine to show the full spectrum of coleco controllers.

Edited by Mike Harris

Share this post


Link to post
Share on other sites

Finally have my 8 directions.

 

MOVE_PLAYER:

CALL POLLER
LD A,(CONTROLLER_BUFFER+3)
LD IY,(SPRTBL)
LD IX,(SPRTBL+1)

CP 01
CALL Z, NORTH
CP 03
CALL Z, NORTH_EAST
CP 02
CALL Z, EAST
CP 06
CALL Z, SOUTH_EAST
CP 04
CALL Z, SOUTH
CP 12
CALL Z, SOUTH_WEST
CP 08
CALL Z, WEST
CP 09
CALL Z, NORTH_WEST
RET

 

If you have a better routine that saves cycles, space or whatever I am all ears.

Share this post


Link to post
Share on other sites

I always use the ports directly, not any bios calls.

I only use bios to turn of the soundchip in the start of the code.

 

Here is the code I used, notice the 3 nops to ensure it work on ADAM computers.

 

JSUP: out ($c0),a
nop
nop
nop
in a,($fc)
bit 0,a
jr nz,JSLEFT
**** CODE for JOYSTICK UP *****


JSLEFT: bit 3,a
jr nz,JSRIGHT
**** CODE for JOYSTICK LEFT *****


JSRIGHT:bit 1,a
jr nz,JSHOME
**** CODE for JOYSTICK RIGHT *****

JSHOME: bit 6,a
jr nz,JSDOWN
**** CODE for JOYSTICK FIRE *****


JSDOWN: bit 2,a
jr nz,JSUD
**** CODE for JOYSTICK DOWN *****

Share this post


Link to post
Share on other sites

The CV also needs those NOPs too. I watched it with a scope and found that the signal pins have a surprisingly large recovery time.

 

OS7 just implements it in the polling routine by first reading the input data, then toggling, then a call to an immediate return for a small delay. Then it takes the reading and flips back and exits, relying on the fact that it won't be called for a while to stabilize the input values for the next poll.

Share this post


Link to post
Share on other sites

This is what I ultimately ended up with.

 

MOVE_PLAYER:

CALL POLLER
LD A, (CONTROLLER_BUFFER+3)
CP 0
JP Z, NO_MOVE

 

LD H, 0
LD L, A
ADD HL, HL
LD DE, JOY_DIR_TABLE
ADD HL, DE
LD A, (HL)
INC HL
LD H, (HL)
LD L, A
JP (HL)

 

NO_MOVE:
RET

JOY_DIR_TABLE:
DW DUMMY,NORTH,EAST,NORTH_EAST,SOUTH,DUMMY,SOUTH_EAST
DW DUMMY,WEST,NORTH_WEST,DUMMY,DUMMY,SOUTH_WEST

DUMMY:

 

 

It works great.

 

But if you guys can really help me out I need a better routine that creates a wall in the tiles that a sprite can not go through.
I have a routine that checks what patterns are underneath or adjacent to the sprite but it has issues and does not work all the time.

Edited by Mike Harris

Share this post


Link to post
Share on other sites

This is what I ultimately ended up with.

 

MOVE_PLAYER:

 

CALL POLLER

LD A, (CONTROLLER_BUFFER+3)

CP 0

JP Z, NO_MOVE

 

LD H, 0

LD L, A

ADD HL, HL

LD DE, JOY_DIR_TABLE

ADD HL, DE

LD A, (HL)

INC HL

LD H, (HL)

LD L, A

JP (HL)

 

NO_MOVE:

RET

 

JOY_DIR_TABLE:

DW DUMMY,NORTH,EAST,NORTH_EAST,SOUTH,DUMMY,SOUTH_EAST

DW DUMMY,WEST,NORTH_WEST,DUMMY,DUMMY,SOUTH_WEST

 

DUMMY:

 

 

It works great.

 

But if you guys can really help me out I need a better routine that creates a wall in the tiles that a sprite can not go through.

I have a routine that checks what patterns are underneath or adjacent to the sprite but it has issues and does not work all the time.

Thats a way to do it too, but I think this routine is slower and take up more space than mine :) anyway its not a problem. If you use HL besure to push and pop it, if you are sure you dont use HL before you call your joystick routine, its not a problem, else you would want to push hl just before you set the H,0, and pop it on each of the adresses in JOY_DIR_TABLE.

Share this post


Link to post
Share on other sites

Thats a way to do it too, but I think this routine is slower and take up more space than mine :) anyway its not a problem. If you use HL besure to push and pop it, if you are sure you dont use HL before you call your joystick routine, its not a problem, else you would want to push hl just before you set the H,0, and pop it on each of the adresses in JOY_DIR_TABLE.

Well, I may change some aspects based on directly accessing the ports. Of course that is faster but my concern was that your version only shows 4 directions where as I am shooting for 8.

 

Mind you I didn't test your code but all I am ready is only 4 directions.

 

That said, I have to have 8 pure directions because my barrier hits also go against a wall in a diagonal direction.

Share this post


Link to post
Share on other sites

A major question in how to improve on this is: What direction-specific processing do you do that disallows the decoding of X and Y separately? If you just used the bit method to figure out destination X,Y, you only have to test 4 directions. For instance, just for the fun of it I wrote a little "not Tetris" game. The input routine looks like:

...
        ; joystick input is in 'a'

        and     #0xe
        jr      z, 7$

        ld      e, PIECE_ADDR(iy)
        ld      d, PIECE_ADDR+1(iy)
        ld      h, PIECE_X(iy)
        ld      l, PIECE_Y(iy)

        bit     #2, a
        jr      z, 4$

        ; Move screen address down a line
        push    hl
        ld      hl, #WIDTH
        add     hl, de
        ex      de, hl
        pop     hl

        ; Increment piece Y
        inc     l

4$:
        ; Check right direction
        bit     #1, a
        jr      z, 5$
        inc     e
        inc     h

5$:
        ; Check left direction
        bit     #3, a
        jr      z, 6$
        dec     e
        dec     h

6$:
        ; Now, is the move legal?
        ld      c, PIECE_ORIENT(iy)
        push    hl
        call    check_collision
        pop     hl
        jr      nz, 7$

        ; Yes.  Update the data
        ld      PIECE_ADDR(iy), e
        ld      PIECE_ADDR+1(iy), d
        ld      PIECE_X(iy), h
        ld      PIECE_Y(iy), l

7$:
        ret

I just figured out where the piece would end up, taking into account both the down and the directions, and then checked whether it was blocked once I knew where to check.

block.zip

Share this post


Link to post
Share on other sites

It actually works with 8 directions. Cause it check each bit for up,down,left,right. So if your routine is doing the same for up+left as up and left, it cover that too.

 

Normaly I use those routines to convert to another bit pattern, cause i normaly do game conversion from other systems. So i "emulate" a Sega SG-1000 game controller bit pattern or MSX joystick etc.

 

My code work like this:

 

is it a up then y=y-1

is it a down then y=y+1

is it a left then x=x-1

is it a right then x=x+1

is it a fire then do something

 

so press up+left will do y=y-1 and x=x-1

Share this post


Link to post
Share on other sites
Posted (edited)

Here is a sample of my 8 bit Z80 Scrolling.
Still working out some of the bugs, this is based off of KIWI'S C Code.

But it does the job for a 64x64 grid

 

MAP_XY:
LD HL, 0
PUSH BC
LD A, (SCROLL_Y)
CP 0
JP Z, Y_WAS_ZERO
LD B, A
LD DE, WIDE
LOOP_Y: ; Scroll Y * Wide
ADD HL, DE
DJNZ LOOP_Y
Y_WAS_ZERO: ;+Scroll X
POP BC
LD A, B
CP 0
JP Z, FINISH_ADJUST
LOOP_ROW: ; Wide * ROW
ADD HL, DE
DJNZ LOOP_ROW

FINISH_ADJUST: ; Add to Map Data put in DE for print
LD BC, (SCROLL_X)
ADD HL, BC
LD (SCROLL), HL
LD HL, NEW_MAP
LD BC, (SCROLL)
ADD HL, BC
EX DE, HL
RET

 

 

When calling MAP_XY you have to pass the row in B as in LD B, Row number
The return values tells where on the 64x64 grid map to print to the screen which prints a 32 column row of data to the screen.

Do this 24 times and you can create a scrolling world in all 8 directions if done right.
Now I have to create a double buffer because although it is very fast in pure z80 assemble it still looks choppy moving 8 its at a time.

 

I am 100% certain I can modify all my code to have a 256x256 scrolling world in 8 directions with any patterns and any color in VRAM.

Edited by Mike Harris

Share this post


Link to post
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.

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...