216. Building a game – demo
I’ll now build a small game using the ideas from the previous post.
It is extremely simple, so the game code doesn’t get in the way of seeing how the design works.
- A spaceship flies around inside a circle, and
- you touch the screen to make it go toward your finger.
- Keep the spaceship inside the circle as long as possible.
Key functions
Here are the important functions – setup, draw and touched. You can see how simple the code is to read.
--these are all the "states", each has a table of functions Splash,MainMenu,Help,Settings={},{},{},{} Play,GameOver,HighScores={},{},{} function setup() ship=readImage("Space Art:Red Ship Bank Left") ChangeState(Splash) --set state to splash initially end function draw() state.draw() end function touched(t) --not all states need a touched function --so we'll check if there is one if state.touched then state.touched(t) end end
Splash state
The splash state draws the spaceship coming towards us for 5 seconds, then switches to the main menu. Here is the code.
function Splash.draw() background(255) sprite(ship,WIDTH/2,HEIGHT/2,ElapsedTime*50) if ElapsedTime>5 then ChangeState(MainMenu) end end
The ChangeState function not only changes the state variable, but it also runs a setup function if there is one. I added this, because if, for example, you replay the game, you need to reset the ship position, scores, etc, each time.
function ChangeState(s) state=s --change state if s.setup then s.setup() end --run setup if there is one end
Main menu
Now here are all the main menu functions
--list of main menu options, and the new state to set --when they are touched MainMenu.options={{"Help",Help}, {"Settings",Settings}, {"Play",Play}, {"High Scores",HighScores}} function MainMenu.setup() SetupMenu(MainMenu.options) end function MainMenu.draw() DrawMenu() end function MainMenu.touched(t) local s=MenuTouch(t) if s then ChangeState(s) end end
Note that the setup function runs another function SetupMenu. This is because we also have a Settings menu which works the same way as this one, and I don’t want to write the same code twice. So SetupMenu is used for both sets of menus, making the code above very compact. There is also a DrawMenu function which is used by all menu states.
Note also that the touched function calls MenuTouch, which tests if we touched one of the menu items. If we did, it returns the second item from the MainMenu.options table above, eg if we touched “High Scores”, it will return HighScores, which is the table for the high scores state. The touched function will then change states.
I’m not going to explain these “helper” functions, SetupMenu, DrawMenu and MenuTouch, in this post, because they are fairly straightforward. You can see them in the full code, linked at the end.
Help state
The code for the Help menu item is simple enough
function Help.draw() background(184, 206, 215, 255) text("HELP TEXT GOES HERE",WIDTH/2,HEIGHT/2) end function Help.touched() ChangeState(MainMenu) --returns to main menu end
Settings
The settings menu is another menu, of course.
--(say) we want to run one of these functions --when something is touched function SettingDifficulty() print("Set difficulty") --your code in here end function SettingJumpLevel() print("Jumping levels") --your code in here end function SettingMain() --back to main menu ChangeState(MainMenu) end --list of settings options, and the functions to run, when touched Settings.options={{"Difficulty",SettingDifficulty}, {"Jump to level",SettingJumpLevel}, {"Return to Main Menu",SettingMain}} function Settings.setup() SetupMenu(Settings.options) end function Settings.draw() DrawMenu() end function Settings.touched(t) --if something is touched, run the function returned f=MenuTouch(t) if f then f() end end
You can see that this uses the same menu functions as MainMenu, to set up, draw, and test for touches on menu items.
The touched function is a little different because the menu items aren’t other states, ie we don’t want to go away from the Settings state if we touch one of them. Instead, we want to write a function for each item and run it if that item is touched. The Settings.options table tells us what function to run for each item.
Play
The Play state does need a setup function, as you can see.
function Play.setup() pos=vec2(WIDTH/2,HEIGHT/2) --initial position vel=vel or vec2(1,0) --direction speed=1 --speed startTime=ElapsedTime end function Play.draw() background(0) Play.DrawShip() end function Play.DrawShip() pos=pos+vel speed=math.min(10,speed+0.01) fill(236, 236, 233, 50) ellipse(WIDTH/2,HEIGHT/2,600) pushMatrix() translate(pos.x,pos.y) --see note below rotate(math.deg(math.atan2(vel.y,vel.x))-90) --see note sprite(ship,0,0) popMatrix() --end of game when you move >300 pixels from centre of screen if pos:dist(vec2(WIDTH/2,HEIGHT/2))>300 then state=GameOver end end function Play.touched(t) vel=vec2(t.x-pos.x,t.y-pos.y):normalize()*speed end
The ship rotates, to point to the last touch. We have to subtract 90 degrees, because although the ship starts off moving to the right – which is an angle of 0 degrees in Codea – the image is drawn facing up the screen, so we need to rotate it an additional 90 degrees to the right, ie -90 degrees.
Note that the touched function subtracts the current position from the touched point to get direction, and uses the normalize function to give it a length of 1, so we can then multiply by speed.
Game Over and High Scores
I won’t show them here because they are very simple (in fact, I haven’t programmed high scores, because it depends on how you want to store user names and scores). You can see them in the full code below.
Summary
I hope you agree that this approach makes it far easier to build, debug, and add more features to your program, because it is laid out so clearly, and broken into small parts that can be modified on their own, rather than as part of a huge tangle of code.
Full code
Trackbacks & Pingbacks