LoginLogin
Nintendo shutting down 3DS + Wii U online services, see our post

Putting ASCII chr's into an array and converting it...

Root / Programming Questions / [.]

DefaultioCreated:
Into background tiles/invisible sprites so that is has collision. How would I set this up? Would I just create an array like:
'Setting up map array, it has 7 rows, each with different chr's
'Think of the "=" symbols as the blocks in the alternate keyboard
DIM MAP$[8]

MAP$[0] = "=========="
MAP$[1] = "= +====+ ="
MAP$[2] = "= ====== ="
...
'and so on until...
MAP$[7] = "=========="
So, would I have to read the individual characters in the string, and if it reads a certain character, it would place a certain "block" of bg/sprite tiles in a set of start and end coordinates; Or would I just have to make a bigger map so that one character represents one bg/sp tile? Like:
FOR I = 0 TO 7
 READ MAP$[8]
 'check for certain characters using string commands
 'and display sprites/bg tiles according to those
 'ASCII characters
NEXT
Or do you have your own way of doing that you could show? I know I could use a FOR loop, READ, and String commands to attempt to start this, but I'm not that great with String commands, but i'll learn them. So If I got the character to bg/sprite conversion to work, would I then have to just set up collision like I normally would? Thanks in advance for answering and/or reading.

So, in essence, you want to represent different kinds of tiles with different ASCII characters? I'm not a whiz with Sprite functions, but I think sprites have in-built collision to them. I fail to see how the ASCII characters have anything to do with what you're attempting.

I think they are attempting to make a stage level kind of set up, like a dungeon and chests sort of thing. If that's the case, then I must ask is sprite collision necessary? If you have a tiled world and tile characters which may only move and exist on tiles, would it not be better to check tile states where the player attempts to move (for say, a wall or an empty space), rather than creating a collision system? I'm only basing my assumption of what they are attempting on the tile-map-looking strings in their code.

Hm, hm, sorry I didn't clarify. http://petitcomputer.wikia.com/wiki/G-ZERO Basically what that program does. It converts ASCII characters that are assigned to an array and gets into sprites/bg sprites and displays them on the screen. Then collision is added, based on those sprites with the player's ship. I wanted to try something like that, but with other types of genres. Here's the code borthers: https://pastebin.com/T8iZ50nT

Okay, I understand this a little better now. The ASCII characters embedded in the MAP$ array constitute a form of storing map data. It doesn't necessarily have to be that method, i.e., you could use a 2D array of values instead. But, with the ASCII method, it would work basically as you describe. You need to describe a program which can identify elements of your MAP$ array and recognize their BG tile/sprite counterparts. Here's some psuedocode (again, I'm not familiar with sprites, someone else'll have to come along and tie this part up)
DIM MAP_X% = 8, MAP_Y% =8
DIM MAP$[0]
PUSH MAP$, "--------"
PUSH MAP$, "- ---- -"
'...
PUSH MAP$, "--------"
DIM X%, Y%
FOR Y% = 0 TO MAP_Y%-1
 FOR X% = 0 TO MAP_X%-1
  IF MAP$[Y%][X%]=="-" THEN 'Draw a specific sprite
  ENDIF
 NEXT X%
NEXT Y%
Because you're working with strings, you need to address MAP$ as if it were a 2D array. Strings function as arrays themselves, more or less. Calling MAP$[Y%] returns the horizontal cross-section of the array, let's say "--------". That string can then be referenced as an array itself, hence MAP$[Y%][X%], or ("--------")[X%]. They both will yield the same results, if you decide to test it.

I might be wrong, but what I think you're trying to do is this: How do I create maps using DATA? but without the DATA part. It would be much easier to use DATA to accomplish this (does not have to be as complicated as the linked page) I am working on another version of this program but instead of exporting the hex number and all (even empty space) tiles, it exports a print character, x location, and y location for all tiles excluding empty spaces. If you would like to see this in action, I may be able to put something together for you to see, but it could take a bit.

I might be wrong, but what I think you're trying to do is this: How do I create maps using DATA? but without the DATA part. It would be much easier to use DATA to accomplish this (does not have to be as complicated as the linked page) I am working on another version of this program but instead of exporting the hex number and all (even empty space) tiles, it exports a print character, x location, and y location for all tiles excluding empty spaces. If you would like to see this in action, I may be able to put something together for you to see, but it could take a bit.
Yea, I wanted to change it to data, but I thought it wouldn't work with what I was trying to do. I'll try it with data. I would love to see what you made! Thanks MZ for helping, I'll get on it right away!

Great! I will try to annotate my program so that it makes sense and have it up tonight or tomorrow evening

Hi, I'm back. So I tried to annotate this project as much as possible and I apologize if it is still difficult to understand. I didn't really set it up for use outside of my game but I tried to fix that. Anyway, expand the "spoilers" below to read what each file is. Key: Q3K33XLM
READMAPThis is probably the most relevant file. I will explain what it does in just a moment but first it requires a little set up. In direct mode:
LOAD "GRP5:TESTBG",0' the custom BG is important to this program file
Open the SmileTool map editor and create a map using the first grouping of gray tiles (essentially, a floor tile, wall tile and edge tiles. When finished, save the layers using SC SAVE. Now, copy the files into the MAPPING folder (or if you saved the SC saves in that folder that is fine too) and run READMAP file. Name the map layer and select the SC file. It will ask if you want to export another layer and save the file. SO with all that said, what this file does is exports a print character (based on the gray tile used), x location, y location of the tile from the map into PRG3. Next, in editor mode, you will have to set the print character associations with whatever tile you want (at this point, you can ACLS as to get rid of custom BG). After you have set the tile associations then you can draw the map with NewDrawMap function. This is how you use that:
NewDrawMap "3:@label",layer number
TESTDATAYou can ignore this file. It is important for the TECHDEMO file (it is loaded automatically into slot 3)
TECHDEMOThis file is a tech demo of a game I am working on. If you have played Kingdom Hearts Chains of Memories back in the GBA days, then this may feel familiar. You move a character around a map to arrows (exits), select a map template for the next zone and repeat. If you don't like the untextured gray you can change "@UNTEXTURED" in line 57 to "@GREEN" to get an untextured green map. The purpose of this project is to separate maps and textures to use as little "maps" as possible but still have an extensive gameplay experience. And also I wanted to see if I could recreate the mapping system in KHCoM.
I hope this helps and I will try my best to answer any questions you might have. Also, I do not plan on making a page for this just yet but I will when it has more definitive gameplay. I will leave this up for ~24 hours or so.

Hi, I'm back. So I tried to annotate this project as much as possible and I apologize if it is still difficult to understand. I didn't really set it up for use outside of my game but I tried to fix that. Anyway, expand the "spoilers" below to read what each file is. Key: Q3K33XLM
READMAPThis is probably the most relevant file. I will explain what it does in just a moment but first it requires a little set up. In direct mode:
LOAD "GRP5:TESTBG",0' the custom BG is important to this program file
Open the SmileTool map editor and create a map using the first grouping of gray tiles (essentially, a floor tile, wall tile and edge tiles. When finished, save the layers using SC SAVE. Now, copy the files into the MAPPING folder (or if you saved the SC saves in that folder that is fine too) and run READMAP file. Name the map layer and select the SC file. It will ask if you want to export another layer and save the file. SO with all that said, what this file does is exports a print character (based on the gray tile used), x location, y location of the tile from the map into PRG3. Next, in editor mode, you will have to set the print character associations with whatever tile you want (at this point, you can ACLS as to get rid of custom BG). After you have set the tile associations then you can draw the map with NewDrawMap function. This is how you use that:
NewDrawMap "3:@label",layer number
TESTDATAYou can ignore this file. It is important for the TECHDEMO file (it is loaded automatically into slot 3)
TECHDEMOThis file is a tech demo of a game I am working on. If you have played Kingdom Hearts Chains of Memories back in the GBA days, then this may feel familiar. You move a character around a map to arrows (exits), select a map template for the next zone and repeat. If you don't like the untextured gray you can change "@UNTEXTURED" in line 57 to "@GREEN" to get an untextured green map. The purpose of this project is to separate maps and textures to use as little "maps" as possible but still have an extensive gameplay experience. And also I wanted to see if I could recreate the mapping system in KHCoM.
I hope this helps and I will try my best to answer any questions you might have. Also, I do not plan on making a page for this just yet but I will when it has more definitive gameplay. I will leave this up for ~24 hours or so.
Do you think I could also have the txt files (if you have homebrew and SBFM that is), because my 3ds likes to die really fast now, and I have Citra on my PC to run SmileBASIC on. If you can't then that's fine, I will let you know when I get the files onto my 3ds. Thank you for the help in understanding your method of map loading!

...
Do you think I could also have the txt files (if you have homebrew and SBFM that is), because my 3ds likes to die really fast now, and I have Citra on my PC to run SmileBASIC on. If you can't then that's fine, I will let you know when I get the files onto my 3ds. Thank you for the help in understanding your method of map loading!
I am sorry, I do not have homebrew or SBFM

...
Do you think I could also have the txt files (if you have homebrew and SBFM that is), because my 3ds likes to die really fast now, and I have Citra on my PC to run SmileBASIC on. If you can't then that's fine, I will let you know when I get the files onto my 3ds. Thank you for the help in understanding your method of map loading!
I am sorry, I do not have homebrew or SBFM
It is fine brother, I have received the package, thanks again.

It sounds like you already have this figured out, but since you mentioned G-Zero, I thought I would post the G-Zero code I ported from Petit Computer to SmileBasic. If you notice, I added a second track, just swap one M$ array for the other to get the new track. You can make your own tracks too. X marks where the player starts. The exhaust is a linked sprite now and I think its code is more elegant than the original. Enjoy
OPTION STRICT
VAR LAYER = 0, X, Y, I, J, FONT$, GAME_OVER
VAR ANG, DA, B, BX, BY, START_LINE, TMP
VAR FRICTION, SPEED, SPEED_MAX, ANG_RAD
VAR T1, T2, DX, DY, EXHAUST_DIST
VAR MAP_W = 9, MAP_H = 9
VAR T_WALL = 842, T_ROAD = 584
VAR T_FINISH = 349, T_SHIP = 1217
VAR T_EXHAUST = 1347
VAR SCREEN_W = 400, SCREEN_H = 240
VAR HALF_W = SCREEN_W / 2
VAR HALF_H = SCREEN_H / 2
VAR ANY_DIR = #UP OR #DOWN OR #LEFT OR #RIGHT
'---------- G-ZERO
DIM M$[MAP_H]
M$[0] = ""
M$[1] = "  X  "
M$[2] = "  "
M$[3] = "  "
M$[4] = "  "
M$[5] = "  "
M$[6] = "   "
M$[7] = "   "
M$[8] = ""

'M$[0] = ""
'M$[1] = "     "
'M$[2] = "  "
'M$[3] = "  X "
'M$[4] = "   "
'M$[5] = "    "
'M$[6] = "     "
'M$[7] = "      "
'M$[8] = ""

CLS
BGSCREEN 0, MAP_W * 8, MAP_H * 8
DX = 0 : DY = 0
FOR X = 0 TO MAP_W - 1 ' DRAW MAP
 FOR Y = 0 TO MAP_H - 1
  FONT$ = CHRREAD(MID$(M$[Y], X, 1))
  FOR J = 0 TO 7
   FOR I = 0 TO 7
    T1 = VAL(MID$(FONT$, I + (J * 8), 1))
    BX = I + X*8 : BY = J + Y*8
    TMP= RND(4) + T_WALL 'WALL
    IF T1 == 1 THEN 
     TMP = RND(4) + T_ROAD 'ROAD
    ELSEIF T1 == 2 THEN
     TMP = T_FINISH 'FINISH LINE
     IF DX == 0 AND DY == 0 THEN
      DX = X * 8 * 16 + (4 * 16)
      DY = Y * 8 * 16 + (4 * 16)
     ENDIF
    ENDIF
    BGPUT LAYER, BX, BY, TMP
   NEXT I
  NEXT J
 NEXT Y
NEXT X
GCLS

'--------PLAYER INIT
SPCLR
SPSET 0, T_SHIP 'SHIP
SPHOME 0, 8, 8
SPOFS 0, HALF_W, HALF_H
 
SPSET 1, T_EXHAUST 'EXHAUST
SPHOME 1, 8, 8
SPOFS 1, HALF_W - 16, HALF_H
SPLINK 1, 0 'LINK TOGETHER

EXHAUST_DIST = 0 : START_LINE = 1
X = DX : Y = DY
DX = 0 : DY = 0
ANG = 180 : DA = 2 : SPEED_MAX = 16
GAME_OVER = FALSE : T1 = MILLISEC

'--------MAIN
WHILE GAME_OVER == FALSE
 B = BUTTON()
 FRICTION = 0.99
 IF B AND #Y THEN GAME_OVER = TRUE
 IF B AND #RIGHT THEN ANG = ANG + DA
 IF B AND #LEFT THEN ANG = ANG - DA
 IF B AND (ANY_DIR) THEN FRICTION = 0.98
 IF ANG < 0 THEN ANG = ANG + 360
 IF ANG > 360 THEN ANG = ANG + 360
 DX = DX * FRICTION : DY = DY * FRICTION
 SPEED = (DX * DX) + (DY * DY)
 IF ((B AND #A) != 0) AND SPEED < SPEED_MAX THEN
  ANG_RAD = RAD((ANG + 180) MOD 360)
  DX = DX + COS(ANG_RAD)/20
  DY = DY + SIN(ANG_RAD)/20
 ENDIF 
 SPROT 0, (ANG + 90) MOD 360
 X = X + DX : Y = Y + DY
 X = MAX(0, MIN(X, (MAP_W * 16 * 8) - 16))
 Y = MAX(0, MIN(Y, (MAP_H * 16 * 8) - 16))
 TMP = BGGET(LAYER, X / 16, Y / 16)
 IF TMP >= T_ROAD AND TMP <= T_ROAD + 3 THEN
  DX = -DX
  DY = -DY
 ENDIF
 BX = MIN(MAX(0, X - HALF_W), (MAP_W * 16 * 8) - SCREEN_W)
 BY = MIN(MAX(0, Y - HALF_H), (MAP_H * 16 * 8) - SCREEN_H)
 BGOFS LAYER, BX, BY
 SPOFS 0, X - BX, Y - BY
 IF ((B AND #A) != 0) AND SPEED < SPEED_MAX THEN
  EXHAUST_DIST = EXHAUST_DIST + 1 : SPEED = SPEED * 700
  IF EXHAUST_DIST > 16 THEN EXHAUST_DIST = 6 : BEEP 1
  SPOFS 1, 0, -EXHAUST_DIST
  SPSHOW 1
 ELSE
  SPHIDE 1
 ENDIF
 TCHK X, Y
 VSYNC
WEND
END

DEF TCHK X, Y
 VAR I, J
 '------------TIME
 I = FLOOR(X / 16) : J = FLOOR(Y / 16)
 IF BGGET(LAYER, I, J) != T_FINISH THEN
  START_LINE = 0 
  RETURN
 ENDIF
 
 IF START_LINE != 0 THEN 
  RETURN
 ELSE
  START_LINE = 1
 ENDIF
 
 BEEP 7 'COIN
 T2 = MILLISEC
 IF T1 THEN
  LOCATE 15, 1
  PRINT "TIME: " + FORMAT$("%03.2F", (T2 - T1) / 1000) + " SEC   ";
  T1 = T2
 ENDIF
END

'POLYFILL FOR PTC ONLY FUNCTION
DEF CHRREAD(CH$)
 VAR RET$ = ""
 VAR I, J
 GCLS
 GPUTCHR 0, 0, CH$ 
 FOR J = 0 TO 7
  FOR I = 0 TO 7
   IF CH$ == "X" THEN
    RET$ = RET$ + "2"
   ELSE
    IF GSPOIT(I, J) != 0 THEN
     RET$ = RET$ + "1"
    ELSE
     RET$ = RET$ + "0"
    ENDIF
   ENDIF 
  NEXT I
 NEXT J
 RETURN RET$
END


It sounds like you already have this figured out, but since you mentioned G-Zero, I thought I would post the G-Zero code I ported from Petit Computer to SmileBasic. If you notice, I added a second track, just swap one M$ array for the other to get the new track. You can make your own tracks too. X marks where the player starts. The exhaust is a linked sprite now and I think its code is more elegant than the original. Enjoy
Ok so, this might be a huge request, but could you comment your code? I would love to be able to read a nice, neat, polished piece of programmed code.

OPTION STRICT 'REQUIRE VARIABLES BE DECLARED BEFORE USE

'THIS IS A PORT OF G-ZERO BY SMILEBOOM ORIGINALLY FOR PETIT COMPUTER ON THE NINTENDO DS
'
'IT WAS FOUND IN THE PETIT COMPUTER OFFICIAL STRATEGY TECHNIC
'STARTING ON PAGE 94 IN THE 100 LINE PROGRAM CHALLENGE SECTION.
'
'YOU RACE A SHIP AROUND A RACE TRACK COMPETING AGAINST YOUR OWN BEST TIME.
'
'CONTROLS.
'[LEFT] TURN THE SHIP LEFT
'[RIGHT] TURN THE SHIP RIGHT
'[A] ACCELERATE
'[Y] EXIT PROGRAM
'

VAR LAYER = 0	'WHAT BACKGROUND LAYER TO READ/WRITE TO
VAR X, Y, I, J	'ITERATE OVER A GRID
VAR FONT$		'VARIABLE TO WHICH THE PIXEL PATTERN OF A LETTER WILL BE UNPACKED TO
VAR GAME_OVER	'FLAG TO SAY IF THE GAME SHOULD KEEP RUNNING.
VAR ANG			'CURRENT ANGLE OF THE SHIP
VAR DA			'HOW MUCH TO CHANGE THE ANGLE WHEN TURNING
VAR B			'USED TO STORE BUTTON STATE
VAR BX, BY		'BACKGROUND LAYER X AND Y COORDINATES
VAR START_LINE	'FLAG TO SAY IF YOU PASSED THE STARTING LINE
VAR TMP			'THROW AWAY TEMPORARY VARIABLE
VAR FRICTION	'SLOWLY REDUCE SPEED OVER TIME WHEN NO FORCE APPLIED
VAR SPEED		'HOW FAST THE SHIP IS MOVING (SQUARED ACTUALLY)
VAR SPEED_MAX	'TOP ALLOWABLE SPEED
VAR ANG_RAD		'CURRENT ANGLE ADJUSTED TO POINT THE SHIP CORRECTLY AND CONVERTED TO RADIANS
VAR T1, T2 		'TIMER VARIABLES TO KEEP TRACK OF TIME SPENT RUNNING A LAP
VAR DX, DY		'HOW FAST WE ARE MOVING IN THE X AND Y DIRECTION
VAR EXHAUST_DIST 'DISTANCE OF THE EXHAUST FROM THE SHIP (MOVES BACK AND FORTH)
VAR MAP_W = 9, MAP_H = 9 'WIDTH AND HEIGHT OF THE MAP, CHANGE THE WIDTH TO 15 (WIDTH OF THAT MAP) IF YOU USE THE OPTIONAL MAP
VAR T_ROAD = 842	'TILE ID FOR THE ROAD. WE ACTUALLY USE A RANGE OF TILES STARTING HERE AND UP TO ID + 3 
VAR T_WALL = 584 	'TILE ID FOR THE WALL. WE ACTUALLY USE A RANGE OF TILES STARTING HERE AND UP TO ID + 3 
VAR T_FINISH = 349	'TILE ID FOR THE FINISH LINE
VAR T_SHIP = 1217 	'SPRITE ID FOR THE SHIP/PLAYER
VAR T_EXHAUST = 1347	'SPRITE ID OF THE EXHAUST FLAME
VAR SCREEN_W = 400, SCREEN_H = 240 'THE SCREEN WIDTH AND HEIGHT
VAR HALF_W = SCREEN_W / 2 			'HALF OF THE SCREEN WIDTH (CONVENIENCE VARIABLE)
VAR HALF_H = SCREEN_H / 2			'HALF OF THE SCREEN HEIGHT (CONVENIENCE VARIABLE)
'FLAG TO COMBINE ALL OF THE DIRECTION BUTTONS TOGETHER IN A FLAG, USED TO SEE IF 
'ANY DIRECTION KEY PRESSED.
VAR ANY_DIR = #UP OR #DOWN OR #LEFT OR #RIGHT 

'---------- G-ZERO
'THE MAP WE ARE RACING ON. EACH PIXEL OF EACH CHARACTER BECOMES A TILE ON THE BACKGROUND.
DIM M$[MAP_H]
M$[0] = ""
M$[1] = "  X  "
M$[2] = "  "
M$[3] = "  "
M$[4] = "  "
M$[5] = "  "
M$[6] = "   "
M$[7] = "   "
M$[8] = ""

'ALTERNATE MAP (REMEMBER TO UPDATE MAP_W IF YOU USE THIS)
'M$[0] = ""
'M$[1] = "     "
'M$[2] = "  "
'M$[3] = "  X "
'M$[4] = "   "
'M$[5] = "    "
'M$[6] = "     "
'M$[7] = "      "
'M$[8] = ""

'CLEAR OUT ANY OLD STUFF FROM THE SCREEN.
CLS

'SET UP THE BACKGROUND SCREEN 
'EVERY PIXEL OF EACH CHARACTER COUNTS SO THE MAP IS 8 TIMES BIGGER DUE TO AN 8X8 FONT.
BGSCREEN LAYER, MAP_W * 8, MAP_H * 8

'SET DIRECTION TO STOPPED
DX = 0 : DY = 0
'DRAW THE MAP. X, Y ITERATE OVER THE CHARACTERS IN THE MAP DATA
'I, J ITERATE OVER THE PIXELS OF EACH CHARACTER.
FOR X = 0 TO MAP_W - 1 ' DRAW MAP
 FOR Y = 0 TO MAP_H - 1
  'GET THE X,Y CHARACTER OF THE MAP
  FONT$ = CHRREAD(MID$(M$[Y], X, 1))
  FOR J = 0 TO 7
   FOR I = 0 TO 7
    'READ THE I,J PIXEL FOR THAT CHARACTER
    T1 = VAL(MID$(FONT$, I + (J * 8), 1))
	'CALCULATE HOW THAT MAPS TO A BACKGROUND TILE
    BX = I + X*8 : BY = J + Y*8
	'GIVE THE MAP A BIT OF VARIETY BY OFFSETING THE ROAD TEXTURE 0 TO 3 TILES
    TMP= RND(4) + T_ROAD 'ROAD
    IF T1 == 1 THEN 
	 'IF WE ARE WALL INSTEAD OF ROAD DO THE SAME THING FOR THE ROAD TILE ID
     TMP = RND(4) + T_WALL 'WALL
    ELSEIF T1 == 2 THEN
	 'THE FINISH LINE IS ALWAYS JUST THE ONE TILE.
     TMP = T_FINISH 'FINISH LINE
     IF DX == 0 AND DY == 0 THEN
	  'SINCE X AND Y ARE BUSY, STORE WHERE WE SHOULD START IN DX, DY
	  'WHEN WE FIND THE FINISH LINE
	  '8 IS FOR THE FONT WIDTH, 16 IS FOR THE TILE WIDTH AND THE 4*16 IS TO PUT IT IN THE CENTER OF THE FINISH LINE.
      DX = X * 8 * 16 + (4 * 16)
      DY = Y * 8 * 16 + (4 * 16)
     ENDIF
    ENDIF
	'WRITE THE TILE OUT TO THE BACKGROUND LAYER
    BGPUT LAYER, BX, BY, TMP
   NEXT I
  NEXT J
 NEXT Y
NEXT X
'CLEAR OUT THE GRAPHICS SCREEN. WE MODIFIED IT WHEN CHECKING PIXELS IN A CHARACTER.
GCLS

'--------PLAYER INIT
'CLEAN UP ANY PREVIOUSLY SET UP SPRITES
SPCLR
'SPRITE ID = 0 WILL BE THE PLAYER SHIP.
'SET THE HOME TO 8,8 SO IT ROTATES AROUND ITS CENTER, THEN PLACE IT IN THE 
'CENTER OF THE SCREEN.
SPSET 0, T_SHIP 'SHIP
SPHOME 0, 8, 8
SPOFS 0, HALF_W, HALF_H
 
'SPRITE ID = 1 WILL BE THE SHIP'S EXHAUST.
'SET THE HOME TO THE MIDDLE JUST LIKE THE SHIP AND FOR THE SAME REASON.
'WE PLACE IT THE SAME POSITION AS THE SHIP, BUT BACK A TILE WIDTH
SPSET 1, T_EXHAUST 'EXHAUST
SPHOME 1, 8, 8
SPOFS 1, HALF_W - 16, HALF_H
'LINK THE EXHAUST TO THE SHIP SO THAT IT MOVE/ROTATES WITH THE SHIP. IT SIMPLIFIES THINGS.
SPLINK 1, 0 'LINK TOGETHER

'THE EXHAUST IS AT THE ZERO DISTANCE FOR THE MOMENT AND WE ARE ON THE STARTING LINE
EXHAUST_DIST = 0 : START_LINE = 1
'MOVE THE CURRENT POSITION BACK INTO THE X AND Y VARIABLES
X = DX : Y = DY
'SET THE X,Y SPEED VARIABLES BACK TO ZERO.
DX = 0 : DY = 0
'WE ARE CURRENTLY POINTED AT 180 DEGREES, MOVE BY TWO DEGREES WHEN TURNING AND TOP SPEED IS 16 PIXELS/FRAME
ANG = 180 : DA = 2 : SPEED_MAX = 16
'WE SHOULD KEEP PLAYING, AND SET THE TIMER AT NOW.
GAME_OVER = FALSE : T1 = MILLISEC

'--------MAIN
'THIS IS THE MAIN GAME LOOP. KEEP GOING UNTIL THE GAME OVER FLAG IS SET TO FALSE (BY CLICKING Y)
WHILE GAME_OVER == FALSE
 'GET BUTTON STATE
 B = BUTTON()
 'DEFAULT VALUE FOR FRICTION
 FRICTION = 0.99
 'CHECK IF WE SHOULD EXIT THE GAME
 IF B AND #Y THEN GAME_OVER = TRUE
 'CHANGE THE ANGLE IF TURNING LEFT OR RIGHT.
 IF B AND #RIGHT THEN ANG = ANG + DA
 IF B AND #LEFT THEN ANG = ANG - DA
 'IF ANY DIRECTION IS PRESSED, REDUCE THE FRICTION TO 98%
 IF B AND (ANY_DIR) THEN FRICTION = 0.98
 
 'MAKE SURE THE ANGLE STAYS IN THE 0 TO 360 RANGE
 IF ANG < 0 THEN ANG = ANG + 360
 IF ANG > 360 THEN ANG = ANG - 360
 
 'SLOW DOWN SPEED DUE TO FRICTION
 DX = DX * FRICTION : DY = DY * FRICTION
 
 'GET THE SQUARED MAGNITUDE OF THE SPEED.
 SPEED = (DX * DX) + (DY * DY)
 
 'IF WE HAVEN'T REACHED TOP SPEED AND A IS PRESSED INCREASE SPEED BY 1/20 OF UNIT VECTOR
 IF ((B AND #A) != 0) AND SPEED < SPEED_MAX THEN
  ANG_RAD = RAD((ANG + 180) MOD 360)
  DX = DX + COS(ANG_RAD)/20
  DY = DY + SIN(ANG_RAD)/20
 ENDIF 
 
 'ROTATE THE SHIP TO MATCH THE CURRENT ANGLE.
 SPROT 0, (ANG + 90) MOD 360
 
 'MODIFY THE X, Y COORDINATES BY THE SPEED X, Y COMPONENTS
 X = X + DX : Y = Y + DY
 'DON'T LET THE SHIP LEAVE THE BACKGROUND
 X = MAX(0, MIN(X, (MAP_W * 16 * 8) - 16))
 Y = MAX(0, MIN(Y, (MAP_H * 16 * 8) - 16))
 
 'GET THE BACKGROUND TILE WE ARE CURRENTLY LOCATED OVER
 TMP = BGGET(LAYER, X / 16, Y / 16)
 'BUMP BACK IF WE HIT A WALL 
 IF TMP >= T_WALL AND TMP <= T_WALL + 3 THEN
  DX = -DX
  DY = -DY
 ENDIF
 'FIND THE SPOT TO POSITION THE BACKGROUND LAYER TO KEEP THE 
 'SHIP AT THE MIDDLE OF THE SCREEN OR AT LEAST WITHIN THE BACKGROUND LAYER.
 BX = MIN(MAX(0, X - HALF_W), (MAP_W * 16 * 8) - SCREEN_W)
 BY = MIN(MAX(0, Y - HALF_H), (MAP_H * 16 * 8) - SCREEN_H)
 'MOVE THE BACKGROUN TO THE CORRECT SPOT.
 BGOFS LAYER, BX, BY
 'IF WE ARE ON THE EDGE OF THE MAP WE WON'T BE AT THE CENTER OF THE SCREEN.
 'CONVERT THE WORLD COORDINATES TO SCREEN CORRDINATES FOR THE SHIP
 SPOFS 0, X - BX, Y - BY
 
 'CHECK TO SEE IF WE ARE HOLDING [A] TO ACCELERATE AND ARE NOT AT TOP SPEED.
 IF ((B AND #A) != 0) AND SPEED < SPEED_MAX THEN
  'MOVE THE EXHAUST BACK FROM THE SHIP A BIT AND SCALE UP THE SPEED.
  EXHAUST_DIST = EXHAUST_DIST + 1 : SPEED = SPEED * 700
  'IF THE EXHAUST GOT TOO FAR AWAY MOVE IT BACK AND PLAY A SPEED UP SOUND.
  IF EXHAUST_DIST > 16 THEN EXHAUST_DIST = 6 : BEEP 1
  SPOFS 1, 0, -EXHAUST_DIST
  SPSHOW 1
 ELSE
  'HIDE THE EXHAUST SPRITE WHEN WE AREN'T ACCELERATING.
  SPHIDE 1
 ENDIF
 'CHECK TO SEE IF WE PASSED INTO THE FINISH LINE
 TCHK X, Y
 'LIMIT SPEED TO REFRESH RATE
 VSYNC
WEND
END

'CHECK TO SEE IF WE ENTERED THE FINISH LINE. IF SO, PRINT THE LAP TIME AND PLAY A 
'COIN SOUND.
'PARAMETERS:
'* X: LOCATION OF THE SHIP X-COORDINATE
'* Y: LOCATION OF THE SHIP Y-COORDINATE
'RETURNS:
'* NONE
'
DEF TCHK X, Y
 VAR I, J	'BACKGROUND TILE COORDINATES
 
 '------------TIME
 'TRANSLATE THE WORLD COORDINATES INTO BACKGROUND COORDINATES BY 
 'DIVIDING BY 16 OR THE SIZE OF A TILE.
 I = FLOOR(X / 16) : J = FLOOR(Y / 16)
 
 'IF WE ARE NOT ON THE FINISH LINE SET THE FLAG SO THAT CROSSING INTO THE 
 'FINISH LINE COUNTS
 IF BGGET(LAYER, I, J) != T_FINISH THEN
  START_LINE = 0 
  RETURN
 ENDIF
 
 IF START_LINE != 0 THEN 
  'IF WE WERE ON THE FINISH LINE LAST FRAME, DON'T CHECK IT AGAIN.
  RETURN
 ELSE
  'TO GET THIS FAR WE MUST BE ON THE FINISH LINE AND WEREN'T LAST TIME
  'THE FUNCTION WAS CALLED, SO SET THE FLAG.
  START_LINE = 1
 ENDIF
 
 BEEP 7 'COIN
 'SAVE THE CURRENT TIME.
 T2 = MILLISEC
 'CONTINUE ONLY IF WE HAVE A STARTING TIME.
 IF T1 THEN
  LOCATE 15, 1
  'PRINT OUT THE LAP TIME. NOTE THE FORMAT$ CALL IS TURNING THE NUMBER INTO A 
  'NICE STRING VALUE WITH A TWO DIGIT DECIMAL AMOUNT (SO 3.333333 WILL PRINT AS 3.33
  PRINT "TIME: " + FORMAT$("%03.2F", (T2 - T1) / 1000) + " SEC   ";
  'NEW START TIME IS THE FINISH TIME
  T1 = T2
 ENDIF
END

'POLYFILL FOR PTC ONLY FUNCTION
'THIS GETS THE PATTERN OF PIXELS FOR A CHARACTER IN AN 8X8 FONT.
'PETIT COMPUTER HAD A NICE CALL FOR THIS THAT SMILEBASIC DOESN'T HAVE.
'TO WORK AROUND IT, I PRINT THE CHARACTER TO POSITION 0, 0 THEN READ 
'EACH PIXEL IN THE 8X8 GRID AND RETURN IT AS A STRING OF 0, 1. 
'UNLESS IT IS THE SPECIAL CHARACTER X THAT MARKS THE FINISH LINE, IN THAT
'CASE YOU JUST GET ALL 2'S.
'PARAMETERS:
'* CH$ - CHARACTER TO READ, ASSUMED TO BE ONE SINGLE CHARACTER.
'RETURNS:
'* A STRING OF 64 2'S IF THE SPECIAL CHARACTER X (START/FINISH LINE). OTHERWISE
'  IT WILL RETURN EACH PIXEL OF THE CHARACTER WITH A 0 IF BLACK/EMPTY AND 1 IF FILLED. IT WILL GO LEFT TO RIGHT, TOP TO BOTTOM.
'
DEF CHRREAD(CH$)
 VAR RET$ = ""	'RETURN VALUE
 VAR I, J		'LOOP OVER THE X, Y COORDINATES OF THE CHARACTER
 'CLEAR OUT OLD JUNK THE LAZY WAY.
 GCLS
 'WRITE THE CHARACTER TO POSITION 0, 0 ON THE SCREEN.
 GPUTCHR 0, 0, CH$ 
 FOR J = 0 TO 7
  FOR I = 0 TO 7
   IF CH$ == "X" THEN	'RETURN ALL 2'S IF THE START/FINISH LINE.
    RET$ = RET$ + "2"
   ELSE
    'CHECK TO SEE IF THE PIXEL IS FILLED OR NOT ON THE SCREEN.
    IF GSPOIT(I, J) != 0 THEN
	 'YES, WRITE A 1
     RET$ = RET$ + "1"
    ELSE
	 'NO, WRITE A 0
     RET$ = RET$ + "0"
    ENDIF
   ENDIF 
  NEXT I
 NEXT J
 'RETURN THE ENCODED STRING TO THE CALLER.
 RETURN RET$
END

Hopefully that works for you. I found a few bugs here and there for instance, the wall/road tiles were reversed. I just edited the text file locally, so if there are comments that are too long or are missing the comment marker, I apologize. The function CHRREAD is something I added to cover up for a font reading function that Petit Computer had that Smile Basic apparently does not. The real trick with this one is that we have not just a tile per character, but we have a tile per pixel in each character. You have to use the box drawing characters to not have strange holes everywhere. To try to make things less monotonous, each road/wall tile is taken from the 0 to 3 spaces from id of the road/wall tile. If you play the game two times in a row, you should get a slightly different looking road/wall pattern. You can easily cheat in the game by going in circles in and out of the finish line. If you are playing fair, the trick is to drift through the turns by turning a bit early and having the trajectory slowly take you the correct path instead of just how you are pointed. If you touch the walls you get bumped back in the opposite direction which will cost you time. Oh, and I forgot if you use the new map I made, make sure to update the map_w and map_h variables to match. It should be fairly simple to make your own track if desired.

Oh my gosh, the mad man! Thank you so much for doing this! This and kitesinpowerlines code should do wonders for my program! Thanks again!