johnnystarr Posted March 13, 2014 Author Share Posted March 13, 2014 Truthfully, the 32 pixel, 48 pixel and sprite-reuse are probably more advance that what a "Newbie" should be worried about. I see where you're coming from, but I've sort of learned things out of order. I'm a newbie to the TIA but not 6502 assembly, and that is probably the most frustrating part! I'm working on a sprite demo right now and I have been playing with repositioning all morning and have had success doing exactly what you and others have described here. Next I'm going to try a 32 pixel mockup based on my current understanding. If I'm offbase, perhaps at that point you could review my source Quote Link to comment Share on other sites More sharing options...
johnnystarr Posted March 13, 2014 Author Share Posted March 13, 2014 So, this is very odd. I've managed to get this to work, however I don't know how it works exactly. As you can see I have 4 unique sprites going on. I have set the NUSIZx to #%00000010 to allow 2 close copies. I've attached screenshots as well as source code. I originally tried positioning using HMPx and HMOVE, however it would reposition both sets of sprites. From what I gather from SpiceWare's source example, we are trying to change the GRPx registers at exactly the right moment when we start drawing the second copy. Somehow my wasted cycles match up at '34' and '42'? ;------------------------------------------------------------- ; 3 part Kernel ;------------------------------------------------------------- LDX #90 Top DEX STA WSYNC BNE Top Layout NOP ; 2 | 2 NOP ; 2 | 4 NOP ; 2 | 6 NOP ; 2 | 8 NOP ; 2 | 10 NOP ; 2 | 12 NOP ; 2 | 14 NOP ; 2 | 16 NOP ; 2 | 18 NOP ; 2 | 20 NOP ; 2 | 22 NOP ; 2 | 24 NOP ; 2 | 26 NOP ; 2 | 28 NOP ; 2 | 30 NOP ; 2 | 32 NOP ; 2 | 34 STA RESP0 STA RESP1 STA WSYNC ; --- kernel --- LDY #13 Kernel LDA SPRITE1,Y ; 4 | 4 STA GRP0 ; 3 | 7 LDA SPRITE2,Y ; 4 | 11 STA GRP1 ; 3 | 14 LDA SPRITE3,Y ; 4 | 18 TAX ; 2 | 20 LDA SPRITE4,Y ; 4 | 24 NOP ; 2 | 26 NOP ; 2 | 28 NOP ; 2 | 30 NOP ; 2 | 32 NOP ; 2 | 34 NOP ; 2 | 36 NOP ; 2 | 38 NOP ; 2 | 40 NOP ; 2 | 42 STX GRP0 STA GRP1 DEY STA WSYNC BNE Kernel ; --- end --- ; quickly turn off the player LDA #0 STA GRP0 STA WSYNC ; kill 1 line STA WSYNC ; kill 2nd LDX #86 Bottom DEX STA WSYNC BNE Bottom Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted March 13, 2014 Share Posted March 13, 2014 Upload your source file and the resulting BIN. A minor tip. For labels, get in the habit of adding a : Top: DEX STA WSYNC BNE Top Layout: NOP ; 2 | 2 NOP ; 2 | 4 ... When your programs get larger you'll be able to jump directly to the routine by finding "label:", whereas finding "label" can take a while because it will also show you every time you reference the label. Quote Link to comment Share on other sites More sharing options...
johnnystarr Posted March 13, 2014 Author Share Posted March 13, 2014 Crazy timing. I actually just got it to work, although I'm not 100% sure how I've attached the source + bin. I'm still a bit unclear on the cycles, and how they match up in this case. All suggestions welcomed here. Thanks, sprite32p.asm sprite32p.bin Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted March 13, 2014 Share Posted March 13, 2014 (edited) Get familiar with Stella's debugger. Enter the debugger then type scanline 81 in the prompt. Hit RETURN, then switch to the TIA tab.At this point repeatedly hit the STEP button in the upper right corner and watch what happens, instruction by instruction. The white dot in the TIA Display (upper-left) is where the video been is currently at. Watch the updates to GRP0 and GRP1 (in the TIA tab) in relation to the movement of the white dot. Edited March 13, 2014 by SpiceWare Quote Link to comment Share on other sites More sharing options...
johnnystarr Posted March 13, 2014 Author Share Posted March 13, 2014 That is very useful. I've tried to compare notes from the details in this thread with the details in http://atariage.com/forums/topic/222918-horizontal-placement-multiple-sprites/ I've taken a stab at calculating the timing, but I must be missing a thing or two. Here's what I've come up with so far. Where you see "CC +n" is just the notation I came up with on the fly to assess how far to the right the NOPs in the "Layout" section move the players. I fine position HMP1 to get it to line up as well, but didn't add those clocks as I wasn't sure if that is part of the equation. I also didn't add the clocks for the indirect Y loads as I didn't know if that was a factor. Is there a simple equation when using this technique? Like +n color clocks, +n HMPx = 32 pixel sprites? Layout NOP ; 2 | 2 NOP ; 2 | 4 NOP ; 2 | 6 NOP ; 2 | 8 NOP ; 2 | 10 NOP ; 2 | 12 NOP ; 2 | 14 NOP ; 2 | 16 NOP ; 2 | 18 NOP ; 2 | 20 NOP ; 2 | 22 - HBLANK stops here NOP ; 2 | 24 | CC +6 NOP ; 2 | 26 | CC +12 NOP ; 2 | 28 | CC +18 NOP ; 2 | 30 | CC +24 NOP ; 2 | 32 | CC +30 NOP ; 2 | 34 | CC +36 NOP ; 2 | 36 | CC +42 STA RESP0 ; 3 | 39| CC +51 after written STA RESP1 ; 3 | 42| CC +60 after written STA WSYNC LDA #%00010000 STA HMP1 STA HMOVE ; --- kernel 1 --- LDY #13 Kernel LDA (SP2),Y STA GRP1 LDA (SP1),Y STA GRP0 LDA (SP3),Y TAX LDA (SP4),Y NOP ; 2 | 2 | CC +6 NOP ; 2 | 4 | CC +12 NOP ; 2 | 6 | CC +18 NOP ; 2 | 8 | CC +24 NOP ; 2 | 10| CC +30 NOP ; 2 | 12| CC +36 STX GRP0 ; 3 | 15| CC +44 after written STA GRP1 ; 3 | 18| CC +53 after written DEY STA WSYNC BNE Kernel ; --- end --- Quote Link to comment Share on other sites More sharing options...
Omegamatrix Posted March 14, 2014 Share Posted March 14, 2014 Your VSYNC is not good. You should start VSYNC following after a WSYNC otherwise the cycle it starts on is variable. This is good: ;do three lines of VSYNC lda #2 sta WSYNC ; <-- use a WSYNC before VSYNC ;--------------------------------------- sta VSYNC ; vsync starts lda #0 sta WSYNC ;1 scanline sta WSYNC ;2 scanlines sta WSYNC ;3 scanlines ;--------------------------------------- sta VSYNC ; vsync ends... . . But this is even better (saves bytes), if you are not doing anything inside those 3 scanlines. This is from Macro.h, and written by Edwin Blink. lda #$0E .loopVsync: sta WSYNC ;--------------------------------------- sta VSYNC lsr bne .loopVsync . . You have probably noticed that I didn't touch VBLANK register in either routine. You've already wrote to the VBLANK register at the start of Overscan, and there is no need to update it here again. That's generally what I do too. I like to start VBLANK right after I draw the screen, and then stop VBLANK right before I start drawing the screen again. Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted March 14, 2014 Share Posted March 14, 2014 You should set HMP1 before you strobe WSYNC again, so you can strobe HMOVE right after WSYNC. In your code HMOVE is getting strobed too late, which will affect the number of pixels that you can shift the players left or right, as well as changing what each value represents (i.e., $10 won't represent "move the sprite left 1 pixel" as you are expecting). Also, setting HMP1 before strobing RESP0 and RESP1 will save a few bytes of ROM: Layout NOP ; 2 | 2 NOP ; 2 | 4 NOP ; 2 | 6 NOP ; 2 | 8 NOP ; 2 | 10 NOP ; 2 | 12 NOP ; 2 | 14 NOP ; 2 | 16 NOP ; 2 | 18 NOP ; 2 | 20 NOP ; 2 | 22 - HBLANK stops here NOP ; 2 | 24 | CC +6 NOP ; 2 | 26 | CC +12 NOP ; 2 | 28 | CC +18 LDA #%00010000 ; 2 | 30 STA HMP1 ; 3 | 33 STA HMP1 ; 3 | 36 STA RESP0 ; 3 | 39 | CC +51 after written STA RESP1 ; 3 | 42 | CC +60 after written STA WSYNC ; 3 | 0 STA HMOVE ; 3 | 3 Note that I used "STA HMP1" twice. That's just to waste 3 more cycles to keep the timing as desired. You could also use "NOP 0" which is a 2-byte, 3-cycle instruction-- but since "NOP 0" is technically a so-called "illegal" 6502 instruction, and takes exactly the same number of bytes and cycles as "STA HMP1," I decided to just write to HMP1 twice in a row since that's a "legal" instruction. As for counting cycles, different programmers have their own formats of choice. The format I like to use would look something like the following: Layout SLEEP 28 ; +28 ; 28 LDA #$10 ; +02 ; 30 STA HMP1 ; +03 ; 33 STA HMP1 ; +03 ; 36 STA RESP0 ; +03 ; 39 ; 117 ; 049 ; 054 STA RESP1 ; +03 ; 42 ; 126 ; 058 ; 063 STA WSYNC ; +03 ; 00 STA HMOVE ; +03 ; 03 I use leading 0s to help keep the numbers lined up nicely in columns, depending on how large the values in a particular column can be-- 2 digits for machine cycles (maximum 76 per line), or 3 digits for color clocks (228 per line) or screen positions (160 per line). The columns after the instructions are as follows: - machine cycles used by the instruction, written with a plus sign since they add to the cycle count; the extra spaces are for asterisks where appropriate (e.g., for a branch instruction I would write +02** since a branch instruction uses 2 cycles if the branch is not taken, plus 1 more cycle if the branch is taken, plus 1 more cycle on top of that if the branch crosses a page boundary) - the current running total of machine cycles used on the given scan line - the current running total of color clocks elapsed on the given scan line (equal to the current machine cycles times 3) - the current screen position on the given scan line (equal to the current color clock minus 68, written with a negative if it's within the HBLANK-- e.g., -68, or -04, or 007, or 029, or 159, etc.) - the screen position where the sprite will appear if it isn't shifted left or right by HMOVE (equal to the current screen position plus 4 if the sprite is a missile or the ball, or plus 5 if the sprite is a player) I omit any columns that aren't pertinent-- for instance, if all I need to know is what the running total of machine cycles happens to be, then I just give the cycles added by the instruction followed by the running total. But if the instruction is related to graphics and it would be helpful to know the corresponding screen position, then I include the current color clock and the current screen position. And if the instruction is resetting a sprite's position, I also include the column showing the sprite's new screen position after the reset instruction has completed. You can simplify the appearance of your code if you use the SLEEP macro instead of writing a bunch of NOP instructions. The assembler will expand the SLEEP instruction into the appropriate number of NOP instructions, so it doesn't actually save you any ROM; but it does look more concise and is more convenient to code. Another thing I like to do is put a blank line before I strobe WSYNC, since that can help make it more clear when reading the code where one scan line ends and another begins. But then I also sometimes like to insert blank lines to group related instructions together for increased legibility, as in the following example: LDA #1 STA $80 LDX #2 STX $81 LDY #3 STY $82 But you should develop whatever format and style works best for you. Quote Link to comment Share on other sites More sharing options...
johnnystarr Posted March 14, 2014 Author Share Posted March 14, 2014 (edited) Thanks a lot SeaGTGruff. That's a good practice and makes more sense than what I had going on. I think everyone has done a great job explaining how horizontal placement and 32 \ 48 pixel sprites can be accomplished. And based on that, I'm sure I could get something to work if I tried enough combinations (like my sprite32p.bin example above) But, I would really like to understand why it works. I've attempted to used SeaGTGruff's notation here to see if someone can explain the SLEEP portion, and why we are wasting cycles there to begin with: Kernel: LDA (SP2),Y ; +5 ; 5 STA GRP1 ; +3 ; 8 LDA (SP1),Y ; +5 ; 13 STA GRP0 ; +3 ; 16 LDA (SP3),Y ; +5 ; 21 TAX ; +2 ; 23 LDA (SP4),Y ; +5 ; 28 SLEEP 12 ; +12 ; 40 ; 120; 52; 57 <-- ??? STX GRP0 ; +3 ; 43 STA GRP1 ; +3 ; 47 DEY STA WSYNC BNE Kernel So, the wasted SLEEP cycles between the write to SP4 and the write to GRP0 eludes me. It is 12 cyles, which puts our line MC count to 40, which puts our CC count to 120. If we subtract 68, this means that the color clock gap comes to 52. Since we're not writing to RESPx, I didn't know if 52 + 5 should be notated, thus the question marks. Ultimately, the goals seems to be to write to GRP0 at the exact moment that the beam reaches the first instance of GRP1. This would update the serial data right before the beam starts drawing the second copy of GRP0. I've ran the Stella debugger, and watched the CC counter right when GRP0 is written to. It is at CC 129 when we write GRP0. If we subtract 68, this equals 61. Now, if we do add +5 to the delay above which is 52, that would equal 57. Does this work because 61 and 57 are "close enough"? ALSO: I find it odd that the 48 pixel examples I've seen don't waste cycles between writes to GRPx. Is this because the horizontal positions aren't a factor because you are using VDELPx ? Edited March 14, 2014 by johnnystarr Quote Link to comment Share on other sites More sharing options...
johnnystarr Posted March 14, 2014 Author Share Posted March 14, 2014 I've been digging through the archives on this site, and I can only find topics related to 48 pixel sprites and not so much 32. Is this one of those tricks that has a technical / mathematical equation? Or is it simply a hack that you have to fine-tune until it works and there isn't an exact formula? I've gotten it to work for me pretty well, but until I know why it's going to bug me! Updated the .bin to that mean old dragon. Haven't begun to figure out the "red eye" trick though. I'm assuming it involves changing the COLUBK register on certain clocks. sprite32p.bin Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted March 14, 2014 Share Posted March 14, 2014 Thanks a lot SeaGTGruff. That's a good practice and makes more sense than what I had going on. I think everyone has done a great job explaining how horizontal placement and 32 \ 48 pixel sprites can be accomplished. And based on that, I'm sure I could get something to work if I tried enough combinations (like my sprite32p.bin example above) But, I would really like to understand why it works. I've attempted to used SeaGTGruff's notation here to see if someone can explain the SLEEP portion, and why we are wasting cycles there to begin with: Kernel: LDA (SP2),Y ; +5 ; 5 STA GRP1 ; +3 ; 8 LDA (SP1),Y ; +5 ; 13 STA GRP0 ; +3 ; 16 LDA (SP3),Y ; +5 ; 21 TAX ; +2 ; 23 LDA (SP4),Y ; +5 ; 28 SLEEP 12 ; +12 ; 40 ; 120; 52; 57 <-- ??? STX GRP0 ; +3 ; 43 STA GRP1 ; +3 ; 47 DEY STA WSYNC BNE Kernel So, the wasted SLEEP cycles between the write to SP4 and the write to GRP0 eludes me. It is 12 cyles, which puts our line MC count to 40, which puts our CC count to 120. If we subtract 68, this means that the color clock gap comes to 52. Since we're not writing to RESPx, I didn't know if 52 + 5 should be notated, thus the question marks. Ultimately, the goals seems to be to write to GRP0 at the exact moment that the beam reaches the first instance of GRP1. This would update the serial data right before the beam starts drawing the second copy of GRP0. I've ran the Stella debugger, and watched the CC counter right when GRP0 is written to. It is at CC 129 when we write GRP0. If we subtract 68, this equals 61. Now, if we do add +5 to the delay above which is 52, that would equal 57. Does this work because 61 and 57 are "close enough"? ALSO: I find it odd that the 48 pixel examples I've seen don't waste cycles between writes to GRPx. Is this because the horizontal positions aren't a factor because you are using VDELPx ? Regarding the format used for counting cycles, use whatever you like or come up with your own style-- what matters is that it makes sense to you. I'm sure some programmers look at my style and say "WTF?" Some people like a very simple, basic style-- and worrying about lining everything up with leading zeros or extra spaces, and/or showing the color clock and screen position counts, may not be worth the extra effort in cases where all you need is to keep a running total of the machine cycles. In the SLEEP 12, there's no need to add 5 to the screen position-- that would be relevant only for a RESP0 or RESP1 instruction (or add 4 for a RESM0, RESM1, or RESBL instruction). There are only two or three reasons I can think of why you'd ever want or need to waste cycles: (1) In 2600 programming, timing can be very important because of the way registers are often updated in the middle of a scan line so as to squeeze the most out of the 2600's limited graphics abilities. (After all, if you had a dozen sprites, or a dozen color registers and fancy multicolor graphics mode at your disposal, there'd be no need to "recycle" any of the graphics registers by changing their values partway through a scan line.) So in order to make some change at just the right point on a scan line, you might need to waste some cycles so that a particular instruction can be executed at a specific cycle. (2) Typically a kernel will be designed to use a loop for drawing one or maybe two scan lines during each pass through the loop. But since the 2600 is so slow-- each machine cycle corresponding to 3 color clocks, and only 76 machine cycles per scan line-- sometimes (or really, just about every time) you don't have quite enough cycles available to do all the things you want, so you have to start making compromises, or else find creative ways to shave off a cycle here and there so you have a little more time to do things. One of the ways that programmers might reclaim a few cycles is to get rid of the WSYNC command-- but since strobing WSYNC is the main way that you keep the instructions lined up nicely from line to line (e.g., so that a graphics change will always occur at a specific cycle on the line), getting rid of WSYNC means you might have to pad the loop so that it takes up exactly 76 cycles (including the cycles used by the comparison and branch instruction). You might even need to "unroll the loop," which means getting rid of the comparison and branch instruction, and drawing the scan lines one after another without using a loop, either for the entire screen or maybe for just a section of the screen. (3) Another possible reason for wasting cycles (and bytes) might be if you have some code in ROM that you want to copy into RAM so you can execute it from RAM. This allows you to modify the code dynamically as the program is executing. This isn't nearly as common as the first two reasons, but it isn't unheard of. In such a case you might conceivably want to pad parts of the code so there's room to change the code as needed-- i.e., you might use filler code such as NOPs, or change the addressing mode used by some of the instructions, so that the code always occupies the same number of bytes in RAM, and/or executes in the same number of cycles, even though portions of the code are being modified as the program executes. Note that it's more common when you execute code from RAM to just change the operands, in which case there's no reason to pad the code by wasting bytes or cycles. I haven't looked at the full code you've quoted from-- I assume this is from Dragonfire-- but in this case the cycles are being wasted for reason 1, to make sure the GRP0 and GRP1 registers get changed at just the right times. I'm not sure whether or not the VDELxx registers are being used for the dragon, but I'm guessing they aren't. That means GRP0 and GRP1 can be loaded much earlier on the scan line for the left half of the dragon (the first copy of player0 and the first copy of player1), but then the program needs to wait until it's safe to change GRP0 and GRP1 for the right half of the dragon, otherwise the graphics would change while the left half is still being drawn and the dragon wouldn't look right. There's a little bit of leeway for updating GRP0 and GRP1 for the right half of the dragon, since GRP0 can be updated any time while the first copy of player1 is being drawn, and then GRP1 can be updated any time while the second copy of player0 is being drawn. I assume the entry into the loop occurs on different cycles based on the position of the dragon, that way the same number of cycles can be wasted each time before updating GRP0 and GRP1 for the right half of the dragon. As for the 48-pixel "score trick," it must be programmed differently than this example because it has more stringent requirements. The 6502/6507 has only 3 data registers-- A, X, and Y-- so that means if you preload them with the desired data then you can write their values to page 0 one after the other and it will take 9 cycles (3 cycles per write). Since 1 cycle equals 3 color clocks, the scanning beam moves 9 color clocks during each write. If you weren't using the VDELP0 and VDELP1 registers, you could preload GRP0 and GRP1 for the first copies of player0 and player1, then write to GRP0, GRP1, and GRP0 at just the right moment for the next 24 pixels. But then you'd need to load another value into A, X, or Y so you can update GRP1 again for the last 8 pixels, and there simply isn't enough time. But if you turn on VDELP0 and VDELP1, you can preload GRP0 twice, since there are really two copies of GRP0 and two copies of GRP1 inside the TIA-- an "old" register and a "new" register. Whenever you write to GRP0, the new data you've written doesn't get displayed until you write to GRP1, and vice versa-- the new data you write to GRP1 isn't displayed until you write to GRP0. So at some early point on the line, you write the first value to GRP0 (but it doesn't display yet), then write the next value to GRP1 (but it doesn't display yet, although it does cause the first value of GRP0 to be displayed), then you write another value to GRP0 (but it doesn't display yet, although it does cause the first value of GRP1 to be displayed). That means you've preloaded the first 3 sprites but only the first 2 have been displayed (by which I mean their graphics are "active," whether or not they've been drawn onscreen yet). Thus, you have only 3 more sprites left to worry about, so you can load up A, X, and Y, then quickly write to GRP1, GRP0, and GRP1 one after the other, causing the third, fourth, and fifth sprites to be displayed. To get the sixth sprite to display you must write to GRP0 one more time, but it doesn't matter what you write to it since the new data won't be displayed, it will merely trigger the data for the sixth sprite (copy 3 of player1) to be displayed. If you're drawing a 40-pixel sprite (2 copies of one player positioned between 3 copies of the other player), or anything less than that-- 32 pixels, 24 pixels, or 16 pixels-- then you generally don't need to use VDELP0 and VDELP1, although they're sometimes used in other cases (apparently they were originally intended to be used in conjunction with "2-line kernels," but then some clever 2600 programmer came up with the idea for the "score trick"). As for "the red eye trick," I haven't looked at the code, but one thing that comes to mind is positioning the ball behind the dragon's head and setting COLUPF to red so the red ball can be seen through the eye hole. Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted March 14, 2014 Share Posted March 14, 2014 Updated the .bin to that mean old dragon. Haven't begun to figure out the "red eye" trick though. I'm assuming it involves changing the COLUBK register on certain clocks.Use Stella's Debugger Mode + Fixed Debug Colors. As for "the red eye trick," I haven't looked at the code, but one thing that comes to mind is positioning the ball behind the dragon's head and setting COLUPF to red so the red ball can be seen through the eye hole.Yep, the eye's drawn using the ball. Difficult to see, so I changed the close-up section to use 4X zoom by right-clicking on it: Quote Link to comment Share on other sites More sharing options...
johnnystarr Posted March 15, 2014 Author Share Posted March 15, 2014 I haven't looked at the full code you've quoted from-- I assume this is from Dragonfire... The code was actually my own, however I updated it to SpiceWare's specifications earlier in this thread. That and I copied the dragon sprites from the Dragonfire source. I think that I understand the 32p example a lot more now. I spent the rest of the afternoon going over SpiceWare's sourcecode for Medieval Mayhem. I was actually able to modify my 32 pixel code and I've ALMOST got the 48 pixel code to work. What I mean by almost is that I got it to work, all but the first graphic has a small "tear" at the bottom. Here's what I would like to know. I totally grasp the VDELPx method, and the pipeling makes sense. I understand the delay in the 32 pixel example because you are basically synchronizing the writes between GRP0 and GRP1. But, all the 48p examples I've seen everywhere all seem to have just about the same timing. I imagine that using indirect Y for each write has something to do with the time formula. Maybe you could take a look at the .bin and .asm for me and help me determine what needs to be changed. I've done my best to line up the sprite pairs and they seem to be lined up perfectly. I have attempted to modify the delay right before RESPx. If I reduce the "SLEEP" count just a bit, the tear goes away, but the sprites aren't in order. I feel like I'm 99% there, and have really enjoyed learning this stuff. sprite48p.bin sprite48p.asm Quote Link to comment Share on other sites More sharing options...
Omegamatrix Posted March 15, 2014 Share Posted March 15, 2014 What I mean by almost is that I got it to work, all but the first graphic has a small "tear" at the bottom. You don't need to use EQU *-1 with your sprite labels. That is screwing up your pointers. Just do: SPRITE1: .BYTE #%11111111 .BYTE #%11111111 .BYTE #%11011011 .BYTE #%11011011 .BYTE #%11011011 .BYTE #%11011011 .BYTE #%11011011 .BYTE #%11011011 .BYTE #%11000011 .BYTE #%11000011 .BYTE #%11011011 .BYTE #%11011011 .BYTE #%11100111 .BYTE #%11111111 .BYTE #%11111111 .BYTE #%11111111 Quote Link to comment Share on other sites More sharing options...
johnnystarr Posted March 15, 2014 Author Share Posted March 15, 2014 Dude! That's awesome. I didn't realize that doing that would screw up the pointer. I had to reduce my loop by one to factor for the fact that it started at 0. I started using EQU *-1 some time back because it made my loops easier to manage. Now I guess I need to understand the BigMove routine to see how it handles movement. Thanks for all the info, you guys have probably taught me in a week what would have taken years! Quote Link to comment Share on other sites More sharing options...
johnnystarr Posted March 15, 2014 Author Share Posted March 15, 2014 Oh yeah, it works perfectly now. 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.