Jump to content
  • entries
    658
  • comments
    2,707
  • views
    906,887

step 11 - add the ball object


The 2LK has been revised to display the ball object. Like player0, the ball needs to be primed before the ArenaLoop begins:

    ; prime ENABL so ball can appear on topmost scanline of Arena
        ldx #1              ; 2  2 - D1=0, so ball will be off
        lda #BOX_HEIGHT-1   ; 2  4 - height of box graphic
        dcp BallDraw        ; 5  9 - Decrement BallDraw and compare with height
        bcs DoEnablPre      ; 2 11 - (3 12) if Carry is Set, then ball is on current scanline
        .byte $24           ; 3 14 - $24 = BIT with zero page addressing, trick that
                            ;        causes the inx to be skipped
DoEnablPre:                 ;   12 - from bcs DoEnablPre
        inx                 ; 2 14 - D1=1, so ball will be ON
        stx ENABL           ; 3 17
        
    ; prime GRP0 so player0 can appear on topmost scanline of the Arena
        lda #HUMAN_HEIGHT-1 ; 2 19 - height of player0 graphics,
        dcp Player0Draw     ; 5 24 - Decrement Player0Draw and compare with height
        bcs DoDrawGrp0pre   ; 2 26 - (3 27) if Carry is Set, then player0 is on current scanline
        lda #0              ; 2 28 - otherwise use 0 to turn off player0
        .byte $2C           ; 4 32 - $2C = BIT with absolute addressing, trick that
                            ;        causes the lda (Player0Ptr),y to be skipped
DoDrawGrp0pre:              ;   27 - from bcs DoDrawGRP0pre
        lda (Player0Ptr),y  ; 5 32 - load the shape for player0
        sta GRP0            ; 3 35 - @0-22, update player0 graphics
        dey                 ; 2 37
        
ArenaLoop:                  ;   37 - (currently 11 from bpl ArenaLoop)
        tya                 ; 2 39 - 2LK loop counter in A for testing
        and #%11            ; 2 41 - test for every 4th time through the loop,
        bne SkipX           ; 2 43 - (3 44) branch if not 4th time
        inc ArenaIndex      ; 5 48 - if 4th time, increase index so new playfield data is used
SkipX:                      ;   48 - use 48 as it's the longest path here

    ; continuation of line 2 of the 2LK
    ; this precalculates data that's used on line 1 of the 2LK
        lda #HUMAN_HEIGHT-1 ; 2 50 - height of the humanoid graphics, subtract 1 due to starting with 0
        dcp Player1Draw     ; 5 55 - Decrement Player1Draw and compare with height
        bcs DoDrawGrp1      ; 2 57 - (3 58) if Carry is Set, then player1 is on current scanline
        lda #0              ; 2 59 - otherwise use 0 to turn off player1
        .byte $2C           ; 4 63 - $2C = BIT with absolute addressing, trick that
                            ;        causes the lda (Player1Ptr),y to be skipped
DoDrawGrp1:                 ;   58 - from bcs DoDrawGrp1
        lda (Player1Ptr),y  ; 5 63 - load the shape for player1
        sta WSYNC           ; 3 66
;---------------------------------------
    ; start of line 1 of the 2LK
        sta GRP1            ; 3  3 - @0-22, update player1 graphics
        ldx ArenaIndex      ; 3  6
        lda ArenaPF0,x      ; 4 10 - get current scanline's playfield pattern
        sta PF0             ; 3 13 - @0-22 and update it
        lda ArenaPF1,x      ; 4 17 - get current scanline's playfield pattern
        sta PF1             ; 3 20 - @71-28 and update it
        lda ArenaPF2,x      ; 4 24 - get current scanline's playfield pattern
        sta PF2             ; 3 27 - @60-39
        
    ; precalculate data that's needed for line 2 of the 2LK
        ldx #1              ; 2 29 - D1=0, so ball will be off
        lda #BOX_HEIGHT-1   ; 2 31 - height of box graphic
        dcp BallDraw        ; 5 36 - Decrement BallDraw and compare with height
        bcs DoEnabl         ; 2 38 - (3 39) if Carry is Set, then ball is on current scanline
        .byte $24           ; 3 41 - $24 = BIT with zero page addressing, trick that
                            ;        causes the inx to be skipped
DoEnabl:                    ;   39 - from bcs DoEnablPre
        inx                 ; 2 41 - D1=1, so ball will be ON
        
        lda #HUMAN_HEIGHT-1 ; 2 43 - height of the box graphics,
        dcp Player0Draw     ; 5 48 - Decrement Player0Draw and compare with height
        bcs DoDrawGrp0      ; 2 50 - (3 51) if Carry is Set then player0 is on current scanline
        lda #0              ; 2 52 - otherwise use 0 to turn off player0
        .byte $2C           ; 4 56 - $2C = BIT with absolute addressing, trick that
                            ;        causes the lda (Player0Ptr),y to be skipped
DoDrawGrp0:                 ;   51 - from bcs DoDrawGRP0
        lda (Player0Ptr),y  ; 5 56 - load the shape for player0
        sta WSYNC           ; 3 59
;---------------------------------------
    ; start of line 2 of the 2LK
        sta GRP0            ; 3  3 - @0-22, update player0 graphics
        stx ENABL           ; 3  6 - @0-22, update ball graphics
        dey                 ; 2  8 - decrease the 2LK loop counter
        bne ArenaLoop       ; 2 10 - (3 11) branch if there's more Arena to draw
        sty PF0             ; 3 13 - Y is 0, blank out playfield
        sty PF1             ; 3 16 - Y is 0, blank out playfield
        sty PF2             ; 3 19 - Y is 0, blank out playfield
        rts                 ; 6 25 - ReTurn from Subroutine
 

 

I then modified RandomLocation to set all objects to the same location for comparision:

RandomLocation:
...
    ; for alignment test, set to (100, 100)
        lda #100
        sta ObjectX,x
        sta ObjectY,x
        rts
 

 

This revealed a minor quirk with TIA - namely that when objects are set to the same X position, missiles and the ball end up 1 pixel to the left of where a player ends up (player1 is the green square and it's directly on top of the red ball).

blogentry-3056-0-47300800-1405117472_thumb.png

 

This is a known issue and the solution is to increase the X value by 1 to compensate. I did so by adding this to the end of RandomLocation:

RandomLocation:
...
    cpx #2
    bcc RLdone
    inc ObjectX,x   ; missile and ball objects need their X adjusted
RLdone:
    rts
 

 

And now player1 and the ball line up:

blogentry-3056-0-60199500-1405117609_thumb.png

 

 

The NewGame routine revised last time already sets the ball to a random X-Y location, so all that's left to make it show up is to revise PositionObjects. Two changes are needed, first is to set the X position of the ball object by starting the POloop with X=4 (in the prior build X was initialized to 1), then prep a new variable BallDraw that's used by the 2LK to draw the ball object on the correct scanlines.

PositionObjects:
        ldx #4              ; position all objects
POloop
        lda ObjectX,x       ; get the object's X position
        jsr PosObject       ; set coarse X position and fine-tune amount
        dex                 ; DEcrement X
        bpl POloop          ; Branch PLus so we position all objects
        sta WSYNC           ; wait for end of scanline
        sta HMOVE           ; use fine-tune values to set final X positions
        
...
        
    ; prep ball's Y position for 2LK
        ldx #1              ; preload X for setting VDELBL
        lda ObjectY+4       ; get the balls's Y position
        clc
        adc #1              ; add 1 to compensate for priming of ball
        lsr                 ; divide by 2 for the 2LK position
        sta Temp            ; save for position calculations
        bcs NoDelayBL        ; if carry is set we don't need Vertical Delay
        stx VDELBL          ; carry was clear, so set Vertical Delay
NoDelayBL:
    ; BallDraw = ARENA_HEIGHT + BOX_HEIGHT - Y position + 1
    ; the + 1 compensates for priming of ENABL
        lda #(ARENA_HEIGHT + BOX_HEIGHT + 1)
        sec
        sbc Temp
        sta BallDraw
        rts
 

 

Lastly, Overscan's been updated to process collisions with the ball.

OverScan:

...

TestCollisions:
    ; Test left player collisions
...
        bit CXP0FB      ; N = player0/playfield, V=player0/ball
...
notP0PF:                ; oVerflow flag is not affected by lda or sta
        bvc notP0BL     ; if V is off, then player0 did not collide with ball
        ldx #4          ; which box was collected
        jsr CollectBox  ; update score and reposition box
        
notP0BL:
...
RightPlayer:
    ; Test right player collisions
...
        bit CXP1FB      ; N = player1/playfield, V=player1/ball
...
notP1PF:                ; oVerflow flag is not affected by lda or sta
        bvc notP1BL     ; if V is off, then player1 did not collide with ball
        ldx #4          ; which box was collected
        jsr CollectBox  ; update score and reposition box 
notP1BL:        
 

 

2 player games are now playable:

blogentry-3056-0-46897500-1405118609_thumb.png

 

and 1 player games have 2 boxes to collect:

blogentry-3056-0-47916000-1405118595_thumb.png

 

 

ROM

 

collect_20140711.bin

 

Source

 

Collect_20140711.zip

 

COLLECT TUTORIAL NAVIGATION
<PREVIOUS> <INDEX> <NEXT>
 

3 Comments


Recommended Comments

2 hours ago, JohnGri said:

Can you elaborate on the .byte $24 trick that causes the inx to be skipped?

 

I think I explained this trick in a comment in another part of the tutorial <searching>

 

Looks like I explained it for .byte $2C which skips over 2 bytes. The concept is the same for .byte $24, except it just skips over 1 byte.

 

  • .byte $2C = BIT absolute address (a 16 bit address, which is 2 bytes)
  • .byte $24 = BIT zero page (an 8 bit address, which is 1 byte)
  • Like 1
Guest
Add a comment...

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