JeremiahK Posted December 21, 2017 Share Posted December 21, 2017 (edited) I believe you forgot to clear the HMP0 value to 0 after positioning Player 0. Every time you strobe HMOVE, it moves all the objects that aren't set to 0. Calling sta HMCLR resets all HMxx registers to 0. If you do that after positioning Player 0, I think it will fix all the issues. But be careful not to write to HMCLR right after HMOVE. You need to wait 20+ cycles or so to keep from messing up the HMOVE operation. When I submitted this post, I saw SpiceWare had covered this already. Another thing I learned is that if you are doing an HMOVE at cycle 73 rather than after WSYNC (to avoid the black "comb" lines, like in my Nyan Cat project), the HMxx values are different so that a zero actually moves the object. You would have to set each non-moving object's HMxx to #$80 instead. Here's a handy link to a table that shows how much HMOVE will move each object and in which direction, depending on when you strobe HMOVE during a scanline (the table is at the bottom). Edited December 21, 2017 by JeremiahK Quote Link to comment Share on other sites More sharing options...
vidak Posted December 21, 2017 Author Share Posted December 21, 2017 I thought SpiceWare was saying I should do exactly what your crossed-out text said - what is SpiceWare suggesting if not that? Quote Link to comment Share on other sites More sharing options...
DirtyHairy Posted December 21, 2017 Share Posted December 21, 2017 (edited) Another thing I learned is that if you are doing an HMOVE at cycle 73 rather than after WSYNC (to avoid the black "comb" lines, like in my Nyan Cat project), the HMxx values are different so that a zero actually moves the object. You would have to set each non-moving object's HMxx to #$80 instead. Strobing HMOVE will raise a flag that causes horizontal blanking to be extended by 8 color clocks. Each sprite is essentially a counter that is not clocked during hblank, and so this will effectively move the sprite 8 pixels to the right (as it will take 8 more color clocks until the counter reaches the value that triggers rendering); the side effect are the black lines. In order to facilitate other movement values, strobing HMOVE will trigger the TIA to start sending extra clock pulses that will drive the sprite counters. The amount of pulses that is sent to each sprite depends on the value of the high nibble of HMXX. The highest bit is internally inverted, so a value of 0 will cause 8 extra clocks, amounting to zero movement, 7 will cause 15 extra clocks, amounting to 7 pixels movement to the left. During the visible part of the scanline, the extra clocks will interfere with the regular clock pulses. The details depend on the exact TIA revision; it is assumed that, on most chips, the extra clocks fall together with the regular ones and have no effect at all. Either way, this is the reason for the timing restrictions on HMOVE. At the end of the scanline, the flag that prolongs hblank is cleared. If you strobe HMOVE before this, the extended blanking will not happen, and all extra clocks will cause a shift of one pixel to the left. This is the reason for the idiosyncrasies of late HMOVE. If you strobe HMOVE before the line ends **and** before the first extra clock is sent, you can achieve 15 pixels of movement to the left this way. On a sidenote, this also explains most of the starfield effect: If you write HMxx while the extra pulses are sent, you can set it to a value below the extra pulse counter **before** the stop condition has been reached. This will cause the sprite to receive extra clocks until the next HMOVE and causes the starfield Edited December 21, 2017 by DirtyHairy 2 Quote Link to comment Share on other sites More sharing options...
RamrodHare Posted December 21, 2017 Share Posted December 21, 2017 Vidak, Keep up the good work! Quote Link to comment Share on other sites More sharing options...
vidak Posted December 21, 2017 Author Share Posted December 21, 2017 Vidak, Keep up the good work! Thanks man : ) I really have to thank you all for helping me. I really love this community : ) 1 Quote Link to comment Share on other sites More sharing options...
JeremiahK Posted December 21, 2017 Share Posted December 21, 2017 (edited) I didn't mean to confuse you with the crossed out text, it is correct. I had connection issues, and I hadn't seen Spice's post until after I posted mine. Thanks for the very detailed explanation of HMOVE, DirtyHairy! Edited December 21, 2017 by JeremiahK 1 Quote Link to comment Share on other sites More sharing options...
vidak Posted December 21, 2017 Author Share Posted December 21, 2017 This forum is amazing, I really mean it. 2 Quote Link to comment Share on other sites More sharing options...
TheHoboInYourRoom Posted December 21, 2017 Share Posted December 21, 2017 The highest bit is internally inverted, so a value of 0 will cause 8 extra clocks, amounting to zero movement, 7 will cause 15 extra clocks, amounting to 7 pixels movement to the left. Another way of saying this is that the TIA automatically converts 4-bit two's complement into excess-8. 2 Quote Link to comment Share on other sites More sharing options...
vidak Posted December 26, 2017 Author Share Posted December 26, 2017 I'm a little stuck again. I implemented the STA HMCLR like people suggested, and that fixed the erratic horizontal movement problems. However I now have an issue with the kernel, and the graphics pointers. In order to save time in the kernel, I store Player0's graphics to the Y register at the bottom of the kernel. HOWEVER, the GRP1 calculation routine is starting too early, and is causing the index of the GRP1 graphics to be loaded into the Y register, which is what is causing the black band of artefacts in each band of the screen where GRP0 doesn't appear. Could someone explain to me how my pointers and Y offset variables are working? I can't seem to understand how to line up the (a) Y offset; and (b) graphics pointer. I think I am also running out of time in my kernel...Anyway, if anyone could have a look, I'd be very grateful : ) guerrilla020_bin_files.zip coloured_guerrilla020.asm Quote Link to comment Share on other sites More sharing options...
JeremiahK Posted December 26, 2017 Share Posted December 26, 2017 I'm not sure where the problem is, but it looks like you are somehow storing your line counter value (instead of the graphics loaded from the offset) into GRP1. Quote Link to comment Share on other sites More sharing options...
ZackAttack Posted December 27, 2017 Share Posted December 27, 2017 You have a branch that is skipping the code which loads the value for GRP0 into Y. This is why Y never contains the graphics data. The use of LDA (PTR),Y appears to be fine. lda #P0_HEIGHT ; 2 47 dcp Player0Offset ; 5 52 bcc .p0FlipDraw ; 2 54 (3 54) <- Branch is taken, leaving Y with offset value ldy Player0Offset ; 3 57 lda (Player0Clr),y ; 5 62 sta COLUP0 ; 3 65 lda (Player0Ptr),y ; 5 70 tay ; 2 72 .p0FlipDraw ;(3 54) 1 Quote Link to comment Share on other sites More sharing options...
vidak Posted December 28, 2017 Author Share Posted December 28, 2017 Thanks for both of your help! I think I can fix this now! Quote Link to comment Share on other sites More sharing options...
vidak Posted December 29, 2017 Author Share Posted December 29, 2017 Just in response to ZackAttack - the graphics code for GRP0 needs to be skipped until the correct Y position for Player0 is reached. If I remove that branch, then Player0 will be drawn at the earliest possible opportunity. That branch is a part of the FlipDraw routine. I think this kernel will not work in the long run. I think I have three options: 1. Use SpiceWare's masking technique 2. Use some version of VDELxx in a 2 Line Kernel in order to try and get single line resolution Option 2 would be considerably more difficult than Option 1. There could be an option 3: 3. Use DoDraw for GRP1, and use FlipDraw for GRP0. This is just an idea, it will almost certainly not work because it will take too long. It would require decrementing the scanline counter in memory and reloading it into Y every time. Overall my current kernel is too slow to draw 2 multi-coloured sprites. 8bitworkshop.com seems to be able to achieve 2 multicoloured sprites AND a playfield, so I will study that code and see what I can learn. 8bitworkshop uses VDELP0, so I think this may be the way forward. Quote Link to comment Share on other sites More sharing options...
ZackAttack Posted December 29, 2017 Share Posted December 29, 2017 I'm not saying you should get rid of the branch. I'm saying that the branch prevents the P0 graphics from being preloaded for the next line. So instead of 0 you get a garbage value. Maybe in pseudo code it could be easier to see. if(drawP0) then y = graphicForNextLine end if GRP0 = y <- y only is set if the if evaluates to true. Instead what you want is this if(drawP0) then y = graphicForNextLine else y = 0 end if GRP0 = y <- now y is 0 if it's not time to draw P0 Diff your previous posted asm file with this one to see the small change which makes all the difference. guerrilla-fix-y.asm 1 Quote Link to comment Share on other sites More sharing options...
vidak Posted December 29, 2017 Author Share Posted December 29, 2017 Ah okay. Is there still enough time in the kernel, though? That's mainly what I was worried about... Quote Link to comment Share on other sites More sharing options...
ZackAttack Posted December 29, 2017 Share Posted December 29, 2017 Plenty of time since you only execute one code path or the other. Speaking of time. Since you're using bands there's no need for flipdraw or any other overhead on P1. Just pad the graphics and color data with a few bytes if you want to allow a small amount of vertical movement. Then offset the pointer to effect the vertical position within each band. Another nice thing about the bands is that you can use mask draw for P0 with a mask that's 3 * band height. So a 32 line band would only need 96 bytes for the mask. Then you can do P0 with only 5 cycles of overhead. Just as important, this gets rid of all the branches and makes it a lot easier to make the kernel exactly 76 cycles. ; Updates both sprites in 37 cycles lda (ptrgrp0),y and (ptrmask),y sta GRP0 lda (prtcol0),y sta COLUP0 lda (ptrgrp1),y sta GRP1 lda (prtcol1),y sta COLUP1 One more thing to consider is how P1 is being positioned between bands. If you want to draw anything between the bands you may need to have different kernel fragments that all do the same thing, but with a RESP1 strobe at different times. Then before hand you figure out which fragment to jump to based on where P1 is to be positioned. Then have a few lines to use HMOVE for fine positioning. If you have one line for HMOVE you'd need 160/15 = 11 fragments, but with 3 lines of HMOVE you'd only need 160/45 = 4 different fragments. You'd be left with at least 4 lines between each P1, but you gain the potential for some playfield or other enhancements. 1 Quote Link to comment Share on other sites More sharing options...
ZackAttack Posted December 29, 2017 Share Posted December 29, 2017 I am about to develop a 2LK for the "Lock and Load" part of the game, the second part, which will feature: 2 coloured sprites 1 missile a coloured asymmetrical playfield A few questions about this. Will the playfield be drawn between bands? Is the missile going to be limited to just a few pixels per band? How tall did you plan on making the PF pixels? What's the largest/tallest PF pixel you'd accept? Will there be more than one PF image for this mode of the game? Can the PF be limited to the middle 32 PF pixels so that updating PF0 can be avoided? What are you trying to draw with the PF? Quote Link to comment Share on other sites More sharing options...
vidak Posted December 29, 2017 Author Share Posted December 29, 2017 I don't think it's true that I'm only executing one code path or the other - I am executing both code paths when GRP0 and GRP1 are both drawn in the same band. I will get back to you about the lock and load section! My short answer is that I will only be drawing the middle 32 pixels - I'd like to have as high a resolution as possible. I am hoping to have at most three different backgrounds. One for the beach, one for the jungle, and another for the mountains. This part of the game will not have bands of soldiers. It will only have 2 multicolored sprites on the screen. I will also use 8x width effects to create different objects. Quote Link to comment Share on other sites More sharing options...
vidak Posted December 29, 2017 Author Share Posted December 29, 2017 The lock and load section of the game is kind of a small strategy game. You can move, block, load, or shoot. The idea is to chase down your opponent soldier and shoot them. If they block in the same turn as you shoot, they avoid any damage. I will be drawing a beach background, a jungle background, and a mountain background. Quote Link to comment Share on other sites More sharing options...
JeremiahK Posted December 29, 2017 Share Posted December 29, 2017 I don't think his point was that you were only executing one code path or the other, it's that you are only loading Y properly in one, but still writing it to graphics in both. This results in the leftover Y value from the counter being written to graphics when the branch is taken. 1 Quote Link to comment Share on other sites More sharing options...
vidak Posted January 4, 2018 Author Share Posted January 4, 2018 Ah okay. I agree. That is the problem. Anyway, I'm back from my enforced relaxation now, and I am going to attempt a new rewrite of the kernel using the masking method, which is undeniably faster. Again, thank you for all your help Quote Link to comment Share on other sites More sharing options...
vidak Posted January 21, 2018 Author Share Posted January 21, 2018 Okay. This project is still alive. I am about to implement a new kernel - the bitwise AND masking kernel that SpiceWare used in Stay Frosty - which ZackAttack recommends. If you'd like to hear a radio interview I did about this project for a radio station in my home state of Western Australia, CLICK HERE. Quote Link to comment Share on other sites More sharing options...
vidak Posted January 21, 2018 Author Share Posted January 21, 2018 This is my newest attempt at a complete kernel rewrite. It incorporates the masking technique and graphics padding that were suggested to me. It is now SO fast that I have 23 cycles left over. (76 - 53 = 23) I think I will incorporate playfield graphics! I wasn't even aiming to do so with this particular kernel! ;--------------------------------- ; ; KERNEL MACRO ; ;--------------------------------- MAC SCREEN_BANDS .BAND SET {1} ;================================= ; ; Load Line Counter for this band ; ;================================= ldy Heights+.BAND ;================================= ; ; Preload GRP0 (Che) Graphics ; ;================================= lda (Player0Ptr+.BAND*2),y ; 5 5 and (Player0Msk+.BAND*2),y ; 5 10 tax ; 2 12 lda (Player0Clr+.BAND*2),y ; 5 17 tay ; 2 19 ;================================= ; Position GRP1 independently for ; each band of the screen. ; ; Accumulator holds X value. ;================================= lda ObjectX+.BAND+1 .PositionGRP1 sec sta WSYNC ;----------------------------------------------------- ENTER FIRST SCANLINE stx GRP0 ; 3 3 sty COLUP0 ; 3 6 .DivideLoop1 sbc #15 ; 2 8 bcs .DivideLoop1 ; 2 10 eor #7 ; 2 12 asl ; 2 14 asl ; 2 16 asl ; 2 18 asl ; 2 20 sta RESP1 ; 2 23 <- set object position sta HMP1 ; 3 26 sta WSYNC ;------------------------------------------------------ ENTER SECOND SCANLINE sta HMOVE ; 3 3 ;================================= ; We haven't had time to preload ; any graphics, so now we have to ; rush and try and make sure we have ; something to draw on this line ;================================= ;================================= ; ; Load Scanline Counter Again ; and Decrement ; ;================================= ldy Heights+.SEC ; 3 6 dey ; 2 8 lda (Player0Ptr),y ; 5 13 and (Player0Msk),y ; 5 18 sta GRP0 ; 3 21 lda (Player0Clr),y ; 5 26 sta COLUP0 ; 3 29 <-- delayed. So we'll have to restrict ; Che's movement on the left of the ; screen? ;================================= ; ; Decrement Scanline Counter ; ;================================= dey ; 2 31 ;================================= ; Preload Che Graphics for THIRD ; scanline. ;================================= lda (Player0Ptr),y ; 5 36 and (Player0Msk),y ; 5 41 sta CheGfxTemp ; 3 44 lda (Player0Clr),y ; 5 49 sta COLUP0 ; 3 52 ;================================= ; ; Decrement Scanline Counter ; ;================================= dey ; 2 54 ; Prime the NUSIZ1 register with the right copies/sizing data lda EnvCopies+.BAND ; 3 57 sta NUSIZ1 ; 3 60 ;================================= ; ; Start of the actual kernel ; ;================================= .KernelLoop sta WSYNC ; 3 75/3 ;----------------------------------------------------- ENTER THIRD SCANLINE ;================================= ; ; Draw Che Graphics in time for left-most ; side of the screen. ; ;================================= lda CheGfxTemp ; 3 3 sta GRP0 ; 3 6 lda EnvGfxTemp ; 3 9 sta GRP1 ; 3 12 ;================================= ; ; Calculate Environment Graphics ; ;================================= lda (EnvGfxPtr+.BAND*2),y ; 5 17 sta EnvGfxTemp ; 3 20 lda (EnvClrPtr+.BAND*2),y ; 5 25 sta COLUP1 ; 3 28 ;================================= ; ; Calculate Che Graphics ; ;================================= lda (Player0Ptr+.BAND*2),y ; 5 33 and (Player0Msk+.BAND*2),y ; 5 38 sta CheGfxTemp ; 3 41 lda (Player0Clr*.BAND*2),y ; 5 46 sta COLUP0 ; 3 49 ;================================= ; ; Decrement line counter, and ; branch out if we're at zero. ; ;================================= dey ; 2 51 bne .KernelLoop ; 2 53 (3 17) What I still have left to do is: Set up the pointers for this kernel Pad the graphics and adjust the pointers so that the graphics appear at the right scanlines I think there's something else... I have attached the source, if you'd like to have a look. coloured_guerrilla021.asm Quote Link to comment Share on other sites More sharing options...
vidak Posted January 27, 2018 Author Share Posted January 27, 2018 OKAY. I have finished coding the pointers for the GRP0 main player character, Che. Almost all the code is lifted from Stay Frosty. Now what I need to do in order to get a full demo working is re-code the pointers for the repeated GRP1 graphics. Please find the attached source code. coloured_guerrilla022.asm Quote Link to comment Share on other sites More sharing options...
vidak Posted January 28, 2018 Author Share Posted January 28, 2018 Okay I've finished my first attempt at the pointers for GRP1.But I need some help - could someone assist in some debugging? The masking for GRP0 works, and the graphics pointers for GRP0 work. The colour pointer for GRP0 is wayyyy off, though. It's pointing way too far down, right into the temporary GRP1 colour data table. When I compiled the code the first time, both the colour and graphics pointers for GRP0 worked, but after I fiddled with the GRP1 labels, the colour pointer stopped working. Confusing. The second problem I have is that the graphics and colour pointers for GRP1 don't work at all. I am attempting to statically and manually fix all 5 bands of GRP1 to a single couple of tables... maybe the tables are crossing a page boundary? The two black bands that comprise most of the glitchy GRP1 graphics is the value $2C. I think the location being loaded is $ED10 - Stella debug reports this as CXP1FB. ANOTHER problem I'm having is that the vertical controls appear to be flipped. Pushing down moves Che upwards and vice versa. BUT: There are no more real artifacts as Che, GRP0 moves between bands. This is a huge improvement over the last kernel version.Anyway, as always, help is always greatly appreciated. Thanks in advance. PS. One weird thing I'm noticing is that the Stella debugger formats my graphics data differently every time I compile a new version of the binary. Sometimes it recognises the graphics data as graphics, and sometimes it doesn't... coloured_guerrilla023.asm guerrilla23.zip 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.