8-direction+fire Joystick

Basic and Machine Language

Moderator: Moderators

Post Reply
User avatar
MrSterlingBS
Vic 20 Enthusiast
Posts: 174
Joined: Tue Jan 31, 2023 2:56 am
Location: Germany,Braunschweig

8-direction+fire Joystick

Post by MrSterlingBS »

Hello,

i have a Joystick routine with fire and 4-direction.
But i need a 8-direction with fire button routine in assembler.
is there someone here in the forum who can help me?

BR
Sven
User avatar
srowe
Vic 20 Scientist
Posts: 1340
Joined: Mon Jun 16, 2014 3:19 pm

Re: 8-direction+fire Joystick

Post by srowe »

MrSterlingBS wrote: Wed Apr 12, 2023 5:06 am i have a Joystick routine with fire and 4-direction.
But i need a 8-direction with fire button routine in assembler.
is there someone here in the forum who can help me?
I'm not sure what you mean by '8-direction': the joystick bits are independent so you can have, say, up and left, active at the same time. Could you post your code?
User avatar
tokra
Vic 20 Scientist
Posts: 1123
Joined: Tue Apr 27, 2010 5:32 pm
Location: Scheessel, Germany

Re: 8-direction+fire Joystick

Post by tokra »

I remember there being such an assembler joystick-routine in the book "Programming the VIC" to be found here:

https://commodore.bombjack.org/vic-20/books-vic.htm
User avatar
chysn
Vic 20 Scientist
Posts: 1205
Joined: Tue Oct 22, 2019 12:36 pm
Website: http://www.beigemaze.com
Location: Michigan, USA
Occupation: Software Dev Manager

Re: 8-direction+fire Joystick

Post by chysn »

I do something like this. The routine returns a single bitfield containing the current directions activated.

Code: Select all

          NORTH = $04
          SOUTH = $08
          WEST = $10
          EAST = $80
          FIRE = $20

Joystick: lda #$7f    ; Set data direction register for VIA2 so that East can be read. This turns
          sta $9122   ;   OFF some keys, so we make sure to restore it later.
          lda $9111   ; Read VIA for North (bit 2), South (bit 3), West (bit 4) and Fire (bit 5)
          and #$3c    ; Clear bits we don't care about (0, 1, 6, 7)*
          sta $fe     ; Stash this value somewhere
          lda $9120   ; Read East (bit 7)
          and #$80    ; We only care about bit 7 of this VIA2 port
          ora $fe     ; Combine bit 7 of VIA2B with previously-stashed value of $fe
          pha         ; Push the final result while we put the data direction register back
          lda #$ff    ; Put the data direction register back for VIA2
          sta $9122   ; ,,
          pla         ; Put the register value in A
          sta $fe     ;   And/or store it for use with BIT
          rts
* AND #$3C is here out of an abundance of caution, because bit 7 is used on this port. If you don't do it, it'll probably be okay.

I usually set the DDR when my game starts up and leave it set. This means that some keys don't work, which I don't care about when the joystick is the only control method. But I wrote this routine to set the DDR temporarily for maximum flexibility. Modify that depending on your needs.

After calling the routine, you just test for directions using the bit values above. For example:

Code: Select all

          jsr Joystick
          cmp #(NORTH | WEST) ; Check northwest
          beq move_nw
          lda #FIRE
          bit $fe
          bne jump
In real life, you probably don't need to do a compare for every possible direction, but this should give you a jumping-off point.
VIC-20 Projects: wAx Assembler, TRBo: Turtle RescueBot, Helix Colony, Sub Med, Trolley Problem, Dungeon of Dance, ZEPTOPOLIS, MIDI KERNAL, The Archivist, Ed for Prophet-5

WIP: MIDIcast BASIC extension

he/him/his
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: 8-direction+fire Joystick

Post by Mike »

As srowe already wrote, the four main directions of the joystick are independent and any combination possible within mechanical limits may appear in the VIA registers. Actually, it requires extra effort to filter out the diagonals - for example by laying out the joystick routine as C-like switch with early bail-outs/breaks, like thus:

Code: Select all

1 S=PEEK(37151):POKE37154,127:T=PEEK(37152):POKE37154,255
2 IF (128ANDT)=0 THEN PRINT "RIGHT":GOTO 7
3 IF (16ANDS)=0 THEN PRINT "LEFT":GOTO 7
4 IF (8ANDS)=0 THEN PRINT "DOWN":GOTO 7
5 IF (4ANDS)=0 THEN PRINT "UP":GOTO 7
6 IF (32ANDS)=0 THEN PRINT "FIRE"
7 [...]
Note the extra GOTO 7 that I added to the end of the IF statements (see the original example in the Denial Wiki). Those extra GOTOs effectively prevent the sensing of the diagonals as any further IF statements are bypassed as soon as one of the directions has been detected.

One way to effectively employ the diagonal directions is actually executing all IF statements regardless and 'collecting' all possible movements into positional changes:

Code: Select all

1 S=PEEK(37151):POKE37154,127:T=PEEK(37152):POKE37154,255
2 IF (128ANDT)=0 THEN X=X+1
3 IF (16ANDS)=0 THEN X=X-1
4 IF (8ANDS)=0 THEN Y=Y+1
5 IF (4ANDS)=0 THEN Y=Y-1
6 IF (32ANDS)=0 THEN [...]
[...]
That can also be combined with checks for screen limits (shown here for left direction):

Code: Select all

[...]
3 IF (16ANDS)=0 AND X>0 THEN X=X-1
[...]
For checks of collisions with fixed objects, the old position should be kept in, say, X2/Y2 and when the new X/Y-position is occupied, then restore the old X2/Y2-position into X/Y.

This is code in BASIC, however it should be straightforward to translate this to machine code.
User avatar
MrSterlingBS
Vic 20 Enthusiast
Posts: 174
Joined: Tue Jan 31, 2023 2:56 am
Location: Germany,Braunschweig

Re: 8-direction+fire Joystick

Post by MrSterlingBS »

Dear VIC-20 friends,

Thank you for your comments, the code and the help.
Please excuse my late reaction to this and my not very precise task.

My task:
I had thought of moving a sprite over the screen with a joystick. With the query of the four cardinal points I get a good result. As an example, let a sprite (arrow) point left, right, up, and down. If no direction is pressed, a smiley appears.

But what if I control the sprite up-right, down-right, down-left or up-left? Then appears at an arrow not pointing in the direction sprite.

So how can I query the corresponding direction and display the correct sprite?

I have attached an example code.

Thank you again for your help.

Code: Select all

Sprite equ $10

z_Regs equ $20

z_HL equ z_Regs
z_L  equ z_Regs
z_H  equ z_Regs+1

z_BC equ z_Regs+2
z_C  equ z_Regs+2
z_B  equ z_Regs+3

z_DE equ z_Regs+4
z_E  equ z_Regs+4
z_D  equ z_Regs+5
z_As  equ z_Regs+6


;Current player pos
PlayerX 	equ $60		
PlayerY 	equ PlayerX+1

;Last player pos (For clearing sprite)
PlayerX2 	equ PlayerX+2
PlayerY2 	equ PlayerX+3


* = $1001
		; BASIC program to boot the machine language code
		db $0b, $10, $0a, $00, $9e, $34, $31, $30, $39, $00, $00, $00
;start of code $100A

;Screen Init
	ldx #16					;We're going to copy 16 registers 
ScreenInitAgain:	
	dex
	lda VicScreenSettings,x	;Get A parameter
	sta $9000,X				;Store to the video registers at $9000
	txa
	bne ScreenInitAgain
	
	
	
	
	lda #$1E	;Clear $1E00-$2000
	sta z_h
	lda #$00
	sta z_l
	
	ldx #$02	;Clear $200 bytes
	tay			;#$00
	lda #9		;Tile 9=Blank
FillZerosB:	
	sta (z_hl),y
	dey
	bne FillZerosB
	inc z_h
	dex 
	bne FillZerosB
	

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
;Define Tiles
		
	lda #<Bitmap					;Source Bitmap Data
	sta z_L
	lda #>Bitmap
	sta z_H

	lda #<(BitmapEnd-Bitmap);Source Bitmap Data Length
	sta z_C
	lda #>(BitmapEnd-Bitmap)
	sta z_B
	
	lda #<$1C00		;Tile 0 in VIC Custom Characters
	sta z_E
	lda #>$1C00
	sta z_D
	
	jsr DefineTiles		;Define the tile patterns
	
	lda #3			;Start SX
	sta PlayerX
	lda #3			;Start SY
	sta PlayerY

	lda #0			;Fake No Keys on first run		
	sta z_h
	jmp StartDraw	;Force Draw of character first run
	
	
infloop:
	lda #20
Raster:
	cmp $9004
	bne Raster
	
	ldx PlayerX		;Back up X
	ldy PlayerY		;Back up Y
	lda #0
	sta Sprite
	jsr DrawPlayer	;Draw Player Sprite
	
	jsr Player_ReadControlsDual
	lda z_h
	cmp #%11111111
	beq infloop		;See if no keys are pressed
	pha
StartDraw:	
		ldx PlayerX		;Back up X
		stx PlayerX2
		
		ldy PlayerY		;Back up Y
		sty PlayerY2
		
		jsr BlankPlayer	;Remove old player sprite
		
		ldx PlayerX		;Back up X
		ldy PlayerY		;Back up Y
	pla
	sta z_h
	and #%00001000	;-FLDU--R
	bne JoyNotUp	;Jump if UP not pressed
	dey				;Move Y Up the screen
	lda #1
	sta sprite
JoyNotUp:
	lda z_h
	and #%00010000	;-FLDU--R
	bne JoyNotDown	;Jump if DOWN not presesd
	iny 			;Move Y Down the screen
	lda #3
	sta Sprite
JoyNotDown:
	lda z_h
	and #%00100000	;-FLDU--R
	bne JoyNotLeft	;Move X Left 
	dex
	lda #2
	sta Sprite
JoyNotLeft:
	lda z_h
	and #%00000001	;-FLDU--R
	bne JoyNotRight	;Move X Right
	inx
	lda #4
	sta Sprite
JoyNotRight:
	
	stx PlayerX		;Update X
	sty PlayerY		;Update Y
	
;X Boundary Check - if we go <0 we will end up back at 255
	cpx #22
	bcs PlayerReset
	
;Y Boundary Check - only need to check 1 byte
	cpy #23
	bcs PlayerReset
	
	jmp PlayerPosYOk ;Not Out of bounds
	
PlayerReset:
	ldx PlayerX2	;Reset Xpos	
	stx PlayerX
	
	ldy PlayerY2	;Reset Ypos
	sty PlayerY
	
PlayerPosYOk:
	jsr DrawPlayer	;Draw Player Sprite
	
	ldx #255
	ldy #100
	jsr PauseXY		;Wait a bit!	
		
	jmp infloop
	
BlankPlayer:
	lda #9		;Tile Num 9 (blank sprite)
	jmp DrawSprite
DrawPlayer:
	lda Sprite		;Tile Num (Smiley)
DrawSprite:
	pha
		stx z_b
		sty z_c
		jsr GetVDPScreenPos	;Calculate Tilemap mempos
	pla
		
	sta (z_hl),y		;Transfer Tile to ram
	lda z_h
	clc
	adc #$78			;add Offset to Color Ram ($9600)
	sta z_h
	lda #4				;Color
	sta (z_hl),y		;Set Tile Color
	rts
	
Bitmap:	;Smiley			Sprite 0
        DB %00111100     ;  0
        DB %01111110     ;  1
        DB %11011011     ;  2
        DB %11111111     ;  3
        DB %11111111     ;  4
        DB %11011011     ;  5
        DB %01100110     ;  6
        DB %00111100     ;  7
		
		; arrow up			Sprite 1
		db    $00,$18,$3C,$7E,$18,$18,$18,$18
		; arrow left		Sprite 2
        db    $00,$10,$30,$7F,$7F,$30,$10,$00
		; arrow down		Sprite 3
        db    $18,$18,$18,$18,$7E,$3C,$18,$00
		; arrow right		Sprite 4
        db    $00,$08,$0C,$FE,$FE,$0C,$08,$00
		; arrow right-up	Sprite 5
		db    $00,$1E,$0E,$1E,$3A,$70,$20,$00
		; arrow left-up		Sprite 6
        db    $00,$78,$70,$78,$5C,$0E,$04,$00
		; arrow left-down		Sprite 7
        db    $00,$04,$0E,$5C,$78,$70,$78,$00
		; arrow right-down	Sprite 8
        db    $00,$20,$70,$3A,$1E,$0E,$1E,$00
		
        DS 8,0			;Blank Sprite 9
BitmapEnd:

	
	
	
	

Player_ReadControlsDual:
	lda #%01111111
	sta $9122	;Set Data Direction of port B to READ (0=read)
	
;	lda #%11000011
;	sta $9113	;Set Data Direction of port A to READ (0=read)
	
	lda $9120	;Port B (R------- Switch)
	sta z_as
	
	lda $911F	;Port A (--FLDU-- Switches)
	rol z_as
	rol 
	sta z_h		;-FLDU--R
	
;	lda #255
;	sta $9122	;Reset port B (for Keyb col scan)
	rts
	
	
PauseXY:
	dex
	bne PauseXY
	dey 
	bne PauseXY
	rts

		
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
	
;Address= $1E00 + (Ypos * 22) + Xpos	
	
GetVDPScreenPos:	; BC=XYpos	
	lda #$1e			;Screen base is $1E00
	sta z_h					;Colors at $9600 (add $7800 offset)
	
	lda z_b				;Xpos
	sta z_l

	ldy z_c				;Ypos
	beq GetVDPScreenPos_YZero
GetVDPScreenPos_Addagain:	;Repeatedly add screen width (22) Y times 
	clc
	lda z_l
	adc #22			;22 bytes per line
	sta z_l
	lda z_h
	adc #0			;Add Carry
	sta z_h
	
	dey
	bne GetVDPScreenPos_Addagain
GetVDPScreenPos_YZero:
	rts
	
;Copy Data to the Character Defs from ram/rom to char ram
DefineTiles:	
		ldy #0
DefineTiles2:
        lda (z_HL),Y		;Copy From z_HL
        sta (z_DE),Y		;To z_ DE
		iny					;Inc Byte
		BNE	DefineTiles_SkipInc1
		INC	z_H				;Inc H bytes
		INC	z_D
DefineTiles_SkipInc1:
		DEC z_C				;Dec Counter
		BNE DefineTiles2
		LDA z_B
		BEQ	DefineTiles_Done
		DEC z_B
		jmp DefineTiles2
DefineTiles_Done:
		rts
		

	;LLLL options
	   ; 0000   ROM   8000  32768
	   ; 0001         8400  33792
	   ; 0010         8800  34816
	   ; 0011         8C00  35840
	   ; 1000   RAM   0000  0000
	   ; 1001         xxxx
	   ; 1010         xxxx  unavail.
	   ; 1011         xxxx
	   ; 1100         1000  4096
	   ; 1101         1400  5120
	   ; 1110         1800  6144
	   ; 1111         1C00  7168		<---
	   
	   
	
VicScreenSettings:
	db $0C		;$9000 - horizontal centering
	db $26		;$9001 - vertical centering
	db $96		;$9002 - set # of columns / 
					;Bit7 = screen base bit ($16 for screen at $1000)
	db $AE		;$9003 - set # of rows
	db $7A		;$9004 - TV raster beam line
	db $FF		;$9005 - bits 0-3 start of character memory /  
					;bits 4-7 is rest of video address 
					;$(CF for screen at $1000)
	db $57		;$9006 - horizontal position of light pen
	db $EA		;$9007 - vertical position of light pen
	db $FF		;$9008 - Digitized value of paddle X
	db $FF		;$9009 - Digitized value of paddle Y
	db $00		;$900A - Frequency for oscillator 1 (low)
	db $00		;$900B - Frequency for oscillator 2 (medium)
	db $00		;$900C - Frequency for oscillator 3 (high)
	db $00		;$900D - Frequency of noise source
	db $00		;$900E - bit 0-3 sets volume of all sound / 
					;bits 4-7 are auxiliary color information
	db $00+13 	;$900F - Screen and border color register
	
	
	

User avatar
chysn
Vic 20 Scientist
Posts: 1205
Joined: Tue Oct 22, 2019 12:36 pm
Website: http://www.beigemaze.com
Location: Michigan, USA
Occupation: Software Dev Manager

Re: 8-direction+fire Joystick

Post by chysn »

The main problem with the above is that you've got four comparisons to a cardinal direction, each falling through to the next, and the sprite used is based on the last match. Rather than doing a bunch of brute-force comparisons, consider a data table containing character codes indexed by the values of a bitfield. Your table will have 16 rows in it (2^4), but you can mark (not skip) conditions that aren't designed to happen (north/south).

Your bitfield could be constructed using the Joystick routine I provided above. To refresh memories, its results are

Code: Select all

          NORTH = $04
          SOUTH = $08
          WEST = $10
          EAST = $80
          FIRE = $20
You can massage this a bit to construct a more compact table index:

Code: Select all

          jsr Joystick      ; Get joystick bitfield as above
          and EAST          ; We want to move East over into bit 5
          lsr               ; ,,
          lsr               ; ,,
          ora $fe           ; Recombine it with North, South, and West
          lsr               ; Shift everything so that bit 0=north, 1=south, 2=west, 3=east
          lsr               ; ,,
          and #$0f          ; Restrict range         
          tay               ; Y is now the index to the sprite character code table
          lda SprTable,y    ; A is the looked-up sprite number
          etc...
And then the data table would look like this. You could simply leave out everything after SOUTHEAST to save a few bytes, since you won't get those results with a regular joystick.

Code: Select all

          
SprTable: .byte SMILEY      ; 0000
          .byte NORTH       ; 0001
          .byte SOUTH       ; 0010
          .byte INVALID     ; 0011 north/south doesn't happen
          .byte WEST        ; 0100
          .byte NORTHWEST   ; 0101
          .byte SOUTHWEST   ; 0110
          .byte INVALID     ; 0111 north/south/west doesn't happen
          .byte EAST        ; 1000
          .byte NORTHEAST   ; 1001
          .byte SOUTHEAST   ; 1010
          .byte INVALID     ; 1011 north/south/east doesn't happen
          .byte INVALID     ; 1100 east/west doesn't happen
          .byte INVALID     ; 1101 north/east/west doesn't happen
          .byte INVALID     ; 1110 south/east/west doesn't happen
          .byte INVALID     ; 1111 north/south/east/west doesn't happen
You can extend this concept to behavior as well as visual presentation. Anything that you can express as data, you can put in a lookup table, so that you don't have to write a bunch of "what if it's this?" code.

And just for some extra info, AND sets the zero flag when no bits match, so keep that in mind for post-AND branching. To be specific, you want it to be

Code: Select all

	and #%00001000	;-FLDU--R
	BEQ JoyNotUp	;Jump if UP not pressed
VIC-20 Projects: wAx Assembler, TRBo: Turtle RescueBot, Helix Colony, Sub Med, Trolley Problem, Dungeon of Dance, ZEPTOPOLIS, MIDI KERNAL, The Archivist, Ed for Prophet-5

WIP: MIDIcast BASIC extension

he/him/his
Post Reply