Introduction to Mobile Game Development
Written July, 2015, by Rachel J. Morris
Introduction to Mobile Game Development by Rachel J. Morris is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. Based on a work at http://www.moosader.com/learn/ccckc/introduction-to-mobile-game-development/.
With Grab the Treasure I, we learned how to make a basic, tap-based game. However – I, personally, find a game is more fun if I have a character that I’m actually playing as. An avatar. So, let’s change our game up to have a character that we control.
Instead of tapping on the screen to get the treasure automatically, we will tap in a location to tell our character where to go. Then, when the character gets close enough to the treasure, they will collect it.
To do this, we will have to change our game a bit so that, when the user taps the screen, we set a goal (x, y) coordinate. Then, each frame, the character will compare where it is currently at to where it wants to be, and move accordingly. Finally, we will need to implement the distance formula in order to check how close the character is to the treasure, so it can be picked up.
We will keep the timer, where the treasure will move after some time, so that the player needs to navigate their character successfully before the treasure disappears. And, in Grab the Treasure III, we will add enemies.
Adding an avatar
In your folder of art for the game, there should be a player.png in there. Make sure it is added to our project. Adding our character is just a matter of loading the texture and the bitmap, and drawing it to the screen:
player = Bitmap.new( Texture.new( "content/player.png" ) ) stage:addChild( player )
When the player taps the screen, we will set a goal (x, y) coordinate that the character will move towards, so we need variables for these. I’ve also created a playerX and playerY variable so we can easily change these values. But remember, the actual Bitmap won’t change position until we call player:setPosition !
playerX = 320/2 - 16 -- Start player in center of screen playerY = 480/2 - 16 goalX = playerX goalY = playerY player:setPosition( playerX, playerY )
We are setting the goalX and goalY variables to equal playerX and playerY so that, when the game starts, the character will already be at the goal position, and won’t be moving.
Setting the goal position when the screen is tapped
Now, we’re going to need to update how the program reacts when the screen is tapped.
Goodbye old logic:
function HandleClick( event ) if ( treasure:hitTestPoint( event.x, event.y ) ) then pickupSound:play() score = score + 1 scoreText:setText( "Score: " .. score ) RandomlyPlaceTreasure() end end
Now, we need to do the following:
- Set goalX to where the screen was tapped horizontally (event.x)
- set goalY to where the screen was tapped vertically (event.y)
Simple enough, right?
function HandleClick( event ) goalX = event.x goalY = event.y end
But if we run the game, the character doesn’t move towards the goal. The goalX and goalY will be set, but there isn’t anything in the program to tell the player’s character to move towards it. For that, we’re going to have to update our Update function, which is called every frame.
Currently, Update is handling the countdown timer for the treasure, and relocating the treasure if the timer reaches 0. We will want to keep this logic, but we want to add more logic so that the player will move.
- If the goal is to the left of the character, move the character left.
- Otherwise, if the goal is to the right of the character, move the character right.
- If the goal is above the character, move the character up.
- Otherwise, if the goal is below the character, move the character down.
But, how can we tell where these are in relation to each other? With our greater-than and less-than operators!
|<=||Less Than or Equal To|
|>=||Greater Than or Equal To|
|~=||Not Equal To|
Now, in order to use these, we will have to understand the coordinate plane of computers. Hint: it isn’t exactly like it was in algebra…
A quick overview of the computer’s coordinate plane
In Algebra, the coordinate plane looked like this:
But on a computer display, it looks more like this:
Where, the x and y axis’ visible area on-screen is what your computer or phone resolution is set to. Our games, for example, have been running at a resolution of 320×480 by default.
The origin, (0, 0), is at the very top-left of the screen. The more X increases, the further right it is. The lower the value of X, the further left. And the bigger Y is, the further down the screen it will be. To raise something upward, the Y would need to decrease.
Using this knowledge of the coordinate plane on a computer, we can compare two points. For example – The green dot is below the blue dot, so greenY > blueY. The green dot is to the right of the blue dot, so greenX > greenY. If the green dot wanted to move towards the blue dot, we would say greenX = greenX – 1, and greenY = greenY – 1, to move it left and up by 1 pixel.
Moving our character toward the goal
We have a goalX and goalY, so every frame of the game, we are going to compare the goal location to the player location. The logic looks something like this:
( goalX < playerX ) -- The goal is to the LEFT ( goalX > playerX ) -- The goal is to the RIGHT ( goalY < playerY ) -- the goal is ABOVE ( goalY > playerY ) -- the goal is BELOW
We will then use if then and elseif then statements to decide the player’s logic: If the goal is to the left, move left. Else, if the goal is to the right, move right. And if neither of these is the case, the player won’t move either direction.
Within our Update function, this code will be added below our treasure countdown timer code:
-- Compare left/right if ( goalX < playerX ) then -- Goal is to the left, move left playerX = playerX - 1 elseif ( goalX > playerX ) then -- Goal is to the right, move right playerX = playerX + 1 end -- Compare up/down if ( goalY < playerY ) then -- Goal is above, move up playerY = playerY - 1 elseif ( goalY > playerY ) then -- Goal is below, move down playerY = playerY + 1 end -- Update bitmap position player:setPosition( playerX, playerY )
Now, let’s test the game. When you tap somewhere on the screen, is your character moving towards it?
The last part of Grab the Treasure II will be to actually have the program recognize when the character is near the treasure, so that we can add to the score and move the treasure elseware.
What is the distance between the player and the treasure?
How would you go about getting distance between two points on a coordinate plane?
No, no, no, you’re thinking of slope. That’s not the right formula.
Do you remember the distance formula? Well, we’re going to need to turn that formula into computer code…:
Now, I’m not going to go into how to derive this formula, though really it is not very difficult. You can find plenty of information about this online, or from your Algebra textbook. But, if you’re not interested in knowing the logic behind it, for now you can just rest happily that the formula already exists, and you just need to put it in code. And, I’ve already put it in code for you.
Many concepts in programming and game programming have been explored in the past, whether you’re going to generate a random world like in Minecraft or want to make realistic looking water, it’s a lot of fun to work on coming up with your own algorithms, but there is also a lot of information out there that you can also study if need be. But, we’re not building Minecraft right now, we just want distance. And we have it.
So, every time our game updates, we’re going to move the player towards the goal. Since the player’s position could be moving every frame, we also want to check every frame to see whether the player is near the treasure. Now, the player doesn’t need to be exactly on top of the treasure – both the player and treasure have a width and height, and aren’t just points in space, so Distance doesn’t need to be exactly 0. 20 pixels or less should do the trick.
local treasureX, treasureY = treasure:getPosition() if ( Distance( playerX, playerY, treasureX, treasureY ) < 20 ) then score = score + 1 scoreText:setText( "Score: " .. score ) pickupSound:play() RandomlyPlaceTreasure() end
One final thing. Remember how the coordinate plane has (0, 0) in the top-left corner of the screen? The (x, y) coordinates of our Bitmaps are also the top-left of the image, rather than the center-point.
It would look a lot nicer if we were comparing their positions based on the center of the Bitmap instead of from the corner. So, when we're creating our player and treasure Bitmaps, let's also set the anchor point to half-way. This specifies where the (x, y) coordinates come from.
treasure = Bitmap.new( treasure_texture ) treasure:setAnchorPoint( 0.5, 0.5 ) player = Bitmap.new( Texture.new( "content/player.png" ) ) player:setAnchorPoint( 0.5, 0.5 )
Now, try testing it out! The following things should be working correctly:
- If the player taps the screen, the character will move towards that area, and stop when it gets there.
- If the character is near the treasure, the score counter will go up and the treasure will be moved.
- If the character doesn't get to the treasure in time, the treasure will be moved automatically after a few seconds.
Next time, we are going to add enemies. We will reuse our Distance function, and even our code to move the player towards the goal - but this time, the enemies will move towards us.
Sample code is available on the GitHub page at: