What's the most efficient way to define a sprite in basic?

ページ 2/2
1 |

By DamnedAngel

Champion (286)

DamnedAngel さんの画像

30-05-2021, 14:21

Pineapple wrote:

Thanks for the replies, but I am trying to optimize more for size than for speed.

Depending on the nature of your problem, you could have pretty optimized solutions.
If you're trying to squeeze your program into a tenliner or alike, the answers above are probably the best.
Now, if you are running out of space in RAM or ROM, you could take advantage of MSX's architecture and the format you plan to have/distribute your program and optimize it in size and, perhaps, speed-wise too!

First, let us establish a baseline.
Suppose the following program to build 16 32x32 sprites:

10 SCREEN2,2:DEFINTA-Z
15 TIME=0
20 DIMA$(15)
100 A$[0]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
110 A$[1]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
120 A$[2]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
130 A$[3]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
140 A$[4]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
150 A$[5]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
160 A$[6]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
170 A$[7]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
180 A$[8]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
190 A$[9]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
200 A$[10]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
210 A$[11]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
220 A$[12]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
230 A$[13]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
240 A$[14]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
250 A$[15]="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C"
300 FORS=0TO15:B$="":FORI=1TO31STEP2:B$=B$+CHR$(val("&H"+MID$(a$[s],I,2))):NEXT:SPRITE$(0)=B$:NEXT
500 A=TIME
510 SCREEN 0
520 PRINT A

The sprite routine (data+code, lines 20-300) takes 1390 bytes in program space, some more space in variable/string space and runs in 166 frames in an MSX2+ 60Hz machine in WebMSX.

The whole program takes 186 frames to run if executed with

time=0:run"a.bas"

Now, if you're embedding you MSXBASIC in a cartridge image (ROM file), you could insert your 32x16=512 sprite bytes somewhere in you rom file and simplify your program to (supposing sprite data in &hBE00-&hBFFF):

10 SCREEN2,2:DEFINTA-Z
15 TIME=0
100 FORI=0TO511:VPOKEBASE(9)+I,PEEK(&hBE00+i):NEXT
500 A=TIME
510 SCREEN 0
520 PRINT A

Now your sprite "routine" is just line 100, and is 43 bytes long. With the 512 bytes of data, it consumes 555 bytes of your ROM, instead of the original 1390 bytes, and no space in string area. The execution, however, jumps from 166 frames to 290 (VPOKE is a slow instruction) and the whole program executed with

time=0:run"a.bas"

takes 303 frames, instead of the original 186. A simple routine in assembler well under 100 bytes could solve that speed problem.

Finally, if you plan to have you program distributed as a BAS file in a disk, you could have all your sprite data in a VRAM dump file, previously saved with

BSAVE"SPRITE.SC2",base(9),base(9)+16*32-1,S

Following that approach, your BASIC program now becomes:

10 SCREEN2,2:DEFINTA-Z
15 TIME=0
100 BLOAD"SPRITE.SC2",S
500 A=TIME
510 SCREEN 0
520 PRINT A

Again your sprite "routine" is just line 100, and it takes only 17 bytes of RAM, instead of the original 1390 bytes, and no space in variable area.
The execution of the BLOAD takes only 6 frames, in opposition to the original 166 frames, and the whole program executed with

time=0:run"a.bas"

takes 19 frames, instead of 186.

Note: you can use this approach if you intend to use cassete tape as well. Just record your sprite file after your basic program.

Hope that helps.

By gdx

Enlighted (6437)

gdx さんの画像

31-05-2021, 02:52

Like I said before, I think using the same variable takes less memory, and the speed doesn't have to change much.

10 SCREEN2,2:DEFINTA-Z
15 TIME=0: S=0
100 A$="1111111111111111111111111111111111111111111111111111111111111111": GOSUB500
110 A$="2222222222222222222222222222222222222222222222222222222222222222": GOSUB500
120 A$="3333333333333333333333333333333333333333333333333333333333333333": GOSUB500
130 A$="4444444444444444444444444444444444444444444444444444444444444444": GOSUB500
140 A$="5555555555555555555555555555555555555555555555555555555555555555": GOSUB500
150 A$="6666666666666666666666666666666666666666666666666666666666666666": GOSUB500
160 A$="7777777777777777777777777777777777777777777777777777777777777777": GOSUB500
170 A$="8888888888888888888888888888888888888888888888888888888888888888": GOSUB500
180 A$="9999999999999999999999999999999999999999999999999999999999999999": GOSUB500
190 A$="3C70E0E0E0E0703E1F0E030D0E1E1E3C3C0E070707070E7CB8D0E0F0F078783C": GOSUB500
300 S=TIME
400 SCREEN0: PRINT S: END
500 B$="":FORI=1TO31STEP2:B$=B$+CHR$(val("&H"+MID$(a$,I,2))): NEXT I: SPRITE$(S)=B$: S=S+1: RETURN

Otherwise, BLOAD is the best solution when the listing is not needed.

By DamnedAngel

Champion (286)

DamnedAngel さんの画像

01-06-2021, 04:06

gdx wrote:

Like I said before, I think using the same variable takes less memory.

You are right. This uses 500 bytes less than my baseline and runs in 98 cycles, instead of 166 - probably due to the lack of array indexing.

Now, an interesting effect is that it should not take less string area. MSXBASIC does create indexes for every variable in the array, but it does not copy the content to string area in this case. It rather points the variable to the constant in the source code. It is pretty smart and efficient! Big smile

ページ 2/2
1 |