-
Content Count
951 -
Joined
-
Last visited
Posts posted by Cybearg
-
-
Changed the 2 to a 1. When you say
You have to jump into the routine with BB.... Do you mean jump into the subroutine? Because the compiler doesn't recognize DrawKernel as a valid subroutine since it's not defined outside of the asm ... end code.
Gah, sorry for the annoyance of all the questions for simple stuff.
EDIT: Oh, wait... Just looked at this, which explains how this sort of thing is supposed to work.
From what I can tell, the .nameHere parts of Assembly are the actual subroutines, not the big DrawKernel: stuff, so I need to call one of those .nameHere parts.
So which subroutine is meant to be called to begin the whole draw process? I see one for .storeShot (do I need to call that when the ball is generated?) .storeblock 1-16 (which I assume I need to call for each of the blocks being generated?) and then things like .loopThreeBlocks and .loopTwoCloseBlocks, etc., which I'm not sure how they would be called correctly.
Also, I included the .asm file at the end of everything rather than the beginning, like so:
rem end loop 800 goto draw_loop asm include "heartkern.asm" end
-
Well, instead of trying to include it with a .inc file, I tried just dropping it in asm ... end before everything else. It compiles with 94 bytes to spare on the ROM, which is great!
... Though nothing seems to happen. That may be because I... need to go back and delete out all the stuff about the flickering? From what you said, the kernel takes the color values directly from the memory addresses of the first sixteen variables, though keep in mind that those variables always have some value. If a block is dead, the color "2" is written to it. Why not black? Because there are black blocks in later levels and I needed a way to distinguish a black block from a dead block. That wasn't the case in the version you made the kernel for.
If it draws the pfpixels directly through the kernel without the aid of the color flicker code:
rem ============== rem COLOR FLICKER rem ============== 100 rem first, set levelcolor[level] into another variable for bitwise operations temp4 = levelcolors[level] 105 rem increment flicker flicker = flicker + 1 & 7 rem determines if a color is being used if setbits[flicker] & temp4 then goto 110 goto 105 data screen_add 2, 2, 7, 15, 23, 31, 39, 42, 42, 41, 37, 28, 20, 12, 5, 1 end data block_bit 128, 8, 1, 8, 16, 8, 1, 8, 128, 16, 1, 4, 8, 4, 1, 16 end data setbits 1, 2, 4, 8, 10, 32, 64, 128 end 110 rem cycle through pfpixels, turning them on if they are equal to the color being drawn temp6 = base for temp5 = 0 to 15 if a[temp6] = blkc[flicker] then temp2 = screen_add[temp5] : $A4[temp2] = $A4[temp2] | block_bit[temp5] temp6 = temp6 + 1 & 15 next rem set playfield to current color COLUPF = blkc[flicker]
... Which I only partially understand since bogax's brilliant reworking, will it still be able to account for that kind of thing?
Currently, I just get a black screen, but I'm likely doing something wrong or maybe the COLOR FLICKER code needs to be removed in order to get it to all work together.
-
Thank you SO MUCH! That demo looks great!
This asm file is meant to be either included directly (as you say above) or chopped into pieces and added to batariBasic in asm statements, correct? It would be very helpful if it wasn't necessary to search for and replace/add to stuff on every new bB iteration.
What kind of set-up for the colors is necessary with the kernel? Since it doesn't use flickering, all those flicker statements should be removed, I assume, but then what would the structure of the color calls look like? Or does this assembly code replace that part?
Is there any risk of me accidentally using register $FA? Is it something that I'm liable to make be not equal to 0 or are you just informing me about that?
Also, can the scope of this kernel extend beyond the limits of Heartbreak in particular? What is its actual full potential and what all can be done with it?
EDIT: I have no experience with this and can't truly read assembly, though I sorta-kinda-maybe get the gist of what that new kernel is doing, kinda?
Anyway, since I don't know how a new kernel like this is supposed to join together with the existing stuff, I tried making a tweaked includes file and added this line to the start of heartbreak.bas:
includesfile heartbreak.inc
The includes file is just the standard include with a mention of heartkern.asm thrown in there after all the standard kernels are loaded. That's apparently wrong, since heartbreak.bas won't compile through bB due to:
heartbreak.bas.asm (421): error: Unknown Mnemonic 'rtsstart'.
I hate to bother Omega with having to explain all this to a complete newbie, so if anyone else can clue me in as to how these puzzle pieces fit together, that'd be much appreciated.
Since I can't upload the .inc file type, this is what heartbreak.inc looks like:
; ; Inclues go below - order is crucial, since this is also the order in which ; they will appear in the generated assembly file ; ; header file 2600basicheader.asm ; standard kernel: two players, two missiles, a ball and an asymmetric playfield. std_kernel.asm ; standard startup routine. startup.asm ; below are collections of subroutines and functions ; if you have any more to add, put them immediately below this line. pf_drawing.asm pf_scrolling.asm std_routines.asm heartkern.asm ; The overscan routine goes below. it sets up sprites for the std_kernel. ; if you have any routines that will not run until the overscan period, ; put them immediately below this line. std_overscan.asm ; below is the generated batari Basic file bB.asm ; score graphics. score_graphics.asm ; below is the footer, which contains the score digits and startup vectors. ; If you want to create your own custom score digits, you may hack the file below, ; but first you should rename it to something else. 2600basicfooter.asm
-
Arrgh.
- Use OpenGL mode in Stella.
- Turn on vsync.
- Set aspect ratio to 80% or so.
- If you really like z26 colours more, use z26 palette.
- Go into TV effects and turn on scanlines and different TV modes (composite, Svideo, RGB, etc).
I don't see how you can say that Stella won't accurately show how a real 2600 looks.
No offense! I meant it in the sense that, out of the box, I saw rolling and other things demonstrating the problems inherent with a real 2600 in z26 but not in Stella. Awesome that there are ways to replicate it (and no, I don't like z26's colors more), and no offense is intended. That was just a side-note to explain that I was assuming that's what the game would look like on a TV, though it may not.
- Use OpenGL mode in Stella.
-
I had planned to use rand16 but simply ran out of variables to do it with. Glad to see that there are some sneaky variables that I can rope into helping me out.
-
Tried the version at the top. At first, I was confused about what was going on. I know it's still a work in progress, but I think that sound effects to demonstrate if hits are doing damage (since otherwise the foursome of monsters just kind of wiggle when hit like I tickled them).
I played in z26 (which seems like it's more accurate at replicating the way a real 2600 looks compared to Stella) and everything was very flickery from what I saw. The life bar, the buildings, the monsters, and the planes were all flickering colors and the planes were flickering between being a block and a rectangle. I thought either this was intended or some rare occurrence until I tried recording it with FRAPS then watched the footage. Things look fine in
after the first few seconds, but the entire game looked like it does in those first few seconds for me, with everything flickering. Also, the score seems to reset and repeat, which I assume wasn't intended.Overall, I think it's neat! I like the little car-blocks moving at the bottom and the buildings scrolling past and it's a great use of pfheights, methinks. I have a couple suggestions.
1. You were probably going to do this anyway, but I'd say break off those groups of four monsters so that the monsters move individually. They can come at the player from different angles/patterns, creating pinch maneuvers that forces the player to get out of the way, etc. On a similar note, maybe (depending on if this would playtest well or not), make colliding with the buildings below to be a bad thing, allowing the player to dip between the buildings here and there but forcing the player to move back up into the more dangerous upper region. That would keep the player moving up and down.
2. I found that I played always on the far left side of the screen and never really moved right, even though I could. I'd recommend doing something to force the player out of the far left of the screen, such as something dropping down from above to drive the player right, or maybe the monsters could move in pinch maneuvers, as mentioned above, which connect at the left, forcing the player to move right to avoid being hit.
Also, some kind of boss after a while would be neat as well.
-
I had the same bug as Pigglets happen at my first try.
First off, big kudos! My favorite part of this? The sound effects. The humming of the plane and the way it shifts as you accelerate/decelerate and the rumble of the guns is enormously satisfying and pleasant to hear, which is surprising for a system that can be infamous for its annoying bleepy-bloopyness.
It took me a little bit to realize that the thing on the right was a radar screen, but it was a neat idea, though I'm not sure if I see how it was implemented here. Now, the bomber would flicker around and come in and out of view, but that seemed more like a bug (and one that got me killed a number of times when it disappeared and then dropped into me without my realizing), so it would be nice to have that fixed. Note: I played this on z26.
Also, depending on whether you anticipate it to be played primarily on emulators or mostly on real 2600s, I'd suggest adding in a restart when the player fires on the KIA screen. You probably have it tied to the reset switch or something, though, so maybe it's just me who wants that.
Overall very neat! Just a bug or two that can really mess one up, but fun and, as I said, fantastic sound effects. Flying and gunning is oh-so rewarding. I'd like to see more types of enemies and planes and maybe, as Piggles suggested, some kind of boss?
While I like the idea of the radar screen, assuming that the bomber flickering in and out is a bug and not intentional, it's not really utilized in the gameplay at all, since it only displays what I can already see. Unless it gets used for a particular gameplay reason that really relies on it, I'd suggest going multisprite so that there are (at least at later stages) more enemies to dogfight with and more room to move around. Just my two cents.
-
Yep, but only if the cursor is red.
Does it need to be a specific space? Is there any visual cue to indicate to the player which of those it would be? Or is the player flipping between whether they can move over black or white? It seemed fully functional to me with the ability to move back and forth as-is. What does the flipping do? Could you post a sample video of the DS game or something demonstrating how it should look?
If you need to remember specifically which pfpixel was touched before without anything to work off of (such as the ability to check whether a pfpixel is active or not), the only way I can see doing it is by setting aside a series of bitmapped variables to represent the "okay" and "not-okay" movement states of the 4x8 playfield blocks. This would, of course, require 4 x 10 = 40 variables, which aren't normally available but may be doable with a superchip.
EDIT: No, silly me, you could just affect the direct variables that already represent the on/off states of the playfield, right? Well, that is, unless there needs to be no visual distinction as to whether or not you can move in a certain place, but this would be a simple way to affect the playfield.
-
What's wrong with 4k or 8k?
It feels good to make it work in the smallest ROM possible. At least for me it does.
-
I don't see what makes them so smelly.
Neat, though! Yeah, I can certainly see why you'd think of it. And I'll add that rand16 in there--I know that I seemed to roll up the same direction multiple times quite often, it seemed.
I've attached the latest version (not that there have been a whole lot of changes--mostly just a few tweaks here and there with some additions and suggestions).
-
If you use the code below to clear the visible screen instead of pfclear, you should be able to safely use the hidden row of playfield variables (var44 = 0 : var45 = 0 : var46 = 0 : var47 = 0).
Niiiice. I loves me some extra variables! These function just like any other but I guess the names are set at var 44/45/46/47?
-
If no one else is going to step up to the plate, then I can write the kernel. It wouldn't be tonight though. Once the kernel is done then you probably won't have to worry about setting the playfield pixels at all. The kernel would simply look at the color of the block, and if the color was black it wouldn't draw that block. In other words you could off-load all the pixel set up to the kernel, and simply deal with the colors.
The kernel would greatly simplify things. No flicker, and pixel perfect hardware collisions.
Ahem...
Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you!
My appreciation knows no bounds! No rush, but I'm massively curious, so if you do make progress, please do pop in and say a thing or two about how it's going. Again, thanks much! I was starting to panic that no one would be willing/able to do it.
-
That's awesome. Is there some way to utilize that to help with the whole flickering problem?
I've made a couple additional little tweaks that have hopefully streamlined things here and there. It's hard to imagine, but it's actually running smoothly at all times, so far as I can tell.
-
Wow, thanks a lot! That works fantastically!
... I have to say I don't understand it, though. It's drawing pfpixels without referencing the pfpixel locations data set I made before and without even saying "pfpixel." How is that?
-
Does "if pulse then goto 10" have any actual cycle advantage over "if pulse <> 0 then goto 10"? Because if not, I'd like to keep things as unobtuse as possible.
I'd be able to save even more cycles here:
if flicker = 0 && temp4{0} then goto 110 if flicker = 1 && temp4{1} then goto 110 if flicker = 2 && temp4{2} then goto 110 if flicker = 3 && temp4{3} then goto 110 if flicker = 4 && temp4{4} then goto 110 if flicker = 5 && temp4{5} then goto 110 if flicker = 6 && temp4{6} then goto 110 if flicker = 7 && temp4{7} then goto 110and here:
if temp4{0} && temp2 >= colorodds[temp3] then a[temp1] = blkc[0]: temp3 = temp3 + 1 if temp4{1} && temp2 >= colorodds[temp3] then a[temp1] = blkc[1]: temp3 = temp3 + 1 if temp4{2} && temp2 >= colorodds[temp3] then a[temp1] = blkc[2]: temp3 = temp3 + 1 if temp4{3} && temp2 >= colorodds[temp3] then a[temp1] = blkc[3]: temp3 = temp3 + 1 if temp4{4} && temp2 >= colorodds[temp3] then a[temp1] = blkc[4]: temp3 = temp3 + 1 if temp4{5} && temp2 >= colorodds[temp3] then a[temp1] = blkc[5]: temp3 = temp3 + 1 if temp4{6} && temp2 >= colorodds[temp3] then a[temp1] = blkc[6]: temp3 = temp3 + 1 if temp4{7} && temp2 >= colorodds[temp3] then a[temp1] = blkc[7]: blkcount = blkcount - 1... if you know of a way for me to refer to a bit operation with a variable, such as:
if temp4{temp3} && temp2 >= colorodds[temp3] then a[temp1] = blkc[temp3]: temp3 = temp3 + 1Anyway, there are probably ways for me to improve my code, but I have as many weeks of programming experience as you can count on one bird-flip, so it's unlikely that I'm going to catch everything.
-
Ahh, I heard about those switch constants but didn't know how they work. Still don't, heh.
if pulse then goto 10
What does this do? Is that a simplified check to see if it's above 0?
Anyway, I did try having the heart beat check not looked at every cycle, but the downside of that is that changes, such as losing a heart from losing 3 lives or getting a new level generated, take a moment to show an effect on the heart, so there's a lagged reaction.
Plus, it doesn't actually save me any cycles. I tried and it's 272 before and after the change.
According to z26, the flicker resulting from that 272 scanline count really isn't so bad, though it may get worse (or better?) if I get that kernel I've been waiting for (hint hint hint).
-
how often will pulse = 0 ?
Every 45 cycles. That's what causes the heart to beat and the colors to change, so it's necessary to constantly be watching to make sure that the colors don't change too early.
I've managed to simplify it a little by reducing some of the use of cooldown and simplifying a bit there. I'm still going over-budget, though:
1. During level generation, frames hit 263 and 264 scanlines.
2. Once the level has been generated, scanlines remain steady at around 272 (at level 1--the fewer of the same color there is on-screen, the fewer the scanline excess). Successfully hitting blocks removes scanlines, about 1 a piece, though I really can't see any code that can be trimmed out for those things.
-
Wish I'd have known about this before now. I've used cyclescore in the past and, while it flashed red here and there, it was always over 0, so I figured I was fine.
The biggest drop happens when generating a new level, so I went back and tried to spread the generation across sixteen frames instead of all in one, but I still seem to be getting constant scanlines of 272, plus the block at twelve o'clock is often missing until you move the joystick left or right. What is sucking up all the cycles, how can I streamline it further, and why is the block at 0 not rendering out immediately at level generation? (that's not rhetorical--I'm asking for help with this)
rem rem ********************************** rem *heartbreak.bin * rem *A re-imagning of breakout with a lonely heart trapped in a void... * rem *Cybearg (aka Nic) * rem *[email protected] * rem ********************************** rem ============== rem INITIALIZATION rem ============== rem set up settings/optimization set optimization speed rem set up my variables dim base = q dim blkcount = r 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 = blkc[0] rem set player 0's location player0x=80:player0y=48 rem set base blockcount blkcount = 16 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 exit for stage generation if pulse > 100 then goto 775 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 set base player sprite player0: %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 end rem if the player has zero lives, skip this part if lives = 0 then goto 410 rem set up possible colors data blkc 66, 28, 150, 46, 214, 102, 14, 00 end rem special occasion for first level if level = 0 then heartcolor = blkc[0]: goto 10 rem special occasion for second level if level = 1 && heartcolor = blkc[0] && pulse = 0 then heartcolor = blkc[1]: goto 10 if level = 1 && heartcolor = blkc[1] && pulse = 0 then heartcolor = blkc[0]: goto 10 rem increment the colors if heartcolor = blkc[1] && pulse = 0 then heartcolor = blkc[2]: goto 10 if heartcolor = blkc[0] && pulse = 0 then heartcolor = blkc[1]: goto 10 if heartcolor = blkc[2] && pulse = 0 then heartcolor = blkc[0] 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 > 6 then goto 50 41 if lives > 3 then goto 60 42 if lives > 0 then goto 70 rem values for the down-beat (5 out of 45 cycles) 44 if lives > 6 then goto 60 45 if lives > 3 then goto 70 46 if lives > 0 then goto 80 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 80 rem ============== rem COLOR FLICKER rem ============== 100 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 first, set levelcolor[level] into another variable for bitwise operations temp4 = levelcolors[level] 105 rem reset flicker if flicker = 8 then flicker = 0 rem determines if a color is being used if flicker = 0 && temp4{0} then goto 110 if flicker = 1 && temp4{1} then goto 110 if flicker = 2 && temp4{2} then goto 110 if flicker = 3 && temp4{3} then goto 110 if flicker = 4 && temp4{4} then goto 110 if flicker = 5 && temp4{5} then goto 110 if flicker = 6 && temp4{6} then goto 110 if flicker = 7 && temp4{7} then goto 110 rem if not, skip it and try the next color flicker = flicker + 1 goto 105 110 rem cycle through pfpixels, turning them on if they are equal to the color being drawn temp6 = base for temp5 = 0 to 15 if a[temp6] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on temp6 = temp6 + 1 & 15 next rem set playfield to current color 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 = blkc[0] 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 < 55 then offset = offset + 1 if joy0right && offset > 45 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 rotate left 435 base = base + 1 & 15 goto 450 rem move all blocks to the right (clockwise) 445 base = base - 1 & 15 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 ==================== 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 check for collision -- if not, bypass everything else as we wait for a collision if !collision(playfield,player1) then goto 800 705 rem double anglevar in order to determine how the number relates to a 0-15 range rather than a 0-7 range temp4 = 4 - anglevar temp4 = temp4 + temp4 + base & 15 rem checks for various hit-types, currently only consists of a single possibility, but there will be more for secondary colors, white, and black rem if one of the primary colors if a[temp4] = ballcolor then goto good_hit rem if orange if a[temp4] = blkc[3] && ballcolor = blkc[0] then goto good_hit if a[temp4] = blkc[3] && ballcolor = blkc[1] then goto good_hit rem if green if a[temp4] = blkc[4] && ballcolor = blkc[1] then goto good_hit if a[temp4] = blkc[4] && ballcolor = blkc[2] then goto good_hit rem if purple if a[temp4] = blkc[5] && ballcolor = blkc[0] then goto good_hit if a[temp4] = blkc[5] && ballcolor = blkc[2] then goto good_hit rem if white if a[temp4] = blkc[6] && lives < 9 then lives = lives + 1: goto good_hit if a[temp4] = blkc[6] then goto good_hit rem in case there's a mistake and a dead block is counted as a hit, make sure that it doesn't cost the player a life if a[temp4] = 2 then goto 800 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 goto 725 rem if the hit is good... good_hit rem set current block to dead a[temp4] = 2: blkcount = blkcount - 1 rem increment score score = score + 25 rem play good hit sound AUDV1 = 6 AUDC1 = 12 AUDF1 = 19 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 = 100: cooldown = 50: level = 0: blkcount = 16: goto 775 rem checks if all blocks have been destroyed if blkcount > 0 then goto 800 rem if so, then score bonus points for completing stage and continue if lives > 6 then score = score + 600: goto 770 if lives > 3 then score = score + 400: goto 770 if lives > 0 then score = score + 200 770 rem increment the level counter level = level + 1 if level = 14 then level = 6 pulse = 100: blkcount = 16 rem generates new stage by looping through and inserting new colors taken from data set under MAIN LOOP 775 rem set up data sets for level generation rem defines the odds of a color for each stage data colorodds 0, 0, 128, 0, 85, 170, 0, 42, 84, 126, 168, 210, 0, 80, 160, 240, 247, 0, 40, 80, 120, 160, 200, 240, 247, 0, 60, 120, 180, 200, 220, 240, 245, 0, 60, 120, 180, 195, 210, 225, 230 end rem saves space by indicating where the colorodds index should begin, per level data startindex 0, 1, 3, 3, 6, 1, 12, 12, 17, 17, 25, 25, 33, 33 end rem defines which color checks are in a stage data levelcolors %00000001, %00000011, %00000111, %00111000, %00111111, %11000000, %11000111, %11000111, %11111111, %11111111, %11111111, %11111111, %11111111, %11111111 end rem determine what the level's index is temp3 = startindex[level] temp4 = levelcolors[level] rem begin the actual generation temp1 = pulse - 100 780 rem generate a random number temp2 = rand rem determine what the level's index is temp3 = startindex[level] rem if a color is in a level and its number has been rolled, set a pfpixel to its color, then increment the index if temp4{0} && temp2 >= colorodds[temp3] then a[temp1] = blkc[0]: temp3 = temp3 + 1 if temp4{1} && temp2 >= colorodds[temp3] then a[temp1] = blkc[1]: temp3 = temp3 + 1 if temp4{2} && temp2 >= colorodds[temp3] then a[temp1] = blkc[2]: temp3 = temp3 + 1 if temp4{3} && temp2 >= colorodds[temp3] then a[temp1] = blkc[3]: temp3 = temp3 + 1 if temp4{4} && temp2 >= colorodds[temp3] then a[temp1] = blkc[4]: temp3 = temp3 + 1 if temp4{5} && temp2 >= colorodds[temp3] then a[temp1] = blkc[5]: temp3 = temp3 + 1 if temp4{6} && temp2 >= colorodds[temp3] then a[temp1] = blkc[6]: temp3 = temp3 + 1 if temp4{7} && temp2 >= colorodds[temp3] then a[temp1] = blkc[7]: blkcount = blkcount - 1 785 rem complete reset by giving full lives and reset if pulse = 116 then lives = 9: flicker = 0: pulse = 0 else pulse = pulse + 1 rem end loop 800 goto draw_loop
-
So going over scanlines (that is, having too many lines rendered on-screen) means that there are too many cycles being used?
Well, what do I do to fix it?
-
Alright. The game is essentially done. I buckled down and wrote out all the levels and a way for the flicker area to only display the colors that are relevant for a certain level.
Basically now I'm just waiting for someone to volunteer to do that kernel so I can get rid of this flickering.
rem rem ********************************** rem *heartbreak.bin * rem *A re-imagning of breakout with a lonely heart trapped in a void... * rem *Cybearg (aka Nic) * rem *[email protected] * rem ********************************** rem ============== rem INITIALIZATION rem ============== rem set up settings/optimization set optimization speed rem set up my variables dim base = q dim blkcount = r 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 = blkc[0] rem set player 0's location player0x=80:player0y=48 rem set base blockcount blkcount = 16 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 set base player sprite player0: %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 end rem if the player has zero lives, skip this part if lives = 0 then goto 410 rem set up possible colors data blkc 66, 28, 150, 46, 214, 102, 14, 00 end rem special occasion for first level if level = 0 then heartcolor = blkc[0]: goto 10 rem special occasion for second level if level = 1 && heartcolor = blkc[0] && pulse = 0 then heartcolor = blkc[1]: goto 10 if level = 1 && heartcolor = blkc[1] && pulse = 0 then heartcolor = blkc[0]: goto 10 rem increment the colors if heartcolor = blkc[1] && pulse = 0 then heartcolor = blkc[2]: goto 10 if heartcolor = blkc[0] && pulse = 0 then heartcolor = blkc[1]: goto 10 if heartcolor = blkc[2] && pulse = 0 then heartcolor = blkc[0] 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 > 6 then goto 50 41 if lives > 3 then goto 60 42 if lives > 0 then goto 70 rem values for the down-beat (5 out of 45 cycles) 44 if lives > 6 then goto 60 45 if lives > 3 then goto 70 46 if lives > 0 then goto 80 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 80 rem ============== rem COLOR FLICKER rem ============== 100 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 first, set levelcolor[level] into another variable for bitwise operations temp4 = levelcolors[level] 105 rem reset flicker if flicker = 8 then flicker = 0 rem determines if a color is being used if flicker = 0 && temp4{0} then goto 110 if flicker = 1 && temp4{1} then goto 110 if flicker = 2 && temp4{2} then goto 110 if flicker = 3 && temp4{3} then goto 110 if flicker = 4 && temp4{4} then goto 110 if flicker = 5 && temp4{5} then goto 110 if flicker = 6 && temp4{6} then goto 110 if flicker = 7 && temp4{7} then goto 110 rem if not, skip it and try the next color flicker = flicker + 1 goto 105 110 rem cycle through pfpixels, turning them on if they are equal to the color being drawn temp6 = base for temp5 = 0 to 15 if a[temp6] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on temp6 = temp6 + 1 & 15 next rem set playfield to current color 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 = blkc[0] 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 < 55 then offset = offset + 1 if joy0right && offset > 45 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 rotate left 435 base = base + 1 & 15 goto 450 rem move all blocks to the right (clockwise) 445 base = base - 1 & 15 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 ==================== 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 check for collision -- if not, bypass everything else as we wait for a collision if !collision(playfield,player1) then goto 800 705 rem double anglevar in order to determine how the number relates to a 0-15 range rather than a 0-7 range temp4 = 4 - anglevar temp4 = temp4 + temp4 + base & 15 rem checks for various hit-types, currently only consists of a single possibility, but there will be more for secondary colors, white, and black rem if one of the primary colors if a[temp4] = ballcolor then goto good_hit rem if orange if a[temp4] = blkc[3] && ballcolor = blkc[0] then goto good_hit if a[temp4] = blkc[3] && ballcolor = blkc[1] then goto good_hit rem if green if a[temp4] = blkc[4] && ballcolor = blkc[1] then goto good_hit if a[temp4] = blkc[4] && ballcolor = blkc[2] then goto good_hit rem if purple if a[temp4] = blkc[5] && ballcolor = blkc[0] then goto good_hit if a[temp4] = blkc[5] && ballcolor = blkc[2] then goto good_hit rem if white if a[temp4] = blkc[6] && lives < 9 then lives = lives + 1: goto good_hit if a[temp4] = blkc[6] then goto good_hit rem in case there's a mistake and a dead block is counted as a hit, make sure that it doesn't cost the player a life if a[temp4] = 2 then goto 800 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 goto 725 rem if the hit is good... good_hit rem set current block to dead a[temp4] = 2: blkcount = blkcount - 1 rem increment score score = score + 25 rem play good hit sound AUDV1 = 6 AUDC1 = 12 AUDF1 = 19 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 checks if all blocks have been destroyed if blkcount > 0 then goto 800 rem if so, then score bonus points for completing stage and continue if lives > 6 then score = score + 600: goto 770 if lives > 3 then score = score + 400: goto 770 if lives > 0 then score = score + 200 770 rem increment the level counter level = level + 1 if level = 14 then level = 6 rem generates new stage by looping through and inserting new colors taken from data set under MAIN LOOP 775 rem set up data sets for level generation rem defines the odds of a color for each stage data colorodds 0, 0, 128, 0, 85, 170, 0, 42, 84, 126, 168, 210, 0, 80, 160, 240, 247, 0, 40, 80, 120, 160, 200, 240, 247, 0, 60, 120, 180, 200, 220, 240, 245, 0, 60, 120, 180, 195, 210, 225, 230 end rem saves space by indicating where the colorodds index should begin, per level data startindex 0, 1, 3, 3, 6, 1, 12, 12, 17, 17, 25, 25, 33, 33 end rem defines which color checks are in a stage data levelcolors %00000001, %00000011, %00000111, %00111000, %00111111, %11000000, %11000111, %11000111, %11111111, %11111111, %11111111, %11111111, %11111111, %11111111 end rem determine what the level's index is temp3 = startindex[level] temp4 = levelcolors[level] rem set blockcount to 16 now, because there may be reason to diminish it blkcount = 16 rem begin the actual generation temp1 = 0 780 if temp1 = 16 then goto 785 rem generate a random number temp2 = rand rem determine what the level's index is temp3 = startindex[level] rem if a color is in a level and its number has been rolled, set a pfpixel to its color, then increment the index if temp4{0} && temp2 >= colorodds[temp3] then a[temp1] = blkc[0]: temp3 = temp3 + 1 if temp4{1} && temp2 >= colorodds[temp3] then a[temp1] = blkc[1]: temp3 = temp3 + 1 if temp4{2} && temp2 >= colorodds[temp3] then a[temp1] = blkc[2]: temp3 = temp3 + 1 if temp4{3} && temp2 >= colorodds[temp3] then a[temp1] = blkc[3]: temp3 = temp3 + 1 if temp4{4} && temp2 >= colorodds[temp3] then a[temp1] = blkc[4]: temp3 = temp3 + 1 if temp4{5} && temp2 >= colorodds[temp3] then a[temp1] = blkc[5]: temp3 = temp3 + 1 if temp4{6} && temp2 >= colorodds[temp3] then a[temp1] = blkc[6]: temp3 = temp3 + 1 if temp4{7} && temp2 >= colorodds[temp3] then a[temp1] = blkc[7]: blkcount = blkcount - 1 temp1 = temp1 + 1: goto 780 785 rem complete reset by giving full lives and reset lives = 9: flicker = 0 rem end loop 800 goto draw_loop
I've still got 867 bytes to spare on the ROM.
I could go back and split a variable or two into nybbles, but I'll worry about that later.
-
I know how Hex and binary work; I just find counting in decimal to be more intuitive.
As for software checks apart from what Omegamatrix
mentioned, I thought you'd already decided not to use
the hardware collision for some reason and that's why
you weren't using it (something you were discussing
several posts back).
Initially I had decided that because I didn't see any way to determine which block was being hit. Ranges of values were simpler there because I knew that the color corresponded to the indexed location of the block that was hit.
Then theloon suggested that I use the direction of the ball's movement to determine which block was being hit, which allowed me to cut down my code from this:
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
to this:
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 check for collision -- if not, bypass everything else as we wait for a collision if !collision(playfield,player1) then goto 800 705 rem double anglevar in order to determine how the number relates to a 0-15 range rather than a 0-7 range temp4 = 4 - anglevar temp4 = temp4 + temp4 + base & 15 rem checks for various hit-types, currently only consists of a single possibility, but there will be more for secondary colors, white, and black if a[temp4] = ballcolor then goto good_hit
... All while reducing cycles by cutting out a for-loop and passing off the collision detection to hardware that's specifically meant for that purpose. It seems like a win-win to me.
-
force of habit, it doesn't seem that way to me
but probably binary is clearer
No, decimal is clearer because it can be quickly read by anyone who glances at the code. Why would base 2 or base 16 be clearer than base 10, unless maybe you grew up with 2 or 16 fingers, respectively? ;P
Anyway, thanks much for your fix! Adding 4 seems pretty obvious, so I'm embarrassed that I didn't think of it right away. Why would everything be offset by 4, I wonder?
As for your code, why does bxtbl have a single value in it all by itself? Is there some advantage to doing that and going back to software checks rather than relying on the hardware collision detection?
-
yanglevar and the colors are different
How are they different? I know that anglevar is a range of 0 to 7 and the colors are a range of 0 to 15, but since each value of anglevar corresponds to every other value of the colors, a[0] to a[15] step 2 = a[anglevar], right? So then a[0] to a[15] step 1 = a[anglevar*2]
I just don't see why it's getting mirrored over the x axis.
anglevar = (rand/32)
Let's say that anglevar = 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
Since angle = 0, we goto 680
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
From this and the tables established above, we find that xmtbl[anglevar] = 50 and ymtbl[anglevar] = 51
So player1x = player1x + 50 - 50 : player1x = player1x
player1y = player1y + 51 - 50 : player1y = player1y + 1
This moves the ball straight up, towards 12 o'clock mark. Then...
rem check for collision -- if not, bypass everything else as we wait for a collision if !collision(playfield,player1) then goto 800
Let's say that there is a collision with the 12 o'clock block. This is then true and the code continues...
rem double anglevar in order to determine how the number relates to a 0-15 range rather than a 0-7 range temp4 = (anglevar + anglevar + base) & 15
Since anglevar = 0 and we haven't rotated left or right, temp4 = (0 + 0 + 0) & 15 : temp4 = 0
rem checks for various hit-types, currently only consists of a single possibility, but there will be more for secondary colors, white, and black if a[temp4] = ballcolor then goto good_hit
Let's say that both are red, so a[temp4] = ballcolor or a[0] = ballcolor : 64 = 64
good_hit rem set current block to dead a[temp4] = 0: blkcount = blkcount - 1
So this should set a[0] to 0, which will mean that it won't be drawn. Instead, it sets a[8] to 0. Where in the code is that made to happen?
-------------------------------
Your code:
rem check for collision type 710 temp4 = temp4 + base & $0F 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...
This doesn't really apply anymore because, using hardware collision and comparing to the angle of the ball, there is no need to loop through and check each block anymore. Instead, I need to offset an equal amount as the color's movement is being offset, then cross-reference the color value by the angle of the ball. Hence my stuff above.
Also, why do you like using $0F when 15 is functionally equivalent and much less confusing to read?
-
Alright. The following implements the hardware-based collision detection and the simpler color rotation. There is one problem remaining:
With the implementation of the hardware collision detection comes the same problem I described in the first post on this page. That is, collisions are mirrored on the x axis for some reason.
If someone can suggest a fix for this problem, things will be working very well.
rem ==================== rem COLLISION DETECTION 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 check for collision -- if not, bypass everything else as we wait for a collision if !collision(playfield,player1) then goto 800 705 rem double anglevar in order to determine how the number relates to a 0-15 range rather than a 0-7 range temp4 = (anglevar + anglevar + base) & 15 rem checks for various hit-types, currently only consists of a single possibility, but there will be more for secondary colors, white, and black if a[temp4] = ballcolor then goto good_hit rem if the hit is bad... bad_hit
Aside from that, everything seems to be working. I understand the way that the base thing works now--I think that I was confused by the odd choice by bogax to use HEX $0F instead of the much simpler and more readable 15 and I didn't grasp how the & actually works in that context, but now I think I understand it better.
Can anyone offer a suggestion why the above would cause collisions to be mirrored on the x axis? Note: it has nothing to do with the implementation of the better color movement style, as I was having the same problem even at the top of this thread's page.

Questions Galore!
in batari Basic
Posted
I guess it's just a question of where to put the drawKernel subroutine in the .asm file, then. The .bas file is attached and it compiles just fine, it's just a question of where the .drawKernel is located relative to everything else.
If it's at the start of the .asm file, when the game runs, it just gets a black screen after the title screen, then kicks back to the title screen again. If it's right before drawKernel:, there is a mess of drawn pfpixel blocks at the top of the screen which, when a shot is fired, sometimes are hit and count as collision and all, but it's clearly not as it's meant to be. If I call it later, after the DrawGap part in the .asm file, no blocks get drawn, but the heart is still there and working.
That is, of course, assuming that I'm meant to chop out everything under COLOR FLICKER entirely and simply call the assembly subroutine.
Wish I had a copy of your working demo's .asm file. Then I could kind of see how the parts work together.
heartkernel.asm
heartbreak.bas