Yoruk Posted April 15, 2020 Share Posted April 15, 2020 (edited) 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 : 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: 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 April 15, 2020 by Yoruk grammar Quote Link to comment Share on other sites More sharing options...
+Karl G Posted April 15, 2020 Share Posted April 15, 2020 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. Quote Link to comment Share on other sites More sharing options...
Yoruk Posted April 15, 2020 Author Share Posted April 15, 2020 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 ? Quote Link to comment Share on other sites More sharing options...
+Andrew Davie Posted April 15, 2020 Share Posted April 15, 2020 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 Quote Link to comment Share on other sites More sharing options...
Yoruk Posted April 15, 2020 Author Share Posted April 15, 2020 I don't know what assembler tool is used in my online IDE, I'll check if DASM is doing the error when using it offline... Quote Link to comment Share on other sites More sharing options...
Yoruk Posted April 15, 2020 Author Share Posted April 15, 2020 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 ? ? Quote Link to comment Share on other sites More sharing options...
+Andrew Davie Posted April 15, 2020 Share Posted April 15, 2020 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. Quote Link to comment Share on other sites More sharing options...
Yoruk Posted April 15, 2020 Author Share Posted April 15, 2020 I am still reading the Stella manual, I missed that part. I thought that D1 was low, but I had an issue with the CTRLPF assignment. Problem solved, thanks again ! ? 1 Quote Link to comment Share on other sites More sharing options...
Yoruk Posted April 18, 2020 Author Share Posted April 18, 2020 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 ! Quote Link to comment Share on other sites More sharing options...
+Andrew Davie Posted April 18, 2020 Share Posted April 18, 2020 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. Quote Link to comment Share on other sites More sharing options...
Yoruk Posted April 18, 2020 Author Share Posted April 18, 2020 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 ! Quote Link to comment Share on other sites More sharing options...
NoLand Posted April 18, 2020 Share Posted April 18, 2020 (edited) 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 April 18, 2020 by NoLand Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted April 18, 2020 Share Posted April 18, 2020 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: 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. 1 Quote Link to comment Share on other sites More sharing options...
NoLand Posted April 18, 2020 Share Posted April 18, 2020 (edited) 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 April 18, 2020 by NoLand Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted April 18, 2020 Share Posted April 18, 2020 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 type frame type savesnap 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 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.zip 1 Quote Link to comment Share on other sites More sharing options...
NoLand Posted April 18, 2020 Share Posted April 18, 2020 (edited) 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: Edited April 18, 2020 by NoLand Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted April 18, 2020 Share Posted April 18, 2020 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: Most likely Javatari is not emulating mid-scanline changes to VBLANK correctly. Quote Link to comment Share on other sites More sharing options...
Yoruk Posted April 19, 2020 Author Share Posted April 19, 2020 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. Quote Link to comment Share on other sites More sharing options...
NoLand Posted April 19, 2020 Share Posted April 19, 2020 (edited) 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 April 19, 2020 by NoLand Quote Link to comment Share on other sites More sharing options...
+splendidnut Posted April 19, 2020 Share Posted April 19, 2020 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. 1 Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted April 19, 2020 Share Posted April 19, 2020 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: However, it's noticeable if the display is mis-adjusted. A clearer example of this using Frantic, display adjusted OK: Display misadjusted: 2 Quote Link to comment Share on other sites More sharing options...
Yoruk Posted April 20, 2020 Author Share Posted April 20, 2020 @SpiceWar : these screens are amazing ? ! It's incredible to think that the 2600 can output this. Thanks for sharing them ! 1 Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted April 20, 2020 Share Posted April 20, 2020 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: 1 Quote Link to comment Share on other sites More sharing options...
Omegamatrix Posted April 22, 2020 Share Posted April 22, 2020 Yeah, with the two color 48 displays there's a few different ways to do them. Here's a link to another version I did that uses a looped kernel. 1 Quote Link to comment Share on other sites More sharing options...
Yoruk Posted April 27, 2020 Author Share Posted April 27, 2020 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 ? Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.