bogax
-
Content Count
902 -
Joined
-
Last visited
Posts posted by bogax
-
-
Can anyone offer a suggestion why the above would cause collisions to be mirrored on the x axis?anglevar and the colors are different
Look at how I did it
-
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 doesa 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
-
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
-
since I don't really understand what a[temp1] = a[(temp1+1)&15] doesin 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
-
it appears that bB sometimes treats random as a call
to randomize ie the same as rand
I suggest you change random to something else, probably
something that doesn't start with rand and see what that
does for you.
-
1
-
-
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
-
I'm not sure I understand the points about:
move_nothing0 player0x = (player0x - 1) if player0x = 0 || player0x > 240 then gosub change_object0 return
..because your before and after look the same to me.
yours is gosub, use goto (since you're going to return right away
any way) that way you save a return
Also, how are the gosubs bankswitched? They should all be in the same bank. Is the bB assembly using complicated gosub code used for multi-bank jumps?
if you've got multiple banks and you don't tell bB you're returning to
the same bank bB assumes you might be returning to a different
bank and checks and that takes more time. (if you want to gosub to
a different bank I think you have to explicitly specify or else bB
assumes it's the same bank)
philosophical statement:
there's nothing wrong with gotos just don't abuse them
-
2
-
-
I didn't really try to understand your code.
I can see things that might possibly speed things up
(I didn't try to figure out if they actually would
or if it would be enough to bother)
for one thing
draw_shieldsp0 if shieldsp0 < 32 then pfscore1 = %10000000 : return if shieldsp0 < 64 then pfscore1 = %11000000 : return if shieldsp0 < 96 then pfscore1 = %11100000 : return if shieldsp0 < 128 then pfscore1 = %11110000 : return if shieldsp0 < 160 then pfscore1 = %11111000 : return if shieldsp0 < 192 then pfscore1 = %11111100 : return if shieldsp0 < 224 then pfscore1 = %11111110 : return if shieldsp0 < 255 then pfscore1 = %11111111 return
could be rewritten as
temp1 = shieldsp0 / 4 / 8 : pfscore1 = sh0tbl[temp1] : return data sh0tbl %10000000, %11000000, %11100000, %11110000, %11111000, %11111100, %11111110, %11111111 end
you've got a number of tail calls that could be optimized eg
move_nothing0 player0x = (player0x - 1) if player0x = 0 || player0x > 240 then gosub change_object0 return
could be
move_nothing0 player0x = (player0x - 1) if player0x = 0 || player0x > 240 then goto change_object0 return
and if I'm reading right
change_object0 player0x = view_width player0y = (random&63) + 1 tempvar = (random&3) + 1 if tempvar > 3 then temp5 = 3 if tempvar = obj_nothing then gosub create_nothing0 if tempvar = obj_4bunnies then gosub create_4bunnies0 if tempvar = obj_comet then gosub create_comet0 return
could be
change_object0 player0x = view_width player0y = (random&63) + 1 tempvar = (random&3) + 1 if tempvar > 3 then temp5 = 3 on tempvar goto RET create_nothing0 create_4bunnies0 create_comet0 RET return
This is just for illustration.
like I used temp1 without regard to whether you were
already using it (if you are you'll have to figure
something else out obviously)
or like you shouldn't need RET, tempvar should vary 0-2
edit:
I see you're doing a lot of bankswitched returns.
it'd probably help a lot if you knocked that off
if you don't/can't then an on..goto that only has two
targets and allows a tail call optimization is probably
faster
-
2
-
-
only problem I had was line 25 of the .bas file
doesn't like the condition expression
changed it to
temp1 = frame & 3
if temp1 = 0 then colorindex = colorindex+1
-
I meant in the context of memory. The 2600 and its cartridges have very limited space, which is why we only get 26 variables, each of which can hold a single byte. How do we also get as many 256-byte data sets as we want? Where is that information stored? It must go into some area of the RAM that isn't available for normal processes, eh?
not in ram, in rom with the code, which is why either the code has to
jump around it or you have to put it out of the way of the code.
and it's read only.
-
the data statements go where ever you put them and the codeWhere is this being stored, out of curiosity?
jumps around them.
there's a compiler optimization, noinlinedata, which I believe just
tells the compiler not to generate the jumps so you have to put
the data statements where code won't run in to them.
-
Now if only I could simplify my big lists of pfpixel coordinates with a data set. Is that possible? Such as pfpixel [temp1]?
it'd help if you posted what you've got now so we
can see where you are.
is it secret?
this is meant to be a more compact version
of what you posted before
untested etc.
for i = 0 to 15 pfclear : pfpixel ctbl[i] rtbl[i] on : COLUPF = a[i] : drawscreen next data ctbl 16, 20, 24, 27, 28, 27, 24, 2, 18, 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
Your suggestion cut my ROM size from about 170 bytes to 734 bytes. I'd love to do THAT again!By the way, how many data sets am I allowed? Or is it just as many as I like, so long as they don't total over 256 bytes?
right
edit as many data statments as you want up to 256 bytes EACH
-
I've been meaning to post an example of this for a while. It shows how to use your own custom assembly display kernel in bB.
Now make it roll the other way (horizontaly)

-
use the asm statementWhat do I need to do to call ASM in bB? Do you know?
p = p ^ 1
in asm
asm lda p eor #$01 sta p end
-
So you would compile the game with some inline assembly in the other bank. At this point the game would still be using the old BB kernel, and flicker. You then have to manually edit the rom with a hex editor (like HOM3) to get the game to bankswitch instead of running the BB kernel. Once inside the new bank the assembly logic would decide if the title screen is being drawn. If it is then a jump and bank switch would occur to go back to the BB kernel. Otherwise the assembly kernel would draw. Finally after the assembly kernel a jump and bankswitch occurs to go back to the BB side, and hand off control.
I know that sounds like a lot, but for an experienced assembly programmer it's not to bad. Since you would be starting out with assembly this might be a little bit too much to ask. You will probably need help to do it, but the plan of attack is there.
Once the game is finalized (and you compile the assembly in) then there should only have to be a few bytes that need patching if you make changes (I.e. to perform a bankswitch in 1 place, maybe 3 bytes total). Everytime you make a new rom you would have to patch that area, and hopefully that area never changes. The idea and key here is that there is only a small area to patch to get the game working, making the work as little as possible.
With the standard caveat IAFFAE (I am far from an expert)
I don't think it would take all that.
you might be able to do it with the normal bB far call
(what ever it's called in bB) but if not I think you'd just have to
have a few bytes of ASM to replace the normal drawscreen
statement.
that is to say you'd have your custom kernel in it's own bank
and go to it instead of the bB kernel using the normal (more or less)
bB facilities I don't think you'd have to go in and patch stuff
(and even if you did you could do it in the ASM listing I expect)
might have trouble with conflicting labels I don't know how that's
handled in bB (ie can you create name spaces on a per bank
basis, can labels be the same if they're in different banks or
will that confuse the assembler)
-
I worry that the back and forth animation to make this possible with be almost as sickening to the player as the flicker itself.
yeah that's why I said it still doesn't look very good.
interestingly I can see it as either two alternating patterns that jump
back and forth with out regard to the colors or as rotating colored
blocks
I don't know how common that would be but it might take some
practice/concentration for some people to see it correctly.
-
Another fix is to make sure your latest pfcolors choice is used every time before drawscreen:
www.randomterrain.com/atari-2600-memories-batari-basic-commands.html#kernop_pfcolors
excellent.
that fixed mine so here it is.
still doesn't look very good to me.
I also wrote a javascript to write out the pfcolors statements
if anybody has a mind to play with it
-
I've gone through and optimized the code as much as I can, squeezing out a total of 183 Bytes that have not yet been used. If this kernel thing works to handle the flicker, that can be upped to about 710 bytes, as a good chunk is spent in the flicker code.
obviously this is untested but it compiles.
I may well have goofed something up.
I rewrote the collision code you posted to get rid of those
redundant if-then statements (and then stuck a couple of
my own in)
if playerx1<50 || playerx1 > 133 then goto skip_collision_test if playery1<9 || playery1 > 94 then goto skip_collision_test for i = 0 to 14 step 2 if a[i] then goto collision_test nexti next skip_collision_test if player1x = 0 || player1y = 0 then goto 750 if player1x=156 || player1y = 140 then goto 750 collision_test temp1 = playerx1-xtbl[i]&127 if temp1>3 then goto nexti temp1 = playery1-ytbl[i]&127 if temp1>5 then goto nexti if a[i]<>ballcolor then goto bad_hit rem good_hit a[i]=0 bad_hit 750 data xtbl 81, 00, 114, 00, 130, 00, 114, 00, 82, 00, 50, 00, 34, 00, 50 end data ytbl 9, 00, 17, 00, 49, 00, 81, 00, 89, 00, 81, 00, 49, 00, 17 end
edit: goofed the datastaments up (now fixed I hope)
should probably interleave the x and y values but
this is just ment as illustration so I didn't bother to
obfuscate
edit somemore
more goofs
-
With 128 bytes of RAM on the 2600 you'd have a hard time to use it as a stack, compiler temporary storage, software parameter stack and your own program variables all at the same time. I suspect that for any non trivial program you'd spend most of your time looking at the assembly language produced by your "C" code to see what it was doing to the extent that you might as well have written it in assembler in the first place
.I think I disagree.
bB does all those things and would probably benefit from a data stack.
I think the problem is the overhead involved in implementing one on a
processor not built for it. And I think that's more a problem of speed
than of space.
-
I haven't looked at your game code yet.
Just to be clear, I'm not saying it's impossible.
I'm saying it's not possible the way you're trying to do
it because the flicker is built in. There's no way to
go fast enough if you have to wait on drawscreen.
And you have to wait on drawscreen to get a box on a
particular line drawn before you change the color for
a different box on the same line. Also since you're
identifying colors with objects you either have to have
the objects the same colors, or wait on drawscreen and
waiting will give you flicker.
If you use a multicolor playfield you're restricted to
11 colors and the colors are per line and since the
objects move in opposite directions relative to the lines
there's probably no practical way to make it work if you
need to have more than one object per line.
So with a limit of 11 colors, one per line and objects
identified with colors, and one object per line so the
colors/positions/objects don't interact in impossible to
implement ways, you're limited to 11 objects each on a
different line.
That may be possible although it might not look as pretty
as hoped. The problem is the pfcolors are normally taken
from tables in rom so you either have to have all
possibilities in rom (probably an impossibly large number)
or coax the kernel to get the playfield color data from
ram where you can manipulate it.
That sounds like an intersting possibility/problem and I
think I'll try and make it work.
But as I said before I'm no expert, I don't know what more
advanced options may be available and I have (almost) no idea
what you can do with DPC+
Don't give up. If you give up you'll never figure it out.
-
However if you're only doing two colors per line, perhapsyou could alternate colors every other drawscreen without
the flicker being too bad. It might be tricky getting it
fast enough. Since your pfpixels are fixed you might
do a playfield statement, change the colors as fast as
possible (and drawscreen) then do a different playfield
statement etc.
I tried it.
It looks like crap, in stella at least.
set kernel_options pfcolors LOOP pfcolors: $90 $90 $90 $90 $90 $40 $40 $40 $40 $40 $40 $40 end playfield: ...X............X........X..... ...X............X........X..... ...X............X........X..... ...X............X........X..... ...X............X........X..... ...X............X........X..... ...X............X........X..... ...X............X........X..... ...X............X........X..... ...X............X........X..... ...X............X........X..... end drawscreen pfcolors: $40 $40 $40 $40 $40 $90 $90 $90 $90 $90 $90 $90 end playfield: ....X............X........X.... ....X............X........X.... ....X............X........X.... ....X............X........X.... ....X............X........X.... ....X............X........X.... ....X............X........X.... ....X............X........X.... ....X............X........X.... ....X............X........X.... ....X............X........X.... end drawscreen goto LOOP
-
I'm no expert
I'm not really sure what you're trying to do
and it may not be possible to do it fast enough
in bB. It may not be possible in ASM.
But I'm guessing that its absolutely impossible
the way you're doing it.
I think drawscreen waits for the next time the
screen needs to be drawn (60 times a second)
and draws it. Since you clear the playfield then
set one pixel and call drawscreen you're only going
to get one (playfield) pixel each time the playfield
is drawn and since you immediately do it again,
it will only last a 1/60 second (except for the last
pixel).
You never say what exactly the problem is you are
having with for-next loops. For-next loops have to be
short. However you can jump out (goto) and come back
(or you could gosub, takes longer).
If that's a problem you're having and since you
probably ought to replace those long strings of
if statements with on..goto statements you could jump
out and back without it costing much (since you'd be
jumping any way).
But there's nothing magic about for-next loops.
It may even be possible to do a faster loop with an if
statement (if you're careful how you structure it, but
I'm not sure about that, and a for-next loop is probably
faster generally).
As I said I'm no expert, but I think the closest you can
get to what (I think) you want in bB is one color per line.
Setting pixels on the fly won't get you more colors with out
the flicker so you should probably give up doing the individual
pixels on the fly and just change the colors.
However if you're only doing two colors per line, perhaps
you could alternate colors every other drawscreen without
the flicker being too bad. It might be tricky getting it
fast enough. Since your pfpixels are fixed you might
do a playfield statement, change the colors as fast as
possible (and drawscreen) then do a different playfield
statement etc.
if you:
dim temp = a
then temp, a, and a[0] (and temp[0]) are all ways
of refering to the same location.
You randomize a (a[temp1] while temp1 = 0) in the
for loop then set it to 0 (temp = 0)
To speed things up you could use on..goto statements, compute
instead of select (as in scaling rand), use look up tables
where appropriate (which may not be faster in and of itself
but could allow you to use faster code)
I don't quite get your randomization of the colors
this time.
They're not equally spaced nor is the spacing a power
of two, so this is not the same as yours.
for temp = 0 to 15 temp2 = rand / 4 / 8 a[temp1] = color_tbl[temp2] next data color_tbl 64, 128, 148, 46, 214, 100, 14, 0 end
It may be possible to speed things up by manipulating
things directly from bB instead of calling the routines
to do it but that would require digging into the kernel
and figuring out what to manipulate.
None of that code is tested but it compiles
-
Memory is addressable
dim one = a dim two = b dim three = c dim four = d dim five = e dim six = f dim seven = h dim eight = i dim nine = j dim ten = k dim eleven = l dim twelve = m dim thirteen = n dim fourteen = o dim fifteen = p dim sixteen = q rem random ranges 0-255 rem scale rand to a range of 0-3 rem by dividing by 64 rem division by 2, 4 or 8 rem is optimized to shifts rem the variables are in order in memory for temp = 0 to 15 one[temp] = rand / 8 / 8 + 1 next
bit ops can't use variables for indexing
I think you'll have to do something like this
rem set a bit var = var | setbits[index] rem clear a bit var = var & clearbits[index] data setbits %00000001, %00000010, %00000100, %00001000 %00010000, %00100000, %01000000, %10000000 end data clearbits %11111110, %11111101, %11111011, %11110111 %11101111, %11011111, %10111111, %01111111 end
That could be built into a subroutine or a macro
And it should be possible to def a substitution
for eg the callmacro statement so you could just
invoke it like "setb var index" but I can seldom get
that to work.
Also the kernel already contains the setbits and
clearbits data but I think where it is depends on
the kernel options.
edit goofed the random color (now fixed)
I guess there's no easy way to build the bit ops
into a macro
-
Here's a more optimized one I developed:
;14 bytes, 24 cycles sta tempOne lsr adc #4 lsr lsr lsr adc tempOne ror lsr lsr lsr
Excellent! I 'd forgotten all about that.
I'm curious, how you derived that.
Did you have some sort of sytematic approach
or was it just sort of by guess and by golly.
(I never did figure out how to make /5 work
past 179 using a similar adjustment)
Ought compile a list of such routines somewhere.
Maybe bump the divide by seven thread.

Questions Galore!
in batari Basic
Posted · Edited by bogax
my code:
for yours it could be
force of habit, it doesn't seem that way to me
but probably binary is clearer
edit
I see I mucked up some of the numbers again (fixed)
(and is why the collision detection was failing)