Cybearg Posted February 3, 2013 Author Share Posted February 3, 2013 My biggest worry is getting this to work without flicker. Adding more rings would be neat, but my biggest worry is getting it to not give people seizures. I don't know anything close to the know-how to create a new kernel or whatever must be done, so I'm pretty much sitting on my hands until someone pops out a genie of a solution. Additionally, a variable is set aside to remember the color in each of the current 16 positions, so adding more is essentially out of the question unless I use a superchip RAM, which I hesitate to do because I'd love the game to all be perfectly packed in your average 4K 6400 cartridge. Doesn't increasing the player size just widen the sprite, though? It doesn't make it any taller, so it would just look like someone stomped on the sprite, rather than like the whole heart was larger, no? Also, I can't draw using player 0 and player 1 because the player 1 is the ball (necessary because the ball takes on the color of the playfield, if I'm not mistaken). Quote Link to comment Share on other sites More sharing options...
Omegamatrix Posted February 3, 2013 Share Posted February 3, 2013 (edited) My biggest worry is getting this to work without flicker. You shouldn't need to worry. It is very doable to write an assembly kernel since you got the colors separated. You're in good hands with SeaGtGruff as he is a very capable programmer doing lots of interesting stuff related to colors, timers, multiple sprites, and sound. Doesn't increasing the player size just widen the sprite, though? Yes. To make the sprite appear proportional you just have to add more lines of graphics to compensate. Also, I can't draw using player 0 and player 1 because the player 1 is the ball (necessary because the ball takes on the color of the playfield, if I'm not mistaken). Yes, but when you refer to your player 1 as the ball it sounds confusing, because the object that borrows its color from the playfield really is called the "ball". Maybe refer to your on screen dot as the projectile or something. In any case you could also draw that dot with missile 1, which is often referred to as M1. Edited February 3, 2013 by Omegamatrix Quote Link to comment Share on other sites More sharing options...
Cybearg Posted February 4, 2013 Author Share Posted February 4, 2013 The problem with using missile 1 or missile 0 is that they take on the colors of their sprites. I need the "projectile" to take on the color of player0 (the heart) at the moment of joy0fire and retain that color (and have it stored somewhere that can be read, since it's important for collision detection), which is what currently happens. If I have to trim out some of the intricacies of the original gameplay design, that's alright so long as what remains works well. Quote Link to comment Share on other sites More sharing options...
Omegamatrix Posted February 4, 2013 Share Posted February 4, 2013 The problem with using missile 1 or missile 0 is that they take on the colors of their sprites. I need the "projectile" to take on the color of player0 (the heart) at the moment of joy0fire and retain that color Right now you are using GRP0 for the heart, and GRP1 for the projectile, correct? M1 shares the same color as GRP1 so you have the choice of using either object. Quote Link to comment Share on other sites More sharing options...
Cybearg Posted February 4, 2013 Author Share Posted February 4, 2013 Right now you are using GRP0 for the heart, and GRP1 for the projectile, correct? M1 shares the same color as GRP1 so you have the choice of using either object. True, but if I was using player 1 and player 0 together to create a megasprite, that would require them to share the same colors in order to make it work, which in turn wouldn't work when missile1 swapped colors to match. Quote Link to comment Share on other sites More sharing options...
Cybearg Posted February 5, 2013 Author Share Posted February 5, 2013 Has anyone had any luck devising (or does anyone know of) a kernel that will allow what I want to happen to happen? How will the code have to change once this is in place? I assume I won't continue to drawscreen every three cycles to change colors and will instead have a color per drawscreen, right? Any idea how that would need to look, so I can work on setting up the code to work for it in the meanwhile? Quote Link to comment Share on other sites More sharing options...
bogax Posted February 6, 2013 Share Posted February 6, 2013 it occured to me that if you use the noinlinedata optimization you can interleave the x and y tables thusly. I have no idea if this is relevant for i = 0 to 14 step 2 if a[i] then goto collision_test nexti next collision_test temp1 = playerx1-xtbl[i] if temp1>3 then goto nexti temp1 = playery1-ytbl[i] if temp1>5 then goto nexti if a[i]<>ballcolor then goto bad_hit rem good_hit a[i]=0 bad_hit data xtbl 81 end data ytbl 9, 114, 17, 130, 49, 114, 81, 82, 89, 50, 81, 34, 49, 50, 17 end and while I'm at it rem move all block values to the right temp2 = a for temp1 = 0 to 14 a[temp1] = b[temp1] next p = temp2 rem move all blocks to the left temp2 = p for temp1 = 14 to 0 step -1 b[temp1] = a[temp1] next a = temp2 Quote Link to comment Share on other sites More sharing options...
Cybearg Posted February 6, 2013 Author Share Posted February 6, 2013 Thanks much for all the advice! I hadn't thought to combine the data sets (though it only saved me about 10 bytes, but still!) and I didn't know that you could do a[temp1+1] with b[temp1]. though it makes sense in hindsight. That's pretty awesome. It occurs to me that I haven't posted the code in a while. I'm always open to input to make things more efficient, and maybe it will help in developing that kernel (hope that everyone hasn't forgotten ). rem Generated 1/28/2013 1:50:36 PM by Visual bB Version 1.0.0.548 rem ********************************** rem *heartbreak.bin * rem *A re-imagning of breakout with a lonely heart trapped in a void... * rem *Cybearg (aka Nic) * rem *cybearg.plays@gmail.com * rem ********************************** rem ============== rem INITIALIZATION rem ============== rem set up settings/optimization set optimization speed rem set up my variables dim level = s dim cooldown=t dim anglevar=u dim pulse=v dim flicker=w dim offset=x dim ballcolor=y dim heartcolor=z rem set offset to a number greater than 0 to allow for "negative" values offset = 50 rem set heartcolor to begin at red heartcolor = 64 rem set player 0's location player0x=80:player0y=48 rem ========== rem MAIN LOOP rem ========== draw_loop rem clear the playfield pfclear rem increment the multi-purpose cooldown variable cooldown = cooldown + 1 rem mute sound at 7 cooldown cycles or after 20 cycles if there's been a titlescreen restart if cooldown = 7 || cooldown = 70 then AUDV0 = 0 : AUDV1 = 0 rem =============== rem BEATING HEART rem =============== rem increment pulse counter pulse = pulse +1 rem cooldown to make sure that player doesn't leave the title screen by firing a ball if pulse = 45 && cooldown >= 50 then cooldown = 0 rem after 45 cycles, increment color if pulse = 45 then pulse = 0 rem special occasion for first level if level = 0 then heartcolor = 64: goto 10 rem special occasion for second level if level = 1 && heartcolor = 64 && pulse = 0 then heartcolor = 28: goto 10 if level = 1 && heartcolor = 28 && pulse = 0 then heartcolor = 64: goto 10 rem increment the colors if heartcolor = 28 && pulse = 0 then heartcolor = 148: goto 10 if heartcolor = 64 && pulse = 0 then heartcolor = 28: goto 10 if heartcolor = 148 && pulse = 0 then heartcolor = 64 10 rem set the playfield colors COLUP0 = heartcolor rem turn the score red if player is on the last life if lives = 1 then scorecolor = 64 else scorecolor = 10 rem swap the heart sprite for 5 cycles to create illusion of beating if pulse < 40 then goto 40 else goto 44 rem values for the up-beat (40 out of 45 cycles) 40 if lives = 0 then goto 80 41 if lives = 1 then goto 70 42 if lives = 2 then goto 60 43 if lives = 3 then goto 50 rem values for the down-beat (5 out of 45 cycles) 44 if lives = 0 then goto 80 45 if lives = 1 then goto 90 46 if lives = 2 then goto 70 47 if lives = 3 then goto 60 rem the various player 0 heart sprites 50 player0: %00010000 %00111000 %01111100 %11111110 %11111110 %11111110 %01101100 %00000000 end 55 goto 100 60 player0: %00000000 %00010000 %00111000 %01111100 %01111100 %00101000 %00000000 %00000000 end 65 goto 100 70 player0: %00000000 %00000000 %00010000 %00111000 %00101000 %00000000 %00000000 %00000000 end 75 goto 100 80 90 player0: %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 end rem ============== rem COLOR FLICKER rem ============== 100 rem if the player has zero lives, skip this part if lives = 0 then goto 410 rem set up possible colors data blkc 64, 28, 148 end rem set up possible pfpixel locations data ctbl 16, 20, 24, 27, 28, 27, 24, 20, 16, 12, 8, 5, 4, 5, 8, 12 end data rtbl 0, 0, 1, 3, 5, 7, 9, 10, 10, 10, 9, 7, 5, 3, 1, 0 end rem cycle through pfpixels, turning them on if they are equal to the color being drawn for temp5 = 0 to 15 if a[temp5] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on next rem set playfield to current color COLUPF = blkc[flicker] rem increment flicker temp1 = blkc_length + 1 if flicker = temp1 then flicker = 0 else flicker = flicker + 1 rem ================== rem MAIN DRAWSCREEN rem ================== rem main drawscreen drawscreen rem skip to COLOR MOVEMENT goto 415 rem ============= rem TITLE SCREEN rem ============= 410 rem set the beat of the title screen heart to the ongoing pulse if pulse < 40 then goto 413 else goto 412 rem the two possible title screen frames 412 playfield: ................................ ...X.X.XXX..X..XX.XXX........... ...X.X.X...X.X.X.X.X............ ...XXX.XX..XXX.XX..X............ ...X.X.XXX.X.X.X.X.X............ .............................. ...........XX..XX..XXX..X..X.X.. ....X.X....X.X.X.X.X...X.X.X.X.. ....XXX....XX..XX..XX..XXX.XX... .....X.....X.X.X.X.XXX.X.X.X.X.. ...........XXX.................. end rem skip to color goto 414 413 playfield: ................................ ...X.X.XXX..X..XX.XXX........... ...X.X.X...X.X.X.X.X............ ...XXX.XX..XXX.XX..X............ ...X.X.XXX.X.X.X.X.X............ ................................ ...XX.XX...XX..XX..XXX..X..X.X.. ..XXXXXXX..X.X.X.X.X...X.X.X.X.. ...XXXXX...XX..XX..XX..XXX.XX... ....XXX....X.X.X.X.XXX.X.X.X.X.. .....X.....XXX.................. end 414 rem color the title screen playfield COLUPF = 64 rem drawscreen for titlescreen only drawscreen rem skip everything else and wait for a trigger goto 760 rem ================= rem COLOR MOVEMENT rem ================= 415 rem NOTE: offset base is 50, so the numbers below determine how sensitive the controls are rem determine block offset if joy0left && offset < 56 then offset = offset + 1 if joy0right && offset > 44 then offset = offset - 1 rem adjust block offset 420 if offset > 55 goto 435 if offset < 45 goto 445 rem if no adjustments are necessary, skip this part goto 500 rem move all block values to the left (counter clockwise) 435 temp2 = a for temp1 = 0 to 14 a[temp1] = b[temp1] next p = temp2 goto 450 rem move all blocks to the right (clockwise) 445 temp2 = p for temp1 = 15 to 0 step -1 b[temp1] = a[temp1] next a = temp2 rem reset the offset 450 offset = 50 rem ============ rem PLAYER FIRE rem ============ 500 rem checks to see that a few cool-down measures are a go, then moves the ball (player 1) to the center of the heart (player 0) rem cooldown ensures that the player cannot fire while a ball is at play rem cooldown also ensures the player doesn't exit a title screen by firing a ball prematurely if joy0fire && lives > 0 && player1x = 0 && player1y = 0 && cooldown < 50 then player1x=80:player1y=48 else goto 600 rem moves the ball's current color from heartcolor (set in the BEATING HEART section) to ballcolor for safe-keeping ballcolor = heartcolor rem set player 1's sprite player1: %00000000 %00000000 %00000000 %00011000 %00011000 %00000000 %00000000 %00000000 end rem generate random number to determine ball movement rem variables ensure that ball speed/angle does not vary once ball has been generated anglevar = (rand/32) rem ========= rem THE BALL rem ========= 600 rem skip everything dealing with the ball if it is at its resting position (0,0) if player1x = 0 && player1y = 0 then goto 800 rem maintain the color of the ball at the moment of firing COLUP1 = ballcolor rem all ball movement possibilities rem allows for ball movement in a direction every 45 degrees 650 rem cooldown is used to manage the speed of the ball if cooldown > 8 then cooldown = 0 rem x motion table data xmtbl 50, 51, 51, 51, 50, 49, 49, 49 end rem y motion table data ymtbl 51, 51, 50, 49, 49, 49, 50, 51 end rem separate out cardinal from diagonal directions if anglevar <> 0 && anglevar <> 2 && anglevar <> 4 && anglevar <> 6 then goto 670 else goto 680 670 rem movements for diagonal directions (45, 125, 225, 315) -- applies a cooldown to ensure that diagonals do not move too fast if cooldown <> 1 && cooldown <> 3 && cooldown <> 5 && cooldown <> 7 then player1x = player1x + xmtbl[anglevar] - 50: player1y = player1y + ymtbl[anglevar] - 50: goto 700 else goto 700 680 rem movement values for cardinal (0, 90, 180, 270 degrees) directions -- applies a cooldown to ensure that cardinal directions do not move too fast if cooldown <> 3 && cooldown <> 7 then player1x = player1x + xmtbl[anglevar] - 50 if cooldown <> 3 && cooldown <> 7 then player1y = player1y + ymtbl[anglevar] - 50 rem ==================== rem COLLISION DETECTION rem === thanks to bogax === rem ==================== 700 rem check to see if player 1 is out of bounds if player1x = 25 || player1y = 0 then goto 750 if player1x=133 || player1y = 140 then goto 750 rem minimum collision data locations (x, y) data btbl 78, 4, 109, 12, 125, 44, 109, 76, 77, 84, 45, 76, 29, 44, 45, 12 end rem check each of the 8 possible collision locations for temp4 = 0 to 14 step 2 temp3 = temp4 + 1 rem set up temporary variables to contain the full range of the x and y potentials temp5 = btbl[temp4] + 4 temp6 = btbl[temp3] + 8 rem if player1x is within the range for the current block and player1y is within the range for the current block, there is a collision if player1x > btbl[temp4] && player1x < temp5 && player1y > btbl[temp3] && player1y < temp6 then goto 710 rem otherwise, check the next block next rem if no collision is detected, skip to the end of the main loop goto 800 rem check for collision type 710 rem check if the block is already dead if a[temp4] = 0 then goto 800 rem check ball color against block color if a[temp4]<>ballcolor then goto bad_hit rem if the hit is good... good_hit rem set current block to dead a[temp4] = 0 rem increment score score = score + 25 rem play good hit sound AUDV1 = 6 AUDC1 = 12 AUDF1 = 19 goto 725 rem if the hit is bad... bad_hit rem lose a life lives = lives - 1 rem play bad hit sound AUDV1 = 6 AUDC1 = 6 AUDF1 = 16 rem reset sound cooldown counter 725 if lives > 0 then cooldown = 0 else cooldown = 50: pulse = 0 750 rem reset player 1 location, unlocking player 0 fire player1x = 0: player1y = 0 rem ================== rem STAGE GENERATION rem ================== 760 rem exits title screen and generates a new stage if joy0fire && lives = 0 && cooldown < 50 then score = 0: pulse = 0: cooldown = 50: level = 0: goto 775 rem cycles through blocks to check if all have been destroyed temp2 = 0 for temp1 = 0 to 15 if a[temp1] = 0 && lives > 0 then temp2 = temp2 + 1 next rem if not, then end cycle if temp2 <> 16 then goto 800 rem if so, then score bonus points for completing stage and continue if lives = 3 then score = score + 600 if lives = 2 then score = score + 400 if lives = 1 then score = score + 200 rem increment the level counter, but make sure it doesn't go too high if level < 10 then level = level + 1 rem generates new stage by looping through and inserting new colors taken from data set under COLOR FLICKER 775 rem different values for different levels if level = 0 then goto 776 if level = 1 then goto 777 else goto 780 776 rem first level has only red blocks, to teach basic mechanics of firing a ball and rotating blocks for temp1 = 0 to 15 a[temp1] = blkc[0] next goto 799 777 rem second level teaches the differences between the colors and how the right color must go to the right ball for temp1 = 0 to 15 temp2 = (rand/64) if temp2 < 2 then a[temp1] = blkc[1] else a[temp1] = blkc[0] next goto 799 780 rem third level introduces all three primary colors for temp1 = 0 to 15 temp2 = rand if temp2 < 86 then a[temp1] = blkc[0] if temp2 > 85 then a[temp1] = blkc[1] if temp2 > 170 then a[temp1] = blkc[2] next 799 rem complete reset by giving full lives lives = 3 rem end loop 800 goto draw_loop heartbreak.bas Current remaining resources: 1234 bytes and 2 variables Note that the way that the colors flicker will likely have to be changed for whatever the kernel ends up being and I intend to have a number of extra pre-set level types to introduce new colors, but I haven't programmed them in because everything relies on the flickering. Quote Link to comment Share on other sites More sharing options...
Omegamatrix Posted February 6, 2013 Share Posted February 6, 2013 Do you mind posting bins as well? Not everyone has BB installed, like me. Quote Link to comment Share on other sites More sharing options...
Cybearg Posted February 6, 2013 Author Share Posted February 6, 2013 Oh, sorry. Here you go! heartbreak.bas.bin Quote Link to comment Share on other sites More sharing options...
+Andrew Davie Posted February 6, 2013 Share Posted February 6, 2013 rem move all block values to the right 435 for temp1 = 0 to 15 temp2 = temp1 + 1 if temp2 = 16 then temp2 = 0 a[temp1] = a[temp2] next offset = 50 goto 500 rem move all blocks to the left 445 for temp1 = 15 to 0 step -1 temp2 = temp1 - 1 if temp2 = 255 then temp2 = 15 a[temp1] = a[temp2] next offset = 50 450 Hey there Not familiar with Bb myself, but what you have there is a power-of-two sized buffer which you're rotating by shifting the whole buffer left or right. What I'd do is not shift the buffer at all, but instead shift the starting point left or right. So instead of starting at 0, I'd start at X, where X is 0 to 15. Also, not sure if you can binary-AND with Bb, but if you can, then you don't really need the >16 checks. rem move all block values to the right <<< yeah, is this comment correct? I think of this sort of shifting as shifting LEFT rem using a 'wrap around' at 16, where the &15 guarantees our range is 0-15 435 for temp1 = 0 to 15 a[temp1] = a[(temp1+1)&15] next But, as I said... the above code is going to be slow; it's moving 16 values in an array. You want to avoid this sort of thing, and instead of moving the whole array around, see if you can start in the middle and have the pointer to the elements wrap around when it goes off the 'edge' of the array. That is, don't shift the array values at all. Just conceptually shift the start of the array by starting your drawing/lookup midway through. For example pointer = (pointer-1)&15 will go 0 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 15 ... because when it's 0, then it decrements to -1 (255) or in 16-bit, 65535, which when binary AND-ed with 15 gives 15, in both cases. The & is what I use for "Binary AND" (as opposed to logical AND). Same thing with pointer = (pointer+1)&15 this will wrap when it gets to 16, back to 0. So if your array doesn't shift at all, but you start 'drawing' at element #7, then you go 7 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 Hope that makes sense.. It may not be workable in your current setup, as I haven't looked at all of your code. I've just realised there are 2 pages more after the message I replied to. The above may be useless info by now Cheers A Quote Link to comment Share on other sites More sharing options...
+Gemintronic Posted February 6, 2013 Share Posted February 6, 2013 I'd suggest having a "loaded" shot near the heart that faces the direction the shot will go in if unleashed. Also, congats on getting advice from Andrew Davie. He's a seasoned developer with enough experience to send both of us back to Kindergarten! Quote Link to comment Share on other sites More sharing options...
Cybearg Posted February 6, 2013 Author Share Posted February 6, 2013 Yeah, it's an honor! Thanks, Andrew! I feel foolish for not having thought of it. It's still certainly relevant, so I'm going to try implementing that now. It'll surely save a number of cycles. What I'm trying to crunch at the moment is a way for the flickering set-up to dynamically adjust to serve however many colors are in the array at a time, but it just isn't working. rem set up possible colors data blkc 64, 28, 154, 44, 202, 122, 14, 0 end rem set up possible pfpixel locations data ctbl 16, 20, 24, 27, 28, 27, 24, 20, 16, 12, 8, 5, 4, 5, 8, 12 end data rtbl 0, 0, 1, 3, 5, 7, 9, 10, 10, 10, 9, 7, 5, 3, 1, 0 end 110 rem cycle through pfpixels, turning them on if they are equal to the color being drawn if flicker = 8 then flicker = 0 for temp5 = 0 to 15 if a[temp5] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on: temp4 = 1 next rem determines if a color shows up; if not, don't bother drawing that color and return for the next if temp4 = 0 then flicker = flicker + 1: goto 110 else COLUPF = blkc[flicker] rem ================== rem MAIN DRAWSCREEN rem ================== rem main drawscreen drawscreen Even though this makes sense to me in my head, it doesn't seem to work correctly. I'm probably just overlooking something painfully obvious. Quote Link to comment Share on other sites More sharing options...
Cybearg Posted February 6, 2013 Author Share Posted February 6, 2013 I tried kind of what you suggested, Andrew, but I can't get it to work. What you wrote precisely just causes the program to do nothing, and since I don't really understand what a[temp1] = a[(temp1+1)&15] does, I can't do much to fix it. I did try keeping the spirit of the suggestion with something like this: rem cycle through pfpixels, turning them on if they are equal to the color being drawn for temp5 = 0 to 15 rem adjust block offset if offset > 55 then temp6 = (temp5 + 1) if offset < 45 then temp6 = (temp5 - 1) else temp6 = temp5 if a[temp6] = blkc[flicker] then pfpixel ctbl[temp6] rtbl[temp6] on next I see your point, though I don't think that it will work with the way the code is currently set up. More than just the visual colors are dependent on the location in the array: the coordinates of each pfpixel is tied to a location in the array which I depend on when determining which color each pfpixel is, so a[0] needs to correspond to ctbl[0] and rtbl[0]. I'm not sure that a single variable is sufficient for carrying that offset in addition to performing the cooldown function (to ensure that the ring rotation isn't per-pixel sensitive), and I'm really not quite sure how it would work at all without the ability for variable values to go into the negatives. Quote Link to comment Share on other sites More sharing options...
bogax Posted February 6, 2013 Share Posted February 6, 2013 (edited) since I don't really understand what a[temp1] = a[(temp1+1)&15] does in this case it effects a mod 16. 0 and anything is 0 1 and anything is that thing. 15 is 00001111 in binary & 15 is a bitwise and so you zero everything but the lower four bits kinda like in decimal if you set all digits of an integer except the first one (least significant) to zero you get that number mod 10 if you keep the first two it's mod 100 etc I see your point, though I don't think that it will work with the way the code is currently set up. More than just the visual colors are dependent on the location in the array: the coordinates of each pfpixel is tied to a location in the array which I depend on when determining which color each pfpixel is, so a[0] needs to correspond to ctbl[0] and rtbl[0]. I'm not sure that a single variable is sufficient for carrying that offset in addition to performing the cooldown function (to ensure that the ring rotation isn't per-pixel sensitive), and I'm really not quite sure how it would work at all without the ability for variable values to go into the negatives. I don't think it would be much of a problem to fit it into what you're doing now. I'm not sure there'd be any advantage. it would greatly simplify the rotation code at the expense of adding code and slowing things down pretty much every where else you indexed the objects. you'd also need a variable to remember where your first object is, or to map the logical location to the actual address or between the colors index and the position paramters index(es) if you like (how ever you want to think of it). you'd either need to translate from a loop variable to an index or maintain the index in parallel with the translation built in. I didn't actually count the cycles but it would save you 450 cycles in the rotation loops at the expense of extra 150 cycles in the rest of the loops. for temp5 = 0 to 15 if a[temp5] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on next would become: translate for temp5 = 0 to 15 temp6 = temp5 + base & $0F if a[temp6] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on next in parallel temp6 = base for temp5 = 0 to 15 if a[temp6] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on temp6 = temp6 + 1 & $0F next that assumes you're starting with the first color you could also make the object color index the for-variable but I think that would complicate things needlessly as an aside you shouldn't count on temp variables if you're going to call something that might use them like pfpixel (although I think the only temp variable pfpixel uses it temp2) rotation is simplified rem rotate left base = base + 1 & $0F possibly I'm missing something but the only thing that changes is how the object colors are mapped to the other stuff I don't see how that effects cooldown I suppose if, where you start has an effect there could be problems ie you assume that the first thing in a table is also the first object/color like if you drew things top down by color here and by table location there but I didn't see that(?) also I don't see what you need negative values for here's the old rotation code in asm (untested) REM rotate left asm lda a pha ldx #$00 LLOOP lda b,x sta a,x inx cpx #15 bne LLOOP pla sta p end rem rotate right asm lda p pha ldx #14 RLOOP lda a,x sta b,x dex bpl RLOOP pla sta a end miscellaneous for temp1 = 0 to 15 temp2 = (rand/64) if temp2 < 2 then a[temp1] = blkc[1] else a[temp1] = blkc[0] next for temp1 = 0 to 15 temp2 = rand if temp2 < 128 then a[temp1] = blkc[1] else a[temp1] = blkc[0] next actually you can use rand instead of temp2 in the if-then but then bB just uses the last value of rand without computing a new one Edited February 7, 2013 by bogax Quote Link to comment Share on other sites More sharing options...
Cybearg Posted February 6, 2013 Author Share Posted February 6, 2013 Egh. Tried fiddling with what you offered there, bogax, and while it does make the movement work just fine, the hit detection is completely buggered by the change. Anyone have any further suggestions about my primary kernel problem? EDIT: And I still can't figure out what's going wrong here: rem set up possible colors data blkc 64, 28, 154, 44, 202, 122, 14, 0 end rem set up possible pfpixel locations data ctbl 16, 20, 24, 27, 28, 27, 24, 20, 16, 12, 8, 5, 4, 5, 8, 12 end data rtbl 0, 0, 1, 3, 5, 7, 9, 10, 10, 10, 9, 7, 5, 3, 1, 0 end 110 rem cycle through pfpixels, turning them on if they are equal to the color being drawn if flicker = 8 then flicker = 0 for temp5 = 0 to 15 if a[temp5] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on: temp4 = 1 next rem determines if a color shows up; if not, don't bother drawing that color and return for the next if temp4 = 0 then flicker = flicker + 1: goto 110 else COLUPF = blkc[flicker]: flicker = flicker + 1 rem ================== rem MAIN DRAWSCREEN rem ================== rem main drawscreen drawscreen Here's what I think it should be doing (let's assume it's a level with only red, 64, and yellow, 28): 1. Since all variables initialize at 0, flicker begins at 0 2. Since flicker is != 8, flicker is not affected by the first if statement 3. A temporary variable (temp5) starts a loop, initializing itself at 0 4. The first block in the ring (a[0]) is checked to see if it conforms with the first color in the data set (blkc[0]) -- let's say that it does match 5. A pfpixel corresponding to location 0 is drawn for the block and temp4 is set to 1 6. The loop continues, finding some yellow blocks that aren't drawn and some red blocks that are drawn 7. Since temp4 != 0, COLUPF is set to blkc[0] (64, red) and flicker is incremented 8. The cycle repeats for yellow (in the next main_loop cycle, after a drawscreen and pfclear), where temp4 gets set to 1 again because a[something] = blkc[1] (28, yellow), so pfpixels are drawn, the "if temp4 = 0" check is passed, and COLUPF = blkc[flicker] and flicker is incremented. 9. This time through the main loop, flicker = 2, and since there are no blue blocks in this particular theoretical randomization, temp4 should remain 1, which triggers the "if temp4 = 0" check, which increments flicker and sends back for another loop through, this time checking for flicker = 3, and so it continues until flicker = 8, whereupon flicker = 0 and the cycle continues at red. In theory, this should only flicker between colors that are actually represented in the playfield. A field with all red blocks should be completely solid because there should never be a cycle where a playfield is rendered with fewer than all of the blocks being red. Similarly, if the playfield consists of half red and half blue, then all the blue blocks are killed by the player, the playfield should become solid red because the above loop would not have any other colors to trip the temp4 = 1 check and get drawn. Instead, it continues to flicker as always, even when all playfield blocks are red. I cannot understand why. rem Generated 1/28/2013 1:50:36 PM by Visual bB Version 1.0.0.548 rem ********************************** rem *heartbreak.bin * rem *A re-imagning of breakout with a lonely heart trapped in a void... * rem *Cybearg (aka Nic) * rem *cybearg.plays@gmail.com * rem ********************************** rem ============== rem INITIALIZATION rem ============== rem set up settings/optimization set optimization speed rem set up my variables dim level = s dim cooldown=t dim anglevar=u dim pulse=v dim flicker=w dim offset=x dim ballcolor=y dim heartcolor=z rem set offset to a number greater than 0 to allow for "negative" values offset = 50 rem set heartcolor to begin at red heartcolor = 64 rem set player 0's location player0x=80:player0y=48 rem ========== rem MAIN LOOP rem ========== draw_loop rem clear the playfield pfclear rem increment the multi-purpose cooldown variable cooldown = cooldown + 1 rem mute sound at 7 cooldown cycles or after 20 cycles if there's been a titlescreen restart if cooldown = 7 || cooldown = 70 then AUDV0 = 0 : AUDV1 = 0 rem =============== rem BEATING HEART rem =============== rem increment pulse counter pulse = pulse +1 rem cooldown to make sure that player doesn't leave the title screen by firing a ball if pulse = 45 && cooldown >= 50 then cooldown = 0 rem after 45 cycles, increment color if pulse = 45 then pulse = 0 rem special occasion for first level if level = 0 then heartcolor = 64: goto 10 rem special occasion for second level if level = 1 && heartcolor = 64 && pulse = 0 then heartcolor = 28: goto 10 if level = 1 && heartcolor = 28 && pulse = 0 then heartcolor = 64: goto 10 rem increment the colors if heartcolor = 28 && pulse = 0 then heartcolor = 148: goto 10 if heartcolor = 64 && pulse = 0 then heartcolor = 28: goto 10 if heartcolor = 148 && pulse = 0 then heartcolor = 64 10 rem set the playfield colors COLUP0 = heartcolor rem turn the score red if player is on the last life if lives = 1 then scorecolor = 64 else scorecolor = 10 rem swap the heart sprite for 5 cycles to create illusion of beating if pulse < 40 then goto 40 else goto 44 rem values for the up-beat (40 out of 45 cycles) 40 if lives = 0 then goto 80 41 if lives = 1 then goto 70 42 if lives = 2 then goto 60 43 if lives = 3 then goto 50 rem values for the down-beat (5 out of 45 cycles) 44 if lives = 0 then goto 80 45 if lives = 1 then goto 90 46 if lives = 2 then goto 70 47 if lives = 3 then goto 60 rem the various player 0 heart sprites 50 player0: %00010000 %00111000 %01111100 %11111110 %11111110 %11111110 %01101100 %00000000 end 55 goto 100 60 player0: %00000000 %00010000 %00111000 %01111100 %01111100 %00101000 %00000000 %00000000 end 65 goto 100 70 player0: %00000000 %00000000 %00010000 %00111000 %00101000 %00000000 %00000000 %00000000 end 75 goto 100 80 90 player0: %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 end rem ============== rem COLOR FLICKER rem ============== 100 rem if the player has zero lives, skip this part if lives = 0 then goto 410 rem set up possible colors data blkc 64, 28, 154, 44, 202, 122, 14, 0 end rem set up possible pfpixel locations data ctbl 16, 20, 24, 27, 28, 27, 24, 20, 16, 12, 8, 5, 4, 5, 8, 12 end data rtbl 0, 0, 1, 3, 5, 7, 9, 10, 10, 10, 9, 7, 5, 3, 1, 0 end 110 rem cycle through pfpixels, turning them on if they are equal to the color being drawn if flicker = 8 then flicker = 0 for temp5 = 0 to 15 if a[temp5] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on: temp4 = 1 next rem determines if a color shows up; if not, don't bother drawing that color and return for the next if temp4 = 0 then flicker = flicker + 1: goto 110 else COLUPF = blkc[flicker]: flicker = flicker + 1 rem ================== rem MAIN DRAWSCREEN rem ================== rem main drawscreen drawscreen rem skip to COLOR MOVEMENT goto 415 rem ============= rem TITLE SCREEN rem ============= 410 rem set the beat of the title screen heart to the ongoing pulse if pulse < 40 then goto 413 else goto 412 rem the two possible title screen frames 412 playfield: ................................ ...X.X.XXX..X..XX.XXX........... ...X.X.X...X.X.X.X.X............ ...XXX.XX..XXX.XX..X............ ...X.X.XXX.X.X.X.X.X............ .............................. ...........XX..XX..XXX..X..X.X.. ....X.X....X.X.X.X.X...X.X.X.X.. ....XXX....XX..XX..XX..XXX.XX... .....X.....X.X.X.X.XXX.X.X.X.X.. ...........XXX.................. end rem skip to color goto 414 413 playfield: ................................ ...X.X.XXX..X..XX.XXX........... ...X.X.X...X.X.X.X.X............ ...XXX.XX..XXX.XX..X............ ...X.X.XXX.X.X.X.X.X............ ................................ ...XX.XX...XX..XX..XXX..X..X.X.. ..XXXXXXX..X.X.X.X.X...X.X.X.X.. ...XXXXX...XX..XX..XX..XXX.XX... ....XXX....X.X.X.X.XXX.X.X.X.X.. .....X.....XXX.................. end 414 rem color the title screen playfield COLUPF = 64 rem drawscreen for titlescreen only drawscreen rem skip everything else and wait for a trigger goto 760 rem ================= rem COLOR MOVEMENT rem ================= 415 rem NOTE: offset base is 50, so the numbers below determine how sensitive the controls are rem determine block offset if joy0left && offset < 56 then offset = offset + 1 if joy0right && offset > 44 then offset = offset - 1 rem adjust block offset 420 if offset > 55 goto 435 if offset < 45 goto 445 rem if no adjustments are necessary, skip this part goto 500 rem move all block values to the left (counter clockwise) 435 temp2 = a for temp1 = 0 to 14 a[temp1] = b[temp1] next p = temp2 goto 450 rem move all blocks to the right (clockwise) 445 temp2 = p for temp1 = 15 to 0 step -1 b[temp1] = a[temp1] next a = temp2 rem reset the offset 450 offset = 50 rem ============ rem PLAYER FIRE rem ============ 500 rem checks to see that a few cool-down measures are a go, then moves the ball (player 1) to the center of the heart (player 0) rem cooldown ensures that the player cannot fire while a ball is at play rem cooldown also ensures the player doesn't exit a title screen by firing a ball prematurely if joy0fire && lives > 0 && player1x = 0 && player1y = 0 && cooldown < 50 then player1x=80:player1y=48 else goto 600 rem moves the ball's current color from heartcolor (set in the BEATING HEART section) to ballcolor for safe-keeping ballcolor = heartcolor rem set player 1's sprite player1: %00000000 %00000000 %00000000 %00011000 %00011000 %00000000 %00000000 %00000000 end rem generate random number to determine ball movement rem variables ensure that ball speed/angle does not vary once ball has been generated anglevar = (rand/32) rem ========= rem THE BALL rem ========= 600 rem skip everything dealing with the ball if it is at its resting position (0,0) if player1x = 0 && player1y = 0 then goto 800 rem maintain the color of the ball at the moment of firing COLUP1 = ballcolor rem all ball movement possibilities rem allows for ball movement in a direction every 45 degrees 650 rem cooldown is used to manage the speed of the ball if cooldown > 8 then cooldown = 0 rem x motion table data xmtbl 50, 51, 51, 51, 50, 49, 49, 49 end rem y motion table data ymtbl 51, 51, 50, 49, 49, 49, 50, 51 end rem separate out cardinal from diagonal directions if anglevar <> 0 && anglevar <> 2 && anglevar <> 4 && anglevar <> 6 then goto 670 else goto 680 670 rem movements for diagonal directions (45, 125, 225, 315) -- applies a cooldown to ensure that diagonals do not move too fast if cooldown <> 1 && cooldown <> 3 && cooldown <> 5 && cooldown <> 7 then player1x = player1x + xmtbl[anglevar] - 50: player1y = player1y + ymtbl[anglevar] - 50: goto 700 else goto 700 680 rem movement values for cardinal (0, 90, 180, 270 degrees) directions -- applies a cooldown to ensure that cardinal directions do not move too fast if cooldown <> 3 && cooldown <> 7 then player1x = player1x + xmtbl[anglevar] - 50 if cooldown <> 3 && cooldown <> 7 then player1y = player1y + ymtbl[anglevar] - 50 rem ==================== rem COLLISION DETECTION rem === thanks to bogax === rem ==================== 700 rem check to see if player 1 is out of bounds if player1x = 25 || player1y = 0 then goto 750 if player1x=133 || player1y = 140 then goto 750 rem minimum collision data locations (x, y) data btbl 78, 4, 109, 12, 125, 44, 109, 76, 77, 84, 45, 76, 29, 44, 45, 12 end rem check each of the 8 possible collision locations for temp4 = 0 to 14 step 2 temp3 = temp4 + 1 rem set up temporary variables to contain the full range of the x and y potentials temp5 = btbl[temp4] + 4 temp6 = btbl[temp3] + 8 rem if player1x is within the range for the current block and player1y is within the range for the current block, there is a collision if player1x > btbl[temp4] && player1x < temp5 && player1y > btbl[temp3] && player1y < temp6 then goto 710 rem otherwise, check the next block next rem if no collision is detected, skip to the end of the main loop goto 800 rem check for collision type 710 rem check if the block is already dead if a[temp4] = 2 then goto 800 rem check ball color against block color if a[temp4]<>ballcolor then goto bad_hit rem if the hit is good... good_hit rem set current block to dead a[temp4] = 2 rem increment score score = score + 25 rem play good hit sound AUDV1 = 6 AUDC1 = 12 AUDF1 = 19 goto 725 rem if the hit is bad... bad_hit rem lose a life lives = lives - 1 rem play bad hit sound AUDV1 = 6 AUDC1 = 6 AUDF1 = 16 rem reset sound cooldown counter 725 if lives > 0 then cooldown = 0 else cooldown = 50: pulse = 0 750 rem reset player 1 location, unlocking player 0 fire player1x = 0: player1y = 0 rem ================== rem STAGE GENERATION rem ================== 760 rem exits title screen and generates a new stage if joy0fire && lives = 0 && cooldown < 50 then score = 0: pulse = 0: cooldown = 50: level = 0: goto 775 rem cycles through blocks to check if all have been destroyed temp2 = 0 for temp1 = 0 to 15 if a[temp1] = 2 && lives > 0 then temp2 = temp2 + 1 next rem if not, then end cycle if temp2 <> 16 then goto 800 rem if so, then score bonus points for completing stage and continue if lives = 3 then score = score + 600 if lives = 2 then score = score + 400 if lives = 1 then score = score + 200 rem increment the level counter, but make sure it doesn't go too high if level < 10 then level = level + 1 rem generates new stage by looping through and inserting new colors taken from data set under COLOR FLICKER 775 rem different values for different levels if level = 0 then goto 776 if level = 1 then goto 777 else goto 780 776 rem first level has only red blocks, to teach basic mechanics of firing a ball and rotating blocks for temp1 = 0 to 15 a[temp1] = blkc[0] next goto 799 777 rem second level teaches the differences between the colors and how the right color must go to the right ball for temp1 = 0 to 15 temp2 = (rand/64) if temp2 < 2 then a[temp1] = blkc[1] else a[temp1] = blkc[0] next goto 799 780 rem third level introduces all three primary colors for temp1 = 0 to 15 temp2 = rand if temp2 < 86 then a[temp1] = blkc[0] if temp2 > 85 then a[temp1] = blkc[1] if temp2 > 170 then a[temp1] = blkc[2] next 799 rem complete reset by giving full lives lives = 3 rem end loop 800 set debug cyclescore goto draw_loop heartbreak.bas heartbreak.bas.bin Quote Link to comment Share on other sites More sharing options...
bogax Posted February 7, 2013 Share Posted February 7, 2013 Egh. Tried fiddling with what you offered there, bogax, and while it does make the movement work just fine, the hit detection is completely buggered by the change. what I posted was just meant to be an example of what would need to be done, the collision routine would need to be fixed, I just did't show it. And I still can't figure out what's going wrong here: I don't think there's anything wrong. Try it with just one color (don't change flicker) and then with two (let flicker cycle 0-1) the asm I posted for the rotation was bugged, fixed now I'd suggest you keep a count of the remaining blocks that gets updated when you have a good hit rather than counting through the blocks to check if there's any left in the flicker code you could pull the color look up out of the loop you could also up date flicker in one place rem cycle through pfpixels, turning them on if they are equal to the color being drawn temp3 = blkc[flicker] for temp5 = 0 to 15 if a[temp5] = temp3 then pfpixel ctbl[temp5] rtbl[temp5] on: temp4 = 1 next flicker = flicker + 1 & 7 rem determines if a color shows up; if not, don't bother drawing that color and return for the next if temp4 then COLUPF = temp3 else goto 110 Quote Link to comment Share on other sites More sharing options...
Cybearg Posted February 7, 2013 Author Share Posted February 7, 2013 what I posted was just meant to be an example of what would need to be done, the collision routine would need to be fixed, I just did't show it. I've spent all day wracking by brain over how it can be done. After much frustration and swearing, I give up. If only I knew what "base" was at any given moment, but score = base gives me nothing; score refuses to provide me any hints as to what any value is that I've ever tried. I have no clue why, but it just doesn't work for me. If only I knew what base was, I could see what was going on and figure out a way to compensate for it, but I can't and I'm out of ideas and extremely annoyed. I don't think there's anything wrong. Try it with just one color (don't change flicker) and then with two (let flicker cycle 0-1) I did, but it doesn't work. If I lower it to just two possible values, there is still far more flicker than there should be. On the first level, where all the blocks are red, there should be no flicker at all because there is no other color to flicker TO. The code SHOULD be recognizing through the loop that there aren't any blocks of any color besides red and thus skipping drawing any colors besides red, but it just doesn't. I don't know why. I've gone over the code dozens of times and spent between six to eight hours among this and the hit detection stuff, all to no avail whatsoever. the asm I posted for the rotation was bugged, fixed now If it makes you feel any better, I have zero clue about ASM, so it was all Greek to me, anyway. I'd suggest you keep a count of the remaining blocks that gets updated when you have a good hit rather than counting through the blocks to check if there's any left But unless I know which color of block is remaining, which, unless I have another 16 variables to spend, I have no way to keep a running memory of, then just knowing how many blocks are left doesn't help me. The point of running through the blocks each time is to count how many of each color remains so that the flicker can reduce to only displaying the colors that are actually on the playfield, but it doesn't work. It still flickers through all the other colors, anyway, and I have no clue why. This is probably all a phenomenal waste of time, anyway, because it is highly unlikely that, when/if/hopefully someone writes that new kernel that I've been begging for over the past week or so, it will rely on the current flickering system. So trying to improve that code is pointless until I have some modicum of an idea of how a new kernel could work or what it would require me to do. in the flicker code you could pull the color look up out of the loop you could also up date flicker in one place rem cycle through pfpixels, turning them on if they are equal to the color being drawn temp3 = blkc[flicker] for temp5 = 0 to 15 if a[temp5] = temp3 then pfpixel ctbl[temp5] rtbl[temp5] on: temp4 = 1 next flicker = flicker + 1 & 7 rem determines if a color shows up; if not, don't bother drawing that color and return for the next if temp4 then COLUPF = temp3 else goto 110 I tried this suggestion. It really doesn't change anything; it just splits apart what's already being done, more or less. I still get a recurring flicker even on level 0, where each of the blocks is red and the code should recognize that is the case and refrain from any flickering. rem Generated 1/28/2013 1:50:36 PM by Visual bB Version 1.0.0.548 rem ********************************** rem *heartbreak.bin * rem *A re-imagning of breakout with a lonely heart trapped in a void... * rem *Cybearg (aka Nic) * rem *cybearg.plays@gmail.com * rem ********************************** rem ============== rem INITIALIZATION rem ============== rem set up settings/optimization set optimization speed rem set up my variables dim level = s dim cooldown=t dim anglevar=u dim pulse=v dim flicker=w dim offset=x dim ballcolor=y dim heartcolor=z rem set offset to a number greater than 0 to allow for "negative" values offset = 50 rem set heartcolor to begin at red heartcolor = 64 rem set player 0's location player0x=80:player0y=48 rem ========== rem MAIN LOOP rem ========== draw_loop rem clear the playfield pfclear rem increment the multi-purpose cooldown variable cooldown = cooldown + 1 rem mute sound at 7 cooldown cycles or after 20 cycles if there's been a titlescreen restart if cooldown = 7 || cooldown = 70 then AUDV0 = 0 : AUDV1 = 0 rem =============== rem BEATING HEART rem =============== rem increment pulse counter pulse = pulse +1 rem cooldown to make sure that player doesn't leave the title screen by firing a ball if pulse = 45 && cooldown >= 50 then cooldown = 0 rem after 45 cycles, increment color if pulse = 45 then pulse = 0 rem special occasion for first level if level = 0 then heartcolor = 64: goto 10 rem special occasion for second level if level = 1 && heartcolor = 64 && pulse = 0 then heartcolor = 28: goto 10 if level = 1 && heartcolor = 28 && pulse = 0 then heartcolor = 64: goto 10 rem increment the colors if heartcolor = 28 && pulse = 0 then heartcolor = 148: goto 10 if heartcolor = 64 && pulse = 0 then heartcolor = 28: goto 10 if heartcolor = 148 && pulse = 0 then heartcolor = 64 10 rem set the playfield colors COLUP0 = heartcolor rem turn the score red if player is on the last life if lives = 1 then scorecolor = 64 else scorecolor = 10 rem swap the heart sprite for 5 cycles to create illusion of beating if pulse < 40 then goto 40 else goto 44 rem values for the up-beat (40 out of 45 cycles) 40 if lives = 0 then goto 80 41 if lives = 1 then goto 70 42 if lives = 2 then goto 60 43 if lives = 3 then goto 50 rem values for the down-beat (5 out of 45 cycles) 44 if lives = 0 then goto 80 45 if lives = 1 then goto 90 46 if lives = 2 then goto 70 47 if lives = 3 then goto 60 rem the various player 0 heart sprites 50 player0: %00010000 %00111000 %01111100 %11111110 %11111110 %11111110 %01101100 %00000000 end 55 goto 100 60 player0: %00000000 %00010000 %00111000 %01111100 %01111100 %00101000 %00000000 %00000000 end 65 goto 100 70 player0: %00000000 %00000000 %00010000 %00111000 %00101000 %00000000 %00000000 %00000000 end 75 goto 100 80 90 player0: %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 end rem ============== rem COLOR FLICKER rem ============== 100 rem if the player has zero lives, skip this part if lives = 0 then goto 410 rem set up possible colors data blkc 64, 28, 154, 44, 202, 122, 14, 0 end rem set up possible pfpixel locations data ctbl 16, 20, 24, 27, 28, 27, 24, 20, 16, 12, 8, 5, 4, 5, 8, 12 end data rtbl 0, 0, 1, 3, 5, 7, 9, 10, 10, 10, 9, 7, 5, 3, 1, 0 end 110 rem cycle through pfpixels, turning them on if they are equal to the color being drawn temp3 = blkc[flicker] for temp5 = 0 to 15 if a[temp5] = temp3 then pfpixel ctbl[temp5] rtbl[temp5] on: temp4 = 1 next flicker = flicker + 1 & 7 rem determines if a color shows up; if not, don't bother drawing that color and return for the next if temp4 then COLUPF = temp3 else goto 110 rem ================== rem MAIN DRAWSCREEN rem ================== rem main drawscreen drawscreen rem skip to COLOR MOVEMENT goto 415 rem ============= rem TITLE SCREEN rem ============= 410 rem set the beat of the title screen heart to the ongoing pulse if pulse < 40 then goto 413 else goto 412 rem the two possible title screen frames 412 playfield: ................................ ...X.X.XXX..X..XX.XXX........... ...X.X.X...X.X.X.X.X............ ...XXX.XX..XXX.XX..X............ ...X.X.XXX.X.X.X.X.X............ .............................. ...........XX..XX..XXX..X..X.X.. ....X.X....X.X.X.X.X...X.X.X.X.. ....XXX....XX..XX..XX..XXX.XX... .....X.....X.X.X.X.XXX.X.X.X.X.. ...........XXX.................. end rem skip to color goto 414 413 playfield: ................................ ...X.X.XXX..X..XX.XXX........... ...X.X.X...X.X.X.X.X............ ...XXX.XX..XXX.XX..X............ ...X.X.XXX.X.X.X.X.X............ ................................ ...XX.XX...XX..XX..XXX..X..X.X.. ..XXXXXXX..X.X.X.X.X...X.X.X.X.. ...XXXXX...XX..XX..XX..XXX.XX... ....XXX....X.X.X.X.XXX.X.X.X.X.. .....X.....XXX.................. end 414 rem color the title screen playfield COLUPF = 64 rem drawscreen for titlescreen only drawscreen rem skip everything else and wait for a trigger goto 760 rem ================= rem COLOR MOVEMENT rem ================= 415 rem NOTE: offset base is 50, so the numbers below determine how sensitive the controls are rem determine block offset if joy0left && offset < 56 then offset = offset + 1 if joy0right && offset > 44 then offset = offset - 1 rem adjust block offset 420 if offset > 55 goto 435 if offset < 45 goto 445 rem if no adjustments are necessary, skip this part goto 500 rem move all block values to the left (counter clockwise) 435 temp2 = a for temp1 = 0 to 14 a[temp1] = b[temp1] next p = temp2 goto 450 rem move all blocks to the right (clockwise) 445 temp2 = p for temp1 = 15 to 0 step -1 b[temp1] = a[temp1] next a = temp2 rem reset the offset 450 offset = 50 rem ============ rem PLAYER FIRE rem ============ 500 rem checks to see that a few cool-down measures are a go, then moves the ball (player 1) to the center of the heart (player 0) rem cooldown ensures that the player cannot fire while a ball is at play rem cooldown also ensures the player doesn't exit a title screen by firing a ball prematurely if joy0fire && lives > 0 && player1x = 0 && player1y = 0 && cooldown < 50 then player1x=80:player1y=48 else goto 600 rem moves the ball's current color from heartcolor (set in the BEATING HEART section) to ballcolor for safe-keeping ballcolor = heartcolor rem set player 1's sprite player1: %00000000 %00000000 %00000000 %00011000 %00011000 %00000000 %00000000 %00000000 end rem generate random number to determine ball movement rem variables ensure that ball speed/angle does not vary once ball has been generated anglevar = (rand/32) rem ========= rem THE BALL rem ========= 600 rem skip everything dealing with the ball if it is at its resting position (0,0) if player1x = 0 && player1y = 0 then goto 800 rem maintain the color of the ball at the moment of firing COLUP1 = ballcolor rem all ball movement possibilities rem allows for ball movement in a direction every 45 degrees 650 rem cooldown is used to manage the speed of the ball if cooldown > 8 then cooldown = 0 rem x motion table data xmtbl 50, 51, 51, 51, 50, 49, 49, 49 end rem y motion table data ymtbl 51, 51, 50, 49, 49, 49, 50, 51 end rem separate out cardinal from diagonal directions if anglevar <> 0 && anglevar <> 2 && anglevar <> 4 && anglevar <> 6 then goto 670 else goto 680 670 rem movements for diagonal directions (45, 125, 225, 315) -- applies a cooldown to ensure that diagonals do not move too fast if cooldown <> 1 && cooldown <> 3 && cooldown <> 5 && cooldown <> 7 then player1x = player1x + xmtbl[anglevar] - 50: player1y = player1y + ymtbl[anglevar] - 50: goto 700 else goto 700 680 rem movement values for cardinal (0, 90, 180, 270 degrees) directions -- applies a cooldown to ensure that cardinal directions do not move too fast if cooldown <> 3 && cooldown <> 7 then player1x = player1x + xmtbl[anglevar] - 50 if cooldown <> 3 && cooldown <> 7 then player1y = player1y + ymtbl[anglevar] - 50 rem ==================== rem COLLISION DETECTION rem === thanks to bogax === rem ==================== 700 rem check to see if player 1 is out of bounds if player1x = 25 || player1y = 0 then goto 750 if player1x=133 || player1y = 140 then goto 750 rem minimum collision data locations (x, y) data btbl 78, 4, 109, 12, 125, 44, 109, 76, 77, 84, 45, 76, 29, 44, 45, 12 end rem check each of the 8 possible collision locations for temp4 = 0 to 14 step 2 temp3 = temp4 + 1 rem set up temporary variables to contain the full range of the x and y potentials temp5 = btbl[temp4] + 4 temp6 = btbl[temp3] + 8 rem if player1x is within the range for the current block and player1y is within the range for the current block, there is a collision if player1x > btbl[temp4] && player1x < temp5 && player1y > btbl[temp3] && player1y < temp6 then goto 710 rem otherwise, check the next block next rem if no collision is detected, skip to the end of the main loop goto 800 rem check for collision type 710 rem check if the block is already dead if a[temp4] = 2 then goto 800 rem check ball color against block color if a[temp4]<>ballcolor then goto bad_hit rem if the hit is good... good_hit rem set current block to dead a[temp4] = 2 rem increment score score = score + 25 rem play good hit sound AUDV1 = 6 AUDC1 = 12 AUDF1 = 19 goto 725 rem if the hit is bad... bad_hit rem lose a life lives = lives - 1 rem play bad hit sound AUDV1 = 6 AUDC1 = 6 AUDF1 = 16 rem reset sound cooldown counter 725 if lives > 0 then cooldown = 0 else cooldown = 50: pulse = 0 750 rem reset player 1 location, unlocking player 0 fire player1x = 0: player1y = 0 rem ================== rem STAGE GENERATION rem ================== 760 rem exits title screen and generates a new stage if joy0fire && lives = 0 && cooldown < 50 then score = 0: pulse = 0: cooldown = 50: level = 0: goto 775 rem cycles through blocks to check if all have been destroyed temp2 = 0 for temp1 = 0 to 15 if a[temp1] = 2 && lives > 0 then temp2 = temp2 + 1 next rem if not, then end cycle if temp2 <> 16 then goto 800 rem if so, then score bonus points for completing stage and continue if lives = 3 then score = score + 600 if lives = 2 then score = score + 400 if lives = 1 then score = score + 200 rem increment the level counter, but make sure it doesn't go too high if level < 10 then level = level + 1 rem generates new stage by looping through and inserting new colors taken from data set under COLOR FLICKER 775 rem different values for different levels if level = 0 then goto 776 if level = 1 then goto 777 else goto 780 776 rem first level has only red blocks, to teach basic mechanics of firing a ball and rotating blocks for temp1 = 0 to 15 a[temp1] = blkc[0] next goto 799 777 rem second level teaches the differences between the colors and how the right color must go to the right ball for temp1 = 0 to 15 temp2 = (rand/64) if temp2 < 2 then a[temp1] = blkc[1] else a[temp1] = blkc[0] next goto 799 780 rem third level introduces all three primary colors for temp1 = 0 to 15 temp2 = rand if temp2 < 86 then a[temp1] = blkc[0] if temp2 > 85 then a[temp1] = blkc[1] if temp2 > 170 then a[temp1] = blkc[2] next 799 rem complete reset by giving full lives lives = 3 rem end loop 800 set debug cyclescore goto draw_loop I'd show you a video, but FRAPS can't capture it right. It's just too messed up. P.S. Sorry if I have a bit of attitude in the above. I'm very, very frustrated by this, particularly since I feel like I'm just spinning my wheels as I wait for someone to make an improved kernel. I don't know how that improved kernel would work, what sort of system flow it would require, or if anyone is even working on it. heartbreak.bas heartbreak.bas.bin Quote Link to comment Share on other sites More sharing options...
+Gemintronic Posted February 7, 2013 Share Posted February 7, 2013 I don't know how that improved kernel would work, what sort of system flow it would require, or if anyone is even working on it. Alas, with lone developers like Fred Quimby of batariBasic you can't count on improved versions as a matter of course. It's more like an awesome, unexpected gift when something new happens. That being said, programming the 2600 is a challenge because of the limited resources. It's actually one of the reasons people DO code for it. It makes you to think out of the box for solutions. You don't really force a game design INTO the Atari 2600. You discover what it can do and grow the game out from there. * Stagger the blocks so they only use one per row to avoid flicker * If needed, use some of the sprite/missile/ball objects as "blocks" for extra fake top and bottom playfield pixels. * player0 should be the heart and missile0 its shot. They share the same color but that is OK * Don't think about the maths for rotation and other nonsense. Think about the color cycle as frames of animation. In this case pfcolors lists. * The shot angle can also be thought of as a static list of trajectories easily fitting in DATA statements. Something like anglex[12] angley[12] where each element stores the per pixel velocity of the shot. 12 in this case is the 12th angle a shot can be placed in. * You can divvy out the 8-bit variables into single bit boolean values. If you use a playfield like in my example a few posts back you only have 13 blocks to worry about. That could fit in 4 variables easy. Just use each bit as a true/false flag for block destruction. OR, you could simply leave a block destroyed when colliding with the shot to save even more space. Let just the colors "rotate". 1 Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted February 7, 2013 Share Posted February 7, 2013 ...and since I don't really understand what a[temp1] = a[(temp1+1)&15] does, I can't do much to fix it. I don't know batari BASIC syntax too, but I think the code has a small bug. Before the loop, you have to store a[temp1] somewhere. And after the loop, you have to write that value to a[(temp1+1)&15] Quote Link to comment Share on other sites More sharing options...
+Andrew Davie Posted February 7, 2013 Share Posted February 7, 2013 I don't know batari BASIC syntax too, but I think the code has a small bug. Before the loop, you have to store a[temp1] somewhere. And after the loop, you have to write that value to a[(temp1+1)&15] Good point. What Thomas is saying is that the code as it stands will "lose" one value in the list. Consider a 4-element ring buffer (just for ease of explanation)... a[0]<-a[1] a[1]<-a[2] a[2]<-a[3] a[3]<-a[0] WHOOPS! a[0] is already over-written with a[1] So first we need to save a[0] and at the end we put it back in place in a[3]. Otherwise we're losing the first element (or last element) depending on which way we go. Nice catch, Thomas Of course, this problem would go away with the pointer method I suggested. Cheers A Quote Link to comment Share on other sites More sharing options...
Cybearg Posted February 7, 2013 Author Share Posted February 7, 2013 So far as I am aware, BASIC, at least bB, can't do pointers, and even if it could, I've only just started learning about pointers in my C class at college, so I don't truly grasp how they work, yet. Anyway, that bug was already accounted for in my original code, as around page 2 I posted that I noticed that colors 15 and 0 always shared the same color, and after a bit of visualizing on paper, I figured the solution of plucking out a[0] and then placing it in a[15] after the loop had completed. I've got so many versions of this game all over the place and I've not really saved it in a long time because none of them are fully functional. While I see the advantage of the new way of doing the color movement, it breaks the hit detection big-time and I'm not sure how to fix it (or maybe just too exhausted with fiddling around with the code to see a solution). And then there's still the constant issue of "this game will not be made if there is not a fix for the flickering." Unless multiple pfpixel colors can be displayed on-screen at once (or some other flicker-free equivalent for the 16 blocks), it hurts the eyes too much to play. Quote Link to comment Share on other sites More sharing options...
+Gemintronic Posted February 7, 2013 Share Posted February 7, 2013 could you just use collision([whateverobjectyouareusingfortheshot], playfield) and detect WHICH block simply by the direction it was shot in? In other words, when you fire the shot record which of the angles the shot was fired from. When it eventually hits a target (using the traditional collision command) you know it came from that last angle - and thus which block it hit. Quote Link to comment Share on other sites More sharing options...
Cybearg Posted February 7, 2013 Author Share Posted February 7, 2013 could you just use collision([whateverobjectyouareusingfortheshot], playfield) and detect WHICH block simply by the direction it was shot in? In other words, when you fire the shot record which of the angles the shot was fired from. When it eventually hits a target (using the traditional collision command) you know it came from that last angle - and thus which block it hit. That's brilliant! Let me fiddle with it and see what I can come up with. Great idea! Quote Link to comment Share on other sites More sharing options...
bogax Posted February 7, 2013 Share Posted February 7, 2013 (edited) Rather than try and respond to indvidual points with quotes I'm just going to make some observations and post this (link to) some code. pointers is what you're doing when you index into memory with a variable, you just don't get the extra layers of abstraction in bB (a good thing) I redid the collision code to remove the loop that takes some of the curse off as far as using an offset (which I call base) into the colors so I incorporated that. mainly to demonstrate. I changed the collision code it misses at six o clock I haven't figured out why. I don't think it has an inordinate amount of flicker for what it's doing but I may be wrong. it goes over on line count. I don't know how stella deals with that timing wise. If you look for just one color it's solid, if you look for two it flickers about like I'd expect if the screen was blanked half the time (which presumably it shouldn't be). using one color should take the most time in the loop and apparently that doesn't mess it up too badly. So my question is could it be its that going over it's line budget? It looks for a color that's being used and only draws the screen if it finds one. It apparently doesn't take too long if it just looks for one color and pfpixels (v) the blocks to the screen and does a drawscreen but if it looks for another color even without having to draw anything it flickers. just looking for another color pushes it over. (hmm occurs to me I didn't check to see how it does if it looks for two colors but only has to draw one color block of one color which would be about as fast as looking for two colors could go) In general it's a good thing to speed things up especially if you're going over time. So I might suggest something with out refernce to a specific problem, eg flicker, that doesn't mean it wouldn't help the situation. to that end I incorprated a block count and removed tha loop for that (and did some other minor stuff) I'm sure there's still plenty of opportunity for streamling the code. theloon had a couple of interesting suggestions. in particular I like the idea of keeping track of which colors you're using instead of searching the blocks for colors that aren't there. for my self I wonder if it might help to bypass pfpixel and write the playfield directly. But I don't think anything's going to help enough untill you have a kernel that can do more than on color per line and takes the colors from ram edit crap wrong version I'll have to find it hopefully this is it http://pastebin.com/3kCzwKJT Edited February 7, 2013 by bogax 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.