Jump to content
IGNORED

Reading byte tables - help !


Yoruk

Recommended Posts

Hello there,

 

I am slowly digging into 6502 assembly language and 2600 programming, so please be indulgent, this is my first experiment ?

 

I first started to deal with drawing a background. I created a small C++ app to help me convert a bitmap picture into code to fill my PF0 to PF2 registers for each scanline. Adding some color changes mid-lines and here we are :

 

exemple.thumb.png.31a52144963193d8de2b7573bacdcc69.png

 

I am working with 8bitworkshop to edit, assemble and run my code.

 

My drawing code was composed by heavy lines like this :

 

PictureLoop1
                 ;clear PF registers
                 lda #0
                 sta PF0
                 sta PF1
                 sta PF2
    			 sta WSYNC  
                    inx  
                  cpx #10  ;total cumule
       			 bne PictureLoop1
                 ;------------------------------------------------   
       
PictureLoop2
                 ;Init playfield patterns for ONE or more scanline
                 lda #%00000000
                 sta PF0
                 lda #%00001000
                 sta PF1
                 lda #%00000000
                 sta PF2
   				  sta WSYNC  
                    inx  
                  cpx #11  ;total cumule
     		   bne PictureLoop2

 

I simply loop on similar scanlines to draw them, and I use the X register as my main scanline counter.

 

To add efficiency I wanted to replace these lines by a call to byte tables, as explained here.

 

So my new drawing routine is this one :

 

    ldx #0   ;2        
Kernel lda PF0Table,x   ;4
    sta PF0   ;3
    lda PF1Table,x   ;4
    sta PF1   ;3
    lda PF2Table,x   ;4
    sta PF2   ;3
    sta WSYNC   ;3
    inx   ;2    
    cpx #192    
    bne Kernel   ;3(2)

With PF0Table my table for PF0, and so one.

 

And of course I have these at the end of my code :

 

PF0Table  ; table 0  
        .byte  #%10000000,
        .byte  #%10000000,
        .byte  #%10000000,
        .byte  #%11000000,
(...)

 

But it doesn't works as expected. Here is the result:

 

erreur.thumb.png.5cf7c426f46273f32f63f3d76e8fc628.png

 

It looks like that my tables are correctly loaded, but why there is a "blank" line after every scanline ? I didn't get why.

 

Attached is the full code.

 

Am I doing something wrong ?

 

Thanks in advance !

 

 

 

problem.asm

Edited by Yoruk
grammar
Link to comment
Share on other sites

Take away the commas after each entry in your tables. These are only used if you have multiple values per line.  The # symbol is also not needed for data.  Your tables should be along the lines of:

 

PF0Table  ; table 0  
        .byte  %10000000
        .byte  %10000000
        .byte  %10000000
        .byte  %11000000
(...)

With this change, it should work as you are expecting.  The trailing commas seem to effectively add a 0 value after every line.

 

Also, as a side note, you don't need to worry about what value you are storing in WSYNC. It is a "strobe register" that will act the same regardless of what value is in the register when you write to it.

Link to comment
Share on other sites

1 minute ago, Yoruk said:

Whoaa, MANY thanks, I was really stuck ! Works perfectly now. ?

 

So in my first case, the system was adding a blank byte after the comma because he was expecting data ?

Looks to be a minor bug in DASM.

Yu can report this and other issues at https://github.com/dasm-assembler/dasm/issues

Link to comment
Share on other sites

I discovered a mistake in my code but again I didn't manage to see what's wrong...

 

My playfield was working fine with this :

 

  ldx #0   
 
Kernel lda PF0Table,x   
 
     sta PF0   
 
     lda PF1Table,x  
 
     sta PF1   
 
     lda PF2Table,x   
 
     sta PF2   
 
     lda #0  
     sta WSYNC   
    
   ;updating colors
   cpx #129
   bne Next
   lda #$C4   ;couleur Vert
   sta COLUBK
    
Next    
             
     cpx #148
   bne Next2
  lda #$F4     ; Marron
  sta COLUP0   ; couleur playfield GAUCHE
  sta COLUP1   ; couleur playfield DROITE
    
Next2
    
    
     
  cpx #106
  bne Next3   
  lda #$B6     ; Vert   
  sta COLUP0   ; couleur playfield GAUCHE  
  sta COLUP1   ; couleur playfield DROITE  
    
Next3
        
            
     inx   
     

       
    cpx #192  
    bne Kernel 

 

I use some CPX instructions to compare my X register value (scanline counting) and apply some changes to the background register and playfield color.

 

But I was wrong, I was actually writing into COLUP0 and COLUP1 registers (player sprites colors).

 

So I updated the code to use COLUPF instead :
 

  ldx #0   
 
Kernel
     lda PF0Table,x   
 
     sta PF0   
 
     lda PF1Table,x  
 
     sta PF1   
 
     lda PF2Table,x   
 
     sta PF2   
 
 
    lda #0  
     sta WSYNC   

   
    
   ;updating colors
   cpx #129
   bne Next
   lda #$C4   ;couleur Vert
   sta COLUBK  ; registre couleur ARRIERE PLAN
      
Next    
             
     cpx #148
   bne Next2
  lda #$F4     ; Marron
  sta COLUPF   ; couleur playfield 
       
    
Next2
     
  cpx #106
  bne Next3   
  lda #$B6     ; Vert   
  sta COLUPF   ; couleur playfield   
     
Next3
    
              
      
     inx   
     

       
    cpx #192  
    bne Kernel

 

But it doesn't works anymore...  All my playfield is black.

 

What I am doing wrong ? ?

Link to comment
Share on other sites

From the Stella manual...
 

"One more priority control is available to be used for displaying the score. When a "1" is written to D1 of the CTRLPF register, the left half of the playfield takes on the color of player 0, and the right half the color of player 1. The game score can now be displayed using the PF graphics register, and the score will be in the same color as its associated player."

 

So my guess would be that you have 1 written to D1 of CTRLPF and so your PF colours are coming from COLUP0/1.

Change that bit to 0.


 
Link to comment
Share on other sites

Question again about byte tables...

 

Could someone help me to understand this syntax :

 

PlayfieldData
    .byte  4,#%00000000,#%11111110,#%00110000
    .byte  8,#%11000000,#%00000001,#%01001000
    .byte 15,#%00100000,#%01111110,#%10000100
    .byte 20,#%00010000,#%10000000,#%00010000
    .byte 20,#%00010000,#%01100011,#%10011000
    .byte 15,#%00100000,#%00001100,#%01000100
    .byte  8,#%11000000,#%00110000,#%00110010
    .byte  4,#%00000000,#%11000000,#%00001100
    .byte 0

 

The binary values are my playfield registers, but I don't what are the left values. The total doesn't even give 192 !

 

And these strange addressing modes :

 

        lda #<PlayfieldData
        sta PFPtr
        lda #>PlayfieldData
        sta PFPtr+1
        lda #<Frame0
        sta SpritePtr
        lda #>Frame0
        sta SpritePtr+1

 

PFPtr and SpritePtr are ".word pointers" but I don't really see what they mean... I'll try to find some documentation on this.

 

This code came from the example here : https://8bitworkshop.com/v3.5.1/?file=examples%2Fcomplexscene.a&platform=vcs

 

Thanks !

Link to comment
Share on other sites

2 hours ago, Yoruk said:

Question again about byte tables...

 

Could someone help me to understand this syntax :

 


PlayfieldData
    .byte  4,#%00000000,#%11111110,#%00110000
    .byte  8,#%11000000,#%00000001,#%01001000
    .byte 15,#%00100000,#%01111110,#%10000100
    .byte 20,#%00010000,#%10000000,#%00010000
    .byte 20,#%00010000,#%01100011,#%10011000
    .byte 15,#%00100000,#%00001100,#%01000100
    .byte  8,#%11000000,#%00110000,#%00110010
    .byte  4,#%00000000,#%11000000,#%00001100
    .byte 0

 

The binary values are my playfield registers, but I don't what are the left values. The total doesn't even give 192 !

 

And these strange addressing modes :

 


        lda #<PlayfieldData
        sta PFPtr
        lda #>PlayfieldData
        sta PFPtr+1
        lda #<Frame0
        sta SpritePtr
        lda #>Frame0
        sta SpritePtr+1

 

PFPtr and SpritePtr are ".word pointers" but I don't really see what they mean... I'll try to find some documentation on this.

 

This code came from the example here : https://8bitworkshop.com/v3.5.1/?file=examples%2Fcomplexscene.a&platform=vcs

 

Thanks !

 

The 6502 addresses 16-bits of memory (that is, 65536 bytes) all numbered from 0 to 65535.

So, obviously, you need to have 16 bits to say which memory location you want to read/write to.

BUT, the 6502 is an 8-bit machine.  Whereas you can go "lda PlayfieldData" this will load directly from that table, the first byte, because the 16-bit address is embdded in the binary code. Look at a list file if you do this. You'll see something 3 bytes for that instruction. The instruction byte, and then the low byte and then the high byte of the address of the PlayfieldData table.

Now, when you don't actually know at assemble time the address you're reading from or writing to - or more specifically it changes on-the-fly, then you need to store the address somewhere, and use that as a pointer to the data you want. The 6502 uses two consecutive zero-page variables to do this through "lda (addr),y" addressing. In this case, (addr) does not contain the address, it contains the address of the first of the two bytes that contains the address of the data. In other words, addr and addr+1 point to the data.

So, to load the low byte of a 16-bit address you use "lda #<address" and for the high byte you use "lda #>address". In the given code, then, the low and high byte of the address of teh PlayfieldData table are written to the zero page pair "PfPtr". Those two bytes (PfPtr, PfPtr+1) now point to the PlayfieldData table. The data in the table can now be accessed through the "lda (PfPtr),y" or "sta (PfPtr),y" instructions.

As to the format of your table; that seems to be code-dependent. I would hazard a guess that the first byte is #scanlines with the following 3 bytes giving data for PF0,PF1,PF2.  So, 4 scanlines of.... then 8 scanlines of.... etc.  But I'd need to see the code to confirm. It would be loading the first byte into the x register (via lda (PfData),y ) and then iny and then retrieving the next three and writing to PF0,PF1,PF2, with iny after each, and then looping x down to 0, then repeat (load first byte = scanline count for next group), etc. That's a guess.

 

Link to comment
Share on other sites

Thanks for taking time to explain this. Please let me re-phrase this to see if I got it completely. Again I'm quite a newbie in this, and english is not my first language ?

The memory addresses of the 6502 are obviously 16 bits. When writing this in my code :

 

PF0Table  ; table 0
        .byte  %00000000
        .byte  %00000000

 
This STATIC label represents the address of the first byte data in this table. During assembly, DASM will replace everywhere in the code "PF0Table" by the actual two bytes of the real address.

But as you explain, we can also use a word as a dynamic pointer. The word must be stored in the zero page memory. We use this syntax to get and store the address :

 

lda #<PlayfieldData
sta PFPtr
lda #>PlayfieldData
sta PFPtr+1

 

into the pointer. "#<PlayfieldData" is the low byte part of the address and "#>" the high part.

To actually use the pointer, I must use this syntax : "lda (pointer),y"

 

Is this correct ?

 

Ok the table it looks like it works as you presented. I don't see why the total of the left column doesn't give me 196 or 196/2, but if I try to modify these values it does affect the pattern height.

 

Thanks again !

Link to comment
Share on other sites

2 hours ago, Yoruk said:

To actually use the pointer, I must use this syntax : "lda (pointer),y"

This is correct.

 

A bit of background on this: While the 6502 has just 3 registers of use for a program, the accumulator (A), X, and Y, the zeropage features as some kind of extended range of registers, especially for instructions `LDA ($LL), Y` and `LDA ($LL, X)`, which have a bit of "magic", as in indirect lookups using an index, added to them. Best think of the parentheses "(…)" as "effectively the address contained in that expression" (or simply, as "the contents of"). The behavior is somewhat different for X and Y in this context

 

`LDA ($LL, X)` adds (ignoring any carry) the offset immediately to the address $LL and will do the actual lookup at the address contained in ($LL + X, $LL + X + 1). So, if $LL = 4 and X = 2, the value loaded will be the address contained in memory locations $06 and $07. If those contained, say, $10 and $F0, this would effectively load the value from memory location $F010. While this allows to iterate over lists of vectors starting at given base address in the zero page (you could probably built a nice state machine based on this), it is rarely used.

 

Generally, `LDA ($LL), Y`is what you want for a lookup table. As the parenthesis suggests, this will do the effective memory lookup at the address in ($LL, $LL + 1) and the offset in Y added to this (with carry). If $LL = 4 and Y = 2 and memory location $04 contains $10 and memory location $05 contains $F0, the lookup would be done at $F010 + 2 = $F012. As we increment Y, we smoothly iterate over $F013, $F014, and so on, exactly what we'd want to do, when loading values from a table. It's generally much like a hard coded `LDA $F010, Y`, but additionally allows us to set the base address to our liking.

Edited by NoLand
Link to comment
Share on other sites

1 hour ago, Yoruk said:

Ok the table it looks like it works as you presented. I don't see why the total of the left column doesn't give me 196 or 196/2, but if I try to modify these values it does affect the pattern height.

 

192's the usual target mentioned when talking about the 2600, not 196.  It comes from Atari's original in-house documentation, the Stella Programmer's Guide, where you'll find this:

802563483_ScreenShot2020-04-18at9_00_19AM.thumb.png.418862e37138de763849bc83272ad29d.png

 

Due to how TIA works, the programmer can change those - such as increase the picture to 200 scanlines while decreasing Vertical Blank to 33 and Overscan to 26. The tradeoff of doing that is you get fewer cycles of CPU time for game logic.

 

I checked my games once and found my screen sizes ranged from 182 to 202.

 

You may also find my tutorial to be useful.

 

  • Like 1
Link to comment
Share on other sites

1 hour ago, SpiceWare said:

I don't see why the total of the left column doesn't give me 196 or 196/2, but if I try to modify these values it does affect the pattern height.

Here is what the actual effect of this is on the output:

PlayfieldData
	.byte  4,#%00000000,#%11111110,#%00110000
	.byte  8,#%11000000,#%00000001,#%01001000
	.byte 15,#%00100000,#%01111110,#%10000100
	.byte 20,#%00010000,#%10000000,#%00010000
	.byte 20,#%00010000,#%01100011,#%10011000
	.byte 15,#%00100000,#%00001100,#%01000100
	.byte  8,#%11000000,#%00110000,#%00110010
	.byte  4,#%00000000,#%11000000,#%00001100
	.byte 0

....XXXXXXX.....XX..   8 lines
..XX.......X...X..X.  16 lines
.X...XXXXXX...X....X  30 lines
X...X...........X...  40 lines
X....XX...XX...XX..X  40 lines
.X......XX....X...X.  30 lines
..XX..XX.....X..XX..  16 lines
....XX........XX....  11 lines + 2 lines at top

sum: 193 lines

However, I can't see, why the pattern is repeated over two scanlines, or, why there's this overspill to the top.

(Mind that the sprite is rendered at scanline resolution.)

; Set up VBLANK timer
        lda #0
        sta PFIndex	; reset playfield offset

NewPFSegment
; Load a new playfield segment.
; Defined by length and then the 3 PF registers.
; Length = 0 means stop
        ldy PFIndex	; load index into PF array
        lda (PFPtr),y	; load length of next segment
        beq NoMoreSegs	; == 0, we're done
        sta PFCount	; save for later
; Preload the PF0/PF1/PF2 registers for after WSYNC
        iny
        lda (PFPtr),y	; load PF0
        tax		; PF0 -> X
        iny
        lda (PFPtr),y	; load PF1
        sta Temp	; PF1 -> Temp
        iny
        lda (PFPtr),y	; load PF2
        iny
        sty PFIndex	; save index of next segment
        tay		; PF2 -> Y
; WSYNC, then store playfield registers
; and also the player 0 bitmap for line 2
...
; Load playfield length, we'll keep this in X for the loop
        ldx PFCount

KernelLoop
...
        dex
        beq NewPFSegment	; end of this playfield segment?
; WSYNC and store values for second line
        sta WSYNC
...
        jmp KernelLoop

 

Edit: The overspill is quite remarkable, since the code at label "NextFrame" continues immediately at "NewPFSegment" (meant to start the playfield pattern at the very first entry), after resetting VBLANK and  a "SLEEP 10", which shouldn't extend over two full scanlines.

Edited by NoLand
Link to comment
Share on other sites

The loop is basically:

 

Scanline 1: update playfield, update player

Scanline 2: update player, calculate values for playfield - but save results for next scanline

 

  • Using Stella you can see the overspill doesn't occur on the very first frame.  Load the ROM
  • hit ` to enter debugger
  • click in the prompt box to give it focus
  • type reset
  • type frame
  • type frame
  • type savesnap
    scene_dbg_8e075401.thumb.png.6bce84b97b18efbd8e4b6d83a0afcd2d.png
  • type frame
  • type savesnap
    scene_dbg_8e078f5e.thumb.png.93d3bea4fbfb17d0367fae505477bd8a.png

 

 

 

What's happening is the values in the TIA register only change when you tell them to.  If you don't want what's shown at the bottom to repeat at the top then you must change them before the top becomes visible again.


Simple fix would be in NextFrame - where you see this:

        lda #0
        sta PFIndex	; reset playfield offset

 

just add 3 more lines:

        sta PFIndex	; reset playfield offset
        sta PF0     ; reset playfield
        sta PF1     ; reset playfield
        sta PF2     ; reset playfield

scene_dbg_8e0de4d7.thumb.png.cc881050abe2a1638080ffbc8cba7077.png

 

The shearing occurs because the video output is turned on mid-scanline:

; Wait for end of VBLANK
	TIMER_WAIT
        lda #0
        sta VBLANK


The way to fix that is to add a sta WSYNC so the video output is turned on at the start of the scanline:

; Wait for end of VBLANK
	TIMER_WAIT
	sta WSYNC
	lda #0
	sta VBLANK

scene_dbg_8e10e242.thumb.png.3ce25a88754691cc3b4b8173339e809a.png

 

scene.zip

  • Like 1
Link to comment
Share on other sites

3 hours ago, SpiceWare said:

The loop is basically:

 

Scanline 1: update playfield, update player

Scanline 2: update player, calculate values for playfield - but save results for next scanline

How could I miss this? (Tunnel vision regarding the playfield?) Two WSYNCs and two occurrences of "lda (SpritePtr),y" for everyone to see in plain daylight…

 

Of course, resetting or preloading the playfield before resetting VBLANK is best practice.

 

So, the answer to the scanline / playfield question is:

a) segment count x 2 as the kernel iterates over pairs of scanlines

b) 2 extra scanlines at the top (repeated as-is, i.e. from the bottom), due to the SLEEP and the time spent until the next WSYNC

c) 3 extra scanlines at the bottom (the kernel actually stops, where the background color is set to black, however, since the playfield registers remain unchanged, the pattern is repeated until the timer kicks in and the code sets VBLANK).

 

Interestingly, Javatari (and by this 8bitworkshop) doesn't show the first scanline starting mid-screen:

 

playfield.png

Edited by NoLand
Link to comment
Share on other sites

59 minutes ago, NoLand said:

Interestingly, Javatari (and by this 8bitworkshop) doesn't show the first scanline starting mid-screen:

 

 

Output from Stella matches my hardware:

IMG_0886.thumb.jpg.10c27e77e8bd831fa7890313a9cee431.jpg

 

Most likely Javatari is not emulating mid-scanline changes to VBLANK correctly.

Link to comment
Share on other sites

Many thanks guys for these explanation, it helps me a lot !

 

@SpiceWare : My mistake, I wanted to say 192, but I now understand that it is possible to adjust a bit this total.

 

Things starts to be more clearer now. Reading through the Random Terrain tutorial I now see who to set-up the playfield, how to put a sprite at a given Y position (I need more time to fully understand the horizontal positioning ?).

 

The problem is that I have issues to mix things together :like how to put two sprites, read the joystick and properly update the PF and background. I've created heavy loops that causes timing issues.

 

I definitely need more tutorials. @SpireWar, yours looks great. I'll print it out and read it.

 

I need to learn if there a clean and "universal" way of building the main scanlines look. Mines are actually like this :

 

set X to 0


load playfield registers

store playfield registers


WSYNC


test the X value to see if I reach a sprite

if no, jump to "Next"


calculate a local Y corrdinate

call and apply the sprite color byte

call and display the sprite data byte




Next : compare the value of X to see if I need to update the background


inx


branch to kernel if x < 192

 

I know that it's better to start my look with X = 192 and decrease the register. But as you can see I have a very heavy loop with too much comparisons, this is what I need to optimize.

 

I tried to study examples from the online 8-bit workshop, but the "advanced" examples are.... too advanced for me. ?

 

Again I need more training. I'll go reading through these new tutorials !

 

Thanks again.

 

Link to comment
Share on other sites

22 hours ago, SpiceWare said:

Most likely Javatari is not emulating mid-scanline changes to VBLANK correctly.

I don't want to diverge too much from the original topic, but does a mid-scanline start mean that the program is displaying even fields on a TV set (instead of the usual odd-only ones)? As I understand it, a mid-scanline start is what triggers the scanline drop for an even field.

 

4 hours ago, Yoruk said:

I know that it's better to start my look with X = 192 and decrease the register. But as you can see I have a very heavy loop with too much comparisons, this is what I need to optimize.

Mind that because of how indirect addressing with pointers works on the 6502, it's generally preferable to use the Y-register for counting lines. Decrementing the index register is also mostly preferable (you save at least one comparison instruction in your kernel, and time is precious). On the other hand, all your graphics are to be stored in reverse order (upside-down) im memory for the purpose, when using a decrementing index.

 

I once made a tiny sprite editor (online), which allows you to import and export assembler code and to reverse the byte order, if required:

https://www.masswerk.at/rc2018/04/TinySpriteEditor/

 

(If there's interest, I can do a similar playfield editor.)

Edited by NoLand
Link to comment
Share on other sites

1 hour ago, NoLand said:

I don't want to diverge too much from the original topic, but does a mid-scanline start mean that the program is displaying even fields on a TV set (instead of the usual odd-only ones)? As I understand it, a mid-scanline start is what triggers the scanline drop for an even field.

 

 

Short answer, no.  Even/odd fields are controlled via mid-scanline change in the VSYNC signal, not VBLANK, which just turns enables/disables the display.  But, there is also quite a bit of setup to do a "proper" NTSC 480i signal.

  • Like 1
Link to comment
Share on other sites

As @splendidnut points out, that'd be VSYNC.

You can turn VBLANK on & off mid-scanline to hide stuff, which is how we originally implemented the two-color 48 pixel kernel that we originally developed for Stay Frosty 2's menu title:

 

looks good.jpg
 

However, it's noticeable if the display is mis-adjusted.


misadjusted.jpg



A clearer example of this using Frantic, display adjusted OK:

 

Frantic - Just Right.jpg

 

Display misadjusted:

 

Frantic - Too Bright.jpg


 

 

  • Like 2
Link to comment
Share on other sites

3 minutes ago, Yoruk said:

@SpiceWar : these screens are amazing ? ! It's incredible to think that the 2600 can output this. Thanks for sharing them !


You're welcome!  Part 7 - Menu of the CDFJ tutorial goes into detail on how it works, just need to scroll down to the section titled 48 pixel 2 color kernel to see it.

CDFJ takes advantage of the ARM chip, but it's not required to create this - @Omegamatrix posted a demo here using a stock 4K ROM:

 

48_bits_2_colors(v2).png

  • Like 1
Link to comment
Share on other sites

I am digging into the tutorial of SpiceWar. I love the concept of explaining a game design step by step (I'm thinking of a game design to apply this) but meanwhile I have to say that the Step 4 (the "two lines kernel) is a bit hard to understand for me. ?

 

I totally understand the concept of this kernel to actually double the scanlines in order to get more time to prepare things. To avoid the small vertical offset between two objects, some registers in the TIA (Vertical delay features) allows us to solve this problem.

 

So this is clear. Here, we are checking if we have to draw the player :

        ldy #ARENA_HEIGHT   ; 2  7 - the arena will be 180 scanlines (from 0-89)*2        
        
ArenaLoop:                  ;   13 - from bpl ArenaLoop
    ; continuation of line 2 of the 2LK
    ; this precalculates data that's used on line 1 of the 2LK
        lda #HUMAN_HEIGHT-1 ; 2 15 - height of the humanoid graphics, subtract 1 due to starting with 0
        dcp HumanDraw       ; 5 20 - Decrement HumanDraw and compare with height
        bcs DoDrawGrp0      ; 2 22 - (3 23) if Carry is Set, then humanoid is on current scanline
        lda #0              ; 2 24 - otherwise use 0 to turn off player0
        .byte $2C           ; 4 28 - $2C = BIT with absolute addressing, trick that
                            ;        causes the lda (HumanPtr),y to be skipped
DoDrawGrp0:                 ;   23 - from bcs DoDrawGrp0
        lda (HumanPtr),y    ; 5 28 - load the shape for player0
        sta WSYNC           ; 3 31
;---------------------------------------
    ; start of line 1 of the 2LK
        sta GRP0            ; 3  3 - @ 0-22, update player0 to draw Human
        ldx #%11111111      ; 2  5 - playfield pattern for vertical alignment testing
        stx PF0             ; 3  8 - @ 0-22

I understand that (please tell me if I don't get this right) in the first part of this code we compare the actual scanline index (Y register) with the actual human Y coordinate (HumanDraw, one byte stored in RAM), to see if we have to jump to "DoDrawGrp0". (I don't see how the .byte line can allow us to jump to WSYNC, but I have time to get this)

 

If yes, the accumulator is then loaded with the byte contents at "$HumanPtr + y" that stores the actual player shape byte for the actual scanline. We then store the accumulator into GRP0 to draw the player.


The player shape is initialized here, in "PositionObjects:"

(...)

   ; HumanPtr = HumanGfx + HUMAN_HEIGHT - 1 - Y position
        lda #<(HumanGfx + HUMAN_HEIGHT - 1)
        sec
        sbc ObjectY
        sta HumanPtr
        lda #>(HumanGfx + HUMAN_HEIGHT - 1)
        sbc #0
        sta HumanPtr+1

     
We load into A the constant value of (HumanGfx + HUMAN_HEIGHT - 1) (low byte part), then we set the carry in order to subtract ObjectY. But in this case, what is exactly  "ObjectY" ? The absolute Y coordinate of the player in the screen, or the local sprite line index ? PositionObjects is actually called before the arena draw routine, that's why I don't see how the ObjectY variable is initialized. 

 

I also don't see what the three last instructions are doing ? Why do we load and store an other gfx part, and why this part doesn't involve ObjectY ?

 

I really want to fully understand the code presented into this tutorial step before going further.

 

Thanks guys for helping me ?
      

 

 

 

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