Jump to content

Cybearg

Members
  • Content Count

    951
  • Joined

  • Last visited

Posts posted by Cybearg


  1. 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


  2. 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
    


  3. 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.

    heartbreak.bas


  4. 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
    

    heartbreak.bas

    heartkern.asm


  5. 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.


  6. 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.

    http://youtu.be/PhVRcm10XMY

     

    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.


  7. 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.


  8. 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.


  9. 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).

    heartbreak.bas

    heartbreak.bas.bin


  10. 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?


  11. 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.


  12. 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?


  13. 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 110
    

     

    and 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 + 1
    

     

    Anyway, 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.


  14. 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).


  15. 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.

    heartbreak.bas.bin

    heartbreak.bas


  16. 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

    heartbreak.bas

    heartbreak.bas.bin


  17. 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.

    heartbreak.bas

    heartbreak.bas.bin


  18. 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.


  19. 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?


  20. anglevar and the colors are different

    y

    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?


  21. 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.

    heartbreak.bas.bin

    heartbreak.bas

×
×
  • Create New...