Anniversary Game

I made a game in 30 days on my iPad to celebrate an anniversary.

Those who create games often say that games are an expression of what they feel. So when I remembered that my one-year anniversary with Reid Main was a month away, I thought of the perfect gift that he would enjoy, and that I would enjoy making: a game.

The first question was a decision on how big the game would be. The first drafts of what I was planning the game to be ended up being scenes upon scenes of a point-and-click adventure. I figured as long as I had a solid point-and-click framework laid out, each of the scenes would be easy to work with. Boy, did I underestimate the asset creation involved. The amount of artwork needed for this approach would have been tremendous. So I ended up fleshing out a smaller mini-game idea that came to fruition while brainstorming the initial idea.

The game would be something simple and contained. There wasn’t enough time to come up with a story and a framework to present it all, so an experience that was contained would work best. The idea was to essentially play off of classic space shooter games with an added fighting game concept of a “second companion” that had the ability to provide you powerup assistance on occasion.

Code overview

Once I got the basis of a very simply game thought out, I went on to figure out what means would be best to build it. I wanted a solid scripting language that has a history of being used in gaming. I decided on the [lua programming language](http://en.wikipedia.org/wiki/Lua) for its short learning curve and its compatibility with iOS. Other options included Python and SpriteKit.

I first mapped out the parts of the game that I would need:

  • Main() — the Main implementation is the code that first runs when the game has been executed. The Main implementation for the most part will do the screen management which means we need…
  • ScreenGame(), ScreenTitle(), ScreenGameOver(), ScreenWin() — These are the different “screens” in a game. Currently only the main game (ScreenGame), the title screen (ScreenTitle) and game over screen (ScreenGameOver, ScreenWin) are implemented.
  • World(), WorldBlock() — Draws the world, using WorldBlock() objects.
  • Monster(), Loot() — Handles the monster and loot objects created in the World()
  • Reidskie(), ReidskieAttack(), ReidskieBullet() — The hero, Reid. Handles all of Reid’s functions like movement, attack, applying powerups, death, etc.
  • Sweetie() — Reid’s companion. Handles the follow movement and animations on powerup
  • PowerUp(), PowerUpHandler() — Powerups. PowerUpHandler() handles the creation of PowerUp() objects
  • Animate() — Animation class that handles keyframe animations. Used for creating powerup animations for Sweetie()
  • Utils() — A utility class that has common functions used on multiple objects. For example, it handles tinting either Reidskie or Monster when hit.

The game is controlled by using the iPads gyroscope and tapping anywhere on the screen would fire a shot. The aim is to shoot all the enemies (BoBos, as they are called) while picking up hearts for limited-time powerups. You win the game once you have killed enough BoBos!

Notable Pieces of Code

PowerUpHandler

I really enjoyed writing the powerup handler. As you would expect, it handles all of the potential powerups you can get by collecting the little hearts.


powerUpList = {
	{["type"]=1, ["name"]="cuteLook"["param"]="movementSpeed",  ["amount"]=10, ["properName"]="Cute Look", ["properParam"]="Movement Speed" },
	{["type"]=2, ["name"]="sexyDance", ["param"]="attackPower",  ["amount"]=5, ["properName"]="Sexy Dance", ["properParam"]="Attack Power" },
	{["type"]=3, ["name"]="toot", ["param"]="movementSpeed",  ["amount"]=20, ["properName"]="Toot", ["properParam"]="Movement Speed" },
	{["type"]=4, ["name"]="kiss", ["param"]="health",  ["amount"]=10, ["properName"]="Kiss", ["properParam"]="Health" },
}

	

I then later create a PowerUp() object based on a random dice roll


randomNumber = math.floor(math.random(1,powerupLength(powerUpList)))
power = PowerUp(powerUpList[randomNumber]["param"],powerUpList[randomNumber]["amount"])
    
Reidskie

Since the game is controlled by the gyroscope, I really wanted the sprite to animate with the players movement.

First we get what the new position is:


function Reidskie:move(dir)
newPos = self.position + dir * self.movementSpeed
newPos = newPos + self.knockVel
	

Then based on the new position relative to the old position, we draw the appropriate sprite.


if(self.currentAttack == nil) then
	if(self.position.x > newPos.x) then
		sprite("Dropbox:reidskie-back", self.position.x + 5, self.position.y + 25, self.size + 20)
	elseif(self.position.x < newPos.x) then
		sprite("Dropbox:reidskie-forward", self.position.x + 5, self.position.y + 25, self.size + 20)
	-- otherwise draw normal reidskie sprite
	else
		sprite("Dropbox:reidskie-normal", self.position.x + 5, self.position.y + 25, self.size + 20)       
	end
end
	
Building the World

Much of the game mechanics are handled in ScreenGame(). The world is created by World() which is actually randomly generated based on a random seed in ScreenGame()


seed = math.random(5000)
math.randomseed(seed)
	

And then at World(), I generate the world by creating blocks at x and y (where WALL is a point where the character will collide and FLOOR is a point where the character will be able to move freely).


for x = 1,w do
	-- create a new array for blocks on the x axis
	self.blocks[x] = {}
	-- do the same for height
	for y = 1,h do
		-- set tile type as FLOOR
		t = FLOOR
		-- set walls
		if math.random() < 0.1 or x == 1 or y == 1 or x == w or y == h then
			t = WALL
		end

	-- create a block at x,y in the array
	self.blocks[x][y] = WorldBlock(t,x,y)

	-- if the type is wall, insert into the walls array and records
	-- the walls position in blocks array
	if t == WALL then
		table.insert(self.walls, self.blocks[x][y])
		
	

At the same time, I also set randomly generated spawn points for monsters and loots


if math.random() < 0.06 then
	table.insert(self.loot, Loot(self.blocks[x][y].actualPosition))
elseif math.random() < 0.05 then
	table.insert(self.monsters, Monster(reid, self.blocks[x][y].actualPosition))
	

Conclusion

Be sure to check out the full source on GitHub. The game is not yet available for public release of course, but not bad for a months worth of working on this on the side of a full-time job! Its really messy but it serves as a record of my first game!

Posted Jun 21 2016
© 2019 Elsie Ng. All rights reserved. RSS