bogax
-
Content Count
902 -
Joined
-
Last visited
Posts posted by bogax
-
-
I'm not sure what you are trying to achieve (why scroll ?)
you can scroll through the sprite data or you can just point at different data
here's some sprite-pointer-animation stuff
might give you some ideas
-
there's some stuff with tables here
the last one (that notes that it's not very accurate) could be made accurate without too much trouble
I should have done an accurate one and one not so accurate for comparison, but I was in a hurry
I doubt the difference would be obvious
edit: there's also this thread
I know I've seen 6502 CORDIC code but I can't remember where
-
works for me with bB.1.1d.reveng37 and Stella 4.5
-
it looks to me like the multisprite kernel doesn't have the paddle code
there may not be time to do both sprite multiplexing and paddle reading
-
I don't know about VBB but bB its self doesn't have any trouble with
if x = 1 then if b = 4 then score = score + 1
however
if x = 1 && b = 4 then score = score + 1
produces exactly the same code
for a random number between 16..124
you need a random number 0..108 + 16
108 = 12 * 9
rand produces numbers 0..255
and you are limited to numbers 0..255 in a byte
and you'd like to keep as many bits as possible for accuracy
9 is 8 + 1
12 is 1.5 * 8
temp1 = rand & 127 will give you (approximately) 1 * 128
then
temp1 = temp1/2 + temp1 will give you (approximately) 0..192 = 1.5 * 128 = 12 * 16
16 = 2 * 8 so now
temp1 = (temp1/8 + temp1) = ((12 * 16 / + 12 * 16) = 12 * (16 / 8 + 16) = 12 * (1 + * 2 = 12 * 9 * 2 = 108 * 2
so
temp1 = rand & 127 : temp1 = temp1/2 + temp1 : temp1 = (temp1/8 + temp1)/2 + 17
due to starting with 127 instead of 128 (max) and rounding, the numbers will be 17..123
due to the limited accuracy the distribution may not be as nice as you'd like
if you realy want 16..124 then its 127 * 109/127
which would be something like this
temp1 = rand/2 : temp1 = ((((temp1/4 + temp1)/2 + temp1)/4 + temp1)/2 + temp1)/2 + 16
in this case rand/2 gives you essentially the same as rand & 127
you've got redundant if statements eg
if pfscore1 = 0 then AUDV0 = 0
if pfscore1 = 0 then AUDV1 = 0
could be done this way
if pfscore1 = 0 then AUDV0 = 0 : AUDV1 = 0
and doing assignments to the same value consecutively on the same line saves you something
it loads 0 into the accumulator and then stores it to AUDV0, if it's done consecutively on the same line
bB won't load 0 again for the store to AUDV1 since 0 is already in the accumulator. it'll just store to AUDV1
it could also be written like this
if !pfscore1 then AUDV0 = 0 : AUDV1 = 0
which also saves you something. because of the way bB and the processor work it doesn't do an explicit compare to zero
you still didn't show your paddle code
I suspect the scoring is not working the way you'd like
-
at first glance
line 973
temp5 = (_PEEK_Frame_Counter) + 1 : _POKE_Frame_Counter temp5 : on temp5 goto donef1 donef1 f1 f22 f33 f44
unless you're limiting frame counter to 4 somewhere I didn't see yet,
temp5 could go up to 16 and you've only got 6 target labels-
1
-
-
Note- since we only use binary, 65,536 is really 11111111,11111111. So that's 16 1s. We fetch 8 at a time to move the whole number.
.
um, notice one of those is even and one is odd?
-
the sine table is built on the (possibly) spurious theory
that it's good to start with the best accuracy and then
throw away what you don't need
so the sines are 0..255 and which would give you
sines -255..255
the sine function immediately throws some of that away and
returns sines that range 0..255
those values are scaled to fit by multiplying by the
reciprocal of the scale factor
that's what the scl function does
if you just want a different radius that can be baked into
the sine table
dim angle = a.c
dim tangle = temp1
angle = 0
gosub su
loop
temp1 = angle/4
player0x = sinetbl[temp1] + 42
temp1 = (angle - 64)/4
player0y = sinetbl[temp1] + 7
angle = angle + 0.5
COLUP0 = $3A
COLUP1 = $14
drawscreen
goto loop
data sinetbl
38, 42, 45, 49, 53, 56, 59, 62
65, 67, 70, 72, 73, 74, 75, 76
76, 76, 75, 74, 73, 72, 70, 67
65, 62, 59, 56, 53, 49, 45, 42
38, 34, 31, 27, 23, 20, 17, 14
11, 9, 6, 4, 3, 2, 1, 0
0, 0, 1, 2, 3, 4, 6, 9
11, 14, 17, 20, 23, 27, 31, 34
end
su
player0:
%00000000
%00000000
%00011000
%00111100
%00111100
%00011000
%00000000
%00000000
end
player1:
%00111100
%01111110
%11111111
%11111111
%11111111
%11111111
%01111110
%00111100
end
COLUPF = $48
player1x = 80
player1y = 48
return
if you want to vary the radius on the fly probably the easiest way is to
scale the sines to suit
here the sines are scaled using an approximate reciprocal calulated from
the radius
you can vary the radius from 4..40 using joy0 up-down
none of it is very accurate
the sine table is not very accurate
the scl function is not very accurate
and the reciprocal approximation is not very accurate
dim angle = a.c
dim tangle = temp1
angle = 0
gosub su
dim num = temp1
dim mul = temp2
r = 20
loop
f = (SWCHA ^ $FF) & f
if f{4} then r = r + 1 : if r > 40 then r = 4
if f{5} then r = r - 1 : if r < 4 then r = 40
f = SWCHA
temp1 = angle/4
temp1 = sinetbl[temp1]
temp2 = r * 2
temp1 = scl(temp1,temp2)
player0x = temp1 + 80 - r
temp1 = (angle - 64)/4
temp1 = sinetbl[temp1]
temp2 = r * 2
temp1 = scl(temp1,temp2)
player0y = temp1 + 48 - r
angle = angle + 0.5
COLUP0 = $3A
COLUP1 = $14
drawscreen
goto loop
; multiply by .328125 so scales 255 -> 83
function scl
asm
lda #$00
sec
ror mul
loop
bcc shift
adc num
shift
ror
enter
lsr mul
bne loop
rts
end
data sinetbl
127, 139, 151, 163, 175, 186, 197, 207
216, 225, 232, 239, 244, 248, 251, 253
253, 253, 251, 248, 244, 239, 232, 225
216, 207, 197, 186, 175, 163, 151, 139
126, 114, 102, 90, 78, 67, 56, 46
37, 28, 21, 14, 9, 5, 2, 0
0, 0, 2, 5, 9, 14, 21, 28
37, 46, 56, 67, 78, 90, 102, 114
end
su
player0:
%00000000
%00000000
%00011000
%00111100
%00111100
%00011000
%00000000
%00000000
end
player1:
%00111100
%01111110
%11111111
%11111111
%11111111
%11111111
%01111110
%00111100
end
COLUPF = $48
player1x = 80
player1y = 48
return
-
I forgot to mention that in the case of the line segment circle
the table is matched to the number of steps in the circle so if you change the number of steps
the circle changes
it will get larger or smaller and if things don't add up just right it will probably wobble
-
here's one that uses a sine table
dim angle = a.c
dim tangle = temp1
angle = 0
gosub su
loop
temp3 = sine(angle)
temp3 = scl(temp3)
player0x = temp3 + 37
temp3 = angle - 64
temp3 = sine(temp3)
temp3 = scl(temp3)
player0y = temp3 + 7
angle = angle + 1.0
COLUP0 = $3A
COLUP1 = $14
drawscreen
goto loop
; multiply by .328125 so scales 255 -> 83
function scl
asm
lda temp1
lsr
lsr
adc temp1
ror
lsr
adc temp1
ror
lsr
rts
end
function sine
temp2 = tangle
if tangle{6} then temp2 = temp2 ^ %00111111 ; if its an odd quadrant complement the angle in 64 (64 is one quadrant)
temp2 = (temp2 & %00111111) ; scale to index table 0..63 /2 for 32 elements /4 for 16 elements
temp2 = sinetbl[temp2]/2
if tangle{7} then temp2 = 255 - temp2 ; if the angle is greater than 128 then complement the sine in 128
temp2 = temp2 + 128 ; add an offset so the sine is 0..255 no negatives
return
; data sinetbl
; 0, 50, 74, 98, 121, 142, 162, 181
; 198, 213, 226, 237, 245, 251, 255, 255
;end
; data sinetbl
; 0, 25, 37, 50, 62, 74, 86, 98
; 109, 120, 131, 142, 152, 162, 171, 180
; 189, 197, 205, 212, 219, 225, 231, 236
; 240, 244, 247, 250, 252, 254, 255, 255
;end
data sinetbl
0, 13, 19, 25, 31, 38, 44, 50
56, 62, 68, 74, 80, 86, 92, 98
104, 109, 115, 121, 126, 132, 137, 142
147, 152, 157, 162, 167, 172, 177, 181
185, 190, 194, 198, 202, 206, 209, 213
216, 220, 223, 226, 229, 231, 234, 237
238, 241, 243, 245, 247, 248, 250, 251
252, 253, 254, 255, 255, 255, 255, 255
end
su
player0:
%00000000
%00000000
%00011000
%00111100
%00111100
%00011000
%00000000
%00000000
end
player1:
%00111100
%01111110
%11111111
%11111111
%11111111
%11111111
%01111110
%00111100
end
COLUPF = $48
player1x = 80
player1y = 48
return
here's one that uses a smaller sine table to form a circle from a set of line segments
dim angle = a.c
dim tangle = temp1
angle = 0
gosub su
loop
temp3 = sine(angle)
x = x + temp3
player0x = scl(x)
player0x = player0x + 39
temp3 = angle + 64
temp3 = sine(temp3)
y = y + temp3
player0y = scl(y)
player0y = player0y + 6
angle = angle + 1.0
COLUP0 = $3A
COLUP1 = $14
drawscreen
goto loop
; multiply by .328125 so scales 255 -> 83
function scl
asm
lda temp1
lsr
lsr
adc temp1
ror
lsr
adc temp1
ror
lsr
rts
end
function sine
temp2 = tangle & %00111111
if tangle{6} then temp2 = 64 - temp2 ; if its an odd quadrant complement the angle in 64 (64 is one quadrant)
temp2 = (temp2 & %00111111)/8 ; scale to index table 0..63 -> 0..7
temp2 = sinetbl[temp2]
if tangle{7} then temp2 = 0 - temp2 ; if the angle is greater than 128 then negate
temp2 = temp2
return
data sinetbl
0, 1, 1, 2, 2, 3, 3, 3
end
su
player0:
%00000000
%00000000
%00011000
%00111100
%00111100
%00011000
%00000000
%00000000
end
player1:
%00111100
%01111110
%11111111
%11111111
%11111111
%11111111
%01111110
%00111100
end
COLUPF = $48
x = 0 : y = 128 : angle = 0
player1x = 80
player1y = 48
return
here's one that uses a parabolic aproximation of sines-cosines
if you look closely you'll see it's actually sort of elliptical
dim dx = v
dim dy = w
gosub su
loop
c = c + 1
if c & 7 then skip
if x{7} then dx = dx - 1 else dx = dx + 1
x = x + dx
player0x = scl(x)
player0x = player0x + 34
if y{7} then dy = dy - 1 else dy = dy + 1
y = y + dy
player0y = scl(y)
player0y = player0y + 2
skip
COLUP0 = $3A
COLUP1 = $14
drawscreen
goto loop
; multiply by .34375 so scales 247 -> 84
function scl
asm
lda temp1
lsr
adc temp1
ror
lsr
adc temp1
ror
lsr
rts
end
su
player0:
%00000000
%00000000
%00011000
%00111100
%00111100
%00011000
%00000000
%00000000
end
player1:
%00111100
%01111110
%11111111
%11111111
%11111111
%11111111
%01111110
%00111100
end
COLUPF = $48
dx = $0E : x = $7F
dy = $00 : y = $F7
player1x = 80
player1y = 46
return
-
3
-
-
indexes are limited to 8 bits so it's definetely best to limit your tables to 256 bytes
when possible
to that end I wrote a bit of javascript that transposes data so that each column goes into
it's own table
for those instances where you need two levels of indirection and still need to compute an index into a
table of tables so to speak I wouldn't use if statements
it's probably smaller and faster to use a lookup table
if you can't fit your table of tables in to 256 bytes you can still do it with microscopic amounts
of asm
using RevEng's example
if roomIndex=0 then roomNumber=room0Data[level]
if roomIndex=1 then roomNumber=room1Data[level]
if roomIndex=2 then roomNumber=room2Data[level]
I'd do it like this (there may be pathological cases where it would be better to use if statments though)
index = roomOffset[roomIndex] ; room_offset is an LUT for number of rooms x number of levels, zero based
roomNumber = roomData[level]
; so if your room index ranges to 0..14 and there are 10 levels your roomOffset table is
data roomOffset
0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140
end
; and your roomData table will be 150 bytes
if the table is more than 256 bytes it'd be something like this
dim indexLo = temp3
dim indexHi = temp4
def load_indirect = callmcro ldin
; looks up a byte from a 16 bit address, lo byte in temp3 hi byte in temp4
; indexed by the value in the variable specified by the first parameter
; and puts it in to the second parameter variable
macro ldin
asm
ldy {1}
lda (temp3),y
sta {2}
end
end
indexLo = roomOffsetLo[roomIndex] ; roomOffsetLo is a table of the lo bytes of the offset
indexHi = roomOffsetHi[roomIndex] ; roomOffsetHi is a table of the hi bytes of the offset
load_indirect level roomNumber
; "<" signifies the lo byte ">" is the hi byte
; these values/expressions are asm not bB
data roomOffsetLo
<(roomData + 0), <(roomData + 10), <(roomData + 20), <(roomData + 30), <(roomData + 40), <(roomData + 50), <(roomData + 60), <(roomData + 70)
<(roomData + 80), <(roomData + 90), <(roomData + 100), <(roomData + 110), <(roomData + 120), <(roomData + 130), <(roomData + 140)
end
data roomOffsetHi
>(roomData + 0), >(roomData + 10), >(roomData + 20), >(roomData + 30), >(roomData + 40), >(roomData + 50), >(roomData + 60), >(roomData + 70)
>(roomData + 80), >(roomData + 90), >(roomData + 100), >(roomData + 110), >(roomData + 120), >(roomData + 130), >(roomData + 140)
end
you break even somwhere around three or four if statements
it would also be possible to calculate the offsets at run time
and if your offsets are a power of 2 that could be fairly fast
(eg in this case, if the number of levels were a power of 2)
you could also do something in between like group them into
tables <= 256 bytes and use if statements to choose a table-
1
-
-
Hello everyone,
I'm trying to finalize a game with the DPC+ kernel. It's got a procedurally generated playfield (among other things), which means I need to call drawscreen a lot to prevent the screen from rolling. To minimize code space, I set up a gosub that looks like this:
screenrefresh DF6FRACINC = 32 DF4FRACINC = 32 DF0FRACINC = 16 DF1FRACINC = 16 DF2FRACINC = 16 DF3FRACINC = 16 drawscreen return
This code works perfectly as a gosub in Stella. But when I put it on my Harmony cart, the game crashes once its reaches it. I'm baffled by the difference. I really, really need this code to work as I'm down to < 100 bytes in each of my banks (many are < 30), and according to my tests, each new drawscreen call takes up 24 bytes. I know I could instead do this with a labyrinthine system of gotos, but that won't be as efficient as I need it to be, either.
I'd really appreciate any advice. Thanks.
I don't know if this would work given the problem you're having
but you don't need a labyrinthine system of gotos
you'd put a single instance of the screenrefresh routine in some bank and return otherbank
then in each bank you'd put a single goto screenrefresh bankx
then when you want to refresh you'd gosub to the goto
edit
I don't know how it works with DPC+
if you're just bank switching and if you're in
the appropriate bank you can use
asm
jsr drawscreen
end
and save the bank switch for the drawscreen
at least that works in stella
-
1
-
-
Again I'm no expert but I think that's not going to work with DPC+
Thats for a different sort of RAM expansion
I think what you want is here
I think iesposta is correct
I think it should be possible to poke the player colors
edit OK maybe not
at least I haven't been able to get it to work
(I thought maybe you could point the player color pointers at the stack)
-
1
-
-
Aha! Now, this is something that I'm pretty sure I understand. I've been wondering how to use tables and it appears that it is easier than I thought... kind of like a 1d (read only?) array... that can be used with multiple objects.
Thanks!!! Now, I just need to put it to use.

Yes but it's read only only because it's in ROM
the variables are in sequence in memory so
a[0] = 3
a[1] = 4
sets a to 3 and b to 4
-
Here is something similar in bB with the tables
the tables have redundancies and symmetries that could be exploited to make them
smaller but it would be slower
I should have mentioned that this assumes that directions is limited to 0..31
dim tmp88 = temp4.temp3
if !joy0up then skip
temp3 = Vx_lo[direction] : temp4 = Vx_hi[direction] : xVel = xVel + tmp88
temp3 = Vy_lo[direction] : temp4 = Vy_hi[direction] : yVel = yVel + tmp88
skip
data Vx_lo
8, 7, 6, 5, 4, 3, 2, 1
248, 255, 254, 253, 252, 251, 250, 249
248, 249, 250, 251, 252, 253, 254, 255
8, 1, 2, 3, 4, 5, 6, 7
end
data Vx_hi
0, 0, 0, 0, 0, 0, 0, 0
255, 255, 255, 255, 255, 255, 255, 255
255, 255, 255, 255, 255, 255, 255, 255
0, 0, 0, 0, 0, 0, 0, 0
end
data Vy_lo
0, 255, 254, 253, 252, 251, 250, 249
0, 249, 250, 251, 252, 253, 254, 255
0, 1, 2, 3, 4, 5, 6, 7
0, 7, 6, 5, 4, 3, 2, 1
end
data Vy_hi
0, 255, 255, 255, 255, 255, 255, 255
0, 255, 255, 255, 255, 255, 255, 255
0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0
end
I may have gotten the tables right
edit: oops nope
(fixed now)
(I hope
)
-
first you consolidate the redundant predicates
then use a lookup table
here's a macro to lookup 8.8 values
you'll have to figure out the table(s) yourself
untested but it should give you the idea
dim tmp88 = temp4.temp3
; lookup an 8.8 constant from a table
; the table is in two data statements one for hi bytes and one for lo bytes
; takes three parameters
; a variable to take the looked up value it must be in consecutive locations
; eg variable a for the lo byte and b for the hi byte b.a or temp4.temp3 etc
; an 8 bit index
; the name of the table if the name supplied is "table" then the data statements
; must be named tablelo, tablehi
macro lu88
asm
ldx {2}
lda {3}lo,x
sta {1}-1
lda {3}hi,x
sta {1}
end
end
if joy0up then callmacro lu88 tmp88 direction Vx_table : xVel = xVel + tmp88 : callmacro lu88 tmp88 direction Vy_table : yVel = yVel + tmp88
-
1
-
-
Wow, that's way over my head. It's good information to have for later when I understand this stuff more. Thanks!
Is there a simple example of a routine that passed a pointer from a variable? I have looked around on the interwebz, but I don't really get the pointer stuff yet.
a pointer is a location in memory that contains the location (memory address) of something else
I suppose by that definition a pointer could be a constant but they're always variables
technically I misspoke I should have said that it passes a reference since I was talking about the value the pointer would contain
(which in this case would be the address of the playercolor table)
-
I'm not all that familiar with the DPC+ kernel
It looks to me like it just passes a pointer to the color table to the ARM code.
so short of modifying the kernel
you could have a routine that passed a pointer from a variable, but the colors themselves would
have to be in a ROM table and they'd have to be in the graphics bank and I think the only
way to get them there is with a player color statement
it might be possible to have all the colors in one big playercolor statement though
-
1
-
-
draw a line then poke a hole in it
-
functions are pretty much useless (or worse) in bB
about the only thing you can do is assign it to a variable
use a subroutine
you don't need (or want) an end statement, just return
whatever is in the accumulator is what the functiion returns
a function always passes two values and puts them in temp1 and temp2
whether you supply parameters or not
function dummy
b = 3
return
c = dummy()
c contains 3
function void
return
l = 5
d = void()
temp1 and d contain 5
-
1
-
-
On a sidenote, I can't figure out how to limit the firebutton properly so the players can't hold them down?
Assuming you mean you want something to happen once when the fire button is pressed and not
happen again until the fire but is (released and) pressed again
check the state of the fire button and if it wasn't pressed last time and is pressed this time
do whatever
save the current state for the next check
something like
if joy0fire && previous_state = 0 then do_something = 1 previous_state = 0 if joy0fire then previous_state = 1 if do_something then go_do_it ; or temp1 = previous_state previous_state = 0 if joy0fire then previous_state = 1 if temp1 = 0 && previous_state = 1 then go_do_something
-
I don't quite follow you so maybe I'm missing something
why don't you just do something like
schnooga=0
for temp1=0 to 17
if shnooga = 2 then skip_schnooga
if ooga-2=booga[temp1] then schnooga=1
if ooga-1=booga[temp1] then schnooga=2
skip_schnooga
next
you can do somthing like modulo for powers of 2 in binary using AND (ie "&" in bB)
15 mod 8 is
15 & 7
7 being 8 - 1
in binary %00001000 (8 ) and %00000111 (7)
bB does a bitwise AND
bits in the result are the ANDing of corresponding bits in the operands
AND is
0 AND 0 = 0
0 AND 1 = 0
1 AND 0 = 0
1 AND 1 = 1
%00001111 (15)
& %00000111 (7)
= %00000111 (7)
%00001110 (14)
& %00001101 (13)
= %00001100 (12)
the player 1..9 variables are in order in memory
so you should be able to eg address player3x as player1x[2]
but I haven't tryed it
-
room_shape[room]
is in ROM, you can't add 1 to it
-
I wrote a short routine to test it and apparently rand16 never returns 0
dim rand16 = aux1 scorecolor = $1E COLUPF = $76 for i = 0 to 255 for j = 0 to 255 if rand = 0 then score = score + 1 if !(j & $3F) then drawscreen next score = score + 1000 next scorecolor = $3A loop drawscreen goto loop
Heck! Darn! (other obscenities as required)
After actually thinking about it for two seconds it occured to me that, since rand16 goes through every number 1..65535,
0 must come up(since there are certainly combinations of bytes that will produce a 0 when XORed).
use rand in an if statement and it just tests the rand variable, it doesn't actually call the rand routine
dim rand16 = aux1 scorecolor = $1E COLUPF = $76 for i = 0 to 255 for j = 0 to 255 temp1 = rand if temp1 = 0 then score = score + 1 if !(j & $1F) then drawscreen next score = score + 1000 next scorecolor = $3A loop drawscreen goto loop

Editing GRP0 into player0
in batari Basic
Posted
yes
you want to scroll one part of the sprite while the other stays (more or less) constant
the obvious thing is to use two sprites if you can
you could flicker the a single sprite ie multiplex the sprite in bB, display the two parts seperately on alternate frames
you could put the sprite in ram
not sure you could find 40 bytes
you wouldn't have room for much else
I can't think of any other way to do it with the standard kernel