Jump to content

Cybearg

Recommended Posts

My biggest worry is getting this to work without flicker. Adding more rings would be neat, but my biggest worry is getting it to not give people seizures. I don't know anything close to the know-how to create a new kernel or whatever must be done, so I'm pretty much sitting on my hands until someone pops out a genie of a solution.

 

Additionally, a variable is set aside to remember the color in each of the current 16 positions, so adding more is essentially out of the question unless I use a superchip RAM, which I hesitate to do because I'd love the game to all be perfectly packed in your average 4K 6400 cartridge.

 

Doesn't increasing the player size just widen the sprite, though? It doesn't make it any taller, so it would just look like someone stomped on the sprite, rather than like the whole heart was larger, no? Also, I can't draw using player 0 and player 1 because the player 1 is the ball (necessary because the ball takes on the color of the playfield, if I'm not mistaken).

Link to comment
Share on other sites

My biggest worry is getting this to work without flicker.

You shouldn't need to worry. It is very doable to write an assembly kernel since you got the colors separated. You're in good hands with SeaGtGruff as he is a very capable programmer doing lots of interesting stuff related to colors, timers, multiple sprites, and sound. ;)

 

Doesn't increasing the player size just widen the sprite, though?

Yes. To make the sprite appear proportional you just have to add more lines of graphics to compensate.

 

Also, I can't draw using player 0 and player 1 because the player 1 is the ball (necessary because the ball takes on the color of the playfield, if I'm not mistaken).

Yes, but when you refer to your player 1 as the ball it sounds confusing, because the object that borrows its color from the playfield really is called the "ball". Maybe refer to your on screen dot as the projectile or something. In any case you could also draw that dot with missile 1, which is often referred to as M1.

Edited by Omegamatrix
Link to comment
Share on other sites

The problem with using missile 1 or missile 0 is that they take on the colors of their sprites. I need the "projectile" to take on the color of player0 (the heart) at the moment of joy0fire and retain that color (and have it stored somewhere that can be read, since it's important for collision detection), which is what currently happens.

 

If I have to trim out some of the intricacies of the original gameplay design, that's alright so long as what remains works well.

Link to comment
Share on other sites

The problem with using missile 1 or missile 0 is that they take on the colors of their sprites. I need the "projectile" to take on the color of player0 (the heart) at the moment of joy0fire and retain that color

Right now you are using GRP0 for the heart, and GRP1 for the projectile, correct? M1 shares the same color as GRP1 so you have the choice of using either object.

Link to comment
Share on other sites

Right now you are using GRP0 for the heart, and GRP1 for the projectile, correct? M1 shares the same color as GRP1 so you have the choice of using either object.

True, but if I was using player 1 and player 0 together to create a megasprite, that would require them to share the same colors in order to make it work, which in turn wouldn't work when missile1 swapped colors to match.

Link to comment
Share on other sites

Has anyone had any luck devising (or does anyone know of) a kernel that will allow what I want to happen to happen? How will the code have to change once this is in place? I assume I won't continue to drawscreen every three cycles to change colors and will instead have a color per drawscreen, right? Any idea how that would need to look, so I can work on setting up the code to work for it in the meanwhile?

Link to comment
Share on other sites

it occured to me that if you use the noinlinedata

optimization you can interleave the x and y tables

thusly.

I have no idea if this is relevant

 for i = 0 to 14 step 2
if a[i] then goto collision_test
nexti
next

collision_test
temp1 = playerx1-xtbl[i]
if temp1>3 then goto nexti
temp1 = playery1-ytbl[i]
if temp1>5 then goto nexti
if a[i]<>ballcolor then goto bad_hit

rem good_hit
a[i]=0

bad_hit

data xtbl
81
end

data ytbl
9, 114, 17, 130, 49, 114, 81, 82, 89, 50, 81, 34, 49, 50, 17
end

 

and while I'm at it

 rem move all block values to the right
temp2 = a
for temp1 = 0 to 14
a[temp1] = b[temp1]
next
p = temp2

rem move all blocks to the left
temp2 = p
for temp1 = 14 to 0 step -1
b[temp1] = a[temp1]
next
a = temp2

Link to comment
Share on other sites

Thanks much for all the advice! I hadn't thought to combine the data sets (though it only saved me about 10 bytes, but still!) and I didn't know that you could do a[temp1+1] with b[temp1]. though it makes sense in hindsight. That's pretty awesome.

 

It occurs to me that I haven't posted the code in a while. I'm always open to input to make things more efficient, and maybe it will help in developing that kernel (hope that everyone hasn't forgotten :().

 


rem Generated 1/28/2013 1:50:36 PM by Visual bB Version 1.0.0.548
rem **********************************
rem *heartbreak.bin                    *
rem *A re-imagning of breakout with a lonely heart trapped in a void...                   *
rem *Cybearg (aka Nic)                        *
rem *cybearg.plays@gmail.com                 *
rem **********************************


rem ==============
rem INITIALIZATION
rem ==============

rem set up settings/optimization
set optimization speed

rem set up my variables
dim level = s
dim cooldown=t
dim anglevar=u
dim pulse=v
dim flicker=w
dim offset=x
dim ballcolor=y
dim heartcolor=z

rem set offset to a number greater than 0 to allow for "negative" values
offset = 50

rem set heartcolor to begin at red
heartcolor = 64

rem set player 0's location
player0x=80:player0y=48


rem ==========
rem MAIN LOOP
rem ==========

draw_loop

rem clear the playfield
pfclear

rem increment the multi-purpose cooldown variable
cooldown = cooldown + 1

rem mute sound at 7 cooldown cycles or after 20 cycles if there's been a titlescreen restart
if cooldown = 7  || cooldown = 70 then AUDV0 = 0 : AUDV1 = 0


rem ===============
rem BEATING HEART
rem ===============

rem increment pulse counter
pulse = pulse +1

rem cooldown to make sure that player doesn't leave the title screen by firing a ball
if pulse = 45 && cooldown >= 50 then cooldown = 0

rem after 45 cycles, increment color
if pulse = 45 then pulse = 0

rem special occasion for first level
if level = 0 then heartcolor = 64: goto 10

rem special occasion for second level
if level = 1 && heartcolor = 64 && pulse = 0 then heartcolor = 28: goto 10
if level = 1 && heartcolor = 28 && pulse = 0 then heartcolor = 64: goto 10

rem increment the colors
if heartcolor = 28 && pulse = 0 then heartcolor = 148: goto 10
if heartcolor = 64 && pulse = 0 then heartcolor = 28: goto 10
if heartcolor = 148 && pulse = 0 then heartcolor = 64

10

rem set the playfield colors
COLUP0 = heartcolor

rem turn the score red if player is on the last life
if lives = 1 then scorecolor = 64 else scorecolor = 10

rem swap the heart sprite for 5 cycles to create illusion of beating
if pulse < 40 then goto 40 else goto 44

rem values for the up-beat (40 out of 45 cycles)
40 if lives = 0 then goto 80
41 if lives = 1 then goto 70
42 if lives = 2 then goto 60
43 if lives = 3 then goto 50

rem values for the down-beat (5 out of 45 cycles)
44 if lives = 0 then goto 80
45 if lives = 1 then goto 90
46 if lives = 2 then goto 70
47 if lives = 3 then goto 60

rem the various player 0 heart sprites
50 player0:
%00010000
%00111000
%01111100
%11111110
%11111110
%11111110
%01101100
%00000000
end

55 goto 100

60 player0:
%00000000
%00010000
%00111000
%01111100
%01111100
%00101000
%00000000
%00000000
end

65 goto 100

70 player0:
%00000000
%00000000
%00010000
%00111000
%00101000
%00000000
%00000000
%00000000
end

75 goto 100

80 

90 player0:
%00000000
%00000000
%00000000
%00000000
%00000000
%00000000
%00000000
%00000000
end


rem ==============
rem COLOR FLICKER
rem ==============

100

rem if the player has zero lives, skip this part
if lives = 0 then goto 410

rem set up possible colors
data blkc
64, 28, 148
end

rem set up possible pfpixel locations
data ctbl
16, 20, 24, 27, 28, 27, 24, 20, 16, 12, 8, 5, 4, 5, 8, 12
end

data rtbl
0, 0, 1, 3, 5, 7, 9, 10, 10, 10, 9, 7, 5, 3, 1, 0
end

rem cycle through pfpixels, turning them on if they are equal to the color being drawn
for temp5 = 0 to 15
if a[temp5] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on
next

rem set playfield to current color
COLUPF = blkc[flicker]

rem increment flicker
temp1 = blkc_length + 1
if flicker = temp1 then flicker = 0 else flicker = flicker + 1

rem ==================
rem MAIN DRAWSCREEN
rem ==================

rem main drawscreen
drawscreen

rem skip to COLOR MOVEMENT
goto 415


rem =============
rem TITLE SCREEN
rem =============


410

rem set the beat of the title screen heart to the ongoing pulse
if pulse < 40 then goto 413 else goto 412

rem the two possible title screen frames
412

playfield:
................................
...X.X.XXX..X..XX.XXX...........
...X.X.X...X.X.X.X.X............
...XXX.XX..XXX.XX..X............
...X.X.XXX.X.X.X.X.X............
..............................
...........XX..XX..XXX..X..X.X..
....X.X....X.X.X.X.X...X.X.X.X..
....XXX....XX..XX..XX..XXX.XX...
.....X.....X.X.X.X.XXX.X.X.X.X..
...........XXX..................
end

rem skip to color
goto 414

413

playfield:
................................
...X.X.XXX..X..XX.XXX...........
...X.X.X...X.X.X.X.X............
...XXX.XX..XXX.XX..X............
...X.X.XXX.X.X.X.X.X............
................................
...XX.XX...XX..XX..XXX..X..X.X..
..XXXXXXX..X.X.X.X.X...X.X.X.X..
...XXXXX...XX..XX..XX..XXX.XX...
....XXX....X.X.X.X.XXX.X.X.X.X..
.....X.....XXX..................
end

414

rem color the title screen playfield
COLUPF = 64

rem drawscreen for titlescreen only
drawscreen

rem skip everything else and wait for a trigger
goto 760


rem =================
rem COLOR MOVEMENT
rem =================

415

rem NOTE: offset base is 50, so the numbers below determine how sensitive the controls are

rem determine block offset
if joy0left && offset < 56 then offset = offset + 1
if joy0right && offset > 44 then offset = offset - 1


rem adjust block offset
420 if offset > 55 goto 435
if offset < 45 goto 445

rem if no adjustments are necessary, skip this part
goto 500


rem move all block values to the left (counter clockwise)
435  temp2 = a
for temp1 = 0 to 14
a[temp1] = b[temp1]
next
p = temp2
goto 450

rem move all blocks to the right (clockwise)
445 temp2 = p
for temp1 = 15 to 0 step -1
b[temp1] = a[temp1]
next
a = temp2

rem reset the offset

450
offset = 50


rem ============
rem PLAYER FIRE
rem ============

500

rem checks to see that a few cool-down measures are a go, then moves the ball (player 1) to the center of the heart (player 0)
rem cooldown ensures that the player cannot fire while a ball is at play
rem cooldown also ensures the player doesn't exit a title screen by firing a ball prematurely
if joy0fire && lives > 0 && player1x = 0 && player1y = 0 && cooldown < 50 then player1x=80:player1y=48 else goto 600

rem moves the ball's current color from heartcolor (set in the BEATING HEART section) to ballcolor for safe-keeping
ballcolor = heartcolor

rem set player 1's sprite

player1:
%00000000
%00000000
%00000000
%00011000
%00011000
%00000000
%00000000
%00000000
end

rem generate random number to determine ball movement
rem variables ensure that ball speed/angle does not vary once ball has been generated

anglevar = (rand/32)


rem =========
rem THE BALL
rem =========

600

rem skip everything dealing with the ball if it is at its resting position (0,0)
if player1x = 0 && player1y = 0 then goto 800

rem maintain the color of the ball at the moment of firing

COLUP1 = ballcolor

rem all ball movement possibilities
rem allows for ball movement in a direction every 45 degrees

650

rem cooldown is used to manage the speed of the ball
if cooldown > 8 then cooldown = 0

rem x motion table
data xmtbl
50, 51, 51, 51, 50, 49, 49, 49
end

rem y motion table
data ymtbl
51, 51, 50, 49, 49, 49, 50, 51
end

rem separate out cardinal from diagonal directions
if anglevar <> 0 && anglevar <> 2 && anglevar <> 4 && anglevar <> 6 then goto 670 else goto 680

670
rem movements for diagonal directions (45, 125, 225, 315) -- applies a cooldown to ensure that diagonals do not move too fast
if cooldown <> 1 && cooldown <> 3 && cooldown <> 5 && cooldown <> 7 then player1x = player1x + xmtbl[anglevar] - 50: player1y = player1y + ymtbl[anglevar] - 50: goto 700 else goto 700

680
rem movement values for cardinal (0, 90, 180, 270 degrees) directions -- applies a cooldown to ensure that cardinal directions do not move too fast
if cooldown <> 3 && cooldown <> 7 then player1x = player1x + xmtbl[anglevar] - 50
if cooldown <> 3 && cooldown <> 7 then player1y = player1y + ymtbl[anglevar] - 50

rem ====================
rem COLLISION DETECTION
rem === thanks to bogax ===
rem ====================

700

rem check to see if player 1 is out of bounds
if player1x = 25 || player1y = 0 then goto 750
if player1x=133 || player1y = 140 then goto 750

rem minimum collision data locations (x, y)
data btbl
78, 4, 109, 12, 125, 44, 109, 76, 77, 84, 45, 76, 29, 44, 45, 12
end

rem check each of the 8 possible collision locations
for temp4 = 0 to 14 step 2
temp3 = temp4 + 1

rem set up temporary variables to contain the full range of the x and y potentials
temp5 = btbl[temp4] + 4
temp6 = btbl[temp3] + 8

rem if player1x is within the range for the current block and player1y is within the range for the current block, there is a collision
if player1x > btbl[temp4] && player1x < temp5 && player1y > btbl[temp3] && player1y < temp6 then goto 710

rem otherwise, check the next block
next

rem if no collision is detected, skip to the end of the main loop
goto 800

rem check for collision type
710

rem check if the block is already dead
if a[temp4] = 0 then goto 800

rem check ball color against block color
if a[temp4]<>ballcolor then goto bad_hit

rem if the hit is good...
good_hit

rem set current block to dead
a[temp4] = 0

rem increment score
score = score + 25

rem play good hit sound
  AUDV1 = 6
  AUDC1 = 12
  AUDF1 = 19

goto 725

rem if the hit is bad...
bad_hit

rem lose a life
lives = lives - 1

rem play bad hit sound
  AUDV1 = 6
  AUDC1 = 6
  AUDF1 = 16

rem reset sound cooldown counter
725 
if lives > 0 then cooldown = 0 else cooldown = 50: pulse = 0

750

rem reset player 1 location, unlocking player 0 fire
player1x = 0: player1y = 0


rem ==================
rem STAGE GENERATION
rem ==================

760

rem exits title screen and generates a new stage
if joy0fire && lives = 0 && cooldown < 50 then score = 0: pulse = 0: cooldown = 50: level = 0: goto 775

rem cycles through blocks to check if all have been destroyed
temp2 = 0
for temp1 = 0 to 15
if a[temp1] = 0 && lives > 0 then temp2 = temp2 + 1
next

rem if not, then end cycle
if temp2 <> 16 then goto 800

rem if so, then score bonus points for completing stage and continue
if lives = 3 then score = score + 600
if lives = 2 then score = score + 400
if lives = 1 then score = score + 200

rem increment the level counter, but make sure it doesn't go too high
if level < 10 then level = level + 1

rem generates new stage by looping through and inserting new colors taken from data set under COLOR FLICKER
775 

rem different values for different levels
if level = 0 then goto 776
if level = 1 then goto 777 else goto 780

776
rem first level has only red blocks, to teach basic mechanics of firing a ball and rotating blocks
for temp1 = 0 to 15
a[temp1] = blkc[0]
next
goto 799

777
rem second level teaches the differences between the colors and how the right color must go to the right ball
for temp1 = 0 to 15
temp2 = (rand/64)
if temp2 < 2 then a[temp1] = blkc[1] else a[temp1] = blkc[0]
next

goto 799

780
rem third level introduces all three primary colors
for temp1 = 0 to 15
temp2 = rand 
if temp2 < 86 then a[temp1] = blkc[0]
if temp2 > 85 then a[temp1] = blkc[1]
if temp2 > 170 then a[temp1] = blkc[2]
next

799
rem complete reset by giving full lives
 lives = 3

rem end loop
800 goto draw_loop

heartbreak.bas

Current remaining resources:

1234 bytes and 2 variables

 

Note that the way that the colors flicker will likely have to be changed for whatever the kernel ends up being and I intend to have a number of extra pre-set level types to introduce new colors, but I haven't programmed them in because everything relies on the flickering.

Link to comment
Share on other sites

rem move all block values to the right
435 for temp1 = 0 to 15
temp2 = temp1 + 1
if temp2 = 16 then temp2 = 0
a[temp1] = a[temp2]
next
offset = 50
goto 500
rem move all blocks to the left
445 for temp1 = 15 to 0 step -1
temp2 = temp1 - 1
if temp2 = 255 then temp2 = 15
a[temp1] = a[temp2]
next
offset = 50
450

 

 

Hey there :)

Not familiar with Bb myself, but what you have there is a power-of-two sized buffer which you're rotating by shifting the whole buffer left or right.

What I'd do is not shift the buffer at all, but instead shift the starting point left or right. So instead of starting at 0, I'd start at X, where X is 0 to 15.

Also, not sure if you can binary-AND with Bb, but if you can, then you don't really need the >16 checks.

 

rem move all block values to the right <<< yeah, is this comment correct?  I think of this sort of shifting as shifting LEFT
rem using a 'wrap around' at 16, where the &15 guarantees our range is 0-15
435 for temp1 = 0 to 15
a[temp1] = a[(temp1+1)&15]
next

 

But, as I said... the above code is going to be slow; it's moving 16 values in an array. You want to avoid this sort of thing, and instead of moving the whole array around, see if you can start in the middle and have the pointer to the elements wrap around when it goes off the 'edge' of the array. That is, don't shift the array values at all. Just conceptually shift the start of the array by starting your drawing/lookup midway through.

 

For example

 

pointer = (pointer-1)&15

will go 0 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 15 ...

because when it's 0, then it decrements to -1 (255) or in 16-bit, 65535, which when binary AND-ed with 15 gives 15, in both cases.

The & is what I use for "Binary AND" (as opposed to logical AND).

 

Same thing with

pointer = (pointer+1)&15

this will wrap when it gets to 16, back to 0.

 

So if your array doesn't shift at all, but you start 'drawing' at element #7, then you go 7 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6

Hope that makes sense.. It may not be workable in your current setup, as I haven't looked at all of your code.

 

I've just realised there are 2 pages more after the message I replied to. The above may be useless info by now :)

 

Cheers

A

Link to comment
Share on other sites

Yeah, it's an honor! Thanks, Andrew! I feel foolish for not having thought of it.

 

It's still certainly relevant, so I'm going to try implementing that now. It'll surely save a number of cycles.

 

What I'm trying to crunch at the moment is a way for the flickering set-up to dynamically adjust to serve however many colors are in the array at a time, but it just isn't working.

 



rem set up possible colors
data blkc
64, 28, 154, 44, 202, 122, 14, 0
end

rem set up possible pfpixel locations
data ctbl
16, 20, 24, 27, 28, 27, 24, 20, 16, 12, 8, 5, 4, 5, 8, 12
end

data rtbl
0, 0, 1, 3, 5, 7, 9, 10, 10, 10, 9, 7, 5, 3, 1, 0
end

110
rem cycle through pfpixels, turning them on if they are equal to the color being drawn
if flicker = 8 then flicker = 0

for temp5 = 0 to 15
if a[temp5] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on: temp4 = 1
next

rem determines if a color shows up; if not, don't bother drawing that color and return for the next
if temp4 = 0 then flicker = flicker + 1: goto 110 else COLUPF = blkc[flicker]

rem ==================
rem MAIN DRAWSCREEN
rem ==================

rem main drawscreen
drawscreen

 

Even though this makes sense to me in my head, it doesn't seem to work correctly. I'm probably just overlooking something painfully obvious.

Link to comment
Share on other sites

I tried kind of what you suggested, Andrew, but I can't get it to work. What you wrote precisely just causes the program to do nothing, and since I don't really understand what a[temp1] = a[(temp1+1)&15] does, I can't do much to fix it.

 

I did try keeping the spirit of the suggestion with something like this:

 

rem cycle through pfpixels, turning them on if they are equal to the color being drawn
for temp5 = 0 to 15
rem adjust block offset
if offset > 55 then temp6 = (temp5 + 1)
if offset < 45 then temp6 = (temp5 - 1) else temp6 = temp5
if a[temp6] = blkc[flicker] then pfpixel ctbl[temp6] rtbl[temp6] on
next

 

I see your point, though I don't think that it will work with the way the code is currently set up. More than just the visual colors are dependent on the location in the array: the coordinates of each pfpixel is tied to a location in the array which I depend on when determining which color each pfpixel is, so a[0] needs to correspond to ctbl[0] and rtbl[0]. I'm not sure that a single variable is sufficient for carrying that offset in addition to performing the cooldown function (to ensure that the ring rotation isn't per-pixel sensitive), and I'm really not quite sure how it would work at all without the ability for variable values to go into the negatives.

Link to comment
Share on other sites

since I don't really understand what a[temp1] = a[(temp1+1)&15] does

in this case it effects a mod 16.

0 and anything is 0

1 and anything is that thing.

15 is 00001111 in binary

& 15 is a bitwise and

so you zero everything but the lower four bits

 

kinda like in decimal if you set all digits of an integer

except the first one (least significant) to zero you get

that number mod 10 if you keep the first two it's mod 100 etc

 

I see your point, though I don't think that it will work with the way the code is currently set up. More than just the visual colors are dependent on the location in the array: the coordinates of each pfpixel is tied to a location in the array which I depend on when determining which color each pfpixel is, so a[0] needs to correspond to ctbl[0] and rtbl[0]. I'm not sure that a single variable is sufficient for carrying that offset in addition to performing the cooldown function (to ensure that the ring rotation isn't per-pixel sensitive), and I'm really not quite sure how it would work at all without the ability for variable values to go into the negatives.

 

I don't think it would be much of a problem to fit it

into what you're doing now. I'm not sure there'd be any

advantage. it would greatly simplify the rotation code

at the expense of adding code and slowing things down

pretty much every where else you indexed the objects.

you'd also need a variable to remember where your first

object is,

or to map the logical location to the actual address

or between the colors index and the position

paramters index(es) if you like (how ever you want to

think of it).

you'd either need to translate from a loop variable

to an index or maintain the index in parallel with the

translation built in.

 

I didn't actually count the cycles but it would save you

450 cycles in the rotation loops at the expense of extra

150 cycles in the rest of the loops.

 

 for temp5 = 0 to 15
if a[temp5] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on
next

would become:

 

translate

for temp5 = 0 to 15
temp6 = temp5 + base & $0F
if a[temp6] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on
next

 

in parallel

temp6 = base
for temp5 = 0 to 15
if a[temp6] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on
temp6 = temp6 + 1 & $0F
next

 

that assumes you're starting with the first color

you could also make the object color index the

for-variable but I think that would complicate

things needlessly

 

as an aside you shouldn't count on temp variables

if you're going to call something that might use them

like pfpixel (although I think the only temp variable

pfpixel uses it temp2)

 

 

rotation is simplified

rem rotate left
base = base + 1 & $0F

 

possibly I'm missing something but the only thing that

changes is how the object colors are mapped to the other

stuff I don't see how that effects cooldown

I suppose if, where you start has an effect there could be

problems ie you assume that the first thing in a table

is also the first object/color

like if you drew things top down by color here and by table

location there

but I didn't see that(?)

 

also I don't see what you need negative values for

 

here's the old rotation code in asm (untested)

 

 REM rotate left
asm
lda a
pha
ldx #$00
LLOOP
lda b,x
sta a,x
inx
cpx #15
bne LLOOP
pla
sta p
end

rem rotate right
asm
lda p
pha
ldx #14
RLOOP
lda a,x
sta b,x
dex
bpl RLOOP
pla
sta a
end

 

 

miscellaneous

 

 for temp1 = 0 to 15
temp2 = (rand/64)
if temp2 < 2 then a[temp1] = blkc[1] else a[temp1] = blkc[0]
next

 

 for temp1 = 0 to 15
temp2 = rand
if temp2 < 128 then a[temp1] = blkc[1] else a[temp1] = blkc[0]
next

 

actually you can use rand instead of temp2 in the if-then

but then bB just uses the last value of rand without computing

a new one

Edited by bogax
Link to comment
Share on other sites

Egh. Tried fiddling with what you offered there, bogax, and while it does make the movement work just fine, the hit detection is completely buggered by the change.

 

Anyone have any further suggestions about my primary kernel problem?

 

EDIT: And I still can't figure out what's going wrong here:

 

rem set up possible colors
data blkc
64, 28, 154, 44, 202, 122, 14, 0
end

rem set up possible pfpixel locations
data ctbl
16, 20, 24, 27, 28, 27, 24, 20, 16, 12, 8, 5, 4, 5, 8, 12
end

data rtbl
0, 0, 1, 3, 5, 7, 9, 10, 10, 10, 9, 7, 5, 3, 1, 0
end

110
rem cycle through pfpixels, turning them on if they are equal to the color being drawn
if flicker = 8 then flicker = 0

for temp5 = 0 to 15
if a[temp5] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on: temp4 = 1
next

rem determines if a color shows up; if not, don't bother drawing that color and return for the next
if temp4 = 0 then flicker = flicker + 1: goto 110 else COLUPF = blkc[flicker]: flicker = flicker + 1

rem ==================
rem MAIN DRAWSCREEN
rem ==================

rem main drawscreen
drawscreen

 

Here's what I think it should be doing (let's assume it's a level with only red, 64, and yellow, 28):

 

1. Since all variables initialize at 0, flicker begins at 0

 

2. Since flicker is != 8, flicker is not affected by the first if statement

 

3. A temporary variable (temp5) starts a loop, initializing itself at 0

 

4. The first block in the ring (a[0]) is checked to see if it conforms with the first color in the data set (blkc[0]) -- let's say that it does match

 

5. A pfpixel corresponding to location 0 is drawn for the block and temp4 is set to 1

 

6. The loop continues, finding some yellow blocks that aren't drawn and some red blocks that are drawn

 

7. Since temp4 != 0, COLUPF is set to blkc[0] (64, red) and flicker is incremented

 

8. The cycle repeats for yellow (in the next main_loop cycle, after a drawscreen and pfclear), where temp4 gets set to 1 again because a[something] = blkc[1] (28, yellow), so pfpixels are drawn, the "if temp4 = 0" check is passed, and COLUPF = blkc[flicker] and flicker is incremented.

 

9. This time through the main loop, flicker = 2, and since there are no blue blocks in this particular theoretical randomization, temp4 should remain 1, which triggers the "if temp4 = 0" check, which increments flicker and sends back for another loop through, this time checking for flicker = 3, and so it continues until flicker = 8, whereupon flicker = 0 and the cycle continues at red.

 

In theory, this should only flicker between colors that are actually represented in the playfield. A field with all red blocks should be completely solid because there should never be a cycle where a playfield is rendered with fewer than all of the blocks being red. Similarly, if the playfield consists of half red and half blue, then all the blue blocks are killed by the player, the playfield should become solid red because the above loop would not have any other colors to trip the temp4 = 1 check and get drawn.

 

Instead, it continues to flicker as always, even when all playfield blocks are red. I cannot understand why.

 



rem Generated 1/28/2013 1:50:36 PM by Visual bB Version 1.0.0.548
rem **********************************
rem *heartbreak.bin                    *
rem *A re-imagning of breakout with a lonely heart trapped in a void...                   *
rem *Cybearg (aka Nic)                        *
rem *cybearg.plays@gmail.com                 *
rem **********************************


rem ==============
rem INITIALIZATION
rem ==============

rem set up settings/optimization
set optimization speed

rem set up my variables
dim level = s
dim cooldown=t
dim anglevar=u
dim pulse=v
dim flicker=w
dim offset=x
dim ballcolor=y
dim heartcolor=z

rem set offset to a number greater than 0 to allow for "negative" values
offset = 50

rem set heartcolor to begin at red
heartcolor = 64

rem set player 0's location
player0x=80:player0y=48


rem ==========
rem MAIN LOOP
rem ==========

draw_loop

rem clear the playfield
pfclear

rem increment the multi-purpose cooldown variable
cooldown = cooldown + 1

rem mute sound at 7 cooldown cycles or after 20 cycles if there's been a titlescreen restart
if cooldown = 7  || cooldown = 70 then AUDV0 = 0 : AUDV1 = 0


rem ===============
rem BEATING HEART
rem ===============

rem increment pulse counter
pulse = pulse +1

rem cooldown to make sure that player doesn't leave the title screen by firing a ball
if pulse = 45 && cooldown >= 50 then cooldown = 0

rem after 45 cycles, increment color
if pulse = 45 then pulse = 0

rem special occasion for first level
if level = 0 then heartcolor = 64: goto 10

rem special occasion for second level
if level = 1 && heartcolor = 64 && pulse = 0 then heartcolor = 28: goto 10
if level = 1 && heartcolor = 28 && pulse = 0 then heartcolor = 64: goto 10

rem increment the colors
if heartcolor = 28 && pulse = 0 then heartcolor = 148: goto 10
if heartcolor = 64 && pulse = 0 then heartcolor = 28: goto 10
if heartcolor = 148 && pulse = 0 then heartcolor = 64

10

rem set the playfield colors
COLUP0 = heartcolor

rem turn the score red if player is on the last life
if lives = 1 then scorecolor = 64 else scorecolor = 10

rem swap the heart sprite for 5 cycles to create illusion of beating
if pulse < 40 then goto 40 else goto 44

rem values for the up-beat (40 out of 45 cycles)
40 if lives = 0 then goto 80
41 if lives = 1 then goto 70
42 if lives = 2 then goto 60
43 if lives = 3 then goto 50

rem values for the down-beat (5 out of 45 cycles)
44 if lives = 0 then goto 80
45 if lives = 1 then goto 90
46 if lives = 2 then goto 70
47 if lives = 3 then goto 60

rem the various player 0 heart sprites
50 player0:
%00010000
%00111000
%01111100
%11111110
%11111110
%11111110
%01101100
%00000000
end

55 goto 100

60 player0:
%00000000
%00010000
%00111000
%01111100
%01111100
%00101000
%00000000
%00000000
end

65 goto 100

70 player0:
%00000000
%00000000
%00010000
%00111000
%00101000
%00000000
%00000000
%00000000
end

75 goto 100

80 

90 player0:
%00000000
%00000000
%00000000
%00000000
%00000000
%00000000
%00000000
%00000000
end


rem ==============
rem COLOR FLICKER
rem ==============

100

rem if the player has zero lives, skip this part
if lives = 0 then goto 410

rem set up possible colors
data blkc
64, 28, 154, 44, 202, 122, 14, 0
end

rem set up possible pfpixel locations
data ctbl
16, 20, 24, 27, 28, 27, 24, 20, 16, 12, 8, 5, 4, 5, 8, 12
end

data rtbl
0, 0, 1, 3, 5, 7, 9, 10, 10, 10, 9, 7, 5, 3, 1, 0
end

110
rem cycle through pfpixels, turning them on if they are equal to the color being drawn
if flicker = 8 then flicker = 0

for temp5 = 0 to 15
if a[temp5] = blkc[flicker] then pfpixel ctbl[temp5] rtbl[temp5] on: temp4 = 1
next

rem determines if a color shows up; if not, don't bother drawing that color and return for the next
if temp4 = 0 then flicker = flicker + 1: goto 110 else COLUPF = blkc[flicker]: flicker = flicker + 1

rem ==================
rem MAIN DRAWSCREEN
rem ==================

rem main drawscreen
drawscreen

rem skip to COLOR MOVEMENT
goto 415


rem =============
rem TITLE SCREEN
rem =============


410

rem set the beat of the title screen heart to the ongoing pulse
if pulse < 40 then goto 413 else goto 412

rem the two possible title screen frames
412

playfield:
................................
...X.X.XXX..X..XX.XXX...........
...X.X.X...X.X.X.X.X............
...XXX.XX..XXX.XX..X............
...X.X.XXX.X.X.X.X.X............
..............................
...........XX..XX..XXX..X..X.X..
....X.X....X.X.X.X.X...X.X.X.X..
....XXX....XX..XX..XX..XXX.XX...
.....X.....X.X.X.X.XXX.X.X.X.X..
...........XXX..................
end

rem skip to color
goto 414

413

playfield:
................................
...X.X.XXX..X..XX.XXX...........
...X.X.X...X.X.X.X.X............
...XXX.XX..XXX.XX..X............
...X.X.XXX.X.X.X.X.X............
................................
...XX.XX...XX..XX..XXX..X..X.X..
..XXXXXXX..X.X.X.X.X...X.X.X.X..
...XXXXX...XX..XX..XX..XXX.XX...
....XXX....X.X.X.X.XXX.X.X.X.X..
.....X.....XXX..................
end

414

rem color the title screen playfield
COLUPF = 64

rem drawscreen for titlescreen only
drawscreen

rem skip everything else and wait for a trigger
goto 760


rem =================
rem COLOR MOVEMENT
rem =================

415

rem NOTE: offset base is 50, so the numbers below determine how sensitive the controls are

rem determine block offset
if joy0left && offset < 56 then offset = offset + 1
if joy0right && offset > 44 then offset = offset - 1


rem adjust block offset
420 if offset > 55 goto 435
if offset < 45 goto 445

rem if no adjustments are necessary, skip this part
goto 500


rem move all block values to the left (counter clockwise)
435  temp2 = a
for temp1 = 0 to 14
a[temp1] = b[temp1]
next
p = temp2
goto 450

rem move all blocks to the right (clockwise)
445 temp2 = p
for temp1 = 15 to 0 step -1
b[temp1] = a[temp1]
next
a = temp2

rem reset the offset

450
offset = 50


rem ============
rem PLAYER FIRE
rem ============

500

rem checks to see that a few cool-down measures are a go, then moves the ball (player 1) to the center of the heart (player 0)
rem cooldown ensures that the player cannot fire while a ball is at play
rem cooldown also ensures the player doesn't exit a title screen by firing a ball prematurely
if joy0fire && lives > 0 && player1x = 0 && player1y = 0 && cooldown < 50 then player1x=80:player1y=48 else goto 600

rem moves the ball's current color from heartcolor (set in the BEATING HEART section) to ballcolor for safe-keeping
ballcolor = heartcolor

rem set player 1's sprite

player1:
%00000000
%00000000
%00000000
%00011000
%00011000
%00000000
%00000000
%00000000
end

rem generate random number to determine ball movement
rem variables ensure that ball speed/angle does not vary once ball has been generated

anglevar = (rand/32)


rem =========
rem THE BALL
rem =========

600

rem skip everything dealing with the ball if it is at its resting position (0,0)
if player1x = 0 && player1y = 0 then goto 800

rem maintain the color of the ball at the moment of firing

COLUP1 = ballcolor

rem all ball movement possibilities
rem allows for ball movement in a direction every 45 degrees

650

rem cooldown is used to manage the speed of the ball
if cooldown > 8 then cooldown = 0

rem x motion table
data xmtbl
50, 51, 51, 51, 50, 49, 49, 49
end

rem y motion table
data ymtbl
51, 51, 50, 49, 49, 49, 50, 51
end

rem separate out cardinal from diagonal directions
if anglevar <> 0 && anglevar <> 2 && anglevar <> 4 && anglevar <> 6 then goto 670 else goto 680

670
rem movements for diagonal directions (45, 125, 225, 315) -- applies a cooldown to ensure that diagonals do not move too fast
if cooldown <> 1 && cooldown <> 3 && cooldown <> 5 && cooldown <> 7 then player1x = player1x + xmtbl[anglevar] - 50: player1y = player1y + ymtbl[anglevar] - 50: goto 700 else goto 700

680
rem movement values for cardinal (0, 90, 180, 270 degrees) directions -- applies a cooldown to ensure that cardinal directions do not move too fast
if cooldown <> 3 && cooldown <> 7 then player1x = player1x + xmtbl[anglevar] - 50
if cooldown <> 3 && cooldown <> 7 then player1y = player1y + ymtbl[anglevar] - 50

rem ====================
rem COLLISION DETECTION
rem === thanks to bogax ===
rem ====================

700

rem check to see if player 1 is out of bounds
if player1x = 25 || player1y = 0 then goto 750
if player1x=133 || player1y = 140 then goto 750

rem minimum collision data locations (x, y)
data btbl
78, 4, 109, 12, 125, 44, 109, 76, 77, 84, 45, 76, 29, 44, 45, 12
end

rem check each of the 8 possible collision locations
for temp4 = 0 to 14 step 2
temp3 = temp4 + 1

rem set up temporary variables to contain the full range of the x and y potentials
temp5 = btbl[temp4] + 4
temp6 = btbl[temp3] + 8

rem if player1x is within the range for the current block and player1y is within the range for the current block, there is a collision
if player1x > btbl[temp4] && player1x < temp5 && player1y > btbl[temp3] && player1y < temp6 then goto 710

rem otherwise, check the next block
next

rem if no collision is detected, skip to the end of the main loop
goto 800

rem check for collision type
710

rem check if the block is already dead
if a[temp4] = 2 then goto 800

rem check ball color against block color
if a[temp4]<>ballcolor then goto bad_hit

rem if the hit is good...
good_hit

rem set current block to dead
a[temp4] = 2

rem increment score
score = score + 25

rem play good hit sound
  AUDV1 = 6
  AUDC1 = 12
  AUDF1 = 19

goto 725

rem if the hit is bad...
bad_hit

rem lose a life
lives = lives - 1

rem play bad hit sound
  AUDV1 = 6
  AUDC1 = 6
  AUDF1 = 16

rem reset sound cooldown counter
725 
if lives > 0 then cooldown = 0 else cooldown = 50: pulse = 0

750

rem reset player 1 location, unlocking player 0 fire
player1x = 0: player1y = 0


rem ==================
rem STAGE GENERATION
rem ==================

760

rem exits title screen and generates a new stage
if joy0fire && lives = 0 && cooldown < 50 then score = 0: pulse = 0: cooldown = 50: level = 0: goto 775

rem cycles through blocks to check if all have been destroyed
temp2 = 0
for temp1 = 0 to 15
if a[temp1] = 2 && lives > 0 then temp2 = temp2 + 1
next

rem if not, then end cycle
if temp2 <> 16 then goto 800

rem if so, then score bonus points for completing stage and continue
if lives = 3 then score = score + 600
if lives = 2 then score = score + 400
if lives = 1 then score = score + 200

rem increment the level counter, but make sure it doesn't go too high
if level < 10 then level = level + 1

rem generates new stage by looping through and inserting new colors taken from data set under COLOR FLICKER
775 

rem different values for different levels
if level = 0 then goto 776
if level = 1 then goto 777 else goto 780

776
rem first level has only red blocks, to teach basic mechanics of firing a ball and rotating blocks
for temp1 = 0 to 15
a[temp1] = blkc[0]
next
goto 799

777
rem second level teaches the differences between the colors and how the right color must go to the right ball
for temp1 = 0 to 15
temp2 = (rand/64)
if temp2 < 2 then a[temp1] = blkc[1] else a[temp1] = blkc[0]
next

goto 799

780
rem third level introduces all three primary colors
for temp1 = 0 to 15
temp2 = rand 
if temp2 < 86 then a[temp1] = blkc[0]
if temp2 > 85 then a[temp1] = blkc[1]
if temp2 > 170 then a[temp1] = blkc[2]
next

799
rem complete reset by giving full lives
 lives = 3

rem end loop
800 
set debug cyclescore
goto draw_loop

heartbreak.bas

heartbreak.bas.bin

Link to comment
Share on other sites

Egh. Tried fiddling with what you offered there, bogax, and while it does make the movement work just fine, the hit detection is completely buggered by the change.

what I posted was just meant to be an example of

what would need to be done, the collision routine

would need to be fixed, I just did't show it.

 

And I still can't figure out what's going wrong here:

I don't think there's anything wrong. Try it with just one color

(don't change flicker) and then with two (let flicker cycle 0-1)

 

the asm I posted for the rotation was bugged, fixed now

 

I'd suggest you keep a count of the remaining blocks that

gets updated when you have a good hit rather than counting

through the blocks to check if there's any left

 

in the flicker code you could pull the color look up out of

the loop

you could also up date flicker in one place

 rem cycle through pfpixels, turning them on if they are equal to the color being drawn
temp3 = blkc[flicker]

for temp5 = 0 to 15
if a[temp5] = temp3 then pfpixel ctbl[temp5] rtbl[temp5] on: temp4 = 1
next
flicker = flicker + 1 & 7
rem determines if a color shows up; if not, don't bother drawing that color and return for the next
if temp4 then COLUPF = temp3 else goto 110

Link to comment
Share on other sites

what I posted was just meant to be an example of

what would need to be done, the collision routine

would need to be fixed, I just did't show it.

I've spent all day wracking by brain over how it can be done. After much frustration and swearing, I give up.

 

If only I knew what "base" was at any given moment, but score = base gives me nothing; score refuses to provide me any hints as to what any value is that I've ever tried. I have no clue why, but it just doesn't work for me. If only I knew what base was, I could see what was going on and figure out a way to compensate for it, but I can't and I'm out of ideas and extremely annoyed.

 

I don't think there's anything wrong. Try it with just one color

(don't change flicker) and then with two (let flicker cycle 0-1)

I did, but it doesn't work. If I lower it to just two possible values, there is still far more flicker than there should be. On the first level, where all the blocks are red, there should be no flicker at all because there is no other color to flicker TO. The code SHOULD be recognizing through the loop that there aren't any blocks of any color besides red and thus skipping drawing any colors besides red, but it just doesn't. I don't know why. I've gone over the code dozens of times and spent between six to eight hours among this and the hit detection stuff, all to no avail whatsoever.

 

the asm I posted for the rotation was bugged, fixed now

If it makes you feel any better, I have zero clue about ASM, so it was all Greek to me, anyway.

 

I'd suggest you keep a count of the remaining blocks that

gets updated when you have a good hit rather than counting

through the blocks to check if there's any left

But unless I know which color of block is remaining, which, unless I have another 16 variables to spend, I have no way to keep a running memory of, then just knowing how many blocks are left doesn't help me. The point of running through the blocks each time is to count how many of each color remains so that the flicker can reduce to only displaying the colors that are actually on the playfield, but it doesn't work. It still flickers through all the other colors, anyway, and I have no clue why.

 

This is probably all a phenomenal waste of time, anyway, because it is highly unlikely that, when/if/hopefully someone writes that new kernel that I've been begging for over the past week or so, it will rely on the current flickering system. So trying to improve that code is pointless until I have some modicum of an idea of how a new kernel could work or what it would require me to do.

 

in the flicker code you could pull the color look up out of

the loop

you could also up date flicker in one place

 rem cycle through pfpixels, turning them on if they are equal to the color being drawn
temp3 = blkc[flicker]

for temp5 = 0 to 15
if a[temp5] = temp3 then pfpixel ctbl[temp5] rtbl[temp5] on: temp4 = 1
next
flicker = flicker + 1 & 7
rem determines if a color shows up; if not, don't bother drawing that color and return for the next
if temp4 then COLUPF = temp3 else goto 110

I tried this suggestion. It really doesn't change anything; it just splits apart what's already being done, more or less. I still get a recurring flicker even on level 0, where each of the blocks is red and the code should recognize that is the case and refrain from any flickering.

 


rem Generated 1/28/2013 1:50:36 PM by Visual bB Version 1.0.0.548
rem **********************************
rem *heartbreak.bin                    *
rem *A re-imagning of breakout with a lonely heart trapped in a void...                   *
rem *Cybearg (aka Nic)                        *
rem *cybearg.plays@gmail.com                 *
rem **********************************


rem ==============
rem INITIALIZATION
rem ==============

rem set up settings/optimization
set optimization speed

rem set up my variables
dim level = s
dim cooldown=t
dim anglevar=u
dim pulse=v
dim flicker=w
dim offset=x
dim ballcolor=y
dim heartcolor=z

rem set offset to a number greater than 0 to allow for "negative" values
offset = 50

rem set heartcolor to begin at red
heartcolor = 64

rem set player 0's location
player0x=80:player0y=48


rem ==========
rem MAIN LOOP
rem ==========

draw_loop

rem clear the playfield
pfclear

rem increment the multi-purpose cooldown variable
cooldown = cooldown + 1

rem mute sound at 7 cooldown cycles or after 20 cycles if there's been a titlescreen restart
if cooldown = 7  || cooldown = 70 then AUDV0 = 0 : AUDV1 = 0


rem ===============
rem BEATING HEART
rem ===============

rem increment pulse counter
pulse = pulse +1

rem cooldown to make sure that player doesn't leave the title screen by firing a ball
if pulse = 45 && cooldown >= 50 then cooldown = 0

rem after 45 cycles, increment color
if pulse = 45 then pulse = 0

rem special occasion for first level
if level = 0 then heartcolor = 64: goto 10

rem special occasion for second level
if level = 1 && heartcolor = 64 && pulse = 0 then heartcolor = 28: goto 10
if level = 1 && heartcolor = 28 && pulse = 0 then heartcolor = 64: goto 10

rem increment the colors
if heartcolor = 28 && pulse = 0 then heartcolor = 148: goto 10
if heartcolor = 64 && pulse = 0 then heartcolor = 28: goto 10
if heartcolor = 148 && pulse = 0 then heartcolor = 64

10

rem set the playfield colors
COLUP0 = heartcolor

rem turn the score red if player is on the last life
if lives = 1 then scorecolor = 64 else scorecolor = 10

rem swap the heart sprite for 5 cycles to create illusion of beating
if pulse < 40 then goto 40 else goto 44

rem values for the up-beat (40 out of 45 cycles)
40 if lives = 0 then goto 80
41 if lives = 1 then goto 70
42 if lives = 2 then goto 60
43 if lives = 3 then goto 50

rem values for the down-beat (5 out of 45 cycles)
44 if lives = 0 then goto 80
45 if lives = 1 then goto 90
46 if lives = 2 then goto 70
47 if lives = 3 then goto 60

rem the various player 0 heart sprites
50 player0:
%00010000
%00111000
%01111100
%11111110
%11111110
%11111110
%01101100
%00000000
end

55 goto 100

60 player0:
%00000000
%00010000
%00111000
%01111100
%01111100
%00101000
%00000000
%00000000
end

65 goto 100

70 player0:
%00000000
%00000000
%00010000
%00111000
%00101000
%00000000
%00000000
%00000000
end

75 goto 100

80 

90 player0:
%00000000
%00000000
%00000000
%00000000
%00000000
%00000000
%00000000
%00000000
end


rem ==============
rem COLOR FLICKER
rem ==============

100

rem if the player has zero lives, skip this part
if lives = 0 then goto 410

rem set up possible colors
data blkc
64, 28, 154, 44, 202, 122, 14, 0
end

rem set up possible pfpixel locations
data ctbl
16, 20, 24, 27, 28, 27, 24, 20, 16, 12, 8, 5, 4, 5, 8, 12
end

data rtbl
0, 0, 1, 3, 5, 7, 9, 10, 10, 10, 9, 7, 5, 3, 1, 0
end

110
rem cycle through pfpixels, turning them on if they are equal to the color being drawn
temp3 = blkc[flicker]

for temp5 = 0 to 15
if a[temp5] = temp3 then pfpixel ctbl[temp5] rtbl[temp5] on: temp4 = 1
next
flicker = flicker + 1 & 7
rem determines if a color shows up; if not, don't bother drawing that color and return for the next
if temp4 then COLUPF = temp3 else goto 110

rem ==================
rem MAIN DRAWSCREEN
rem ==================

rem main drawscreen
drawscreen

rem skip to COLOR MOVEMENT
goto 415


rem =============
rem TITLE SCREEN
rem =============


410

rem set the beat of the title screen heart to the ongoing pulse
if pulse < 40 then goto 413 else goto 412

rem the two possible title screen frames
412

playfield:
................................
...X.X.XXX..X..XX.XXX...........
...X.X.X...X.X.X.X.X............
...XXX.XX..XXX.XX..X............
...X.X.XXX.X.X.X.X.X............
..............................
...........XX..XX..XXX..X..X.X..
....X.X....X.X.X.X.X...X.X.X.X..
....XXX....XX..XX..XX..XXX.XX...
.....X.....X.X.X.X.XXX.X.X.X.X..
...........XXX..................
end

rem skip to color
goto 414

413

playfield:
................................
...X.X.XXX..X..XX.XXX...........
...X.X.X...X.X.X.X.X............
...XXX.XX..XXX.XX..X............
...X.X.XXX.X.X.X.X.X............
................................
...XX.XX...XX..XX..XXX..X..X.X..
..XXXXXXX..X.X.X.X.X...X.X.X.X..
...XXXXX...XX..XX..XX..XXX.XX...
....XXX....X.X.X.X.XXX.X.X.X.X..
.....X.....XXX..................
end

414

rem color the title screen playfield
COLUPF = 64

rem drawscreen for titlescreen only
drawscreen

rem skip everything else and wait for a trigger
goto 760


rem =================
rem COLOR MOVEMENT
rem =================

415

rem NOTE: offset base is 50, so the numbers below determine how sensitive the controls are

rem determine block offset
if joy0left && offset < 56 then offset = offset + 1
if joy0right && offset > 44 then offset = offset - 1


rem adjust block offset
420 if offset > 55 goto 435
if offset < 45 goto 445

rem if no adjustments are necessary, skip this part
goto 500


rem move all block values to the left (counter clockwise)
435  temp2 = a
for temp1 = 0 to 14
a[temp1] = b[temp1]
next
p = temp2
goto 450

rem move all blocks to the right (clockwise)
445 temp2 = p
for temp1 = 15 to 0 step -1
b[temp1] = a[temp1]
next
a = temp2

rem reset the offset

450
offset = 50


rem ============
rem PLAYER FIRE
rem ============

500

rem checks to see that a few cool-down measures are a go, then moves the ball (player 1) to the center of the heart (player 0)
rem cooldown ensures that the player cannot fire while a ball is at play
rem cooldown also ensures the player doesn't exit a title screen by firing a ball prematurely
if joy0fire && lives > 0 && player1x = 0 && player1y = 0 && cooldown < 50 then player1x=80:player1y=48 else goto 600

rem moves the ball's current color from heartcolor (set in the BEATING HEART section) to ballcolor for safe-keeping
ballcolor = heartcolor

rem set player 1's sprite

player1:
%00000000
%00000000
%00000000
%00011000
%00011000
%00000000
%00000000
%00000000
end

rem generate random number to determine ball movement
rem variables ensure that ball speed/angle does not vary once ball has been generated

anglevar = (rand/32)


rem =========
rem THE BALL
rem =========

600

rem skip everything dealing with the ball if it is at its resting position (0,0)
if player1x = 0 && player1y = 0 then goto 800

rem maintain the color of the ball at the moment of firing

COLUP1 = ballcolor

rem all ball movement possibilities
rem allows for ball movement in a direction every 45 degrees

650

rem cooldown is used to manage the speed of the ball
if cooldown > 8 then cooldown = 0

rem x motion table
data xmtbl
50, 51, 51, 51, 50, 49, 49, 49
end

rem y motion table
data ymtbl
51, 51, 50, 49, 49, 49, 50, 51
end

rem separate out cardinal from diagonal directions
if anglevar <> 0 && anglevar <> 2 && anglevar <> 4 && anglevar <> 6 then goto 670 else goto 680

670
rem movements for diagonal directions (45, 125, 225, 315) -- applies a cooldown to ensure that diagonals do not move too fast
if cooldown <> 1 && cooldown <> 3 && cooldown <> 5 && cooldown <> 7 then player1x = player1x + xmtbl[anglevar] - 50: player1y = player1y + ymtbl[anglevar] - 50: goto 700 else goto 700

680
rem movement values for cardinal (0, 90, 180, 270 degrees) directions -- applies a cooldown to ensure that cardinal directions do not move too fast
if cooldown <> 3 && cooldown <> 7 then player1x = player1x + xmtbl[anglevar] - 50
if cooldown <> 3 && cooldown <> 7 then player1y = player1y + ymtbl[anglevar] - 50

rem ====================
rem COLLISION DETECTION
rem === thanks to bogax ===
rem ====================

700

rem check to see if player 1 is out of bounds
if player1x = 25 || player1y = 0 then goto 750
if player1x=133 || player1y = 140 then goto 750

rem minimum collision data locations (x, y)
data btbl
78, 4, 109, 12, 125, 44, 109, 76, 77, 84, 45, 76, 29, 44, 45, 12
end

rem check each of the 8 possible collision locations
for temp4 = 0 to 14 step 2
temp3 = temp4 + 1

rem set up temporary variables to contain the full range of the x and y potentials
temp5 = btbl[temp4] + 4
temp6 = btbl[temp3] + 8

rem if player1x is within the range for the current block and player1y is within the range for the current block, there is a collision
if player1x > btbl[temp4] && player1x < temp5 && player1y > btbl[temp3] && player1y < temp6 then goto 710

rem otherwise, check the next block
next

rem if no collision is detected, skip to the end of the main loop
goto 800

rem check for collision type
710

rem check if the block is already dead
if a[temp4] = 2 then goto 800

rem check ball color against block color
if a[temp4]<>ballcolor then goto bad_hit

rem if the hit is good...
good_hit

rem set current block to dead
a[temp4] = 2

rem increment score
score = score + 25

rem play good hit sound
  AUDV1 = 6
  AUDC1 = 12
  AUDF1 = 19

goto 725

rem if the hit is bad...
bad_hit

rem lose a life
lives = lives - 1

rem play bad hit sound
  AUDV1 = 6
  AUDC1 = 6
  AUDF1 = 16

rem reset sound cooldown counter
725 
if lives > 0 then cooldown = 0 else cooldown = 50: pulse = 0

750

rem reset player 1 location, unlocking player 0 fire
player1x = 0: player1y = 0


rem ==================
rem STAGE GENERATION
rem ==================

760

rem exits title screen and generates a new stage
if joy0fire && lives = 0 && cooldown < 50 then score = 0: pulse = 0: cooldown = 50: level = 0: goto 775

rem cycles through blocks to check if all have been destroyed
temp2 = 0
for temp1 = 0 to 15
if a[temp1] = 2 && lives > 0 then temp2 = temp2 + 1
next

rem if not, then end cycle
if temp2 <> 16 then goto 800

rem if so, then score bonus points for completing stage and continue
if lives = 3 then score = score + 600
if lives = 2 then score = score + 400
if lives = 1 then score = score + 200

rem increment the level counter, but make sure it doesn't go too high
if level < 10 then level = level + 1

rem generates new stage by looping through and inserting new colors taken from data set under COLOR FLICKER
775 

rem different values for different levels
if level = 0 then goto 776
if level = 1 then goto 777 else goto 780

776
rem first level has only red blocks, to teach basic mechanics of firing a ball and rotating blocks
for temp1 = 0 to 15
a[temp1] = blkc[0]
next
goto 799

777
rem second level teaches the differences between the colors and how the right color must go to the right ball
for temp1 = 0 to 15
temp2 = (rand/64)
if temp2 < 2 then a[temp1] = blkc[1] else a[temp1] = blkc[0]
next

goto 799

780
rem third level introduces all three primary colors
for temp1 = 0 to 15
temp2 = rand 
if temp2 < 86 then a[temp1] = blkc[0]
if temp2 > 85 then a[temp1] = blkc[1]
if temp2 > 170 then a[temp1] = blkc[2]
next

799
rem complete reset by giving full lives
 lives = 3

rem end loop
800 
set debug cyclescore
goto draw_loop

 

I'd show you a video, but FRAPS can't capture it right. It's just too messed up.

 

P.S. Sorry if I have a bit of attitude in the above. I'm very, very frustrated by this, particularly since I feel like I'm just spinning my wheels as I wait for someone to make an improved kernel. I don't know how that improved kernel would work, what sort of system flow it would require, or if anyone is even working on it.

heartbreak.bas

heartbreak.bas.bin

Link to comment
Share on other sites

I don't know how that improved kernel would work, what sort of system flow it would require, or if anyone is even working on it.

Alas, with lone developers like Fred Quimby of batariBasic you can't count on improved versions as a matter of course. It's more like an awesome, unexpected gift when something new happens.

 

That being said, programming the 2600 is a challenge because of the limited resources. It's actually one of the reasons people DO code for it. It makes you to think out of the box for solutions. You don't really force a game design INTO the Atari 2600. You discover what it can do and grow the game out from there.

 

* Stagger the blocks so they only use one per row to avoid flicker

* If needed, use some of the sprite/missile/ball objects as "blocks" for extra fake top and bottom playfield pixels.

* player0 should be the heart and missile0 its shot. They share the same color but that is OK

* Don't think about the maths for rotation and other nonsense. Think about the color cycle as frames of animation. In this case pfcolors lists.

* The shot angle can also be thought of as a static list of trajectories easily fitting in DATA statements. Something like anglex[12] angley[12] where each element stores the per pixel velocity of the shot. 12 in this case is the 12th angle a shot can be placed in.

* You can divvy out the 8-bit variables into single bit boolean values. If you use a playfield like in my example a few posts back you only have 13 blocks to worry about. That could fit in 4 variables easy. Just use each bit as a true/false flag for block destruction. OR, you could simply leave a block destroyed when colliding with the shot to save even more space. Let just the colors "rotate".

  • Like 1
Link to comment
Share on other sites

...and since I don't really understand what a[temp1] = a[(temp1+1)&15] does, I can't do much to fix it.

I don't know batari BASIC syntax too, but I think the code has a small bug.

 

Before the loop, you have to store a[temp1] somewhere. And after the loop, you have to write that value to a[(temp1+1)&15]

Link to comment
Share on other sites

I don't know batari BASIC syntax too, but I think the code has a small bug.

 

Before the loop, you have to store a[temp1] somewhere. And after the loop, you have to write that value to a[(temp1+1)&15]

 

Good point. What Thomas is saying is that the code as it stands will "lose" one value in the list.

Consider a 4-element ring buffer (just for ease of explanation)...

 

a[0]<-a[1]

a[1]<-a[2]

a[2]<-a[3]

a[3]<-a[0] WHOOPS! a[0] is already over-written with a[1]

 

So first we need to save a[0] and at the end we put it back in place in a[3].

Otherwise we're losing the first element (or last element) depending on which way we go.

 

Nice catch, Thomas :)

Of course, this problem would go away with the pointer method I suggested.

 

Cheers

A

Link to comment
Share on other sites

So far as I am aware, BASIC, at least bB, can't do pointers, and even if it could, I've only just started learning about pointers in my C class at college, so I don't truly grasp how they work, yet.

 

Anyway, that bug was already accounted for in my original code, as around page 2 I posted that I noticed that colors 15 and 0 always shared the same color, and after a bit of visualizing on paper, I figured the solution of plucking out a[0] and then placing it in a[15] after the loop had completed.

 

I've got so many versions of this game all over the place and I've not really saved it in a long time because none of them are fully functional. While I see the advantage of the new way of doing the color movement, it breaks the hit detection big-time and I'm not sure how to fix it (or maybe just too exhausted with fiddling around with the code to see a solution).

 

And then there's still the constant issue of "this game will not be made if there is not a fix for the flickering." Unless multiple pfpixel colors can be displayed on-screen at once (or some other flicker-free equivalent for the 16 blocks), it hurts the eyes too much to play.

Link to comment
Share on other sites

could you just use collision([whateverobjectyouareusingfortheshot], playfield) and detect WHICH block simply by the direction it was shot in? In other words, when you fire the shot record which of the angles the shot was fired from. When it eventually hits a target (using the traditional collision command) you know it came from that last angle - and thus which block it hit.

Link to comment
Share on other sites

could you just use collision([whateverobjectyouareusingfortheshot], playfield) and detect WHICH block simply by the direction it was shot in? In other words, when you fire the shot record which of the angles the shot was fired from. When it eventually hits a target (using the traditional collision command) you know it came from that last angle - and thus which block it hit.

That's brilliant! Let me fiddle with it and see what I can come up with. Great idea!

Link to comment
Share on other sites

Rather than try and respond to indvidual points

with quotes I'm just going to make some observations

and post this (link to) some code.

 

pointers is what you're doing when you index into

memory with a variable, you just don't get the

extra layers of abstraction in bB (a good thing)

 

I redid the collision code to remove the loop

 

that takes some of the curse off as far as using

an offset (which I call base) into the colors so

I incorporated that. mainly to demonstrate.

 

I changed the collision code it misses at

six o clock I haven't figured out why.

 

I don't think it has an inordinate amount of flicker

for what it's doing but I may be wrong. it goes over

on line count. I don't know how stella deals with that

timing wise. If you look for just one color it's solid,

if you look for two it flickers about like I'd expect

if the screen was blanked half the time (which presumably

it shouldn't be). using one color should take the most

time in the loop and apparently that doesn't mess it

up too badly. So my question is could it be its that

going over it's line budget?

It looks for a color that's being used and only draws

the screen if it finds one. It apparently doesn't

take too long if it just looks for one color and

pfpixels (v) :) the blocks to the screen and does

a drawscreen but if it looks for another color even

without having to draw anything it flickers.

just looking for another color pushes it over.

(hmm occurs to me I didn't check to see how it does

if it looks for two colors but only has to draw one

color block of one color which would be about as fast

as looking for two colors could go)

 

In general it's a good thing to speed things up

especially if you're going over time.

So I might suggest something with out refernce

to a specific problem, eg flicker, that doesn't mean

it wouldn't help the situation.

to that end I incorprated a block count and removed

tha loop for that (and did some other minor stuff)

 

I'm sure there's still plenty of opportunity for

streamling the code.

 

theloon had a couple of interesting suggestions.

in particular I like the idea of keeping track of

which colors you're using instead of searching the

blocks for colors that aren't there.

 

for my self I wonder if it might help to bypass pfpixel

and write the playfield directly.

 

But I don't think anything's going to help enough untill

you have a kernel that can do more than on color per line

and takes the colors from ram

 

edit

crap wrong version I'll have to find it

 

hopefully this is it

http://pastebin.com/3kCzwKJT

Edited by bogax
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...