Some observations:
Your use of 'single shot' gosub is probably costing you a lot of execution time. unrolling 1000 through 4000 and just letting them run would probably speed it up a lot.
when you detect the start of game and the launch, you aren't flushing the keyboard probe by peeking 49168... this means if you don't move and lose it will auto-relaunch the ball, and if you start the game with space, the ball will launch automatically.
converting key to button$ may be convenient from a code legibility standpoint, but it's a pointless conversion/typecast -- same for the subtracting 128 from the keyboard read. Do the math, don't make the interpreter have to work harder on figuring out fixed values.
Rather than having a separate if statements to move the paddle, make sure the paddle stays in bounds, and redraw the paddle -- you could combine those down to single statements.
Instead of redrawing the entire paddle, just erase and draw the ends -- 2 pixels is probably faster than a line AND a pixel.
Think about this:
4020 if xv<>0 then x=x+xv
4025 if yv<>0 then y=y+yv
If they are zero, adding them won't change them, and as a rule of thumb doing a flat addition is going to be FASTER than an IF statement, even when false.
Longer variable names also take longer for Applesoft basic to parse on the real hardware.... The book says to stick to one, I've found the difference between one or two is negligible.
Oh, and in Applesoft using line numbers greater than 999 is slower, don't know why, but it is.'
Between local emulation and my IIe Platinum, I did a quick rewrite:
Code:
10 s=-16336 : py=8 : goto 50
30 z=peek(s)+peek(s)-peek(s)+peek(s)-peek(s)+peek(s)-peek(s)
40 return
50 gosub 800
60 flash : htab(10) : vtab(16) : print "PRESS ANY KEY TO START"
70 k=peek(49152) : if k<128 goto 70
80 z=peek(49168)
100 normal : gr : color=3
110 hlin 0,39 at 0
120 hlin 0,39 at 39
130 vlin 0,39 at 39
140 vtab(22) : htab(3) : print "A = UP"
150 htab(3) : print "Z = DOWN"
160 vtab(22) : htab(24) : print "Q = QUIT"
170 htab(20) : print "SPACE = LAUNCH BALL"
200 x=2 : y=py+3 : oy=1 : ox=0 : dx=0 : dy=0
210 color=15 : vlin py,py+6 at 1
250 k=peek(49152) : if k=209 goto 900
300 if (k<>193 or py=1) goto 350
310 color=0 : plot 1,py+6
320 py=py-1
330 color=15 : plot 1,py
340 goto 400
350 if (k<>218 or py=32) goto 400
360 color=0 : plot 1,py
370 py=py+1
380 color=15 : plot 1,py+6
400 if (dx<>0) goto 500
410 y=py+3
420 if k<>160 then goto 600
430 z=peek(49168)
440 dx=1 : dy=1
450 if y>20 then dy=-1
500 x=x+dx : y=y+dy
510 if x<0 goto 700
520 if x=38 then dx=-1 : gosub 30
530 if (y<=1 or y>=38) then dy=-dy : gosub 30
540 if (dx<0 and x=2 and y>=py and y<=py+6) then dx=1 : gosub 30
600 if (oy=y and ox=x) goto 690
610 color=0 : plot ox,oy : color=15 : plot x,y
620 ox=x : oy=y
690 for l=0 to 200 : next : goto 250
700 for t=0 to 60 step 2 : gosub 30
710 for n=0 to t : next : next
720 color=0 : plot ox,oy
730 goto 200
800 text : home
810 vtab(5) : htab(17) : print chr$(162)+"PONG"+chr$(162)
820 vtab(8) : htab(5) : print "Originally By Alexander G. Tozzi"
830 htab(8) : print "http://www.wumpustales.com"
840 print : htab(7) : print "Rewritten By Jason M. Knight"
850 htab(8) : print "http://www.deathshadow.com"
860 return
900 gosub 800
910 print : htab(12) : print "Thanks for playing." : print
To break it down:
I renamed everything to one or two letter vars using a consistent naming convention. Helps to list your vars in basic thanks to the cryptic names -- I always try to maintain such a list.
Code:
[b]Variables:[/b]
dx == direction of ball on x axis
dy == direction of ball on y axis
k == keyboard input
ox == last ball x position
oy == last ball y position
py == paddle location
s == speaker address
t,n,i == counters
x == ball x position
y == ball y position
z == discard (used for speaker and key strobe clear)
Lines:
10 -- The memory location -16336 is the speaker 'toggle'; I added sound effects and putting this in a variable lets us 'peek' that location faster getting us a bit higher a pitch. Set the paddle to the starting position, then the goto skips over the speaker function.
30-40 -- Since the speaker function is going to be called a lot and gosubs are faster when at the start of the code in applesoft basic, we really want that front and center. Quickly reading this memory location toggles a flip-flop connected to the speaker. Toggling it back to back gives a roughly 110khz chirp in Basic (yes, applesoft basic is that slow) -- so 7 toggles gives us roughly a fifteenth of a second chirp. Decent for when the ball strikes a surface. I alternate between + and - there so that the result is more likely to stay within byte-bounds -- as toggling an overflow on a 8 bit cpu can slow down how fast we can call those peeks.
50-80 -- First I call the credits. I left this as a function so credits could be called a second time when exiting the program. Drawing the flashing press any key is no different, nor is the keyboard peek/loop -- what is different is that I then peek 49168 after the check to 'flush' the value so that if you hit space to start, the ball doesn't automatically launch.
100-170 -- no real changes apart from my omitting some of the vtab's as unneccessary. Print automatically goes to the next line, so why waste time saying to go where it already is?
200-210 -- Sets up our game start values and draws the paddle in it's starting spot. I also call this later on to reset the ball position when you 'miss'.
250 -- keyboard handler and abort on q.
300-340 -- "a" handler. As mentioned checking by numeric value, and if the paddle y position is where we even allow it to move. If neither is true we just goto to skip this section. If py isn't 1, we can move it, so first we erase the bottom pixel, move it, then draw the bottom pixel. Cleaner/simpler than erasing a pixel then drawing the whole line. The goto skips over our check for 'z' since obviously if it reaches that point, we don't need to do that.
350-380 -- 'z' handler, same basic check, just we flip the redraw.
400-450 -- since dy and dx are both either non-zero or zero, there's no reason to ever check both! So if dx (and by extension dy) isn't zero, the ball is launched so skip this section. Otherwise we set the ball to the center of the paddle, check for the launch key... if it's not the launch key skip past all the game logic to the redraw... otherwise flush the keyboard strobe (so if you lose without moving it doesn't auto-launch again!), set it in motion. Notice I set dy to one and then run an if statement. This is simpler/faster than playing with multiple if statements or playing with goto/gosub.
500-540 -- move it, check for loss and goto to the loss handler. Otherwise check for our bounces, and if it is bouncing not only flip direction but play our little 'bounce' sound.
600 to 620 -- if the ball didn't move, don't erase and redraw it. Otherwise erase it's old location and draw the new one. Little bit of extra variables needed, but has the advantage of no flickering of the ball when it's not moving. It also reduces the delay between erasing it and drawing it so the overall movement effect seems smoother too.
690 -- same delay you had.. though it runs a bit faster since I'm not saying which variable to next. By default next will work with whatever flow operation is at the top of the stack, so not saying the variable makes for/next loops faster in Applesoft basic... Then of course it loops back to the keyboard check.
700-730 -- "Loss" routine. Plays a "beyooo" noise, then erases the ball, then does a GOTO back to our game reset/startup.
800-860 -- the Credits. Notice once again I skip using vtab anywhere near as much and let print do most of the work.
900 -- Our exit handler. Show the credits again, show 'thanks for playing', done.
... and that's it! About 200 bytes less code, runs anywhere from 10-15% faster so you may want to play with the 'delay' loop. Often wish the apple had an actual system timer you could trap for things like this, but thankfully Apple milked the same piss poor clock speed for a decade and a half so unlike the PC side of things you don't have to worry about every machine that can run it native being anywhere from 4.77mhz to 4ghz...
Hope this helps, or at least gets you thinking on different ways of handling things.
Mein gott, to think it's been almost twenty-five years since I did any real coding in Applesoft Basic... but this at least gave me something to play with now that I've dragged my IIE platinum out of storage... made me remember a lot of the oddball quirks and headaches the language had -- like the lack of an ELSE statement.