I've found that taking other people's code and modifying it can be just as rewarding as making your own programs (especially if the code was badly written to start with). You might think I'm crazy willingly taking on spaghetti code but it is really satisfying when you come out with something that works well and is better structured to allow you to add your own ideas to the program.
I think I understand why people who renovate old sports cars love it so much.
I've also learned some things that will help with my own programs.
For instance, writing as many remarks as possible helps, even if it is obvious what a piece of code does.
My coding process is to write code inside the main loop until I see a block that I can turn into a function or subroutine. Commenting on what each bit of code does makes it easy to find blocks you can turn into subroutines or functions.
There was something else I learnt but I've forgotten what it was.
I stumbled across a charming little game called Bounce, written by Databug, and I have been tinkering with it since yesterday.
Here is the original code:
`gravity program
randomize timer()
lines = 10
dim x#(2)
dim y#(2)
dim velocity#(2)
size = 2:targets = 4
dim xvelocity#(2)
dim yprev#(2)
dim linesx(lines)
dim linesx2(lines)
dim linesy(lines)
dim collision(2)
dim points(2)
winner = 10
do
x#(1) = 340.00000
x#(2) =340.00000
y#(1) = 0.00000
y#(2) = 0.00000
velocity#(1) = 0.00000
velocity#(2) = 0.00000
gravity# =0.00981
xvelocity#(1) = 0.00
xvelocity#(2) = 0.00 `24
center text 320, 240, "Be the first to score " + str$(winner) + " points by hitting the blue circle"
center text 320, 255, "Move with the arrow keys. Up and Down control how high you bounce."
center text 320, 270, "The 'R' key resets the map."
wait key
repeat
for n = 1 to lines
linesx(n) = rnd(600) + 20
repeat
linesx2(n) = rnd(600) + 20
until linesx2(n) > linesx(n)
linesy(n) = rnd(440) + 20
next n
targetx = rnd(640 - (2*targets)) +targets
targety = rnd (480 - (2*targets)) +targets
collect = 0
repeat
cls
ink rgb(0,255,255),0
circle targetx, targety, targets
for z = 1 to 2:collision(z) = 0
ink rgb(255,255,255),0
if z = 2
ink rgb(255,0,0),0
endif
print points(z)
circle x#(z), y#(z), size
velocity#(z) = velocity#(z) + gravity#
y#(z) = y#(z) + velocity#(z)
if y#(z) > 480 - size
y#(z) = 480 - size
velocity#(z) = velocity#(z) * -0.7
collision(z) = 1
xvelocity#(z) = xvelocity#(z) * 0.6
endif
if y#(z) < 0 + size
y#(z) = 0 + size
velocity#(z) = velocity#(z) * -0.7
endif
for n = 1 to lines
if z = 1
line linesx(n),linesy(n),linesx2(n),linesy(n)
endif
if x#(z) > linesx(n) and x#(z) < linesx2(n)
if yprev#(z) <= linesy(n) - size and y#(z) > linesy(n) - size
y#(z) = linesy(n) - size
velocity#(z) = velocity#(z) * -0.7
collision(z) = 1
xvelocity#(z) = xvelocity#(z) * 0.6
endif
endif
next n
yprev#(z) = y#(z)
if x#(z) <= 0 + size or x#(z) >= 640 - size
xvelocity#(z) = xvelocity#(z) * -1
if x#(z) < 0
x#(z) = 0 + size
endif
if x#(z) > 640
x#(z) = 640 - size
endif
endif
if collision(1) = 1
if leftkey() = 1 and downkey() <> 1
xvelocity#(1) = xvelocity#(1) - 0.4
if upkey() <> 1
velocity#(1) = velocity#(1) - 0.09
endif
endif
if rightkey() = 1 and downkey() <> 1
xvelocity#(1) = xvelocity#(1) + 0.4
if upkey() <> 1
velocity#(1) = velocity#(1) - 0.09
endif
endif
if upkey() = 1
velocity#(1) = velocity#(1) - 0.4
endif
if downkey() = 1
velocity#(1) = velocity#(1) + 0.2
endif
endif
if collision(2) = 1
if x#(2) < targetx
xvelocity#(2) = xvelocity#(2) + 0.4
velocity#(2) = velocity#(2) - 0.09
endif
if x#(2) > targetx
xvelocity#(2) = xvelocity#(2) - 0.4
velocity#(2) = velocity#(2) - 0.09
endif
if y#(2) > targety + 15
velocity#(2) = velocity#(2) - 0.4
endif
if y#(2) < targety
if x#(2) < targetx
xvelocity#(2) = xvelocity#(2) + 0.4
velocity# = velocity# +0.2
endif
endif
endif
x#(z) = x#(z) + xvelocity#(z)
if x#(z) + size > targetx - targets and x#(z) - size < targetx + targets
if y#(z) + size > targety - targets and y#(z) - size < targety + targets
collect = 1
points(z) = points(z) + 1
endif
endif
next z
until collect = 1 or inkey$() = "r"
if points(1) = winner
cls
ink rgb(255,255,255),0
center text 320, 240, "Congratulations! You won!"
wait key
endif
if points(2) = winner `here
cls
center text 320, 240, "You lost..."
wait key
endif
until points(1) = 10 or points(2) = 10
cls
repeat
input "Play again?(y/n)", yesno$
until yesno$ = "y" or yesno$ = "n"
if yesno$ = "n"
end
endif
loop
As you can see it is pretty messy and doesn't use a single subroutine or function! Everything is crammed inside the main loop. There are lots of loops here and it was quite a job to untangle them but here is my effort so far:
rem Program Name: Gravity Program
rem Edited by: OBese87
rem Date: 25/03/2010
rem ==================
rem Original Author: Databug
rem 1st Edition Date: 09/11/2008
rem ==================
set display mode 640,480,32
hide mouse
randomize timer()
sync rate 60
sync on
rem Constants
gravity# =0.00981
lines = 10
size = 2
targetd = 4
winner = 5
p1color = rgb(255,255,0)
p2color = rgb(255,0,0)
targetcolor = rgb(255,0,255)
lvlcolor = rgb(0,255,255)
txtcolor = rgb(255,255,255)
dim x#(2)
dim y#(2)
dim yprev#(2)
dim xvelocity#(2)
dim yvelocity#(2)
dim collision(2)
dim points(2)
dim linesx1(lines)
dim linesx2(lines)
dim linesy(lines)
rem === MAIN ===
Start_Game:
gosub initialize_game
rem loop till game finished
while points(1) < winner and points(2) < winner
gosub generate_level
rem play through current level until target collected or "r" to generate new level.
while collect = 0 and inkey$() ! "r"
ink targetcolor,0
circle targetx, targety, targetd
for z = 1 to 2
collision(z) = 0
if z = 1 then ink p1color,0 else ink p2color,0
print points(z)
circle x#(z), y#(z), size
gosub platforms_and_collision
gosub border_collision
if collision(1) = 1 then gosub control_player
if collision(2) = 1 then gosub control_cpu
if x#(z) + size > targetx - targetd and x#(z) - size < targetx + targetd
if y#(z) + size > targety - targetd and y#(z) - size < targety + targetd
collect = 1
points(z) = points(z) + 1
endif
endif
next z
sync:cls
endwhile
endwhile
rem end of game
if points(1)=winner then msg$ = "Congratulations! You won!" else msg$ = "You lost..."
ink txtcolor,0
repeat
cls
center text 320,240,msg$
input "Play again?(y/n)", yn$
yn$ = upper$(yn$)
until yn$ = "Y" or yn$ = "N"
if yn$ = "Y" then goto start_game
END
rem === SUBROUTINES
border_collision:
if y#(z) > 480 - size
y#(z) = 480 - size
yvelocity#(z) = yvelocity#(z) * -0.7
collision(z) = 1
xvelocity#(z) = xvelocity#(z) * 0.6
endif
if y#(z) < 0 + size
y#(z) = 0 + size
yvelocity#(z) = yvelocity#(z) * -0.7
endif
if x#(z) <= 0 + size or x#(z) >= 640 - size
xvelocity#(z) = xvelocity#(z) * -1
if x#(z) < 0 then x#(z) = 0 + size
if x#(z) > 640 then x#(z) = 640 - size
endif
return
`//
control_cpu:
if x#(2) < targetx
xvelocity#(2) = xvelocity#(2) + 0.4
yvelocity#(2) = yvelocity#(2) - 0.09
endif
if x#(2) > targetx
xvelocity#(2) = xvelocity#(2) - 0.4
yvelocity#(2) = yvelocity#(2) - 0.09
endif
if y#(2) > targety + 15
yvelocity#(2) = yvelocity#(2) - 0.4
endif
if y#(2) < targety
if x#(2) < targetx
xvelocity#(2) = xvelocity#(2) + 0.4
yvelocity# = yvelocity# +0.2
endif
endif
return
`//
control_player:
if leftkey() = 1 and downkey() ! 1
xvelocity#(1) = xvelocity#(1) - 0.4
if upkey() ! 1 then yvelocity#(1) = yvelocity#(1) - 0.09
endif
if rightkey() = 1 and downkey() ! 1
xvelocity#(1) = xvelocity#(1) + 0.4
if upkey() ! 1 then yvelocity#(1) = yvelocity#(1) - 0.09
endif
if upkey() = 1 then yvelocity#(1) = yvelocity#(1) - 0.4
if downkey() = 1 then yvelocity#(1) = yvelocity#(1) + 0.2
return
`//
generate_level:
rem place target and set its collection variable to false
targetx = rnd(640 - (2*targetd)) +targetd
targety = rnd(480 - (2*targetd)) +targetd
collect = 0
rem generate random platforms
for n = 1 to lines
linesx1(n) = rnd(600) + 20
linesx2(n) = linesx1(n) + rnd(620-linesx1(n)) + 20
linesy(n) = rnd(440) + 20
next n
return
`//
initialize_game:
x#(1) = 340.0
x#(2) = 340.0
y#(1) = 0.0
y#(2) = 0.0
yvelocity#(1) = 0.0
yvelocity#(2) = 0.0
xvelocity#(1) = 0.0
xvelocity#(2) = 0.0
points(1) = 0
points(2) = 0
cls
center text 320, 240, "Be the first to score " + str$(winner) + " points by hitting the blue circle"
center text 320, 255, "Move with the arrow keys. Up and Down control how high you bounce."
center text 320, 270, "The 'R' key resets the map."
sync:wait key
return
`//
platforms_and_collision:
rem apply gravity
yvelocity#(z) = yvelocity#(z) + gravity#
y#(z) = y#(z) + yvelocity#(z)
rem apply lateral velocity
x#(z) = x#(z) + xvelocity#(z)
ink lvlcolor,0
for n = 1 to lines
rem only draw platforms once
if z = 1 then line linesx1(n),linesy(n),linesx2(n),linesy(n)
if x#(z) > linesx1(n) and x#(z) < linesx2(n)
if yprev#(z) <= linesy(n) - size and y#(z) > linesy(n) - size
y#(z) = linesy(n) - size
yvelocity#(z) = yvelocity#(z) * -0.7
collision(z) = 1
xvelocity#(z) = xvelocity#(z) * 0.6
endif
endif
next n
rem update yprev
yprev#(z) = y#(z)
return
`//
I haven't added any new features yet, it should work exactly the same as the original.
"With games, we create these elaborate worlds in our minds, and the computer is there to do the bookkeeping." - Will Wright