Virtual World BASIC manual -------------------------- 0. Introduction to Virtual World BASIC 1. Virtual World BASIC Syntax 2. Virtual World BASIC Commands 3. Fun with variable arrays and strings! 4. Redefining part of a sprite 5. Printing strings with the print@ command 6. Array transformations 7. Raising an event 8. Getting BASIC in ROM 9. Debugging your programs A. Load Balancing B. Resources, Samples and Examples Introducing Virtual World BASIC ------------------------------- Virtual World BASIC allows you to create games in BASIC for the Atari 2600 that take place in a virtual world ten times larger than the Television screen. You have a playfield camera to pan about the virtual world, and sprites which you can bind to virtual world pixels (tile mapping). And, virtual world collision detection. You design the large virtual world by "drawing it" with ASCII art in your vwBASIC program, just below your code. Same for the sprite graphics. vwBASIC also has an fx sound engine - You can define chip tunes that repeat in the background and for specific game events in the musical score table below the ASCII art. vwBASIC is designed for programatically and visually manipulating arrays, graphical tables and binary strings. The virtual world contains thousands of pixels that you control programatically with the vwpixel command. The playfield camera view links relationally to the virtual world and shows a 200 tile pixel view (20x10) on the television screen whenever you change the cam coordinates. vwBASIC's objects can also be addressed as arrays in BASIC, and you can define hundreds of additional variables as named arrays. Setting up ---------- Extract the files to c:\vwBASIC (You can create a different folder but you will have to edit the paths in the compiler script). Now just edit the program.txt file, it's loaded with a sample program you can modify or use as a guide to write new programs. Note that the compiler always compiles the program.txt file (so be sure to rename files appropriately when ready to compile your code if you have more than one program file). vwBASIC language syntax ----------------------- Almost pure TinyBASIC simple expressions with no parenthesis. 100 e=5*n is ok, but "e=5*n-3" must be written as two statements: 100 e=5*n:e=e-3 bitwise operators: ^ xor, & and, | or. number prefixes: none - decimal(255), % binary (%11111111), $ hex ($ff) if then else ------------ if then else is supported in BASIC horizontal format: 10 if e>=5*n or g*2=r-3 then e=10:i=17 else i=33:e=e+2 Note: You cannot mix and and or in the same if statement (use another if). If must always be the first statement in a line. Language commands: ------------------ vwpixel - sets, flips, polls virtual world pixels and binds sprites to the virtual world. Examples: 10 vwpixel(0,0,on):rem turn on upper left pixel in the virtual world. 20 vwpixel(x,y,flip):rem flip the virtual world pixel at x,y. 30 if vwipxel(5,5,poll)>0 then COLUBK=255:rem change background color if virtual world pixel 5,5 is on. 40 vwpixel(5,5,bindplayer0):rem bind sprite to virtual world pixel 5,5. 45 player0x=player0x+3:player0y=player0y+2: fine grain control Line 45 shows the fine grain coordinate system variables for the sprite which get set by vwpixel; you can adjust them for fine grain movement between tiles. 10 Loadplayer0(8): rem load second sprite definition from library --------------------------------- Loads the player 1 sprite with a definition (8 rows of 8 pixels) from the sprite library, starting at the specified index of 8. 20 loadplayer1upsidedown(0): rem load first sprite def from library -------------------------------- Loads the player 2 sprite from the sprite library, flipped upside down. You have control over horizontal flip via TIA system var REFP0: 10 REFP1=255:rem flip player 2 horizontally reading the joysticks --------------------- Joysticks are read using friendly named variables that return 1 or 0: 10 if joy0left=1 then f=3: rem joystick 0 pushed left 20 if joy1fire=1 then f=4: rem joystick 1 botton pressed data statements --------------------- Named variable arrays get declared and initialized in data statements: 90 rem: create boats data array; dimension and initialize 100 data boats 1,3,2,3,2,4,7 read --------------------- 110 read i(boats,j):rem read element j from boats array into i. 120 i=boats(j):rem read array element var into another var 130 boats(i)=boats(j): read array element i, assign to array element j write [alias: print] ------------------------ 120 print %11111111(Sprite0SCR,0):rem draw top row of player 1 sprite 130 write i(boats,j):rem write value i into boats array at element j. 140 boats(j)=5:rem standard BASIC array syntax is also supported 150 boats(j)=boats(x)*5:rem assign element j to element x transformation For Next loops --------------------- 10 rem nested looping, inner/outer example: 20 for x= 3 to 5: for y = 12 to 2 step -2: vwpixel(x,y,on): next y,x goto gosub return --------------------- 10 if e=33 then gosub 100 else gosub 200 20 goto 300 200 e=33:return 300 rem fun with vwBASIC variable arrays and strings! --------------------------------------------- vwBASIC has a small number of predefined variables in low RAM (e-z,var1,var2,px,py,bx,by) and virtually unlimited named arrays and binary string variables with commands for manipulating them. vwBASIC lets you declare and initialize named variable arrays in data statements: 100 data boats 1,3,2,3,2,4,7 Manipulating array variables: ------------------------------------ 110 i=boats(0): rem assign the value in i to element(0) of boats 120 boats(0)=i+1 130 boats(0)=boats(3)*2: rem assign one element to a multiple of another An alternate array syntax is also supported: 110 read i(boat,0):rem read 1st element of boats into i 120 write i(boats,1):rem write i into 2nd element of boats array. You can add as many named arrays as you wish. If you reach a total of 254 total element variables for all of your arrays combined you must start a new array. You can continue on until up to 255 element variables are reached (254+255 total) and then must start a new array again. It is possible to have over 1,000 bytes of array variables in this manner if you desire it. This is unlikely, but when you're used to working with 26 variables just declaring an extra 50 gives you much more flexibility to code. Nearly all of the abstract objects in vwBASIC are arrays or multidimensional arrays. If you look at the ASCII art definition for the virtual world and the sprite library, they are binary tabular arrays you can work with visually or programatically - the virtual world contains 2,000 binary variables and each sprite definition contains 64. vwBASIC has special commands like vwpixel to address the individual bits in the virtual world, and a load sprite function that reads 8 binary strings out of the sprite library (comprising an 8x8 sprite image) to load one of the system sprite tables, SpriteSCR0 or SpriteSCR1. Visually redefining part of a sprite: ------------------------------------- 10 print %11111111(SpriteSCR0,0) 20 print %11000011(SpriteSCR0,1) 30 print %11111111(SpriteSCR0,2) We just printed three rows of pixels on player1 sprite, which has 8 rows. loadsprite0 and loadsprite0upsidedown contain a loop that read 8 rows out of a section of the sprite library and loads them much like this - we could have written that function in vwBASIC! Printing strings on the world with the PRINT@ command: ------------------------------------------------------ You can poll,flip or set the individual pixels or bind the sprites to them with vwpixel but you can also print a binary string to the virtual world, 8 bits at a time much like the BASIC PRINT@ command. print %10101010(virtualworld,3) --------------------------------------- Prints the binary pattern block at the position of the 3rd byte - the table is 12 bytes accross to hold the 92 pixel wide virtual world, and 20 bytes deep, as per it's ASCII art definition. You can calculate the @ index by multiplying rows x 12 (row length) and adding to find the target byte column. Note: the first byte in each row is partially obscured. Array transformations --------------------- The above works because all arrays, regardless of the number of dimensions or type, may also be accessed as a single dimensional byte array. You can also read past the end of one array into the next array: 100 i=array1(7):rem can read past boundry 105 data array1 5,6,7,8 110 data array2 1,2,3,4 The utilty in the example above is that you can use the two 4 element arrays or use them as one 8 element array as needed. You can assign one arrays elements to another and reference transformations in expressions just like with scalar variables: 10 array1(n)=array2(5)*3 30 rem BASIC array manipulation syntax Double Buffering in RAM ----------------------- While virtualworld is the system table array for the virtual world, there is another system table array for the playfield camera, RAMplayfield. This is another x,y addressable buffer and can be modified independently of the virtual world for special effects and a higher resolution playfield. There is no physical object to draw with ASCII art for this table as there is for the virtualworld, because the table is linked relationally and populated from a coordinate view section of the virtual world whenever you raise an event. Relational Database core ------------------------ Commands like vwpixel modify both 2D binary system tables when their coordinates overlap using relational calculus behind the scenes as does raising an event, which creates a playfield camera view table from anywhere within the virtual world table as described below - you could think of the playfield CAM like a sheet of glass that you can annotate and then wipe off. Raising an event ---------------- Raising an event causes the camera view to refresh at the virtual world coordinates specified by XIndex and BYTErowoffset (system variables for the playfield CAM). XIndex is the CAM's x coordinate, and BYTErowoffset is the CAM's y*12 coordinate. You can raise an event anytime you want by flipping on the system variable to scroll the virtual world: 10 scrollvirtualworldtoggle=1 Raising an event also runs whatever code you've got in the Kitchen sink section using a larger time window to run code - more time than there is in either of the gameloop sections so it's a good place for a long running routine. The variable is automatically toggled back off (0) until you set it again for the next event. Note that events should only be raised conditionally; there is usually no need to raise an event to refresh the playfield camera view unless it's virtual world coordinates have changed, doing so constantly will result in flicker. chiptunes --------- below the ASCII art, there is a table for chiptunes: chiptunes 7,30,0,0,8 7,24,0,0,8 7,20,0,0,8 7,24,0,0,7 30,0,0,30,0 10,20,5,11,25 7,7,6,5,20 6,4,4,6,10 0,0,0,0,0 The chiptunes table works like this; each line contains data for both voices of the Atari sound chip and a common duration: frequency, channel, frequency, channel, duration Music is processed through an fx engine that changes the envelope. The table is designed to hold multiple chiptunes; a repeating main theme and multiple sub themes that return control to the main theme. In this example the first song loops after it reaches a duration of 0 (line 5). Playing the next tune --------------------- Setting the music index (system var MUSICINDEX) to 5 will start the player at the following line (line 6), the second theme in this case. The second theme only plays once - when it reaches a duration of 0 (line 9) it goes back to playing the main theme. Getting BASIC in ROM -------------------- First compile your program with the compiler: Run the vwBASIC_compiler.ps1 script from the shell or command line; it will take the basic program in c:\vwBASIC\program.txt and compile it into c:\vwBASIC\program.asm. Next, assemble to a ROM binary with dasm. from the command line: dasm c:\vwBASIC\program.asm -oprogram.bin -f3 You can play the ROM binary in an emulator like Z26 or Stella, or on the real hardware with a ROM flashcart or a custom built cartridge. If you have the makewav.exe utility and wish to create a WAV file to put the game on Tape or compact disc for the SuperCharger or Cuttle Cart, the syntax is: makewav -ts program.bin Debugging: ---------- If there are errors, dasm will usually show you the line number (shown with an L prefix) of the errant code so you can locate it in your BASIC program, this is different than the line number of the Assembly file. Syntax errors can also show up when you are compiling your program - you should only see the assembly output scrolling by during compile time. If you do see an error dasm, will likely flag it for you in more detail. Load balancing: --------------- If the screen rolls (scanline count>262) you are doing to much in a single frame and need to load balance by either moving some of the code branch to gameloop2 (the other vertical blank), or running it in a different frame; a simple framecounter variable can allow you to split your code up on different branches for different frames to balance it. Some system variables are write only ------------------------------------ COLUPF, COLUP0, COLUP1 and COLUBK: These are the system vars that hold the virtualworld color, the player colors and the background colors. 10 COLUP0=255:COLUP1=$FF:rem set the player colors Works, but you cannot read back from these variables. Some system arrays are read only: *Do not write to the sprite library table ----------------------------------------- It is not page aligned so doing this might break the code, the two system sprite tables SpriteSCR0 and SpriteSCR1 are the objects to write to, to update sprites visibly on screen. If you want the library to be malleable, you could define your own sprite library in contiguous table array variables. Ditto for writing to the music table, it's not page aligned either. vwBASIC resources: ------------------ Random Terrain's batari BASIC pages are an excellent resource as most of the Atari system variables are in common. And there are great tools like color lookup tables and a sound development kit where you can hear the fx. Sample programs ---------------------------- The sample program provides examples of working with vwBASIC functions and language intrinsics and it's unique abilities manipulating arrays: The camera follows Player 1 about the virtual world, if the button is pressed Player 1 leaves a trail like in Tron/surround. The screen flashes whenever Player 1 drives over an existing virtual world pixel, and the pixel is erased. Player 2 can do the same things but the camera doesn't follow them - player 2 can drive off screen. Player 2's virtual world offscreen collisions can be verified by Player 1 following them with the camera. When Player 2 is leaving a trail, Player 1 becomes animated - three rows of the Player 1 sprite are mapped to the Player 2 sprite. Game example ---------------------------- Breakout Adventure (program and compiled ROM image included) is a demo you can also play: Featuring the Ball as Player1 and the Atari logo as Player2 (or the CPU). To start the game/demo move the ball at an angle. After you clear the first screen (by hitting 250 bricks) it get's really intense and may be more fun just to watch and listen to. Note: If you wait too long to start, the Atari logo will get a big head start collecting the bricks and it will take a long time to clear the screen - you collect extra bricks by going through the moving phrase section of the virtual world whenever the phrase dribbles the ball. KC Munchkin Monster Maze is a limited edition homebrew release that illustrates some of the effects you can achieve with vwBASIC and a tube Television: https://www.youtube.com/watch?v=aghqgf6qqRw This complex game example uses 50 variables - the 28 scalar variables were not enough, so another 20 array variables were utilized. It also takes advantage of preinitialization to save code space. About the extra colors in the games: ------------------------------------ The Atari can exploit ideosyncracies in the NTSC signal and RF carrier to display artifact colors (multiplying the depth of the bitmap for free to get additional colors in a monochrome image). On an antique tube Television this is a very pleasant effect. 4-switch models of the Atari produce the strongest artifact colors and moire effects through their RF connection (they leak chroma). vwBASIC lets you produce artifact colors on virtual world tile pixels and nearby sprites by choosing high luminosity colors for the tile pixels - both of the games above use an array of preseleted artifact colors to produce their effects.