Jump to content
IGNORED

bB Tricks Thread


Gemintronic

Recommended Posts

Basically, if you've come up with a novel technique for code ease, speed, size or economy of variables post it here. Examples are worth a thousand words.

 

Oh, and don't be shy of posting on techniques at are only SLIGHTLY different. Every viewpoint or take on a problem counts.

 

My first try?

 

TheLoon Tip #1 (EASE OF CODING) - Constants for colors.

 

Not everyone remembers $0E is white. Using constants to pick colors can be easier than constantly flipping through VisualbBs chart. Also, it lends greater readability to your fellow coders should they peruse your code. A further use would be to have a comparable set of constants for both NTCS and PAL. Choosing between regions would be as easy as removing the color set for the opposite standard.

 

Here are my colors:

 rem My 25 standard colors for NTSC
const _brown = $F2
const _pink = $3C
const _skyblue = $98
const _olive = $E4
const _lilac = $7A
const _aqua = $B8
const _orange = $38
const _blue = $86
const _red = $46
const _purple = $64
const _lime = $DA
const _gold = $2E
const _navy = $84
const _green = $C6
const _maroon = $42
const _yellow = $1E
const _fuchsia = $58
const _cyan = $A6
const _white = $0E
const _ltgray = $0C
const _silver = $0A
const _gray = $08
const _dkgray = $02
const _black = $00
const _tan = $FC
const _forestgreen = $D2

  • Like 3
Link to comment
Share on other sites

For me, trying to remember something like _lilac is harder than just selecting a color from either Visual batari Basic's color chart or from one of these color charts:

 

www.randomterrain.com/atari-2600-memories-batari-basic-commands.html#colorchart

 

www.randomterrain.com/atari-2600-memories-tia-color-charts.html#ntsc_color_tool

 

 

This isn't exactly a trick, but I start variable aliases with one underscore and labels with two underscores. Then I don't have to worry if I'm using a keyword by mistake and I don't have to worry if a label has the same name as a variable alias.

  • Like 1
Link to comment
Share on other sites

@R.T. I like your style. If we're gonna comment on the tips we may as well try to add one of our own at the same time. The topic would get pretty dirty fast if we all called out the lunacy of my techniques :)

 

TheLoon Tip #2 (ECONOMY OF VARIABLES) - Boolean and tender

 

Variables are very scarce in bB. If something is either one state or another then you can use single bits out of a variable to store that state. making boolean variables is a two step process. First, we must use up a variable:

 

dim boolean = a

 

THEN we use defines to cut up our one variable into up to 8 true/false variables. The {0} through {7} part marks which bit in variable a to use.

 

def enemydir=boolean{0}

def canshoot=boolean{1}

def scrolling=boolean{2}

def heatseeking=boolean{3}

def youwon=boolean{4}

etc..

 

The one variable a was defined multiple times in different bit-wise places to give us up to 8 different boolean variables!

 

Remember: you must make your if .. then statements slightly different when using bitwise values. They look more like this:

 

rem If scrolling (boolean{2}) equals 1 (true) then scroll down.

if scrolling then pfscroll down

 

Notice we didn't say if scrolling = 1? We CAN, however declare scrolling = 1 to indicate scrolling should be true and scrolling = 0 for false. IF .. THEN statements just can't handle it the = 0/1 way. Another gotcha is that we cannot use constants for bitwise statements. So if scrolling = _false is out of the question (if _false is defined as a constant)

  • Like 1
Link to comment
Share on other sites

Nice topic, theloon!

 

RevEng Tip #1 - organising a large multi-bank game

 

When I'm working on a large multi-bank game, I add descriptions of what each bank does to the bB compile messages. It allows me to see at a glance which part of the program is getting tight on space, and allows me to quickly jump to the right bit of code I want by searching for the bank.

 

Here's an example of the description for the first bank in 21 Blue...

 

 asm
 echo " "
 echo "****** Starting a new pass..."
 echo " "
 echo "BANK 1: main game loop."
end

 

...and the sample output from compiling 21 Blue...

 

****** Starting a new pass...

BANK 1: main game loop.
106 bytes of ROM space left in bank 1

BANK 2: girl data, game+minigame vblank code. (soundfx, score adjust)
51 bytes of ROM space left in bank 2

BANK 3: girl data, titlescreen basic code.
112 bytes of ROM space left in bank 3

BANK 4: girl data, player/dealer hand score updater, draw boss-dealer.
18 bytes of ROM space left in bank 4

BANK 5: girl data, main blakjuko code.
62 bytes of ROM space left in bank 5

BANK 6: titlescreen kernel.
20 bytes of ROM space left in bank 6

BANK 7: kernel to draw chat, cards, etc.
148 bytes of ROM space left in bank 7

BANK 8: girl data, blakjuko utility routines, atarivox routines.
54 bytes of ROM space left in bank 8
Build complete.

  • Like 1
Link to comment
Share on other sites

I ran into all kinds of weird, pull your hair out, suicide-inducing problems when using def in a very large program, so I gave up and use dim instead. Here's an example:

 

  rem  ****************************************************************
  rem  *
  rem  *  Create aliases for variables.
  rem  *
  rem  ****************************************************************
  rem  `
  rem  `  (You can have more than one alias for each variable.)
  rem  `
  rem  ````````````````````````````````````````````````````````````````
  rem  `  BitOp group 01.
  rem  `
  dim _BitOp_Group_01 = i


  rem  ````````````````````````````````````````````````````````````````
  rem  `  Tells program when to flip the playfield colors.
  rem  `
  dim _Bit0_Color_Flip = i


  rem  ````````````````````````````````````````````````````````````````
  rem  `  Keeps collision detection from registering more than once.
  rem  `
  dim _Bit1_Player_Hit_Wall = i


  rem  ````````````````````````````````````````````````````````````````
  rem  `  Turns the bonus item on or off.
  rem  `
  dim _Bit2_Bonus_On_Off = i


  rem  ````````````````````````````````````````````````````````````````
  rem  `  Channel 0 sound effects (group 1).
  rem  `
  dim _BitOp_Sound_Ch_0_Group_01 = j


  rem  ````````````````````````````````````````````````````````````````
  rem  `  Player hit wall sound effect.
  rem  `
  dim _Bit0_Sound_Wall_Hit = j


  rem  ````````````````````````````````````````````````````````````````
  rem  `  Channel 01 sound effects (group 1).
  rem  `
  dim _BitOp_Sound_Ch_1_Group_01 = k


  rem  ````````````````````````````````````````````````````````````````
  rem  `  Bonus item appearance sound effect.
  rem  `
  dim _Bit0_Sound_Bonus_Appear = k

 

 

Here's a small example in use:

 

  if _Bit0_Sound_Wall_Hit{0} then goto __Sound_Effect_Wall_Hit

 

 

 

Here's a tip for this thread. Instead of underlining title text, which usually means link on the internet, use larger, bold text.

 

So instead of this:

 

TheLoon Tip #3 (SPEED) - Eventually, everyone's survival rate falls to 0

 

You'd use this:

 

TheLoon Tip #3 (SPEED) - Eventually, everyone's survival rate falls to 0

 

Or this:

 

TheLoon Tip #3 (SPEED) - Eventually, everyone's survival rate falls to 0

 

Or this:

 

TheLoon Tip #3 (SPEED) - Eventually, everyone's survival rate falls to 0

Link to comment
Share on other sites

TheLoon Tip #3 (SPEED) - Eventually, everyone's survival rate falls to 0

 

According to R.T.s guide some variables get cleared after each DRAWSCREEN. We can actually use that expectation to simplfy and speed up our code.

 

For instance, if we assume a variable is used up as a counter (dim counter = a) and an alarm for an animation is defined as such (def march = counter{4}) we can do this:

 

if march then REFP0 = 8 : REFP1 = 8

 

So, every time the forth bit of counter gets set to 1 we change the reflection flag on player0 and player1. When march is 0 (false) DRAWSCREEN already makes the reflection = 0 for both sprites without us doing any more code ourselves.

Link to comment
Share on other sites

RevEng Tip #2 - display how much rom a section of code uses

 

Putting a couple of labels around the section of code and a single line of asm will allow you to see how many bytes the routine takes.

 

 rem ** checking how much space a particular bit of code uses

 player0:
 %11111111
 %11111111
 %11111111
 %11111111
end

 player0x=80
 player0y=40

mainloop
 COLUP0=$98
 drawscreen

control
 if joy0left then player0x=player0x-1
 if joy0right then player0x=player0x+1
 if joy0up then player0y=player0y-1
 if joy0down then player0y=player0y+1
controlend

 goto mainloop

 asm
 echo "DEBUG: the joystick control uses ",(.controlend-.control)d," bytes."
end

 

Here's the compilation output...

 

Starting build of scratch.bas
batari Basic v1.01 (C)2005-2007
2600 Basic compilation complete.
DEBUG: the joystick control uses 32 bytes.
bytes of ROM space left
DEBUG: the joystick control uses 32 bytes.
2809 bytes of ROM space left
Build complete.

  • Like 4
Link to comment
Share on other sites

@R.T. I'll defer to your professional web expertise. No underlines.. sigh :)

 

TheLoon Tip #4 (ECONOMY OF VARIABLES) - You don't hafta work for the TSA to screen

 

If you lay out your game correctly you can use the playfield for both visual queues and variable use. For instance, in my game M.M.S.B.C. II the topmost playfield pixels represent the main heath bar:

 

playfield:

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX <--

................................

................................

................................

...........X..................X.

..........XXXXX..............X.X

....................X...........

X..XXX.X.X.X..XX.X.X.X.X..X..XXX

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

X..X.X.X.X.X...X.X.X.X.X..X..X..

XX.XXX.XXX.X.XX...X..X.XX.XX.XXX

end

 

As the players lose hit points the rightmost pixels get turned off until even the very leftmost pixels are gone. AT THAT POINT the var0 (top-leftmost 8 pixels) should equal 0.

 

if var0 = 0 then goto game_over

 

Notice I didn't have to use a variable for that main health stat!

  • Like 2
Link to comment
Share on other sites

TheLoon Tip #5 (GRAPHICS) - Flip the ball over for massive damage!

 

While the missiles and balls can only be one rectangular shape at a time we can alternate between shapes to create distinct objects! Once again this example relies on a variable called counter that increments once every main game loop. Since counter{0} is true every other frame we can use that to change our missile/ball shape quickly enough so that our eyes see a more complicated shape - in this case a sword with hilt!

draw_weapon
bally = bally - 2
if bally < 4 then bally = 0 : ballx = 0 : return
if counter{0} then goto shaft else goto hilt
shaft
ballx = ballx + 1
bally = bally + 2
CTRLPF = $11
ballheight = 9
return
hilt
ballx = ballx - 1
bally = bally - 2
CTRLPF = $21
ballheight = 1
return

 

There are one or two gotchas with this technique. First off, any area of the sword that isn't overlapping both frames of animation will be semi-transparent. So, count on the edges of the hilt and tip/handle of the sword to be darker than the middle. In addition, collision will be effected due to the actual ball/missile being shifted around each frame.

  • Like 1
Link to comment
Share on other sites

RevEng Tip #3 - (GRAPHICS) cheap transporter/yars safety zone/explosion with the standard kernel

 

Originally from this thread. (well, originally from Yar's Revenge)

 

You can point the player data pointers to random game code, and set the height as you like. If you test this with a an empty program the effect will be be more solid, but as your bank fills up with code the effect will become more randomish.

 

datastart
 const datastarthi=(#>.datastart)

 player0x=50
 player0y=90
 player0height=90
 player0pointerhi=datastarthi

gameloop
 rem divide by two to avoid hotspots in bank-switched games...
 player0pointerlo=rand/2
 COLUP0=rand
 REFP0=rand
 NUSIZ0=$07
 drawscreen
 goto gameloop

  • Like 1
Link to comment
Share on other sites

  • 2 months later...

TheLoon Tip #6 (EDITOR) - Import Changes back into VisualbB

 

Sometimes you may start out creating a sprite or playfield in the VisualbB editor but end up hand tweaking things until your code and VisualbB don't match. Fear not! You can manually re-import the changes with ease!

 

1. Select the entire pfcolors: and playfield/playercolors: section for your sprite or playfield in your code and copy them to the clipboard. Make sure you copy *just* the bare two sections mentions and not any extraneous code.

2. Open your original sprite/playfield in VisualbB.

3. Right mouse-click on your selected sprite.spr or playfield.pla filename and hit "View in Notepad..."

4. In notepad clear out the old contents and PASTE the contents of the clipboard.

5. SAVE in Notepad.

6. Back in VisualbB right mouse-click on the sprite.spr or playfield.pla we were working with and hit Reload.

 

BAM! Now our hand-tweaked items are back in the full editor for great justice.

Link to comment
Share on other sites

  • 1 month later...

Ive read the tip 1 of revenge with the echo command but I lack knowledge how I can use it to write the state of a variable. I would like to see which number is stored on a certain variable thru the game by using the echo command several time to check if the number is constant or modified by something I m missing. Could someone help?

Link to comment
Share on other sites

Ive read the tip 1 of revenge with the echo command but I lack knowledge how I can use it to write the state of a variable. I would like to see which number is stored on a certain variable thru the game by using the echo command several time to check if the number is constant or modified by something I m missing. Could someone help?

 

If you'd like to have the value of a variable displayed in the score, you can use this:

 

randomterrain.com/atari-2600-memories-batari-basic-commands.html#testvariables

Link to comment
Share on other sites

thanks for the help guys :) I ve seen the page you mention RT but I hoped something prior to play the game on stella.

 

I'm not sure what you are saying, but I wasn't just linking to a page, I was linking to a specific place on the page that has code you can use in your program to run using Stella.

Link to comment
Share on other sites

  • 2 months later...

iesposta Tip #1 (MUSIC) data reduction.

 

If the Control channel [aka Tone, Voice, Distortion] doesn't change in your data for AUDC0 and/or AUDC1,

set the AUDC0 = (that value) and/or AUDC1 = (value) and remove all the repeated channel numbers (and any 0's) from the data statement.

Any Control value with a volume of 0 is still Volume 0, so 0, 0, 0 or 0, 4, 0 act the same.

 

Example saved (approximately) 57 bytes (the value 12 in Channel 0 and the value 4 in Channel 1):

Before:

 
 
   rem  *  Play channel 0
   AUDV0 = musicData[x] : x = x + 1
   AUDC0 = musicData[x] : x = x + 1
   AUDF0 = musicData[x] : x = x + 1
 
   rem  *  Play channel 1
   AUDV1 = musicData[x] : x = x + 1
   AUDC1 = musicData[x] : x = x + 1
   AUDF1 = musicData[x] : x = x + 1
 
   rem  *  Set duration
   duration = musicData[x] : x = x + 1
   goto GotMusic
 
   rem  *****************************************************
   rem  *  Music Data Block
   rem  *****************************************************
   rem  *  Format:
   rem  *  v,c,f (channel 0)
   rem  *  v,c,f (channel 1) 
   rem  *  d
   rem  *
   rem  *  Explanation:
   rem  *  v - volume (0 to 15)
   rem  *  c - control [a.k.a. tone, voice, and distortion] (0 to 15)
   rem  *  f - frequency (0 to 31)
   rem  *  d - duration
 
  data musicData
  4,12,19
  4,4,19
  24
  4,12,19
  4,4,17
  8
  4,12,26
  0,0,0
  16
  4,12,26
  4,4,14
  16
  4,12,19
  4,4,14
  8
  4,12,19
  0,0,0
  8
  4,12,19
  4,4,17
  8
  4,12,19
  4,4,17
  8
  4,12,26
  4,4,19
  16
  4,12,26
  4,4,17
  16
  4,12,29
  4,4,21
  16
  4,12,26
  4,4,21
  8
  4,12,23
  3,4,21
  8
  4,12,21
  2,4,21
  8
  4,12,19
  1,4,21
  8
  4,12,17
  0,0,0
  8
  4,12,15
  0,0,0
  8
  4,12,14
  0,0,0
  16
  2,12,14
  0,0,0
  16
  255
end
   goto GotMusic

After:

 
   rem  *  Check for end of current note
   duration = duration - 1
   if duration>0 then GotMusic
 
   rem  *  Check for end of data
   if musicData[x]=255 then duration = 1 : x = 0 : goto GotMusic
 
   rem  *  Play channel 0
   AUDV0 = musicData[x] : x = x + 1
   AUDC0 = 12
   AUDF0 = musicData[x] : x = x + 1
 
   rem  *  Play channel 1
   AUDV1 = musicData[x] : x = x + 1
   AUDC1 = 4
   AUDF1 = musicData[x] : x = x + 1
 
   rem  *  Set duration
   duration = musicData[x] : x = x + 1
   goto GotMusic
 
   rem  *****************************************************
   rem  *  Music Data Block
   rem  *****************************************************
   rem  *  Format:
   rem  *  v,c,f (channel 0)
   rem  *  v,c,f (channel 1) 
   rem  *  d
   rem  *
   rem  *  Explanation:
   rem  *  v - volume (0 to 15)
   rem  *  c - control [a.k.a. tone, voice, and distortion] (0 to 15)
   rem  *  f - frequency (0 to 31)
   rem  *  d - duration
 
  data musicData
  4,19
  4,19
  24
  4,19
  4,17
  8
  4,26
  0,0
  16
  4,26
  4,14
  16
  4,19
  4,14
  8
  4,19
  0,0
  8
  4,19
  4,17
  8
  4,19
  4,17
  8
  4,26
  4,19
  16
  4,26
  4,17
  16
  4,29
  4,21
  16
  4,26
  4,21
  8
  4,23
  3,21
  8
  4,21
  2,21
  8
  4,19
  1,21
  8
  4,17
  0,0
  8
  4,15
  0,0
  8
  4,14
  0,0
  16
  2,14
  0,0
  16
  255
end
   goto GotMusic
 
  • Like 1
Link to comment
Share on other sites

  • 3 years later...

This is small, but variable-saving. The playerNx and playerNy variables can be used as part of fixed point variables. I was surprised that this worked, but I guess they are variables like any other.:

   dim EnemyXPos = player1x.f
   dim EnemyYPos = player1y.g

  • Like 1
Link to comment
Share on other sites

This is small, but variable-saving. The playerNx and playerNy variables can be used as part of fixed point variables. I was surprised that this worked, but I guess they are variables like any other.:

   dim EnemyXPos = player1x.f
   dim EnemyYPos = player1y.g

Yep, that's actually on the bB page, but you have to scroll down to the fourth example box to see it:

 

randomterrain.com/atari-2600-memories-batari-basic-commands.html#fixedpoint

 

Maybe I should make it stand out somehow so people won't miss it.

Link to comment
Share on other sites

Yep, that's actually on the bB page, but you have to scroll down to the fourth example box to see it:

 

randomterrain.com/atari-2600-memories-batari-basic-commands.html#fixedpoint

 

Maybe I should make it stand out somehow so people won't miss it.

 

 

Perhaps, but me missing something like that is hardly unprecedented. :-) I did read the section on fixed point variables, but I must have missed that.

  • Like 1
Link to comment
Share on other sites

  • 4 weeks later...

Optimizations to save cycles, get ROM space:

 

Put all same value declarations on one line (until compile errors out due to too many).

 

examples:

player0x=0: c=0: d=0: missile1x=0: temp2=0: timer=0

 

DFRACINC0=32: DFRACINC1=32: DFRACINC2=32: DFRACINC3=32: DFRACINC4=32: DFRACINC6=32

 

------------------------------------

 

Technical explanation:

 

This

DFRACINC0=32: DFRACINC1=32: DFRACINC2=32: DFRACINC3=32: DFRACINC4=32: DFRACINC6=32

compiles into: load register with 32, set all the data-fetchers to 32

 

This

DFRACINC0=32

DFRACINC1=32

DFRACINC2=32

DFRACINC3=32

DFRACINC4=32

DFRACINC6=32

compiles into: load register with 32, set data-fetcher 0 to 32, load register with 32, set data-fetcher 1 to 32, load register with 32, set data-fetcher 2 with 32, load register with 32, set data-fetcher 3 to 32, load register with 32, set data-fetcher 4 to 32, load register with 32, set data-fetcher 6 to 32

 

See how efficient the first explanation is, and how wasteful the second explanation is?

  • Like 1
Link to comment
Share on other sites

RevEng Tip #4 - (CYCLES) only run things when you need to, with a simple scheduler

 

Not everything needs to happen at 60Hz/50Hz in your game. Some things can happen every other frame, or every 4th frame. Balance when these things happen, to make the most of available cycles...

 

 

mainloop
  frame=frame+1

  rem ** alternate "goat AI" routine with "check goat collision", every other frame
  rem ** (frame&1 is always either 0 or 1)
  if (frame&1)=0 then gosub GoatAI
  if (frame&1)=1 then gosub CheckGoatCollision

  rem ** spread movement logic for 4 enemy trolls across 4 frames
  rem ** (frame&3 is either 0, 1, 2, or 3)
  if (frame&3)=0 then gosub Troll1Logic
  if (frame&3)=1 then gosub Troll2Logic
  if (frame&3)=2 then gosub Troll3Logic
  if (frame&3)=3 then gosub Troll4Logic

 [...]
  • Like 1
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...