# improve player movement

## Recommended Posts

I've already received some great help to improve my little game. My next step is to see if there is a way to improve the "joystick" (actually keyboard arrow keys in Altira) moving the character. Sometimes when you press an arrow key the character does not move until you tap the arrow key a second time, and other times the character moves 2 spaces with one key press.

The movement code is as follows. The first 4 IF STK lines are to block the character movement like wall. Touching the wall costs a life, thus when the movements jumps two spaces, you hit the wall and inadvertently die. Thus the lack of movement control is a struggle.

```90 ME=SCREEN+I+20*Y
91 IF PEEK(ME)=120 THEN FOR BK=50 TO 30 STEP -3:FOR BH=5 TO 15 STEP +5:SOUND 0,BK,12,BH:NEXT BH:NEXT BK
92 SOUND 0,0,0,0
94 IF PEEK(ME)=120 THEN SCO=SCO+2:HU=HU+1:POSITION 13,23:? #6;SCO
95 IF PEEK(ME)=234 THEN GOSUB 1900
96 POKE ME,250:IF HU>=35 THEN BM=1:GOTO 500
97 IF (HU<35 AND SCO<0) THEN 800
100 STK=PEEK(54016):TR=PEEK(53264)
101 IF STK=247 AND PEEK(SCREEN+(I+1)+20*Y)=12 THEN GOSUB 9094
102 IF STK=251 AND PEEK(SCREEN+(I-1)+20*Y)=12 THEN GOSUB 9094
103 IF STK=254 AND PEEK(SCREEN+I+20*(Y-1))=12 THEN GOSUB 9094
104 IF STK=253 AND PEEK(SCREEN+I+20*(Y+1))=12 THEN GOSUB 9094
110 IF STK=247 THEN POKE SCREEN+I+20*Y,0:IF PEEK(SCREEN+(I+1)+20*Y)<>12 THEN I=I+1:IF I>=18 THEN I=18
120 IF STK=251 THEN POKE SCREEN+I+20*Y,0:IF PEEK(SCREEN+(I-1)+20*Y)<>12 THEN I=I-1:IF I<=1 THEN I=1
130 IF STK=254 THEN POKE SCREEN+I+20*Y,0:IF PEEK(SCREEN+I+20*(Y-1))<>12 THEN Y=Y-1:IF Y<=1 THEN Y=1
140 IF STK=253 THEN POKE SCREEN+I+20*Y,0:IF PEEK(SCREEN+I+20*(Y+1))<>12 THEN Y=Y+1:IF Y>=22 THEN Y=22
150 IF TR=0 THEN GOSUB 300
200 GOTO 90
```

##### Share on other sites

The problem is time...you should find ways to streamline your code (not rechecking STK or the PEEK locations is a start).  What is at 9094?

##### Share on other sites

You'd be better off using the STICK(0) function - PEEK(54016) gives both sticks so you'd get unwanted values if the other one is used.

Also, I believe STICK(0) should be a little bit faster.

Another thing - using boolean operators can be quicker than IF/THEN.

In some circumstances (depends on the game) you can do your position calculations then check if it's a legal move, then copy the new X/Y to current.

There's also a trick using X=X+PTRIG(0)-PTRIG(1) which can do a quick horizontal position change.  It's slightly more work to do vertical.

##### Share on other sites
The routine as the stick read is used, could be interesting for direct machine code speed.
It's that kind of Joystick read that causes basic games to run evil by always too late reaction of the game.

Isn't it better to do direct read of the stick value , then branch to check the screen?
Also: adding or substracting x and y...
After the controls for "move to the right" has been identified, check whether the value is 18 or not. Do not any calculation then. Just jump back to the main routine, if the value is 18. And so on.
If the max. or min. value isn't reached, do the further subroutine.
And, why is the sound command in that main loop?

##### Share on other sites
Btw. The GOSUB command is only for subroutines, if you don't know where to point to , after a Subroutine is done.But it looks like that Subroutine at 9094 just turns back to the main loop.
Exchanging that with GOTO, will bring some benefit.

##### Share on other sites
Posted (edited)
And, you do peek(ME) two times.
The sound routine could also run without much interfering the gameplay

In line 94 you could add a "bk=50"
Then change the line 91 to get "If bk<>50 ....
change 91 to 92
Put into line 91 : If bk=29 then sound 0,0,0,0: goto 94

In line (new 92 ) , just substract bk-3 , instead of the for next function.

At the end you have to find yourself the best sound solution. Edited by emkay

##### Share on other sites

The problem is time...you should find ways to streamline your code (not rechecking STK or the PEEK locations is a start).  What is at 9094?

9094 is the start of 4 lines of code for losing a life if you hit a "wall piece" (char 12) as detected by the first 4 STK lines. The code plays a sound, subtracts 1 life, checks if no lives remain, then either returns or uses a GOTO to trigger end game sequence.

##### Share on other sites

The sound command is in the main loop to pay a sound each time the player collects an item (char 120), instead of leaving and returning to the main loop.

The "non-touchable" area of the game is not just the edges of the screen. The player starts in the middle and the screen is filled will non-touchable characters, embedded with 35 items to collect. Thus I must check each direction of movement to see if a non-touch char was hit and not let the player move on to it.

Is it better to use a GOTO 9094 then after that code runs use another GOTO to retrun to the main loop, over using a GOSUB?

I should combiine the two IF PEEK(ME)=120 into one line if it will fit or should I use another GOTO/GOSUB?

I will look into STICK(0) over PEEK(54016)

##### Share on other sites
Posted (edited)

how would either of these routines that I found work over using PEEK(632)? (I read PEEK(632) is slightly quicker than STICK(0) thus I changed my code from PEEK(54016) to PEEK(632).) Either way I found no improvement in play between the two.

```5 GOSUB 500
10 P=STICK(0)
20 X=USR(1764,P)
30 Y=USR(1781,P)
50 ON X GOTO 80,60,70
60 ? "LEFT";X;" ":GOTO 80
70 ? "RIGHT";X;" ":GOTO 80
80 ON Y GOTO 110,90,100
90 ? "UP";Y:GOTO 10
100 ? "DOWN";Y:GOTO 10
120 GOTO 10
500 REM POKES STICK READER INTO LOCATIONS S06E4 TO \$06FE
510 FOR I=1764 TO 1790:READ X:POKE I,X:NEXT I
520 DATA 104,104,133,213,104,41,12,74,74,73,3,24,105,1
530 DATA 133,212,96,104,104,133,213,104,41,3,76,237,6
540 RETURN

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

10 REM Atari 800 Joystick Driver Demonstration Program
20 REM James E. Korenthal, 1981
30 GOSUB 1000:REM load machine language code
40 X=0:Y=1:REM direction codes (for read ability)
50 POKE 201,8:REM use narrow columns
60 JSTICK=0
70 DELTAX = USR(JOY,JSTICK,X)-1:REM geT horizontal change
80 DELTAY = 1-USR(JOY,JSTICK,Y):REM get vertical change
90 PRINT DELTAX;",";DELTAY,:REM print values
120 GOTO 60:REM loop until break or reset is pressed
1000 REM subroutine to load joystick driver machine code
1010 DIM JOY\$(29):JOY=ADR(JOY\$):REM setup code Be pointer
1020 FOR J=JOY TO JOY+28 :REM read and store 29 bytes
1040 REM machine code goes here:
1050 DATA 104,104,104,170,104,189,120,2,40,176,2,74,74,41
1060 DATA 3,56,233,2,16,2,169,2,133,212,169,0,133,213,96

```
Edited by pmgraphics

##### Share on other sites
Posted (edited)

This ASM routine will not help as the problem is in the code around.

You can check joystick and move x and y this way:

```s=stick(0)
dx=(s=7)-(s=11)
dy=(s=13)-(s=14)
x=x+dx:y=y+dy
```
It can be speeded up with
```s=stick(0):x=x+(s=7)-(s=11):y=y+(s=13)-(s=14)
```
For checking boundaries you can use a similar trick:
```x = x + scrX*((x=-1) - (x=scrX))
y = y + scrY*((y=-1) - (y=scrY))```

Where scrX and scrY are dimensions of the screen.

This wraps x and y around the screen, it can be modified to your needs.

Definitely avoid GOSUBs as these are slow. Better have some fall through code or even inline if the subroutine is small.

Edited by pirx

##### Share on other sites
Posted (edited)
Avoiding calculations is the best optimization in Atari Basic.
Shortening the command line doesn't usually mean to get more speed. Edited by emkay

##### Share on other sites

101 IF STK=247 AND PEEK(SCREEN+(I+1)+20*Y)=12 THEN GOSUB 9094

Just looking at this: The calculation from +20*Y=12 doesn't seem to make a lot of sense. Are you actually using fractions i.e. Y<1? If so and you have to, just do a YY=Y*20 at the head of the tree and be done with it. It looks like you were headed that way in the first line but switched/continued using Y instead of ME. Just a point of order, don't do multiplication on an Atari, it sacrifices speed for accuracy.

The branching and continual evaluation of the expression all lead to the same GOSUB 9094 and the only thing that changes is the STICK so the tree should only have that in it. You'd probably be better off with a VBI sound routine too, hard to say if you don't already have it of course. :)

##### Share on other sites

Here is my revised code. I got rid of the numerous STK PEEKs and POKEs.

Old code lines 91,92, and 94 are consolidated into line 91 with a GOSUB to perform  the sound and score increase for collecting an item (char 120)

93 replaces old code lines 101-104 which detect a blocking/lose life character (char 12)

Lines 110 to 145 are the cleaner player movement and boundary code (thanks Moonsweeper), over all the PEEKs and POKEs with calculations in them.

GOSUB 210 is code for collecting an item

GOSUB 1900 is code for earning an extra life

GOSUB 9094 is code for losing a life

I still have the GOSUBs since they are things that happen after player movement and must complete before player moves again.

```23 I=10:Y=12:SCRI=18:SCRY=22
90 ME=SCREEN+I+20*Y
91 IF PEEK(ME)=120 THEN GOSUB 210
92 IF PEEK(ME)=234 THEN GOSUB 1900
93 IF PEEK(ME)=12 THEN I=I-DI:Y=Y-DY:ME=SCREEN+I+20*Y:GOSUB 9094
96 POKE ME,250
100 STK=PEEK(632):TR=PEEK(644)
110 DI=(STK=7)-(STK=11)
115 DY=(STK=13)-(STK=14)
120 I=I+DI:Y=Y+DY
125 IF I>=SCRI THEN I=SCRI
130 IF I<=1 THEN I=1
135 IF Y>=SCRY THEN Y=SCRY
140 IF Y<=1 THEN Y=1
145 IF STK<>15 THEN POKE (ME),0
150 IF TR=0 THEN GOSUB 300
155 IF (HU<35 AND SCO<0) THEN 800
200 GOTO 90
```

##### Share on other sites

FWIW: There is an old thread that had some of the same topics. It had some tips for using ON GOTO/GOSUB that may apply. It just scaled the results to line numbers by doing an multiplication to get line numbers on a scale with the expressions. I think you have it cornered though, code is starting to look tight and efficient. If you don't need it don't use it IMO. Multiple line numbers are slow too because Atari stores the line numbers in floating point format I think. A single line of ON GOSUB if the overhead of the calculation wasn't to bad would probably be quicker. As it is, the way you are doing now is pretty clear and easy to understand compared to a crammed line of confusion.

http://atariage.com/forums/topic/146867-optimising-code-in-turbobasic/?hl=%2Boptimising#entry3176724

##### Share on other sites

Here's a video of a run through of the game.

https://youtu.be/xIvToVF_Qag

##### Share on other sites

What I was told (a very long long long time ago, when I was writing BASIC programs for other systems), is that with interpreted BASIC, put the subroutines at the top of the program and jump (GOTO) over them in the very first lines.

An interpreter typically searches from the beginning of the program for the line of GOSUBs (and GOTOs), and if they are at the beginning this search is faster.

Don't know if this is the same in ATARI BASIC. Just wanted to mention it.

regards,

chris

##### Share on other sites

Yes, it is the same in Atari Basic. Turbo Basic XL alleviates it by storing a table with line addresses.

##### Share on other sites

A key to maintaining speed is to minimize any sort of branch in Atari Basic - the use of tables (arrays) and logic operations instead of IF/THEN can help out there.

A little used trick with games that only want left/right movement is to use the PTRIG() funciton, which corresponds to joystick left/right.

So you can have something like:

1000 X=X+PTRIG(0)-PTRIG(1)

which is way quicker than using IF/THEN and should be slightly faster than boolean/logic operations.

Of course you'd want a bounds check as well but that can be done with a boolean operation such as

1010 X=X-(X>159)+(X<0)

## Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.