Game speed in basic

Basic and Machine Language

Moderator: Moderators

ravenxau
Vic 20 Devotee
Posts: 296
Joined: Fri May 28, 2004 10:03 pm

Game speed in basic

Post by ravenxau »

While playing zombie yard, i decided to try a write a routine for moving many enemies will still maintaining good game speed using only basic on an unexpanded vic. this is what i have come up with

Code: Select all

0 gosub 100
1 x=d(rnd(.)*4):pokea(c),32:a(c)=a(c)-x*(peek(a(c)+x)=32)
2 pokea(c),c:c=c+1+10*(c=9):goto1
100 poke36879,8:printchr$(147):d(0)=-22:d(1)=1:d(2)=22:d(3)=-1:dima(9)
101 forx=0to9:a(x)=7726+int(rnd(1)*15)+int(rnd(1)*15)*22:next
102 forx=0to505:poke7680+x,160:next:forx=0to20
103 printchr$(29);"                    ":next:return: rem 20 spaces
the "magic" happens in lines 1 and 2, line 1 has movement and elementary collision detection in 1 statement. line 2 increments and resets the object counter in a single statement. Both of these operations are carried out without the need for if-then statements, which i find are a game programmers nemesis when it comes to fast execution in basic. The main 2 lines are kept as close to the top of the program as possible for maximum speed for the goto.

Currently the program animates 10 objects at a good rate. I did try running it with 30 objects and all 30 were updated in less than a second. It looked a bit clunky but was workable if you really need that many enemies at one time.

This might also be a good routine for a large "Boss" character at the end of a level. just move six or eight characters as a uniform group. The logic for boundary detection would take some effort to work out for a single statement - but would be worthwhile for a good game concept
Android Tablet running Frodo 64 emulator running VIC 20 emulator....
User avatar
Jeff-20
Denial Founder
Posts: 5759
Joined: Wed Dec 31, 1969 6:00 pm

Re: Game speed in basic

Post by Jeff-20 »

ravenxau wrote:While playing zombie yard. . .
Cool! Someone played zombie yard! :lol:
High Scores, Links, and Jeff's Basic Games page.
ravenxau
Vic 20 Devotee
Posts: 296
Joined: Fri May 28, 2004 10:03 pm

Re: Game speed in basic

Post by ravenxau »

Jeff-20 wrote:
ravenxau wrote:While playing zombie yard. . .
Cool! Someone played zombie yard! :lol:
Come on Jeff- you know people play your games, the are after all, AWESOME examples of how to program unexpanded/basic :D
Android Tablet running Frodo 64 emulator running VIC 20 emulator....
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

Double duty of variables can be helpful, too.

In my version of TRON lightcycles, I also use the D() array with all directions (1, -22, -1, 22), but additionally the indices C and H access the shape (like in '59+C') so the character faces the correct direction. This is the inner loop of the game:

Code: Select all

9 GETA$
10 IFA$="C"THENC=0
11 IFA$="{F1}"THENC=1
12 IFA$="Z"THENC=2
13 IFA$="{F7}"THENC=3
14 POKEV+11,140:POKEB,58:POKEB+CO,6:B=B+D(C):IFPEEK(B)<>219THENLI=LI-1:GOTO20
15 POKEB,59+C:SC=SC+1:NL=NL-1:PRINT"{HOME,BLK,7 RIGHT,RVS ON}"SC:POKEV+11,0
16 IFNL<0THENNL=NL+1000:LI=LI+1:GOSUB40
17 IFPEEK(G+D(H))<>219ORRND(1)<.1THENI=C:GOSUB41
18 POKEG,58:POKEG+CO,5:G=G+D(H):IFPEEK(G)<>219THENSC=SC+100:NL=NL-100:B=G:GOTO20
19 POKEG,59+H:GOTO9
It is executed ~8 times a second, reading the keyboard, moving 2 lightcycles, leaving the trails behind, updating the score and checking collisions for both cycles. Some 'extraordinary' conditions (extra live awarded, enemy lightcycle shall turn) are handled in sub-routines, and are barely noticible, when done.
ravenxau wrote:line 2 increments and resets the object counter in a single statement.

Code: Select all

1 x=d(rnd(.)*4):pokea(c),32:a(c)=a(c)-x*(peek(a(c)+x)=32) 
2 pokea(c),c:c=c+1+10*(c=9):goto1
I presume a FOR..NEXT loop would work quite as fast:

Code: Select all

1 forc=0to9:x=d(rnd(.)*4):pokea(c),32:a(c)=a(c)-x*(peek(a(c)+x)=32) 
2 pokea(c),c:next:goto1
if-then statements, which i find are a game programmers nemesis when it comes to fast execution in basic
Is there really a noticable slow-down here? Of course, the next statement after IF..THEN now forcibly must go into a new line. I even can rewrite this using a temporary address variable (replacing x), which removes unnecessary calculations - and the characters don't "blink" when they can't move:

Code: Select all

1 forc=0to9:t=a(c)+d(rnd(.)*4):ifpeek(t)=32thenpokea(c),32:a(c)=t:pokea(c),c
2 next:goto1
This might also be a good routine for a large "Boss" character at the end of a level. just move six or eight characters as a uniform group.
There also is the mighty PRINT statement, which is eminently useful in moving large objects. You can frame the object which spaces, so leftover characters on one side are always deleted:

Code: Select all

PRINT"{5 SPACE,DOWN,5 LEFT,SPACE}ABC{SPACE,DOWN,5 LEFT,SPACE}DEF{SPACE,DOWN,5 LEFT,SPACE}GHI{SPACE,DOWN,5 LEFT,5 SPACE}"
This technique is used in 'Tank-V-Ufo', for example. And the positioning can be done in pure BASIC as follows:

Code: Select all

Q$="{HOME,22 DOWN}" (<- assigned once to during initialising)

PRINTLEFT$(Q$,Y)TAB(X)"..."
Greetings,

Michael
ravenxau
Vic 20 Devotee
Posts: 296
Joined: Fri May 28, 2004 10:03 pm

Post by ravenxau »

Mike wrote:There also is the mighty PRINT statement, which is eminently useful in moving large objects. You can frame the object which spaces, so leftover characters on one side are always deleted:

Code: Select all

PRINT"{5 SPACE,DOWN,5 LEFT,SPACE}ABC{SPACE,DOWN,5 LEFT,SPACE}DEF{SPACE,DOWN,5 LEFT,SPACE}GHI{SPACE,DOWN,5 LEFT,5 SPACE}"
This technique is used in 'Tank-V-Ufo', for example. And the positioning can be done in pure BASIC as follows:

Code: Select all

Q$="{HOME,22 DOWN}" (<- assigned once to during initialising)

PRINTLEFT$(Q$,Y)TAB(X)"..."
yes - this is a great way to move large objects, the only draw back I find is that when two large objects interact, the framing with the spaces causes a terrible amount of flickering. My routine was just a suggestion of a possible solution to avoid this.

Also, using the boolean calculation method of determining outcomes can be translated fairly easily to machine code - good for speed up routines ( if necessary)
Android Tablet running Frodo 64 emulator running VIC 20 emulator....
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

I added quote tags to your previous post. Hope you don't mind. :)

There's also a nice non-obvious way to scroll the entire screen down except the first line:

Code: Select all

PRINT"{HOME,DOWN,LEFT}"CHR$(148):POKE218,PEEK(218)OR128
I use this in Meteor Storm.

And, there I wanted to use as few lines as possible, so the space ship is moved with a Boolean expression, as

Code: Select all

GETA$:A=A+(A$="Z"ANDA>8164)-(A$="C"ANDA<8185)
readily demonstrates. It's not necessary to delete the space ship at the bottom of the screen to move it to a new position, the scroll down takes care of that. ;)

Greetings,

Michael
IsaacKuo
Vic 20 Hobbyist
Posts: 147
Joined: Tue Aug 04, 2009 5:45 am

Post by IsaacKuo »

Hello--new guy who just dusted off his old (NTSC) VIC-20...

I notice the code at the top uses a "*" to multiply with. I don't know if it's any faster, but I'd use an "AND" instead of "*". Back in my 68000 coding days, an "AND" would be faster than a multiply.

The results of an AND against -1 is positive, rather than negative, so keep that in mind. It's not a drop in replacement for "*"--you need to swap "-" and "+" also.

This tight little IF-less technique inspires me to code a Robotron style game for my VIC. After I figure out all those old POKE locations...
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

Hi, IsaacKuo,

welcome to Denial! :)
IsaacKuo wrote:I don't know if it's any faster, but I'd use an "AND" instead of "*".
Interesting idea! If in the expression 'X AND P' the predicate P is either 0, or -1, your method indeed works, but you are restricted to integer values of X.
The results of an AND against -1 is positive, rather than negative, so keep that in mind.
Yep, CBM BASIC does not distinguish between AND on Bool, or integer values. However, both sides are converted to signed 16-bit ints, and all bits are ANDed. Comparisons give 0, or -1 (all bits 1) as result.

Of course, on an 68000, AND is a single logical operation on the ALU, multiply involves lots of ANDs, shifts, and ADDs. But here we're against many other instructions in the BASIC interpreter surrounding these two operations, on a 6502 CPU:

The conversion to integer of both sides, in case of AND, may eat up the speedup of that method, compared to multiplying these values: Assignments, and value fetches of integer variables, and AND/OR/NOT always involve conversions between floating point and integer. Within expressions, CBM BASIC generally uses float values.

This program measures the speed of both methods. R is evaluated 10 times within a loop, so computing P uses a smaller fraction of time:

Code: Select all

1 T1=TI:FORX=1TO1000
2 P=-INT(RND(1)*2):REM either 0, or -1
3 R=XANDP:R=XANDP:R=XANDP:R=XANDP:R=XANDP
4 R=XANDP:R=XANDP:R=XANDP:R=XANDP:R=XANDP
5 NEXT:T2=TI
6 PRINT T2-T1
gives: T2-T1 ~= 2370 jiffies. I.e. time ~ 40 seconds.

R=X*P (10 times) instead gives: T2-T1 ~= 2035 jiffies, ~34 seconds.

So your method, as interesting it is, is slower. Oh, well. :(
This tight little IF-less technique inspires me to code a Robotron style game for my VIC. After I figure out all those old POKE locations...
Good luck!

Michael
IsaacKuo
Vic 20 Hobbyist
Posts: 147
Joined: Tue Aug 04, 2009 5:45 am

Post by IsaacKuo »

Interesting! I don't know the details of CBM basic, I just remember it being slow. Your test suggests that replacing:

Code: Select all

A=A+(A$="Z"ANDA>8164)-(A$="C"ANDA<8185)
with:

Code: Select all

A=A-(A$="Z")*(A>8164)+(A$="C")*(A<8185)
might actually be marginally faster. But I don't know how the extra parenthesis brackets affect the speed.

Of course, for a user input routine the speed factor doesn't really matter.

I'll have to do some tests to satisfy my curiosity. I'm going to have a lot of moving bullets and robots, so I need to figure out whether I should bother with integer variables and such. Thanks for showing the code for making a timing test! I didn't know about "TI".
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

IsaacKuo wrote:

Code: Select all

A=A+(A$="Z"ANDA>8164)-(A$="C"ANDA<8185)
Let's see:

Code: Select all

1 A=8170
2 T1=TI:FORT=1TO1000
3 A$="H"
4 A=A+(A$="Z"ANDA>8164)-(A$="C"ANDA<8185)
5 A$="Z"
6 A=A+(A$="Z"ANDA>8164)-(A$="C"ANDA<8185)
7 A$="C"
8 A=A+(A$="Z"ANDA>8164)-(A$="C"ANDA<8185)
9 NEXT:T2=TI
10 PRINT T2-T1
exercises the statement with 'left', 'right', and 'do-nothing' commands, and it gives 3772 jiffies.

Replacing 'AND' with ')*(', and exchanging signs gives ... 3572 jiffies. So, you're right. :shock:

I mainly chose AND as there are Bool values on both sides of AND. Replacing the constants with variables would make a bigger difference (8185, for example, is internally processed as (((8*10+1)*10+8 )*10+5, every time, so here's one of the *big* time-wasters).
Of course, for a user input routine the speed factor doesn't really matter.
Well, indeed it gives a small speed-up in the main loop of the game. :)

Greetings,

Michael
wimoos
Vic 20 Afficionado
Posts: 348
Joined: Tue Apr 14, 2009 8:15 am
Website: http://wimbasic.webs.com
Location: Netherlands
Occupation: farmer

Speed of compound conditions

Post by wimoos »

What also may help in certain cases is the following:

10 IF ..simple condition.. THEN IF ..complex condition.. THEN ..statement..

instead of

10 IF ..simple condition.. AND ..complex condition.. THEN ..statement..

In the first example the complex condition is not evaluated when the simple condition is already false.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

That's the reason I don't always use conditional expressions, especially when a IF ... THEN statement can "prevent" the permanent execution of a complicated expression located in the THEN clause, which normally only would have been evaluated with low probability (but always in the conditional expression variant).

Here's an interesting thread regarding the speed of the access to variables.

Michael
wimoos
Vic 20 Afficionado
Posts: 348
Joined: Tue Apr 14, 2009 8:15 am
Website: http://wimbasic.webs.com
Location: Netherlands
Occupation: farmer

Post by wimoos »

What also speeds up quite a bit in a condition is to remove '<>0'.

For example, compare the following:
10 IF A<>0 THEN ..statement..
against:
10 IF A THEN ..statement..

But also:
10 IF A<>B THEN ..statement..
against:
10 IF A-B THEN ..statement..

Only works properly in IF-THEN and is not to be used in compound conditions.

The alternative is bound to be quicker because a comparison is always determined as:
1. calculate the difference between the two terms
2. check the difference against zero (like SGN)
3. XOR the result of 2. against the requested comparison
4. return true or false based on the result of 3.

Using the alternative saves steps 2. and 3. and saves parsing characters
Last edited by wimoos on Wed Aug 05, 2009 2:51 am, edited 2 times in total.
carlsson
Class of '6502
Posts: 5516
Joined: Wed Mar 10, 2004 1:41 am

Post by carlsson »

IsaacKuo wrote:I don't know the details of CBM basic, I just remember it being slow.
Bzzt! That is a false statement! Among the 6502 and Z80 based home computers, Commodore Basic is one of the ten fastest. In particular considering it runs on a ~1 MHz machine, while some others run at almost twice the clock frequency.

Of course compared to compiled or even better hand optimized machine code, all forms of Basic will appear slow but relatively speaking Commodore Basic is faster than many of its competitors.
Anders Carlsson

Image Image Image Image Image
Boray
Musical Smurf
Posts: 4064
Joined: Mon May 03, 2004 10:47 am

Post by Boray »

carlsson wrote:but relatively speaking Commodore Basic is faster than many of its competitors.
At least Basic V2 I would guess. Later versions are slower.
PRG Starter - a VICE helper / Vic Software (Boray Gammon, SD2IEC music player, Vic Disk Menu, Tribbles, Mega Omega, How Many 8K etc.)
Post Reply