Quantcast
Channel: Envato Tuts+ Code - Mobile Development
Viewing all 1836 articles
Browse latest View live

Tuts+ is Hiring Android & Java Course Instructors

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-22929

Are you an experienced Android developer looking for the next step in your career? Have you considered sharing your knowledge through teaching comprehensive online video courses?

We're growing our Code course topics here at Tuts+, expanding into teaching more mobile content areas, including Android. It's been a while since we've covered Java so we're hoping to work on some new Java content too! This is a unique opportunity to become part of the core Tuts+ instructor team.

What We're Looking For

  • You have extensive experience working with both Java and Android SDK and possibly other technologies.
  • You have some experience and are comfortable with mentoring, teaching or screencasting.
  • You love learning and are constantly expanding your knowledge of new technologies.

What Is a Course?

Tuts+ courses provide students with in-depth video training on a specific topic. Here’s how the process works:

  • Create 90+ minutes of video-based teaching.
  • Present with screencasts and slides.
  • Organize your course into chapters and bite-size lessons.
  • Teach skills comprehensively from start to finish.

Why Teach for Tuts+?

  • Work from home in your own time.
  • Give back to the community and share your skills teaching others.
  • Get paid a competitive per course rate of $3,500 USD.
  • We'll provide you with curriculum and screencasting setup support.

If you've created online video before we'd love to hear about it, but it's not essential. We'll get you set up with equipment, and we have a team of people ready to help you get started.

Interested? Get in Touch

  1. Prepare a short application video following the instructions below.
  2. Complete our application form answering a few questions about why you’d be suitable as a Tuts+ instructor, and include an accessible link to your application video in the Screencast Video section.

Special Instructions

In three minutes or less, give us a whirlwind tour of an interesting Android library.

We’re not concerned with audio quality at this point, or which library you choose. We’d just like to see how you teach.

Applications close on 14 January 2015, but the sooner you can get your application in, the better! We'll be reaching out to promising candidates as quickly as possible. 

2014-12-23T09:42:46.000Z2014-12-23T09:42:46.000ZJoel Bankhead

Quick Tip: Leveraging the Power of Git Stash

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-22988

Imagine that you're working on a feature in a Git-controlled software project. You're right in the middle of making some changes when you get a request to fix a critical bug. To start resolving the issue, you need a new branch and a clean working directory. When it comes to basic Git commands, you have two options:

  • Run git reset --hard to remove your uncommitted changes.
  • Record your incomplete work as a new commit.

The former option loses all of your work while the latter results in a partial commit that isn’t meaningful. Neither of these scenarios is all that desirable.

This is where the git stash command comes into play. Like git reset --hard, it gives you a clean working directory, but it also records your incomplete changes internally. After fixing the critical bug, you can re-apply these changes and pick up where you left off. You can think of git stash as a "pause button" for your in-progress work.

Prerequisites

This tutorial assumes that you have installed Git and that you're familiar with its basic workflow. You should be comfortable staging changes, creating commits, and working with branches. You'll also need a Git repository to experiment on.

1. Stashing Changes

Before you can run git stash, you need to have some uncommitted changes in your Git repository. For example, if you edited a file called foo.py, your git status output would look like this:

On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   foo.py

To stash these changes, simply execute git stash without any arguments.

git stash

This will take both your staged and unstaged changes, record them internally, then clear the working directory. This gives you the opportunity to switch to a new branch and develop other features without worrying about your partial commit messing anything up.

2. Re-Applying Stashed Changes

When you're ready to come back to your incomplete work, run the following command to re-apply the stashed changes:

git stash pop

The most recently stashed changeset will re-appear in your working directory and you can continue exactly where you left off. That's all there is to it.

3. Resolving Conflicts

Much like the git merge command, git stash pop can result in conflicts if the same sections of source code have changed since you executed git stash. When this happens, you'll see the following message after running git stash pop:

Auto-merging foo.py
CONFLICT (content): Merge conflict in foo.py

You'll also find the affected file listed under the Unmerged paths section in the git status output, as well as the affected lines in the source file.

<<<<<<< Updated upstream
print("Recently committed changes");
=======
print("Incomplete work");>>>>>>> Stashed changes

You'll need to manually resolve the conflict in the source file, but you usually don't want to commit it immediately like you would after a git merge conflict. Most of the time, you'll continue working on your unfinished feature until you have prepared a meaningful commit. Then, you can simply add it to the index and commit it as usual. In other words, you can treat git stash pop conflicts just like any other uncommitted changes.

4. The Stash Stack

For most scenarios, the above commands are all you need when it comes to a "pause button". But, understanding how stashed changes are represented opens the door for more advanced usage.

So far, we've only been talking about stashing a single changeset. However, each time you run git stash, uncommitted changes are stored on a stack. This means that you can stash multiple changesets at the same time.

This is useful in the early stages of development when you're not sure which direction you want to take. Instead of losing your changes with git reset --hard, you can keep your work-in-progress snapshots on the stash stack in case you want to re-apply one of them later.

You can inspect the stash stack with the list parameter.

git stash list

If you had previously executed git stash three times, this would output something like the following:

stash@{0}: WIP on new-feature: 5cedccc Try something crazy
stash@{1}: WIP on new-feature: 9f44b34 Take a different direction
stash@{2}: WIP on new-feature: 5acd291 Begin new feature

The git stash pop command always re-applies the most recent snapshot, the one at the top of the stash stack. But, it's also possible to pick and choose which stashed snapshot you want to re-apply with the apply command. For example, if you wanted to re-apply the second set of changes, you would use the following command:

git stash apply stash@{1}

Just like git stash pop, the changes will re-appear in your working directory and you can continue working on the incomplete feature. Note that this will not automatically remove the snapshot from the stash stack. Instead, you'll need to manually delete it with the drop command.

git stash drop stash@{1}

Again, working with the stash stack is more of an edge case for most Git users. The git stash and git stash pop commands should suffice for most of your needs, although git stash list can also prove useful if you forgot where your last stash operation took place.

Conclusion

Committing meaningful snapshots is at the heart of any Git workflow. Purposeful, encapsulated commits make it much easier to navigate your project history, figure out where bugs were introduced, and revert changes.

While not exactly an everyday command, git stash can be a very convenient tool for creating meaningful commits. It allows you to store incomplete work while avoiding the need to commit partial snapshots to your permanent project history. Keep this in mind the next time you wish you could pause whatever you were working on and come back to it later.

2015-01-05T16:45:38.000Z2015-01-05T16:45:38.000ZRyan Hodson

Create a Space Invaders Game in Corona: Implementing Gameplay

$
0
0
Final product image
What You'll Be Creating

In the first part of this series, we se tup some defaults for the game and laid the foundation for transitioning between scenes. In this part, we'll begin implementing the game's gameplay.

1. A Word about Metatables

The Lua programming language does not have a class system built in. However, by using Lua's metatable construct we can emulate a class system. There is a good example on the Corona website showing how to implement this.

An important thing to note is that Corona's Display objects cannot be set as the metatable. This has to do with how the underlying C language interfaces with them. A simple way to get around this is to set the Display object as a key on a new table and then put that table as the metatable. This is the approach that we'll take in this tutorial.

If you read the above article on the Corona website, you will have noticed that the __Index metamethod was being used on the metatable. The way the __Index metamethod works, is that when you try to access an absent field in a table, it triggers the interpreter to look for an __Index metamethod. If the __Index is there, it will look for the field and provide the result, otherwise it will result in nil.

2. Implementing PulsatingText Class

The game has text that continuously grows and shrinks, creating a pulsating text effect. We will create this functionality as a module so we can use it throughout the project. Also, by having it as a module, we can use it in any project that would require this type of functionality.

Add the following to the pulsatingtext.lua file you created in the first part of this tutorial. Make sure this code and all code from here on is placed above where you are returning the scene object.

local pulsatingText = {}
local pulsatingText_mt = {__index = pulsatingText}

function pulsatingText.new(theText,positionX,positionY,theFont,theFontSize,theGroup)
      local theTextField = display.newText(theText,positionX,positionY,theFont,theFontSize)
      
local newPulsatingText = {
    theTextField = theTextField}
    theGroup:insert(theTextField)                                             
	return setmetatable(newPulsatingText,pulsatingText_mt)
end

function pulsatingText:setColor(r,b,g)
  self.theTextField:setFillColor(r,g,b)
end

function pulsatingText:pulsate()
	transition.to( self.theTextField, { xScale=4.0, yScale=4.0, time=1500, iterations = -1} )
end

return pulsatingText

We create the main table pulsatingText and the table to be used as the metatable pulsatingText_mt. In the new method, we create the TextField object and add it to the table newPulsatingText that will be set as the metatable. We then add the TextField object to the group that was passed in through the parameter, which will be the scene's group in which we instantiate an instance of PulsatingText.

It's important to make sure that we add it to the scene's group so it will be removed when the scene is removed. Finally, we set the metatable.

We have two methods that access the TextField object and perform operations on its properties. One sets the color by using the setFillColor method and takes as parameters the R, G, and B colors as a number from 0 to 1. The other uses the Transition library to make the text grow and shrink. It enlarges the text by using the xScale and yScale properties. Setting the iterations property to -1 makes the action repeat forever.

3. Using the PulsatingText Class

Open start.lua and add the following code to the scene:create method.

function scene:create(event)
    --SNIP--
    local   invadersText =  pulsatingText.new("INVADERZ",display.contentCenterX,display.contentCenterY-200,"Conquest", 20,group)
    invadersText:setColor( 1, 1, 1 )
    invadersText:pulsate()
end

We create an new TextField instance with the word "INVADERZ", set its color, and call the pulsate method. Notice how we passed the group variable as a parameter to ensure the TextField object gets added to this scene's view hierarchy.

I have included a font in the downloads named "Conquest" that has a futuristic look to it. Make sure you add it to your project folder if you want to use it. I downloaded the font from dafont.com, which is a great website for finding custom fonts. However, make sure you adhere to the license the font author has put in place.

To use the font, we also need to update the project's build.settings file. Take a look at the updated build.settings file.

settings = {
    orientation =
    {
       default ="portrait",
        supported =
        {
          "portrait"
        },
    },
    iphone =
    {
        plist=
        {
            UIAppFonts = {
                    "Conquest.ttf"
                }
        },
    },
}

If you test the project now, you should see the text was added to the scene and pulsates as expected.

4. Star Field Generator

To make the game a little more interesting, a moving star field is created in the background. To accomplish this, we do the same as we did with the PulsatingText class and create a module. Create a file named starfieldgenerator.lua and add the following to it:

local starFieldGenerator= {}
local starFieldGenerator_mt = {__index = starFieldGenerator}

function starFieldGenerator.new(numberOfStars,theView,starSpeed)
    local starGroup = display.newGroup()
    local allStars     ={} -- Table that holds all the stars

    for i=0, numberOfStars do
		local star = display.newCircle(math.random(display.contentWidth), math.random(display.contentHeight), math.random(2,8))
		star:setFillColor(1 ,1,1)
		starGroup:insert(star)
		theView:insert(starGroup)
		table.insert(allStars,star)
    end
	local newStarFieldGenerator = {
        allStars    =  allStars,
        starSpeed = starSpeed
    }
	return setmetatable(newStarFieldGenerator,starFieldGenerator_mt)
end


function starFieldGenerator:enterFrame()
	self:moveStars()
	self:checkStarsOutOfBounds()
end


function starFieldGenerator:moveStars()
        for i=1, #self.allStars do
              self.allStars[i].y = self.allStars[i].y+self.starSpeed
        end

end
function  starFieldGenerator:checkStarsOutOfBounds()
	for i=1, #self.allStars do
		if(self.allStars[i].y > display.contentHeight) then
			self.allStars[i].x  = math.random(display.contentWidth)
			self.allStars[i].y = 0
		end
	end
end

return starFieldGenerator

We first create the main table starFieldGenerator and the metatable starFieldGenerator_mt. In the new method, we have a table allStars that will be used to hold a reference to the stars that are created in the for loop. The number of iterations of the for loop is equal to numberOfStars and we use the Display object's newCircle method to create a white circle.

We position the circle randomly within the game screen bounds and also give it a random size between 2 and 8. We insert each star into the allStars table and place them into the view that was passed in as a parameter, which is the scene's view.

We set allStars and starSpeed as keys on the temporary table and then assign it as the metatable. We need access to the allStars table and starSpeed properties when we move the stars.

We'll use two methods to move the stars. The starFieldGenerator:moveStars method does the moving of the stars while the starFieldGenerator:checkStarsOutOfBounds method checks if the stars are out of the screen's bounds.

If the stars are out of the playing screen area, it generates a random x position for that particular star and sets the y position just above the top of the screen. By doing so, we are able to reuse the stars and it gives the illusion of a never-ending stream of stars.

We call these functions in the starFieldGenerator:enterFrame method. By setting the enterFramemethod directly on this object, we can set this object as the context when we add the event listener.

Add the following code block to the scene:create method in start.lua:

function scene:create(event)
    local group = self.view
    starGenerator =  starFieldGenerator.new(200,group,5)
    startButton = display.newImage("new_game_btn.png",display.contentCenterX,display.contentCenterY+100)
    group:insert(startButton)
end

Notice that we invoked the starGenerator.new method when we are adding the startButton. The order in which you add things to the scene does matter. If we were to add it after the start button, then some of the stars would have been on top of the button.

The order in which you add things to the scene is the order in which they will show up. There are a two methods of the Display class, toFront and toBack, that can change this order.

If you test the game now, you should see the scene littered with random stars. They are not moving, however. We need to move them in the scene:show method. Add the following to the scene:show method of start.lua.

function scene:show(event)
    --SNIP--
   if ( phase == "did" ) then
   startButton:addEventListener("tap",startGame)
   Runtime:addEventListener("enterFrame", starGenerator)
   end
end

Here we add the enterFrame event listener, which, if you recall, makes the stars move and checks if they are out of bounds.

Whenever you add an event listener, you should make sure you are also removing it at some point later in the program. The place to do that in this example is when the scene is removed. Add the following to the scene:hide event.

unction scene:hide(event)
    local phase = event.phase
        if ( phase == "will" ) then
            startButton:removeEventListener("tap",startGame)
            Runtime:removeEventListener("enterFrame", starGenerator)
    end
end

If you test the game now, you should see the stars moving and it will seem like an endless stream of stars. Once we add the player, it will also give the illusion of the player moving through space.

5. Game Level

When you press the startButton button, you are taken to the game level scene, which is a blank screen at the moment. Let's fix that.

Step 1: Local Variables

Add the below code snippet to gamelevel.lua. You should make sure this code and all code from this point on is above where you are returning the scene object. These are the local variables we need for the game level, most of which are self-explanatory.

local starFieldGenerator = require("starfieldgenerator")
local pulsatingText = require("pulsatingtext")
local physics = require("physics")
local gameData = require( "gamedata" )
physics.start()
local starGenerator -- an instance of the starFieldGenerator
local player
local playerHeight = 125
local playerWidth = 94
local invaderSize = 32 -- The width and height of the invader image
local leftBounds = 30 -- the left margin
local rightBounds = display.contentWidth - 30 - the right margin
local invaderHalfWidth = 16
local invaders = {} -- Table that holds all the invaders
local invaderSpeed = 5
local playerBullets = {} -- Table that holds the players Bullets
local canFireBullet = true
local invadersWhoCanFire = {} -- Table that holds the invaders that are able to fire bullets
local invaderBullets = {}
local numberOfLives = 3
local playerIsInvincible = false
local rowOfInvadersWhoCanFire = 5
local invaderFireTimer -- timer used to fire invader bullets
local gameIsOver = false;
local drawDebugButtons = {}  --Temporary buttons to move player in simulator
local enableBulletFireTimer -- timer that enables player to fire

Step 2: Adding a Star Field

Like the previous scene, this scene also has a moving star field. Add the following to gamelevel.lua.

function scene:create(event)
    local group = self.view
    starGenerator =  starFieldGenerator.new(200,group,5)
end

We are adding a star field to the scene. As before, we need to make the stars move, which we do in the scene:show method.

function scene:show(event)
    local phase = event.phase
    local previousScene = composer.getSceneName( "previous" )
    composer.removeScene(previousScene)
	local group = self.view
	if ( phase == "did" ) then
       Runtime:addEventListener("enterFrame", starGenerator)
     end
end

We are removing the previous scene and adding the enterFrame event listener. As I mentioned earlier, whenever you add an event listener, you need to make sure you eventually remove it. We do this in the scene:hide method.

function scene:hide(event)
    local phase = event.phase
    local group = self.view
    if ( phase == "will" ) then
           Runtime:removeEventListener("enterFrame", starGenerator)
    end
end

Lastly, we should add the listeners for the create, show, and hide methods. If you run the application now, you should have a moving star field.

scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )

Step 3: Adding the Player

In this step, we'll add the player to the scene and get it moving. This game uses the accelerometer to move the player. We will also use an alternative way to move the player in the simulator by adding buttons to the scene. Add the following code snippet to gamelevel.lua.

function setupPlayer()
    local options = { width = playerWidth,height = playerHeight,numFrames = 2}
    local playerSheet = graphics.newImageSheet( "player.png", options )
	local sequenceData = {
  	 {  start=1, count=2, time=300,   loopCount=0 }
	}
	player = display.newSprite( playerSheet, sequenceData )
	player.name = "player"
	player.x=display.contentCenterX- playerWidth /2 
	player.y = display.contentHeight - playerHeight - 10
	player:play()
	scene.view:insert(player)
	local physicsData = (require "shapedefs").physicsData(1.0)
	physics.addBody( player, physicsData:get("ship"))
	player.gravityScale = 0
end

The player is a SpriteObject instance. By having the player be a sprite instead of a regular image, we can animate it. The player hastwo separate images, one with the thruster engaged and one with the thruster switched off.

By switching between the two images, we create the illusion of a never-ending thrust. We'll accomplish this with an image sheet, which is one large image composed of a number of smaller images. By cycling through the different images, you can create an animation.

The options table holds the width, height, and numFrames of the individual images in the larger image. The numFrames variable contains the value of the number of smaller images. The playerSheet is an instance of the ImageSheet object, which takes as parameters the image and the options table.

The sequenceData variable is used by the SpriteObject instance, the start key is the image you wish to start the sequence or animation on while the count key is how many total images there are in the animation. The time key is how long it will take the animation to play and the loopCount key is how many times you wish the animation to play or repeat. By setting loopCount to 0, it will repeat forever.

Lastly, you create the SpriteObject instance by passing in the ImageSheet instance and sequenceData.

We give the player a name key, which will be used to identify it later. We also set its x and y coordinates, invoke its play method, and insert it into the scene's view.

We will be using Corona's built in physics engine, which uses the popular Box2d engine under the hood, to detect collisions between objects. The default collision detection uses a bounding box method of detecting collisions, which means it places a box around the object and uses that for collision detection. This works fairly well for rectangular objects, or circles by using a radius property, but for oddly shaped objects it does not work out so well. Take a look at the below image to see what I mean.

You will notice that even though the laser is not touching the ship, it still registers as a collision. This is because it is colliding with the bounding box around the image.

To overcome this limitation, you can pass in a shape parameter. The shape parameter is a table of x and y coordinate pairs, with each pair defining a vertex point for the shape. These shape parameter coordinates can be quite difficult to figure out by hand, depending on the complexity of the image. To overcome this, I use a program called PhysicsEditor.

The physicsData variable is the file that was exported from PhysicsEditor. We call the addBody method of the physics engine, passing in the player and the physicsData variable. The result is that the collision detection will use the actual bounds of the spaceship instead of using bounding box collision detection. The below image clarifies this.

You can see that even though the laser is within the bounding box, no collision is triggered. Only when it touches the object's edge will a collision be registered.

Lastly, we set gravityScale to 0 on the player since we do not want it to be affected by gravity.

Now, invoke setupPlayer in the scene:create method.

function scene:create(event)
    local group = self.view
    starGenerator =  starFieldGenerator.new(100,group,5)
    setupPlayer()
end

If you run the game now, you should see the player added to the scene with its thruster engaged and activated.

Step 4: Moving the player

As mentioned earlier, we'll be moving the player using the accelerometer. Add the following code to gamelevel.lua.

local function onAccelerate(event)
    player.x = display.contentCenterX + (display.contentCenterX * (event.xGravity*2))
end
system.setAccelerometerInterval( 60 )
Runtime:addEventListener ("accelerometer", onAccelerate)

The onAccelerate function will be called each time the accelerometer interval is fired. It is set to fire 60 times per second. It's important to know that the accelerometer can be a big drain on the device's battery. In other words, if you are not using it for an extended period of time, it would be wise to remove the event listener from it.

If you test on a device, you should be able to move the player by tilting the device. This doesn't work when testing in the simulator however. To remedy this, we'll create a few temporary buttons.

Step 5: Debug Buttons

Add the following code to draw the debug buttons to the screen.

function drawDebugButtons()
    local function movePlayer(event)
    	if(event.target.name == "left") then
			player.x = player.x - 5
		elseif(event.target.name == "right") then
			player.x = player.x + 5
		end
	end
	local left = display.newRect(60,700,50,50)
	left.name = "left"
    scene.view:insert(left)
	local right = display.newRect(display.contentWidth-60,700,50,50)
	right.name = "right"
	scene.view:insert(right)
    left:addEventListener("tap", movePlayer)
    right:addEventListener("tap", movePlayer)
end

This code uses the Display's newRect method to draw two rectangles to the screen. We then add a tap even listener to them that calls the local movePlayer function.

6. Firing Bullets

Step 1: Adding and Moving Bullets

When the user taps the screen, the player's ship will fire a bullet. We will be limiting how often the user can fire a bullet by using a simple timer. Take a look at the implementation of the firePlayerBullet function.

function firePlayerBullet()
    if(canFireBullet == true)then
    	local tempBullet = display.newImage("laser.png", player.x, player.y - playerHeight/ 2)
		tempBullet.name = "playerBullet"
		scene.view:insert(tempBullet)
		physics.addBody(tempBullet, "dynamic" )
    	tempBullet.gravityScale = 0
    	tempBullet.isBullet = true
    	tempBullet.isSensor = true
		tempBullet:setLinearVelocity( 0,-400)
		table.insert(playerBullets,tempBullet)
		local laserSound = audio.loadSound( "laser.mp3" )
		local laserChannel = audio.play( laserSound )
		audio.dispose(laserChannel)
		canFireBullet = false

	else
		return
	end
	local function enableBulletFire()
		canFireBullet = true
	end
	timer.performWithDelay(750,enableBulletFire,1)
end

We first check if the user is able to fire a bullet. We then create a bullet and give it a name property so we can identify it later. We add it as a physics body and give it the type dynamic since it will be moving with a certain velocity.

We set the gravityScale to 0, because we do not want it to be affected by gravity, set the isBullet property to true, and set it to be sensor for collision detection. Lastly, we call setLinearVelocity to get the bullet moving on vertically. You can find out more about these properties in the documentation for Physics Bodies.

We load and play a sound, and then immediately release the memory associated with that sound. It's important to release the memory from sound objects when they are no longer in use. We set canFireBullet to false and start a timer that sets it back to true after a short time.

We now need to add the tap listener to the Runtime. This is different from adding a tap listener to an individual object. No matter where you tap on the screen, the Runtime listener is fired. This is because the Runtime is the global object for listeners.

function scene:show(event)
    --SNIP--
    if ( phase == "did" ) then
     	Runtime:addEventListener("enterFrame", starGenerator)
		Runtime:addEventListener("tap", firePlayerBullet)
    end
end

We also need to make sure that we remove this event listener when we no longer need it.

function scene:hide(event)
    if ( phase == "will" ) then
           Runtime:removeEventListener("enterFrame", starGenerator)
           Runtime:removeEventListener("tap", firePlayerBullet)
    end
end

If you test the game and tap the screen, a bullet should be added to the screen and move to the top of the device. There is a problem though. Once the bullet moves off-screen, they keep moving forever. This is not very useful for the game's memory. Imagine having hundreds of bullets off-screen, moving into infinity. It would take up unnecessary resources. We'll fix this issue in the next step.

Step 2: Removing Bullets

Whenever a bullet is created, it is stored in the playerBullets table. This makes it easy to reference each bullet and check its properties. What we will do is loop through the playerBullets table, check its y property, and, if it is off-screen, remove it from the Display and from the playerBullet table.

function checkPlayerBulletsOutOfBounds()
    if(#playerBullets > 0)then
		for i=#playerBullets,1,-1 do
 			if(playerBullets[i].y < 0) then
 				playerBullets[i]:removeSelf()
 				playerBullets[i] = nil
 				table.remove(playerBullets,i)
 			end
 		end
	end
end

An important point to note is that we are looping through the playersBullet table in reverse order. If we were to loop through the table in normal fashion, when we remove an object it would throw the index off and cause a processing error. By looping through the table in reverse order, the object has already been processed. Also important to note is that when you remove an object from the Display, it should be set to nil.

Now we need a place to call this function. The most common way to do this is to create a game loop. If you are unfamiliar with the concept of the game loop, you should read this short article by Michael James Williams. We'll implement the game loop in the next step.

Step 3: Create the Game Loop

Add the following code to gamelevel.lua to get started.

function gameLoop()
    checkPlayerBulletsOutOfBounds()
end

We need to call this function repeatedly for as long as the game is running. We will do this by using the Runtime's enterFrame event. Add the following in the scene:show function.

function scene:show(event)
    --SNIP--
    if ( phase == "did" ) then
	    Runtime:addEventListener("enterFrame", gameLoop)
     	Runtime:addEventListener("enterFrame", starGenerator)
		Runtime:addEventListener("tap", firePlayerBullet)
    end
end

We need to make sure we remove this event listener, when we leave this scene. We do this in the scene:hide function.

function scene:hide(event)
    if ( phase == "will" ) then
        Runtime:removeEventListener("enterFrame", gameLoop)
       	Runtime:removeEventListener("enterFrame", starGenerator)
       	Runtime:removeEventListener("tap", firePlayerBullet)
    end
end

7. Invaders

Step 1: Adding Invaders

In this step, we will add the invaders. Start by adding the following code block.

function setupInvaders()
    local xPositionStart =display.contentCenterX - invaderHalfWidth - (gameData.invaderNum *(invaderSize + 10))
    local numberOfInvaders = gameData.invaderNum *2+1 
	for i = 1, gameData.rowsOfInvaders do
		for j = 1, numberOfInvaders do
			local tempInvader = display.newImage("invader1.png",xPositionStart + ((invaderSize+10)*(j-1)), i * 46 )
			tempInvader.name = "invader"
			if(i== gameData.rowsOfInvaders)then
				table.insert(invadersWhoCanFire,tempInvader)
			end
			physics.addBody(tempInvader, "dynamic" )
			tempInvader.gravityScale = 0
			tempInvader.isSensor = true
			scene.view:insert(tempInvader)
			table.insert(invaders,tempInvader)
		end
	end
end

Depending on which level the player is on, the rows will contain a different number of invaders. We set how many rows to create when we add the rowsOfInvaders key to the gameData table (3). The invaderNum is used to keep track of which level we're on, but it is also used in some calculations.

To get the starting x position for the invader, we subtract half the invader's width from the screen's center. We then subtract whatever (invaderNum * invaderSize + 10) is equal to. There is an offset of ten pixels between each invader, which is why we are adding to the invaderSize. That might all seem a little confusing so take your time to understand it.

We determine how many invaders there are per row by taking invaderNum * 2 and adding 1 to it. For example, on the first level invaderNum is 1 so we will have three invaders per row (1 * 2 + 1). On the second level, there will be five invaders per row, (2 * 2 + 1), etc.

We use nested for loops to set up the rows and columns respectively. In the second for loop we create the invader. We give it a name property so we can reference it later. If i is equal to the gameData.rowsOfInvaders, then we add the invader to the invadersWhoCanFire table. This ensures all invaders on the bottom row start out as being able to fire bullets. We set the physics up in the same way as the we did with the player earlier, and insert the invader into the scene and into the invaders table so we can reference it later.

Step 2: Moving Invaders

In this step, we will move the invaders. We will use the gameLoop to check the invaders's position and reverse their direction if necessary. Add the following code block to get started.

function moveInvaders()
    local changeDirection = false
    for i=1, #invaders do
          invaders[i].x = invaders[i].x + invaderSpeed
     	if(invaders[i].x > rightBounds - invaderHalfWidth or invaders[i].x < leftBounds + invaderHalfWidth) then
          	changeDirection = true;
     	end
	 end
    if(changeDirection == true)then
        invaderSpeed = invaderSpeed*-1
        for j = 1, #invaders do
            invaders[j].y = invaders[j].y+ 46
        end
        changeDirection = false;
    end 
end

We loop through the invaders and change their x position by the value stored in the invaderSpeed variable. We see if the invader is out of bounds by checking leftBounds and rightBounds, which we set up earlier.

If an invader is out of bounds, we set changeDirection to true. If changeDirection is set to true, we negate the invaderSpeed variable, move the invaders down on the y axis by 16 pixels, and reset the changeDirection variable to false.

We invoke the moveInvaders function in the gameLoop function.

function gameLoop()
    checkPlayerBulletsOutOfBounds()
    moveInvaders()
end

8. Detecting Collisions

Now that we have some invaders on screen and moving, we can check for collisions between any of the player's bullets and the invaders. We perform this check in the onCollision function.

function onCollision(event)
    local function removeInvaderAndPlayerBullet(event)
      	local params = event.source.params
	  	local invaderIndex = table.indexOf(invaders,params.theInvader)
	  	local invadersPerRow = gameData.invaderNum *2+1
   	    if(invaderIndex > invadersPerRow) then
			table.insert(invadersWhoCanFire, invaders[invaderIndex - invadersPerRow])
   	   end
	  	params.theInvader.isVisible = false
   	    physics.removeBody(  params.theInvader )
        table.remove(invadersWhoCanFire,table.indexOf(invadersWhoCanFire,params.theInvader))
		physics.removeBody(params.thePlayerBullet)
	  	table.remove(playerBullets,table.indexOf(playerBullets,params.thePlayerBullet))
	  	display.remove(params.thePlayerBullet)
	  	params.thePlayerBullet = nil
	  end
      if ( event.phase == "began" ) then
			if(event.object1.name == "invader" and event.object2.name == "playerBullet")then
				local tm = timer.performWithDelay(10, removeInvaderAndPlayerBullet,1)
				tm.params = {theInvader = event.object1 , thePlayerBullet = event.object2}
			end
   	  if(event.object1.name == "playerBullet" and event.object2.name == "invader") then
			local tm = timer.performWithDelay(10, removeInvaderAndPlayerBullet,1)
			tm.params = {theInvader = event.object2 , thePlayerBullet = event.object1}
   	  end
  	end
end	

There are two ways to do collision detection using Corona's built-in physics engine. One way is to register for the collision on the objects themselves. The other way is to listen globally. We use the global approach in this tutorial.

In the onCollision method, we check the name properties of the objects, set a small delay, and invoke the removeInvaderAndPlayerBullet function. Because we do not know what event.object1 and event.object2 will point to, we have to check both situations hence the two opposite if statements.

We send along some parameters with the timer so we can identify the playerBullet and the invader within the removePlayerAndBullet function. Whenever you are modifying an object's properties in a collision check, you should apply a small delay before doing so. This is the reason for the short timer.

Inside the removeInvaderAndPlayerBullet function, we get a reference to the params key. We then get the index of the invader within the invaders table. Next, we determine how many invaders there are per row. If this number it is greater than invadersPerRow, we determine which invader to add to the invadersWhoCanFire table. The idea is that whichever invader was hit, the invader in the same column one row up can now fire.

We then set the invader to not be visible, remove its body from the physics engine, and remove it from theinvadersWhoCanFire table.

We remove the bullet from the physics engine, remove it from the playerBullets table, remove it from display, and set it to nil to be certain it is marked for garbage collection.

To make all this work, we need to listen for collision events. Add the following code to the scene:show method.

function scene:show(event)
    local phase = event.phase
    local previousScene = composer.getSceneName( "previous" )
    composer.removeScene(previousScene)
	local group = self.view
	if ( phase == "did" ) then
	    Runtime:addEventListener("enterFrame", gameLoop)
     	Runtime:addEventListener("enterFrame", starGenerator)
		Runtime:addEventListener("tap", firePlayerBullet)
		Runtime:addEventListener( "collision", onCollision )
	end
end

We need to make sure we remove this event listener when we leave the scene. We do this in the scene:hide method.

function scene:hide(event)
    if ( phase == "will" ) then
           Runtime:removeEventListener("enterFrame", starGenerator)
           Runtime:removeEventListener("tap", firePlayerBullet)
       	Runtime:removeEventListener("enterFrame", gameLoop)
       	Runtime:removeEventListener( "collision", onCollision )
    end
end

If you test the game now, you should be able to fire a bullet, hit an invader, and have both the bullet and the invader removed from the scene.

Conclusion

This brings this part of the series to a close. In the next and final part of this series, we will make the invaders fire bullets, make sure the player can die, and handle game over as well as new levels. I hope to see you there.

2015-01-07T17:15:29.000Z2015-01-07T17:15:29.000ZJames Tyner

Create a Space Invaders Game in Corona: Implementing Gameplay

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-22788
Final product image
What You'll Be Creating

In the first part of this series, we set up some defaults for the game and laid the foundation for transitioning between scenes. In this part, we'll begin implementing the game's gameplay.

1. A Word about Metatables

The Lua programming language does not have a class system built in. However, by using Lua's metatable construct we can emulate a class system. There is a good example on the Corona website showing how to implement this.

An important thing to note is that Corona's Display objects cannot be set as the metatable. This has to do with how the underlying C language interfaces with them. A simple way to get around this is to set the Display object as a key on a new table and then put that table as the metatable. This is the approach that we'll take in this tutorial.

If you read the above article on the Corona website, you will have noticed that the __Index metamethod was being used on the metatable. The way the __Index metamethod works, is that when you try to access an absent field in a table, it triggers the interpreter to look for an __Index metamethod. If the __Index is there, it will look for the field and provide the result, otherwise it will result in nil.

2. Implementing PulsatingText Class

The game has text that continuously grows and shrinks, creating a pulsating text effect. We will create this functionality as a module so we can use it throughout the project. Also, by having it as a module, we can use it in any project that would require this type of functionality.

Add the following to the pulsatingtext.lua file you created in the first part of this tutorial. Make sure this code and all code from here on is placed above where you are returning the scene object.

local pulsatingText = {}
local pulsatingText_mt = {__index = pulsatingText}

function pulsatingText.new(theText,positionX,positionY,theFont,theFontSize,theGroup)
      local theTextField = display.newText(theText,positionX,positionY,theFont,theFontSize)
      
local newPulsatingText = {
    theTextField = theTextField}
    theGroup:insert(theTextField)                                             
	return setmetatable(newPulsatingText,pulsatingText_mt)
end

function pulsatingText:setColor(r,b,g)
  self.theTextField:setFillColor(r,g,b)
end

function pulsatingText:pulsate()
	transition.to( self.theTextField, { xScale=4.0, yScale=4.0, time=1500, iterations = -1} )
end

return pulsatingText

We create the main table pulsatingText and the table to be used as the metatable pulsatingText_mt. In the new method, we create the TextField object and add it to the table newPulsatingText that will be set as the metatable. We then add the TextField object to the group that was passed in through the parameter, which will be the scene's group in which we instantiate an instance of PulsatingText.

It's important to make sure that we add it to the scene's group so it will be removed when the scene is removed. Finally, we set the metatable.

We have two methods that access the TextField object and perform operations on its properties. One sets the color by using the setFillColor method and takes as parameters the R, G, and B colors as a number from 0 to 1. The other uses the Transition library to make the text grow and shrink. It enlarges the text by using the xScale and yScale properties. Setting the iterations property to -1 makes the action repeat forever.

3. Using the PulsatingText Class

Open start.lua and add the following code to the scene:create method.

function scene:create(event)
    --SNIP--
    local   invadersText =  pulsatingText.new("INVADERZ",display.contentCenterX,display.contentCenterY-200,"Conquest", 20,group)
    invadersText:setColor( 1, 1, 1 )
    invadersText:pulsate()
end

We create an new TextField instance with the word "INVADERZ", set its color, and call the pulsate method. Notice how we passed the group variable as a parameter to ensure the TextField object gets added to this scene's view hierarchy.

I have included a font in the downloads named "Conquest" that has a futuristic look to it. Make sure you add it to your project folder if you want to use it. I downloaded the font from dafont.com, which is a great website for finding custom fonts. However, make sure you adhere to the license the font author has put in place.

To use the font, we also need to update the project's build.settings file. Take a look at the updated build.settings file.

settings = {
    orientation =
    {
       default ="portrait",
        supported =
        {
          "portrait"
        },
    },
    iphone =
    {
        plist=
        {
            UIAppFonts = {
                    "Conquest.ttf"
                }
        },
    },
}

If you test the project now, you should see the text was added to the scene and pulsates as expected.

4. Star Field Generator

To make the game a little more interesting, a moving star field is created in the background. To accomplish this, we do the same as we did with the PulsatingText class and create a module. Create a file named starfieldgenerator.lua and add the following to it:

local starFieldGenerator= {}
local starFieldGenerator_mt = {__index = starFieldGenerator}

function starFieldGenerator.new(numberOfStars,theView,starSpeed)
    local starGroup = display.newGroup()
    local allStars     ={} -- Table that holds all the stars

    for i=0, numberOfStars do
		local star = display.newCircle(math.random(display.contentWidth), math.random(display.contentHeight), math.random(2,8))
		star:setFillColor(1 ,1,1)
		starGroup:insert(star)
		table.insert(allStars,star)
    end
    
    theView:insert(starGroup)
    
	local newStarFieldGenerator = {
        allStars    =  allStars,
        starSpeed = starSpeed
    }
	return setmetatable(newStarFieldGenerator,starFieldGenerator_mt)
end


function starFieldGenerator:enterFrame()
	self:moveStars()
	self:checkStarsOutOfBounds()
end


function starFieldGenerator:moveStars()
        for i=1, #self.allStars do
              self.allStars[i].y = self.allStars[i].y+self.starSpeed
        end

end
function  starFieldGenerator:checkStarsOutOfBounds()
	for i=1, #self.allStars do
		if(self.allStars[i].y > display.contentHeight) then
			self.allStars[i].x  = math.random(display.contentWidth)
			self.allStars[i].y = 0
		end
	end
end

return starFieldGenerator

We first create the main table starFieldGenerator and the metatable starFieldGenerator_mt. In the new method, we have a table allStars that will be used to hold a reference to the stars that are created in the for loop. The number of iterations of the for loop is equal to numberOfStars and we use the Display object's newCircle method to create a white circle.

We position the circle randomly within the game screen bounds and also give it a random size between 2 and 8. We insert each star into the allStars table and place them into the view that was passed in as a parameter, which is the scene's view.

We set allStars and starSpeed as keys on the temporary table and then assign it as the metatable. We need access to the allStars table and starSpeed properties when we move the stars.

We'll use two methods to move the stars. The starFieldGenerator:moveStars method does the moving of the stars while the starFieldGenerator:checkStarsOutOfBounds method checks if the stars are out of the screen's bounds.

If the stars are out of the playing screen area, it generates a random x position for that particular star and sets the y position just above the top of the screen. By doing so, we are able to reuse the stars and it gives the illusion of a never-ending stream of stars.

We call these functions in the starFieldGenerator:enterFrame method. By setting the enterFramemethod directly on this object, we can set this object as the context when we add the event listener.

Add the following code block to the scene:create method in start.lua:

function scene:create(event)
    local group = self.view
    starGenerator =  starFieldGenerator.new(200,group,5)
    startButton = display.newImage("new_game_btn.png",display.contentCenterX,display.contentCenterY+100)
    group:insert(startButton)
end

Notice that we invoked the starGenerator.new method when we are adding the startButton. The order in which you add things to the scene does matter. If we were to add it after the start button, then some of the stars would have been on top of the button.

The order in which you add things to the scene is the order in which they will show up. There are a two methods of the Display class, toFront and toBack, that can change this order.

If you test the game now, you should see the scene littered with random stars. They are not moving, however. We need to move them in the scene:show method. Add the following to the scene:show method of start.lua.

function scene:show(event)
    --SNIP--
   if ( phase == "did" ) then
   startButton:addEventListener("tap",startGame)
   Runtime:addEventListener("enterFrame", starGenerator)
   end
end

Here we add the enterFrame event listener, which, if you recall, makes the stars move and checks if they are out of bounds.

Whenever you add an event listener, you should make sure you are also removing it at some point later in the program. The place to do that in this example is when the scene is removed. Add the following to the scene:hide event.

unction scene:hide(event)
    local phase = event.phase
        if ( phase == "will" ) then
            startButton:removeEventListener("tap",startGame)
            Runtime:removeEventListener("enterFrame", starGenerator)
    end
end

If you test the game now, you should see the stars moving and it will seem like an endless stream of stars. Once we add the player, it will also give the illusion of the player moving through space.

5. Game Level

When you press the startButton button, you are taken to the game level scene, which is a blank screen at the moment. Let's fix that.

Step 1: Local Variables

Add the below code snippet to gamelevel.lua. You should make sure this code and all code from this point on is above where you are returning the scene object. These are the local variables we need for the game level, most of which are self-explanatory.

local starFieldGenerator = require("starfieldgenerator")
local pulsatingText = require("pulsatingtext")
local physics = require("physics")
local gameData = require( "gamedata" )
physics.start()
local starGenerator -- an instance of the starFieldGenerator
local player
local playerHeight = 125
local playerWidth = 94
local invaderSize = 32 -- The width and height of the invader image
local leftBounds = 30 -- the left margin
local rightBounds = display.contentWidth - 30 - the right margin
local invaderHalfWidth = 16
local invaders = {} -- Table that holds all the invaders
local invaderSpeed = 5
local playerBullets = {} -- Table that holds the players Bullets
local canFireBullet = true
local invadersWhoCanFire = {} -- Table that holds the invaders that are able to fire bullets
local invaderBullets = {}
local numberOfLives = 3
local playerIsInvincible = false
local rowOfInvadersWhoCanFire = 5
local invaderFireTimer -- timer used to fire invader bullets
local gameIsOver = false;
local drawDebugButtons = {}  --Temporary buttons to move player in simulator
local enableBulletFireTimer -- timer that enables player to fire

Step 2: Adding a Star Field

Like the previous scene, this scene also has a moving star field. Add the following to gamelevel.lua.

function scene:create(event)
    local group = self.view
    starGenerator =  starFieldGenerator.new(200,group,5)
end

We are adding a star field to the scene. As before, we need to make the stars move, which we do in the scene:show method.

function scene:show(event)
    local phase = event.phase
    local previousScene = composer.getSceneName( "previous" )
    composer.removeScene(previousScene)
	local group = self.view
	if ( phase == "did" ) then
       Runtime:addEventListener("enterFrame", starGenerator)
     end
end

We are removing the previous scene and adding the enterFrame event listener. As I mentioned earlier, whenever you add an event listener, you need to make sure you eventually remove it. We do this in the scene:hide method.

function scene:hide(event)
    local phase = event.phase
    local group = self.view
    if ( phase == "will" ) then
           Runtime:removeEventListener("enterFrame", starGenerator)
    end
end

Lastly, we should add the listeners for the create, show, and hide methods. If you run the application now, you should have a moving star field.

scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )

Step 3: Adding the Player

In this step, we'll add the player to the scene and get it moving. This game uses the accelerometer to move the player. We will also use an alternative way to move the player in the simulator by adding buttons to the scene. Add the following code snippet to gamelevel.lua.

function setupPlayer()
    local options = { width = playerWidth,height = playerHeight,numFrames = 2}
    local playerSheet = graphics.newImageSheet( "player.png", options )
	local sequenceData = {
  	 {  start=1, count=2, time=300,   loopCount=0 }
	}
	player = display.newSprite( playerSheet, sequenceData )
	player.name = "player"
	player.x=display.contentCenterX- playerWidth /2 
	player.y = display.contentHeight - playerHeight - 10
	player:play()
	scene.view:insert(player)
	local physicsData = (require "shapedefs").physicsData(1.0)
	physics.addBody( player, physicsData:get("ship"))
	player.gravityScale = 0
end

The player is a SpriteObject instance. By having the player be a sprite instead of a regular image, we can animate it. The player hastwo separate images, one with the thruster engaged and one with the thruster switched off.

By switching between the two images, we create the illusion of a never-ending thrust. We'll accomplish this with an image sheet, which is one large image composed of a number of smaller images. By cycling through the different images, you can create an animation.

The options table holds the width, height, and numFrames of the individual images in the larger image. The numFrames variable contains the value of the number of smaller images. The playerSheet is an instance of the ImageSheet object, which takes as parameters the image and the options table.

The sequenceData variable is used by the SpriteObject instance, the start key is the image you wish to start the sequence or animation on while the count key is how many total images there are in the animation. The time key is how long it will take the animation to play and the loopCount key is how many times you wish the animation to play or repeat. By setting loopCount to 0, it will repeat forever.

Lastly, you create the SpriteObject instance by passing in the ImageSheet instance and sequenceData.

We give the player a name key, which will be used to identify it later. We also set its x and y coordinates, invoke its play method, and insert it into the scene's view.

We will be using Corona's built in physics engine, which uses the popular Box2d engine under the hood, to detect collisions between objects. The default collision detection uses a bounding box method of detecting collisions, which means it places a box around the object and uses that for collision detection. This works fairly well for rectangular objects, or circles by using a radius property, but for oddly shaped objects it does not work out so well. Take a look at the below image to see what I mean.

You will notice that even though the laser is not touching the ship, it still registers as a collision. This is because it is colliding with the bounding box around the image.

To overcome this limitation, you can pass in a shape parameter. The shape parameter is a table of x and y coordinate pairs, with each pair defining a vertex point for the shape. These shape parameter coordinates can be quite difficult to figure out by hand, depending on the complexity of the image. To overcome this, I use a program called PhysicsEditor.

The physicsData variable is the file that was exported from PhysicsEditor. We call the addBody method of the physics engine, passing in the player and the physicsData variable. The result is that the collision detection will use the actual bounds of the spaceship instead of using bounding box collision detection. The below image clarifies this.

You can see that even though the laser is within the bounding box, no collision is triggered. Only when it touches the object's edge will a collision be registered.

Lastly, we set gravityScale to 0 on the player since we do not want it to be affected by gravity.

Now, invoke setupPlayer in the scene:create method.

function scene:create(event)
    local group = self.view
    starGenerator =  starFieldGenerator.new(100,group,5)
    setupPlayer()
end

If you run the game now, you should see the player added to the scene with its thruster engaged and activated.

Step 4: Moving the player

As mentioned earlier, we'll be moving the player using the accelerometer. Add the following code to gamelevel.lua.

local function onAccelerate(event)
    player.x = display.contentCenterX + (display.contentCenterX * (event.xGravity*2))
end
system.setAccelerometerInterval( 60 )
Runtime:addEventListener ("accelerometer", onAccelerate)

The onAccelerate function will be called each time the accelerometer interval is fired. It is set to fire 60 times per second. It's important to know that the accelerometer can be a big drain on the device's battery. In other words, if you are not using it for an extended period of time, it would be wise to remove the event listener from it.

If you test on a device, you should be able to move the player by tilting the device. This doesn't work when testing in the simulator however. To remedy this, we'll create a few temporary buttons.

Step 5: Debug Buttons

Add the following code to draw the debug buttons to the screen.

function drawDebugButtons()
    local function movePlayer(event)
    	if(event.target.name == "left") then
			player.x = player.x - 5
		elseif(event.target.name == "right") then
			player.x = player.x + 5
		end
	end
	local left = display.newRect(60,700,50,50)
	left.name = "left"
    scene.view:insert(left)
	local right = display.newRect(display.contentWidth-60,700,50,50)
	right.name = "right"
	scene.view:insert(right)
    left:addEventListener("tap", movePlayer)
    right:addEventListener("tap", movePlayer)
end

This code uses the Display's newRect method to draw two rectangles to the screen. We then add a tap even listener to them that calls the local movePlayer function.

6. Firing Bullets

Step 1: Adding and Moving Bullets

When the user taps the screen, the player's ship will fire a bullet. We will be limiting how often the user can fire a bullet by using a simple timer. Take a look at the implementation of the firePlayerBullet function.

function firePlayerBullet()
    if(canFireBullet == true)then
    	local tempBullet = display.newImage("laser.png", player.x, player.y - playerHeight/ 2)
		tempBullet.name = "playerBullet"
		scene.view:insert(tempBullet)
		physics.addBody(tempBullet, "dynamic" )
    	tempBullet.gravityScale = 0
    	tempBullet.isBullet = true
    	tempBullet.isSensor = true
		tempBullet:setLinearVelocity( 0,-400)
		table.insert(playerBullets,tempBullet)
		local laserSound = audio.loadSound( "laser.mp3" )
		local laserChannel = audio.play( laserSound )
		audio.dispose(laserChannel)
		canFireBullet = false

	else
		return
	end
	local function enableBulletFire()
		canFireBullet = true
	end
	timer.performWithDelay(750,enableBulletFire,1)
end

We first check if the user is able to fire a bullet. We then create a bullet and give it a name property so we can identify it later. We add it as a physics body and give it the type dynamic since it will be moving with a certain velocity.

We set the gravityScale to 0, because we do not want it to be affected by gravity, set the isBullet property to true, and set it to be sensor for collision detection. Lastly, we call setLinearVelocity to get the bullet moving on vertically. You can find out more about these properties in the documentation for Physics Bodies.

We load and play a sound, and then immediately release the memory associated with that sound. It's important to release the memory from sound objects when they are no longer in use. We set canFireBullet to false and start a timer that sets it back to true after a short time.

We now need to add the tap listener to the Runtime. This is different from adding a tap listener to an individual object. No matter where you tap on the screen, the Runtime listener is fired. This is because the Runtime is the global object for listeners.

function scene:show(event)
    --SNIP--
    if ( phase == "did" ) then
     	Runtime:addEventListener("enterFrame", starGenerator)
		Runtime:addEventListener("tap", firePlayerBullet)
    end
end

We also need to make sure that we remove this event listener when we no longer need it.

function scene:hide(event)
    if ( phase == "will" ) then
           Runtime:removeEventListener("enterFrame", starGenerator)
           Runtime:removeEventListener("tap", firePlayerBullet)
    end
end

If you test the game and tap the screen, a bullet should be added to the screen and move to the top of the device. There is a problem though. Once the bullet moves off-screen, they keep moving forever. This is not very useful for the game's memory. Imagine having hundreds of bullets off-screen, moving into infinity. It would take up unnecessary resources. We'll fix this issue in the next step.

Step 2: Removing Bullets

Whenever a bullet is created, it is stored in the playerBullets table. This makes it easy to reference each bullet and check its properties. What we will do is loop through the playerBullets table, check its y property, and, if it is off-screen, remove it from the Display and from the playerBullet table.

function checkPlayerBulletsOutOfBounds()
    if(#playerBullets > 0)then
		for i=#playerBullets,1,-1 do
 			if(playerBullets[i].y < 0) then
 				playerBullets[i]:removeSelf()
 				playerBullets[i] = nil
 				table.remove(playerBullets,i)
 			end
 		end
	end
end

An important point to note is that we are looping through the playersBullet table in reverse order. If we were to loop through the table in normal fashion, when we remove an object it would throw the index off and cause a processing error. By looping through the table in reverse order, the object has already been processed. Also important to note is that when you remove an object from the Display, it should be set to nil.

Now we need a place to call this function. The most common way to do this is to create a game loop. If you are unfamiliar with the concept of the game loop, you should read this short article by Michael James Williams. We'll implement the game loop in the next step.

Step 3: Create the Game Loop

Add the following code to gamelevel.lua to get started.

function gameLoop()
    checkPlayerBulletsOutOfBounds()
end

We need to call this function repeatedly for as long as the game is running. We will do this by using the Runtime's enterFrame event. Add the following in the scene:show function.

function scene:show(event)
    --SNIP--
    if ( phase == "did" ) then
	    Runtime:addEventListener("enterFrame", gameLoop)
     	Runtime:addEventListener("enterFrame", starGenerator)
		Runtime:addEventListener("tap", firePlayerBullet)
    end
end

We need to make sure we remove this event listener, when we leave this scene. We do this in the scene:hide function.

function scene:hide(event)
    if ( phase == "will" ) then
        Runtime:removeEventListener("enterFrame", gameLoop)
       	Runtime:removeEventListener("enterFrame", starGenerator)
       	Runtime:removeEventListener("tap", firePlayerBullet)
    end
end

7. Invaders

Step 1: Adding Invaders

In this step, we will add the invaders. Start by adding the following code block.

function setupInvaders()
    local xPositionStart =display.contentCenterX - invaderHalfWidth - (gameData.invaderNum *(invaderSize + 10))
    local numberOfInvaders = gameData.invaderNum *2+1 
	for i = 1, gameData.rowsOfInvaders do
		for j = 1, numberOfInvaders do
			local tempInvader = display.newImage("invader1.png",xPositionStart + ((invaderSize+10)*(j-1)), i * 46 )
			tempInvader.name = "invader"
			if(i== gameData.rowsOfInvaders)then
				table.insert(invadersWhoCanFire,tempInvader)
			end
			physics.addBody(tempInvader, "dynamic" )
			tempInvader.gravityScale = 0
			tempInvader.isSensor = true
			scene.view:insert(tempInvader)
			table.insert(invaders,tempInvader)
		end
	end
end

Depending on which level the player is on, the rows will contain a different number of invaders. We set how many rows to create when we add the rowsOfInvaders key to the gameData table (3). The invaderNum is used to keep track of which level we're on, but it is also used in some calculations.

To get the starting x position for the invader, we subtract half the invader's width from the screen's center. We then subtract whatever (invaderNum * invaderSize + 10) is equal to. There is an offset of ten pixels between each invader, which is why we are adding to the invaderSize. That might all seem a little confusing so take your time to understand it.

We determine how many invaders there are per row by taking invaderNum * 2 and adding 1 to it. For example, on the first level invaderNum is 1 so we will have three invaders per row (1 * 2 + 1). On the second level, there will be five invaders per row, (2 * 2 + 1), etc.

We use nested for loops to set up the rows and columns respectively. In the second for loop we create the invader. We give it a name property so we can reference it later. If i is equal to the gameData.rowsOfInvaders, then we add the invader to the invadersWhoCanFire table. This ensures all invaders on the bottom row start out as being able to fire bullets. We set the physics up in the same way as the we did with the player earlier, and insert the invader into the scene and into the invaders table so we can reference it later.

Step 2: Moving Invaders

In this step, we will move the invaders. We will use the gameLoop to check the invaders's position and reverse their direction if necessary. Add the following code block to get started.

function moveInvaders()
    local changeDirection = false
    for i=1, #invaders do
          invaders[i].x = invaders[i].x + invaderSpeed
     	if(invaders[i].x > rightBounds - invaderHalfWidth or invaders[i].x < leftBounds + invaderHalfWidth) then
          	changeDirection = true;
     	end
	 end
    if(changeDirection == true)then
        invaderSpeed = invaderSpeed*-1
        for j = 1, #invaders do
            invaders[j].y = invaders[j].y+ 46
        end
        changeDirection = false;
    end 
end

We loop through the invaders and change their x position by the value stored in the invaderSpeed variable. We see if the invader is out of bounds by checking leftBounds and rightBounds, which we set up earlier.

If an invader is out of bounds, we set changeDirection to true. If changeDirection is set to true, we negate the invaderSpeed variable, move the invaders down on the y axis by 16 pixels, and reset the changeDirection variable to false.

We invoke the moveInvaders function in the gameLoop function.

function gameLoop()
    checkPlayerBulletsOutOfBounds()
    moveInvaders()
end

8. Detecting Collisions

Now that we have some invaders on screen and moving, we can check for collisions between any of the player's bullets and the invaders. We perform this check in the onCollision function.

function onCollision(event)
    local function removeInvaderAndPlayerBullet(event)
      	local params = event.source.params
	  	local invaderIndex = table.indexOf(invaders,params.theInvader)
	  	local invadersPerRow = gameData.invaderNum *2+1
   	    if(invaderIndex > invadersPerRow) then
			table.insert(invadersWhoCanFire, invaders[invaderIndex - invadersPerRow])
   	   end
	  	params.theInvader.isVisible = false
   	    physics.removeBody(  params.theInvader )
        table.remove(invadersWhoCanFire,table.indexOf(invadersWhoCanFire,params.theInvader))
        if(table.indexOf(playerBullets,params.thePlayerBullet)~=nil)then
		    physics.removeBody(params.thePlayerBullet)
	  	    table.remove(playerBullets,table.indexOf(playerBullets,params.thePlayerBullet))
	  	    display.remove(params.thePlayerBullet)
	  	    params.thePlayerBullet = nil
        end
	  end
      if ( event.phase == "began" ) then
			if(event.object1.name == "invader" and event.object2.name == "playerBullet")then
				local tm = timer.performWithDelay(10, removeInvaderAndPlayerBullet,1)
				tm.params = {theInvader = event.object1 , thePlayerBullet = event.object2}
			end
   	  if(event.object1.name == "playerBullet" and event.object2.name == "invader") then
			local tm = timer.performWithDelay(10, removeInvaderAndPlayerBullet,1)
			tm.params = {theInvader = event.object2 , thePlayerBullet = event.object1}
   	  end
  	end
end	

There are two ways to do collision detection using Corona's built-in physics engine. One way is to register for the collision on the objects themselves. The other way is to listen globally. We use the global approach in this tutorial.

In the onCollision method, we check the name properties of the objects, set a small delay, and invoke the removeInvaderAndPlayerBullet function. Because we do not know what event.object1 and event.object2 will point to, we have to check both situations hence the two opposite if statements.

We send along some parameters with the timer so we can identify the playerBullet and the invader within the removePlayerAndBullet function. Whenever you are modifying an object's properties in a collision check, you should apply a small delay before doing so. This is the reason for the short timer.

Inside the removeInvaderAndPlayerBullet function, we get a reference to the params key. We then get the index of the invader within the invaders table. Next, we determine how many invaders there are per row. If this number it is greater than invadersPerRow, we determine which invader to add to the invadersWhoCanFire table. The idea is that whichever invader was hit, the invader in the same column one row up can now fire.

We then set the invader to not be visible, remove its body from the physics engine, and remove it from theinvadersWhoCanFire table.

We remove the bullet from the physics engine, remove it from the playerBullets table, remove it from display, and set it to nil to be certain it is marked for garbage collection.

To make all this work, we need to listen for collision events. Add the following code to the scene:show method.

function scene:show(event)
    local phase = event.phase
    local previousScene = composer.getSceneName( "previous" )
    composer.removeScene(previousScene)
	local group = self.view
	if ( phase == "did" ) then
	    Runtime:addEventListener("enterFrame", gameLoop)
     	Runtime:addEventListener("enterFrame", starGenerator)
		Runtime:addEventListener("tap", firePlayerBullet)
		Runtime:addEventListener( "collision", onCollision )
	end
end

We need to make sure we remove this event listener when we leave the scene. We do this in the scene:hide method.

function scene:hide(event)
    if ( phase == "will" ) then
           Runtime:removeEventListener("enterFrame", starGenerator)
           Runtime:removeEventListener("tap", firePlayerBullet)
       	Runtime:removeEventListener("enterFrame", gameLoop)
       	Runtime:removeEventListener( "collision", onCollision )
    end
end

If you test the game now, you should be able to fire a bullet, hit an invader, and have both the bullet and the invader removed from the scene.

Conclusion

This brings this part of the series to a close. In the next and final part of this series, we will make the invaders fire bullets, make sure the player can die, and handle game over as well as new levels. I hope to see you there.

2015-01-07T17:15:29.000Z2015-01-07T17:15:29.000ZJames Tyner

Swift from Scratch: An Introduction to Functions

$
0
0

To get anything done in Swift, you'll need to learn the ins and outs of functions. Functions are exceptionally powerful and flexible in Swift. The basics are simple—especially if you've worked with other programming languages before—but because of Swift's flexible syntax it can easily become complex if you're not familiar with the basics.

In this article, we'll focus on those basics first and explore the more complex syntax and use cases in the next article. It's important that you don't skim the basics as they are essential to understand where a function's power comes from in Swift. Let's start with an example to dissect the anatomy of a function in Swift.

1. Learn by Example

A function is nothing more than a block of code that can be executed whenever it's needed. I'd like to start with an example to discuss the basic anatomy of a Swift function. Fire up Xcode and create a new playground. Add the following function definition to the playground.

func printHelloWorld() {
    println("Hello World!")
}

A function begins with the func keyword and is followed by the name of the function, printHelloWorld in our example. As in many other languages, the name of the function is followed by a pair of parentheses that contain the function's parameters, the function's input.

The body of the function is wrapped in a pair of curly braces. The printHelloWorld function contains one statement in which we print the string Hello World! in the standard output. This is what a basic function looks like in Swift. The syntax is simple, clean, and minimalist.

You can invoke the function by typing the name of the function, followed by a pair of parentheses.

printHelloWorld()

2. Parameters

Let's make the above example a bit more complex by adding parameters to the function definition. This simply means that we provide the function with input values it can use in the function's body. In the following example, we define the printMessage function, which accepts one parameter, message, of type String.

func printMessage(message: String) {
    println(message)
}

A function can accept multiple parameters or input values. The parameters are wrapped by the parentheses that follow the function's name. The name of the parameter is followed by a colon and the parameter's type. As you remember, this is very similar to declaring a variable or constant. It simply says that the message parameter is of typeString.

Instead of printing a hard-coded string like we did in the printHelloWorld function, we print the message parameter's value. This makes the function flexible and more useful.

Invoking the function is very similar to what we saw earlier. The only difference is that we pass in an argument when invoking the function.

printMessage("Hello World!")

Note that the terms parameters and arguments are often used interchangeably, but there is a subtle, semantic difference in Swift. In Swift, parameters are the values specified in the function definition while arguments are the values passed to the function when it is invoked.

Multiple Parameters

As I mentioned earlier, the syntax of functions is very flexible and it shouldn't surprise you that it's perfectly possible to pass multiple arguments to a function. In the next example, we create a variation on the printMessage function that allows us to print the message multiple times.

func printMessage(message: String, times: Int) {
    for i in 0..<times {
        println("\(i) message")
    }
}

While the name of the function is identical to that of the original printMessage function, the function's type is different. It's important you understand the previous sentence. Read it again.

Each function has a type, consisting of the parameter types and the return type. We'll explore return types in a moment. Functions can have the same name as long as their type is different as shown by the previous two function definitions.

The type of the first function is (String) -> () while the type of the second function is(String, Int) -> (). The name of both functions is the same. Don't worry about the -> symbol. Its meaning will become clear in a few moments when we discuss return types.

The second printMessage function defines two parameters, message of type String and times of type Int. This definition illustrates one of the features Swift has adopted from Objective-C, readable function/method names. While the name of the function is printMessage, by reading the names of the function's parameters, it's easy to understand what the function is supposed to do.

In the second printMessage function, we create a for-in loop to print the message string times times. We use the half-open range operator, ..<, as we saw earlier in this series.

When we start typing printMessage in the playground, Xcode displays both functions in the autocompletion menu. Thanks to the function's type, it's easy to choose the function we're interested in. Calling the second printMessage function is as simple as:

printMessage("Hello World", 3)

Default Values

One of my favorite features is the ability to define default values for parameters. This may sound silly if you're coming from a language that has had this feature for ages, but this is pretty great if you've been working with C and Objective-C for many years.

In short, Swift allows developers to define default values for the parameters of a function. Let's define a new function that prints the current date in a specific format. Make sure you add the following import statement at the top of your playground to import the UIKit framework.

import UIKit

Let's first define the printDate function without making use of default values for any of the parameters.

func printDate(date: NSDate, format: String) {
    let dateFormatter = NSDateFormatter()
    dateFormatter.dateFormat = format
    println(dateFormatter.stringFromDate(date))
}

If you're not familiar with the Foundation framework and you're not understanding what's happening in the function body, then that's fine. The focus of this example isn't on the implementation of formatting the date. In printDate, we use the value of the format parameter to format the value of date. If we don't pass in a value for the format parameter, Swift will let us know by throwing an error.

We can remedy this by defining a default value for the function's second parameter as shown in the updated function definition below.

func printDate(date: NSDate, format: String = "YY/MM/dd") {
    let dateFormatter = NSDateFormatter()
    dateFormatter.dateFormat = format
    println(dateFormatter.stringFromDate(date))
}

Defining a default value is as simple as specifying a value in the list of parameters in the function's definition. The result is that Swift will no longer complain and the error disappears.

printDate(NSDate())

What if we do want to pass in a value for the format parameter? Let's try it out and see what Swift tells us.

Because the format parameter has a default value and is therefore optional, we need to pass in the argument's name to tell Swift what parameter we're referring to. The fix is very simple as you can see below.

printDate(NSDate(), format: "dd/MM/YY")

Note that Apple recommends to position parameters with a default value at the end of the list of parameters. This is certainly a good idea and common in most other programming languages that support optional parameters.

3. Return Type

The functions we've seen so far don't return anything to us when we invoke them. Let's make the printDate function more useful by returning the formatted date as a string, instead of printing the formatted date from within the function. This requires two changes as you can see below.

func printDate(date: NSDate, format: String = "YY/MM/dd") -> String {
    let dateFormatter = NSDateFormatter()
    dateFormatter.dateFormat = format
    return dateFormatter.stringFromDate(date)
}

The first thing we change is the function's definition. After the list of parameters we specify the return type, String. The return type is preceded by the -> symbol. If you've worked with CoffeeScript, then this will look familiar.

Instead of printing the formatted date using the println function, we use the return keyword to return the value from the function. That's all we need to do. Let's try it out.

let formattedDate = printDate(NSDate(), format: "dd/MM/YY")

println(formattedDate)

We invoke the printDate function, store the returned value in the constant formattedDate, and print the value of formattedDate in the standard output. Note that the name of the printDate function no longer reflects what it does so you may want to change it to formatDate.

No Return Type

The other functions we've defined in this tutorial didn't have a return type. When a function doesn't have a return type, it isn't necessary to include the -> symbol in the function definition.

A few paragraphs earlier, I told you that none of the functions we had defined returned a value to us. That's actually not entirely true. Let me explain the nitty-gritty details with an experiment. Add the following line to your playground and see what happens.

This is interesting. Swift doesn't have a problem that we store the return value of the printHelloWorld function in a constant, but it does complain that it is unable to infer the type of the value constant.

What's happening here? Every function in Swift returns a value, even if we don't define a return type in the function definition. When a function doesn't explicitly specify a return type, the function implicitly returns Void, which is equivalent to an empty tuple, or () for short. You can see this in the playground's output pane as shown in the above screenshot.

We can get rid of the above warning by explicitly declaring the type of value, an empty tuple. I agree that it's not very useful to store an empty tuple in a constant, but it illustrates you that every function has a return value.

let value: () = printHelloWorld()

Tuples

Another great feature of Swift is the ability to return multiple values from a function by returning a tuple. The following example illustrates how this works. Let me repeat that it's not important that you understand how the timeComponentsForDate function does its job. The focus is the return value of the timeComponentsForDate function, a tuple with three elements.

func timeComponentsForDate(date: NSDate) -> (hour: Int, minute: Int, second: Int) {
    let dateComponents = NSCalendar.currentCalendar().components((.CalendarUnitHour | .CalendarUnitMinute | .CalendarUnitSecond), fromDate: date)
    let hour = dateComponents.hour
    let minute = dateComponents.minute
    let second = dateComponents.second
    return (hour, minute, second)
}

The function accepts one argument, an NSDate instance, and returns a tuple with three labeled values. Labeling the tuple's values is only for convenience, it is possible to omit the labels.

func timeComponentsForDate(date: NSDate) -> (Int, Int, Int) {
    let dateComponents = NSCalendar.currentCalendar().components((.CalendarUnitHour | .CalendarUnitMinute | .CalendarUnitSecond), fromDate: date)
    let hour = dateComponents.hour
    let minute = dateComponents.minute
    let second = dateComponents.second
    return (hour, minute, second)
}

However, as the following example illustrates, labeling the values of the tuple returned from the function is very convenient and makes your code easier to understand.

let timeComponents = timeComponentsForDate(NSDate())

println(timeComponents.hour)
println(timeComponents.minute)
println(timeComponents.second)

It's also possible to return an optional value from a function if there are scenarios in which the function has no value to return. This is as simple as defining the return type of the function as optional as shown below.

func timeComponentsForDate(date: NSDate) -> (hour: Int, minute: Int, second: Int)? {
    let dateComponents = NSCalendar.currentCalendar().components((.CalendarUnitHour | .CalendarUnitMinute | .CalendarUnitSecond), fromDate: date)
    let hour = dateComponents.hour
    let minute = dateComponents.minute
    let second = dateComponents.second
    return (hour, minute, second)
}

Conclusion

In this tutorial, we've focused on the basics of functions in Swift. It's important that you understand the syntax of functions, because in the next article we will explore more advanced functions that build upon what we've covered in this tutorial.

I encourage you to read the article again if necessary and, more importantly, write a few functions in a playground to become familiar with the syntax. The basics are easy to understand, but you only get the hang of them by practicing.

2015-01-09T18:05:17.000Z2015-01-09T18:05:17.000ZBart Jacobs

Swift from Scratch: An Introduction to Functions

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-22879

To get anything done in Swift, you'll need to learn the ins and outs of functions. Functions are exceptionally powerful and flexible in Swift. The basics are simple—especially if you've worked with other programming languages before—but because of Swift's flexible syntax it can easily become complex if you're not familiar with the basics.

In this article, we'll focus on those basics first and explore the more complex syntax and use cases in the next article. It's important that you don't skim the basics as they are essential to understand where a function's power comes from in Swift. Let's start with an example to dissect the anatomy of a function in Swift.

1. Learn by Example

A function is nothing more than a block of code that can be executed whenever it's needed. I'd like to start with an example to discuss the basic anatomy of a Swift function. Fire up Xcode and create a new playground. Add the following function definition to the playground.

A function begins with the func keyword and is followed by the name of the function, printHelloWorld in our example. As in many other languages, the name of the function is followed by a pair of parentheses that contain the function's parameters, the function's input.

The body of the function is wrapped in a pair of curly braces. The printHelloWorld function contains one statement in which we print the string Hello World! in the standard output. This is what a basic function looks like in Swift. The syntax is simple, clean, and minimalist.

You can invoke the function by typing the name of the function, followed by a pair of parentheses.

2. Parameters

Let's make the above example a bit more complex by adding parameters to the function definition. This simply means that we provide the function with input values it can use in the function's body. In the following example, we define the printMessage function, which accepts one parameter, message, of type String.

A function can accept multiple parameters or input values. The parameters are wrapped by the parentheses that follow the function's name. The name of the parameter is followed by a colon and the parameter's type. As you remember, this is very similar to declaring a variable or constant. It simply says that the message parameter is of typeString.

Instead of printing a hard-coded string like we did in the printHelloWorld function, we print the message parameter's value. This makes the function flexible and more useful.

Invoking the function is very similar to what we saw earlier. The only difference is that we pass in an argument when invoking the function.

Note that the terms parameters and arguments are often used interchangeably, but there is a subtle, semantic difference in Swift. In Swift, parameters are the values specified in the function definition while arguments are the values passed to the function when it is invoked.

Multiple Parameters

As I mentioned earlier, the syntax of functions is very flexible and it shouldn't surprise you that it's perfectly possible to pass multiple arguments to a function. In the next example, we create a variation on the printMessage function that allows us to print the message multiple times.

While the name of the function is identical to that of the original printMessage function, the function's type is different. It's important you understand the previous sentence. Read it again.

Each function has a type, consisting of the parameter types and the return type. We'll explore return types in a moment. Functions can have the same name as long as their type is different as shown by the previous two function definitions.

The type of the first function is (String) -> () while the type of the second function is(String, Int) -> (). The name of both functions is the same. Don't worry about the -> symbol. Its meaning will become clear in a few moments when we discuss return types.

The second printMessage function defines two parameters, message of type String and times of type Int. This definition illustrates one of the features Swift has adopted from Objective-C, readable function/method names. While the name of the function is printMessage, by reading the names of the function's parameters, it's easy to understand what the function is supposed to do.

In the second printMessage function, we create a for-in loop to print the message string times times. We use the half-open range operator, ..<, as we saw earlier in this series.

When we start typing printMessage in the playground, Xcode displays both functions in the autocompletion menu. Thanks to the function's type, it's easy to choose the function we're interested in. Calling the second printMessage function is as simple as:

Default Values

One of my favorite features is the ability to define default values for parameters. This may sound silly if you're coming from a language that has had this feature for ages, but this is pretty great if you've been working with C and Objective-C for many years.

In short, Swift allows developers to define default values for the parameters of a function. Let's define a new function that prints the current date in a specific format. Make sure you add the following import statement at the top of your playground to import the UIKit framework.

Let's first define the printDate function without making use of default values for any of the parameters.

If you're not familiar with the Foundation framework and you're not understanding what's happening in the function body, then that's fine. The focus of this example isn't on the implementation of formatting the date. In printDate, we use the value of the format parameter to format the value of date. If we don't pass in a value for the format parameter, Swift will let us know by throwing an error.

We can remedy this by defining a default value for the function's second parameter as shown in the updated function definition below.

Defining a default value is as simple as specifying a value in the list of parameters in the function's definition. The result is that Swift will no longer complain and the error disappears.

What if we do want to pass in a value for the format parameter? Let's try it out and see what Swift tells us.

Because the format parameter has a default value and is therefore optional, we need to pass in the argument's name to tell Swift what parameter we're referring to. The fix is very simple as you can see below.

Note that Apple recommends to position parameters with a default value at the end of the list of parameters. This is certainly a good idea and common in most other programming languages that support optional parameters.

3. Return Type

The functions we've seen so far don't return anything to us when we invoke them. Let's make the printDate function more useful by returning the formatted date as a string, instead of printing the formatted date from within the function. This requires two changes as you can see below.

The first thing we change is the function's definition. After the list of parameters we specify the return type, String. The return type is preceded by the -> symbol. If you've worked with CoffeeScript, then this will look familiar.

Instead of printing the formatted date using the println function, we use the return keyword to return the value from the function. That's all we need to do. Let's try it out.

We invoke the printDate function, store the returned value in the constant formattedDate, and print the value of formattedDate in the standard output. Note that the name of the printDate function no longer reflects what it does so you may want to change it to formatDate.

No Return Type

The other functions we've defined in this tutorial didn't have a return type. When a function doesn't have a return type, it isn't necessary to include the -> symbol in the function definition.

A few paragraphs earlier, I told you that none of the functions we had defined returned a value to us. That's actually not entirely true. Let me explain the nitty-gritty details with an experiment. Add the following line to your playground and see what happens.

This is interesting. Swift doesn't have a problem that we store the return value of the printHelloWorld function in a constant, but it does complain that it is unable to infer the type of the value constant.

What's happening here? Every function in Swift returns a value, even if we don't define a return type in the function definition. When a function doesn't explicitly specify a return type, the function implicitly returns Void, which is equivalent to an empty tuple, or () for short. You can see this in the playground's output pane as shown in the above screenshot.

We can get rid of the above warning by explicitly declaring the type of value, an empty tuple. I agree that it's not very useful to store an empty tuple in a constant, but it illustrates you that every function has a return value.

Tuples

Another great feature of Swift is the ability to return multiple values from a function by returning a tuple. The following example illustrates how this works. Let me repeat that it's not important that you understand how the timeComponentsForDate function does its job. The focus is the return value of the timeComponentsForDate function, a tuple with three elements.

The function accepts one argument, an NSDate instance, and returns a tuple with three labeled values. Labeling the tuple's values is only for convenience, it is possible to omit the labels.

However, as the following example illustrates, labeling the values of the tuple returned from the function is very convenient and makes your code easier to understand.

It's also possible to return an optional value from a function if there are scenarios in which the function has no value to return. This is as simple as defining the return type of the function as optional as shown below.

Conclusion

In this tutorial, we've focused on the basics of functions in Swift. It's important that you understand the syntax of functions, because in the next article we will explore more advanced functions that build upon what we've covered in this tutorial.

I encourage you to read the article again if necessary and, more importantly, write a few functions in a playground to become familiar with the syntax. The basics are easy to understand, but you only get the hang of them by practicing.

2015-01-09T18:05:17.000Z2015-01-09T18:05:17.000ZBart Jacobs

The Ins and Outs of Gradle

$
0
0

As the first IDE (Integrated Development Environment) dedicated entirely to Android, the Google-backed Android Studio is an exciting prospect for Android developers. But it also means getting to grips with some new technology, most notably the Gradle build system.

This article gets you up and running with Android's new build system, from the basics of what Gradle is and what it does, to an in-depth look at some of the most important Gradle files, to learning how to execute and monitor Gradle tasks.

You'll also take a closer look at the various Gradle tool windows in Android Studio, and learn how to add dependencies to a project, all with no previous Gradle experience necessary.

The first step in getting to grips with Android's new build system is understanding exactly what Gradle is and why its inclusion in Android Studio is such good news for Android developers.

1. What is Gradle?

Gradle is an automated build toolkit that can integrate into lots of different environments, via plugins. In Android Studio, Gradle integration is achieved via the aptly-named Android Gradle plugin.

If you've never used Gradle before, it may seem like a frustrating barrier to entry when you're considering making the move to Android Studio. However, Gradle has lots to offer to Android developers, so it's well worth investing some time into learning the ins and outs of Gradle. Here's just a few of the things you can do with Gradle.

Minimize Configuration Required for New Projects

Gradle has a set of default configuration settings that are automatically applied to every project you create in Android Studio. If you're developing a project that doesn't adhere to these default configuration rules, Gradle is easy to customize.

Declare Project Dependencies

Dependencies can be modules, JAR files or libraries, and they can be located either on the local file system or a remote server.

Test Your Project

Gradle automatically generates a test directory and a test APK from your project's test sources and can run your tests during the build process.

Generate Signed APKs

If you add all the necessary information, such as keyPassword and keyAlias, to your Gradle build file, you can use Gradle to generate signed APKs.

Generate Multiple APKs from a Single Module

Gradle can generate multiple APKs with different package and build configurations from a single module. This feature is particularly handy for Android developers, for several reasons:

1. Support a Wide Range of Devices

A big part of developing for the Android platform is supporting as many different Android devices and versions of the Android operating system as possible. The Google Play store even has multi APK support, so you can create multiple versions of your app, where each version targets a different device configuration, offering them as a single Play store listing.

This is where Gradle comes in. You can use Android's new build system to generate multiple APK variants from the same module. Just give these variants the same package name and you can upload them to the same Google Play listing.

2. Offer Different Versions of an App

Sometimes, you’ll want to list multiple versions of your app in the Play store, for example, if you're offering a free and a "Pro" version of your app. Again, you can use Gradle to generate multiple APKs from the same module and give each APK a different package name. You can then upload each APK to the Play store separately.

2. Exploring the Gradle Files

Whenever you create a project in Android Studio, the build system automatically generates all the necessary Gradle build files.

Since you'll encounter the same set of Gradle files every time you create an Android Studio project, we'll create a basic sample project and then take a closer look at these automatically generated files.

The first step is creating your sample project:

  1. Launch Android Studio.
  2. Click Start a new Android Studio project.
  3. Give your project a name, enter a domain, and choose where your sample project should be stored. Click Next.
  4. Ensure only Phone and tablet is selected, and accept the default Minimum SDK settings. Click Next.
  5. Select Blank Activity and click Next.
  6. Stick with the default settings, and click Finish.

Gradle Build Files

Gradle build files use a Domain Specific Language or DSL to define custom build logic and to interact with the Android-specific elements of the Android plugin for Gradle.

Android Studio projects consist of one or more modules, which are components that you can build, test, and debug independently. Each module has its own build file, so every Android Studio project contains two kinds of Gradle build files:

  • Top-Level Build File: This is where you'll find the configuration options that are common to all the modules that make up your project.
  • Module-Level Build File: Each module has its own Gradle build file that contains module-specific build settings. You'll spend most of your time editing module-level build file(s) rather than your project's top-level build file.

To take a look at these build.gradle files, open Android Studio's Project panel (by selecting the Project tab) and expand the Gradle Scripts folder. In our sample project, the first two items in the list are your project's top-level and module-level build files.

The first two items in the Gradle Scripts folder are the project-level and module-level Gradle build files

Our sample project only has a single module-level build file, but the screenshot below gives you an idea of how the Gradle Scripts folder might look for a project with multiple modules.

Example of how the Gradle Scripts folder looks for a multiple module project

Top-Level Gradle Build File

Every Android Studio project contains a single, top-level Gradle build file. This build.gradle file is the first item that appears in the Gradle Scripts folder and is clearly marked Project.

Most of the time, you won't need to make any changes to this file, but it's still useful to understand its contents and the role it plays within your project. Below is an annotated version of a typical top-level build file.

Module-Level Gradle Build Files

In addition to the project-level Gradle build file, each module has a Gradle build file of its own. Below is an annotated version of a basic, module-level Gradle build file.

Other Gradle Files

In addition to the build.gradle files, your Gradle Scripts folder contains some other Gradle files. Most of the time you won't have to manually edit these files as they'll update automatically when you make any relevant changes to your project. However, it's a good idea to understand the role these files play within your project.

gradle-wrapper.properties (Gradle Version)

This file allows other people to build your code, even if they don't have Gradle installed on their machine. This file checks whether the correct version of Gradle is installed and downloads the necessary version if necessary. In our sample app, gradle-wrapper.properties contains the following:

settings.gradle

This file references all the modules that make up your project. Since our sample project has a single module, this file is very straightforward as you can see below.

gradle.properties (Project Properties)

This file contains configuration information for your entire project. It's empty by default, but you can apply a wide range of properties to your project by adding them to this file.

local.properties (SDK Location)

This file tells the Android Gradle plugin where it can find your Android SDK installation. For example:

Note that local.properties contains information that's specific to the local installation of the Android SDK. This means that you shouldn't keep this file under source control.

3. Android Studio User Interface

Now that you're familiar with all the automatically generated Gradle files, it's time to move onto interacting with the Gradle build system. The good news is that you can interact with Gradle directly from the Android Studio user interface.

Around the vertical and horizontal edges of Andorid Studio are tabs that open various tool windows. In the next few sections, I'll introduce you to some of Android Studio's Gradle-specific tool windows and show how to interact with the Gradle build system via these windows.

Gradle Tasks Window

You can use the Gradle tasks window to browse and execute the various tasks involved in compiling your project into an executable application.

To open the Gradle tasks window, click the Gradle tab along the right-hand side of your Android Studio installation. If you've customised your Android Studio user interface and can no longer find the Gradle tab, then you can select View > Tool Windows > Gradle instead.

In the Gradle tasks tab, double-click your project, followed by your module. You'll see a list of all the Gradle tasks related to this module.

Select the Gradle tab to reveal the Gradle tasks window

When you double-click a task in the Gradle tasks window, it starts executing and the output appears in another Gradle-specific window, the Gradle Console.

Gradle Console

The Gradle Console displays the output of Gradle tasks as they execute, alongside any error messages or warnings.

To open the Gradle Console, select the Gradle Console tab towards the bottom-right of your IDE. If you've customized Android Studio's user interface and can no longer find this tab, you can always select View > Tool Windows > Gradle Console instead.

Let's take the Gradle Console for a spin. In the Gradle tasks window, find the assemble task, which builds a release version of your application ready for distribution, and double-click it. As the assemble task executes, the task's output appears in the Gradle Console.

The Gradle Console will then either notify you that your project has built successfully or it will display a "build failed" message alongside information about why your build has failed.

Example of the assemble task output in the Gradle Console

Terminal

You can also run Gradle tasks from Android Studio's integrated Terminal. If you know exactly what Gradle task you want to execute, the Terminal is usually much quicker and more convenient than browsing the lists of tasks in the Gradle Console.

To open the Terminal, click the Terminal tab towards the bottom-left of Android Studio, or select View > Tool Windows > Gradle Console. The Terminal will then open with the current directory already selected. You can then execute Gradle tasks by typing them into the Terminal and pressing either the Return or the Enter key on your keyboard.

4. Adding Dependencies

In this section, we'll explore how you can use Gradle to manage your project's module dependencies, local binary dependencies, and remote binary dependencies.

When it comes to adding dependencies to your project, Gradle gives you several options.

Option 1: Drop Files Into Project's libs/directory

The relevant build.gradle file will then update automatically.

Option 2: Modify build.gradle File Manually

Open your build.gradle file and add a new build rule to the dependencies closure. For example, if you wanted to add Google Play Services, your project's dependencies section would look something like this:

Option 3: Use Android Studio's User Interface

In the Project panel, Control+Click the module you want to add the dependency to and select Open Module Settings.

Add a dependency via the Android Studio UI

Select the Dependencies tab, followed by the + button in the bottom-left corner. You can choose from the following list of options:

  • Library Dependency
  • File Dependency
  • Module Dependency

You can then enter more information about the dependency you want to add to your project. For example, if you choose Library Dependency, Android Studio displays a list of libraries for you to choose from.

Once you've added your dependency, check your module-level build.gradle file. It should have automatically updated to include the new dependency.

Conclusion

This article has introduced you to all the automatically generated Gradle build files you'll find in your typical Android Studio project, particularly the top-level and module-level Gradle build files. You've also learned how to interact directly with the Gradle build system from the Android Studio user interface.

If you're interested in learning more about Gradle, then you'll find lots of additional information on the Android developer website and on the Gradle website.

2015-01-12T17:45:52.000Z2015-01-12T17:45:52.000ZJessica Thornsby

The Ins and Outs of Gradle

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-22978

As the first IDE (Integrated Development Environment) dedicated entirely to Android, the Google-backed Android Studio is an exciting prospect for Android developers. But it also means getting to grips with some new technology, most notably the Gradle build system.

This article gets you up and running with Android's new build system, from the basics of what Gradle is and what it does, to an in-depth look at some of the most important Gradle files, to learning how to execute and monitor Gradle tasks.

You'll also take a closer look at the various Gradle tool windows in Android Studio, and learn how to add dependencies to a project, all with no previous Gradle experience necessary.

The first step in getting to grips with Android's new build system is understanding exactly what Gradle is and why its inclusion in Android Studio is such good news for Android developers.

1. What is Gradle?

Gradle is an automated build toolkit that can integrate into lots of different environments, via plugins. In Android Studio, Gradle integration is achieved via the aptly-named Android Gradle plugin.

If you've never used Gradle before, it may seem like a frustrating barrier to entry when you're considering making the move to Android Studio. However, Gradle has lots to offer to Android developers, so it's well worth investing some time into learning the ins and outs of Gradle. Here's just a few of the things you can do with Gradle.

Minimize Configuration Required for New Projects

Gradle has a set of default configuration settings that are automatically applied to every project you create in Android Studio. If you're developing a project that doesn't adhere to these default configuration rules, Gradle is easy to customize.

Declare Project Dependencies

Dependencies can be modules, JAR files or libraries, and they can be located either on the local file system or a remote server.

Test Your Project

Gradle automatically generates a test directory and a test APK from your project's test sources and can run your tests during the build process.

Generate Signed APKs

If you add all the necessary information, such as keyPassword and keyAlias, to your Gradle build file, you can use Gradle to generate signed APKs.

Generate Multiple APKs from a Single Module

Gradle can generate multiple APKs with different package and build configurations from a single module. This feature is particularly handy for Android developers, for several reasons:

1. Support a Wide Range of Devices

A big part of developing for the Android platform is supporting as many different Android devices and versions of the Android operating system as possible. The Google Play store even has multi APK support, so you can create multiple versions of your app, where each version targets a different device configuration, offering them as a single Play store listing.

This is where Gradle comes in. You can use Android's new build system to generate multiple APK variants from the same module. Just give these variants the same package name and you can upload them to the same Google Play listing.

2. Offer Different Versions of an App

Sometimes, you’ll want to list multiple versions of your app in the Play store, for example, if you're offering a free and a "Pro" version of your app. Again, you can use Gradle to generate multiple APKs from the same module and give each APK a different package name. You can then upload each APK to the Play store separately.

2. Exploring the Gradle Files

Whenever you create a project in Android Studio, the build system automatically generates all the necessary Gradle build files.

Since you'll encounter the same set of Gradle files every time you create an Android Studio project, we'll create a basic sample project and then take a closer look at these automatically generated files.

The first step is creating your sample project:

  1. Launch Android Studio.
  2. Click Start a new Android Studio project.
  3. Give your project a name, enter a domain, and choose where your sample project should be stored. Click Next.
  4. Ensure only Phone and tablet is selected, and accept the default Minimum SDK settings. Click Next.
  5. Select Blank Activity and click Next.
  6. Stick with the default settings, and click Finish.

Gradle Build Files

Gradle build files use a Domain Specific Language or DSL to define custom build logic and to interact with the Android-specific elements of the Android plugin for Gradle.

Android Studio projects consist of one or more modules, which are components that you can build, test, and debug independently. Each module has its own build file, so every Android Studio project contains two kinds of Gradle build files:

  • Top-Level Build File: This is where you'll find the configuration options that are common to all the modules that make up your project.
  • Module-Level Build File: Each module has its own Gradle build file that contains module-specific build settings. You'll spend most of your time editing module-level build file(s) rather than your project's top-level build file.

To take a look at these build.gradle files, open Android Studio's Project panel (by selecting the Project tab) and expand the Gradle Scripts folder. In our sample project, the first two items in the list are your project's top-level and module-level build files.

The first two items in the Gradle Scripts folder are the project-level and module-level Gradle build files

Our sample project only has a single module-level build file, but the screenshot below gives you an idea of how the Gradle Scripts folder might look for a project with multiple modules.

Example of how the Gradle Scripts folder looks for a multiple module project

Top-Level Gradle Build File

Every Android Studio project contains a single, top-level Gradle build file. This build.gradle file is the first item that appears in the Gradle Scripts folder and is clearly marked Project.

Most of the time, you won't need to make any changes to this file, but it's still useful to understand its contents and the role it plays within your project. Below is an annotated version of a typical top-level build file.

Module-Level Gradle Build Files

In addition to the project-level Gradle build file, each module has a Gradle build file of its own. Below is an annotated version of a basic, module-level Gradle build file.

Other Gradle Files

In addition to the build.gradle files, your Gradle Scripts folder contains some other Gradle files. Most of the time you won't have to manually edit these files as they'll update automatically when you make any relevant changes to your project. However, it's a good idea to understand the role these files play within your project.

gradle-wrapper.properties (Gradle Version)

This file allows other people to build your code, even if they don't have Gradle installed on their machine. This file checks whether the correct version of Gradle is installed and downloads the necessary version if necessary. In our sample app, gradle-wrapper.properties contains the following:

settings.gradle

This file references all the modules that make up your project. Since our sample project has a single module, this file is very straightforward as you can see below.

gradle.properties (Project Properties)

This file contains configuration information for your entire project. It's empty by default, but you can apply a wide range of properties to your project by adding them to this file.

local.properties (SDK Location)

This file tells the Android Gradle plugin where it can find your Android SDK installation. For example:

Note that local.properties contains information that's specific to the local installation of the Android SDK. This means that you shouldn't keep this file under source control.

3. Android Studio User Interface

Now that you're familiar with all the automatically generated Gradle files, it's time to move onto interacting with the Gradle build system. The good news is that you can interact with Gradle directly from the Android Studio user interface.

Around the vertical and horizontal edges of Andorid Studio are tabs that open various tool windows. In the next few sections, I'll introduce you to some of Android Studio's Gradle-specific tool windows and show how to interact with the Gradle build system via these windows.

Gradle Tasks Window

You can use the Gradle tasks window to browse and execute the various tasks involved in compiling your project into an executable application.

To open the Gradle tasks window, click the Gradle tab along the right-hand side of your Android Studio installation. If you've customised your Android Studio user interface and can no longer find the Gradle tab, then you can select View > Tool Windows > Gradle instead.

In the Gradle tasks tab, double-click your project, followed by your module. You'll see a list of all the Gradle tasks related to this module.

Select the Gradle tab to reveal the Gradle tasks window

When you double-click a task in the Gradle tasks window, it starts executing and the output appears in another Gradle-specific window, the Gradle Console.

Gradle Console

The Gradle Console displays the output of Gradle tasks as they execute, alongside any error messages or warnings.

To open the Gradle Console, select the Gradle Console tab towards the bottom-right of your IDE. If you've customized Android Studio's user interface and can no longer find this tab, you can always select View > Tool Windows > Gradle Console instead.

Let's take the Gradle Console for a spin. In the Gradle tasks window, find the assemble task, which builds a release version of your application ready for distribution, and double-click it. As the assemble task executes, the task's output appears in the Gradle Console.

The Gradle Console will then either notify you that your project has built successfully or it will display a "build failed" message alongside information about why your build has failed.

Example of the assemble task output in the Gradle Console

Terminal

You can also run Gradle tasks from Android Studio's integrated Terminal. If you know exactly what Gradle task you want to execute, the Terminal is usually much quicker and more convenient than browsing the lists of tasks in the Gradle Console.

To open the Terminal, click the Terminal tab towards the bottom-left of Android Studio, or select View > Tool Windows > Gradle Console. The Terminal will then open with the current directory already selected. You can then execute Gradle tasks by typing them into the Terminal and pressing either the Return or the Enter key on your keyboard.

4. Adding Dependencies

In this section, we'll explore how you can use Gradle to manage your project's module dependencies, local binary dependencies, and remote binary dependencies.

When it comes to adding dependencies to your project, Gradle gives you several options.

Option 1: Drop Files Into Project's libs/directory

The relevant build.gradle file will then update automatically.

Option 2: Modify build.gradle File Manually

Open your build.gradle file and add a new build rule to the dependencies closure. For example, if you wanted to add Google Play Services, your project's dependencies section would look something like this:

Option 3: Use Android Studio's User Interface

In the Project panel, Control+Click the module you want to add the dependency to and select Open Module Settings.

Add a dependency via the Android Studio UI

Select the Dependencies tab, followed by the + button in the bottom-left corner. You can choose from the following list of options:

  • Library Dependency
  • File Dependency
  • Module Dependency

You can then enter more information about the dependency you want to add to your project. For example, if you choose Library Dependency, Android Studio displays a list of libraries for you to choose from.

Once you've added your dependency, check your module-level build.gradle file. It should have automatically updated to include the new dependency.

Conclusion

This article has introduced you to all the automatically generated Gradle build files you'll find in your typical Android Studio project, particularly the top-level and module-level Gradle build files. You've also learned how to interact directly with the Gradle build system from the Android Studio user interface.

If you're interested in learning more about Gradle, then you'll find lots of additional information on the Android developer website and on the Gradle website.

2015-01-12T17:45:52.000Z2015-01-12T17:45:52.000ZJessica Thornsby

Create a Space Invaders Game in Corona: Finishing Gameplay

$
0
0
Final product image
What You'll Be Creating

In the previous part of this series, we got the player's ship moving, got the invaders moving, and detected when a player bullet had hit an invader. In this final part of the series, we will get the invaders attacking the player, handle levels, and add the ability for the player to die.

1. Firing Bullets

Every so often one of the invaders fires a bullet. We'll use a timer to accomplish this. Add the following code to gamelevel.lua.

In this function, we first check if the invadersWhoCanFire table has at least one element in it. If that's the case, then we execute the code in the if statement. Otherwise it means the level is over and we invoke the levelComplete function.

There will always be at least one invader who can fire a bullet until you kill the last invader, at which point the invadersWhoCanFire table will be empty.

Inside the if statement, we generate a random number randomIndex depending on how many items are in the invadersWhoCanFire table. We then choose that item, randomInvader, from the invadersWhoCanFire table.

We create a bullet image, give it a name property so we can identify it later, insert it into the scene, and set the same properties as we did on the player's bullet. Finally, we insert the bullet into the invaderBullets table so we can reference it later.

We now need to set up the timer. Add the following to the scene:show method.

Every 1500 milliseconds fireInvaderBullet is invoked. Note that the last parameter we pass in is -1, which means the timer repeats forever. Whenever you create a timer that repeats forever, you should eventually cancel it. We do this in thescene:hide function as shown below.

2. Removing Bullets

Like the player's bullets, the invaders' bullets will move off-screen and keep moving, taking up valuable memory. To remedy this, we remove them just like we did with the player's bullets.

This code is very similar to checking if the player's bullets are out of bounds so I won't discuss its implementation in detail.

3. Detecting a Hit

Step 1: Collision Detection

The next step is to detect whether an invader's bullet has hit the player. Add the following code to the onCollision function.

Like before, we do not know what object event.object1 and event.object2 will be so we use two if statements to check both situations. We remove the invader's bullet from the invaderBullets table, remove it from the display, and set it to nil. If the player isn't invincible, we kill the it.

Step 2: Killing the Player

When we kill the player, we give him a short time of invincibility. This gives the user time to regain focus on the game. If the numberOfLives variable is equal to 0, we know the game is over and transition to the start scene where the user can begin a  new game.

Step 3: Spawning a New Player

The spawnNewPlayer function makes the player fade in and out for a few seconds. It's a nice effect to let the user know that the ship is temporarily invincible.

We use a local function, fadePlayer, that uses the transition library to modify the alpha value of the player. We keep track of how many times the player has faded in and out, and set the player's invincibility to false once we reach the numberOfTimesToFadePlayer. We use a timer to call the fadePlayer function for however many times numberOfTimesToFadePlayer is equal to.

Run the game to test this out. The player should die when an invader's bullet hits the ship. If three bullets hit the ship, you should be taken to the start scene where you can start a new game.

To make this easier to test, comment out the call to moveInvaders in the gameLoop function as shown below.

4. Completing a Level

If you've managed to kill every invader, the game would have called the levelComplete function, which doesn't exist yet. Let fix that. Add the following code block.

We increment gameData.invaderNum and, if it is less than gameData.maxLevels, we transition to the gameover scene. Otherwise, the player has completed every level and we reset gameData.invaderNum to 1. We transition to the start scene where the player can begin a new game.

An easy way to test this is by commenting out the call to moveInvaders in the gameLoop function and use the buttons to move the ship. If that's still too hard, then you can also comment out the two calls to killPlayer in the onCollision method.

5. Game Over

Add the following code to gameover.lua to implement the game over scene.

This code is very similar to the start scene so you should be familiar with it by now.

6. Colliding with an Invader

The last collision check we need to perform is a collision between the player and on of the invaders. Add the following code block to the onCollision method we saw earlier.

As usual, we need to check both collision situations. We set the numberOfLives to 0 and call killPlayer. By setting numberOfLives to 0 and invoking killPlayer, the game is over and the game transitions to the start scene.

7. More Features

This completes our game, but I suggest you try to expand the game with a few additional features. For example, you could display the player's lives in a HUD.

I have also included a UFO graphic in the source files. You could try make a UFO randomly appear and if the player hits it with a bullet give them an extra life.

If you need help with these concepts, then check out my Plane Fighting Game series on Tuts+.

Conclusion

If you've followed this series, then you should now have a fully functional game similar to the original Space Invaders. Expand on it and make it your own. I hope you found this tutorial helpful and have learned some new techniques. Thank you for for reading.

2015-01-14T17:15:41.000Z2015-01-14T17:15:41.000ZJames Tyner

Create a Space Invaders Game in Corona: Finishing Gameplay

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-22789
Final product image
What You'll Be Creating

In the previous part of this series, we got the player's ship moving, got the invaders moving, and detected when a player bullet had hit an invader. In this final part of the series, we will get the invaders attacking the player, handle levels, and add the ability for the player to die.

1. Firing Bullets

Every so often one of the invaders fires a bullet. We'll use a timer to accomplish this. Add the following code to gamelevel.lua.

In this function, we first check if the invadersWhoCanFire table has at least one element in it. If that's the case, then we execute the code in the if statement. Otherwise it means the level is over and we invoke the levelComplete function.

There will always be at least one invader who can fire a bullet until you kill the last invader, at which point the invadersWhoCanFire table will be empty.

Inside the if statement, we generate a random number randomIndex depending on how many items are in the invadersWhoCanFire table. We then choose that item, randomInvader, from the invadersWhoCanFire table.

We create a bullet image, give it a name property so we can identify it later, insert it into the scene, and set the same properties as we did on the player's bullet. Finally, we insert the bullet into the invaderBullets table so we can reference it later.

We now need to set up the timer. Add the following to the scene:show method.

Every 1500 milliseconds fireInvaderBullet is invoked. Note that the last parameter we pass in is -1, which means the timer repeats forever. Whenever you create a timer that repeats forever, you should eventually cancel it. We do this in thescene:hide function as shown below.

2. Removing Bullets

Like the player's bullets, the invaders' bullets will move off-screen and keep moving, taking up valuable memory. To remedy this, we remove them just like we did with the player's bullets.

This code is very similar to checking if the player's bullets are out of bounds so I won't discuss its implementation in detail.

3. Detecting a Hit

Step 1: Collision Detection

The next step is to detect whether an invader's bullet has hit the player. Add the following code to the onCollision function.

Like before, we do not know what object event.object1 and event.object2 will be so we use two if statements to check both situations. We remove the invader's bullet from the invaderBullets table, remove it from the display, and set it to nil. If the player isn't invincible, we kill the it.

Step 2: Killing the Player

When we kill the player, we give him a short time of invincibility. This gives the user time to regain focus on the game. If the numberOfLives variable is equal to 0, we know the game is over and transition to the start scene where the user can begin a  new game.

Step 3: Spawning a New Player

The spawnNewPlayer function makes the player fade in and out for a few seconds. It's a nice effect to let the user know that the ship is temporarily invincible.

We use a local function, fadePlayer, that uses the transition library to modify the alpha value of the player. We keep track of how many times the player has faded in and out, and set the player's invincibility to false once we reach the numberOfTimesToFadePlayer. We use a timer to call the fadePlayer function for however many times numberOfTimesToFadePlayer is equal to.

Run the game to test this out. The player should die when an invader's bullet hits the ship. If three bullets hit the ship, you should be taken to the start scene where you can start a new game.

To make this easier to test, comment out the call to moveInvaders in the gameLoop function as shown below.

4. Completing a Level

If you've managed to kill every invader, the game would have called the levelComplete function, which doesn't exist yet. Let fix that. Add the following code block.

We increment gameData.invaderNum and, if it is less than gameData.maxLevels, we transition to the gameover scene. Otherwise, the player has completed every level and we reset gameData.invaderNum to 1. We transition to the start scene where the player can begin a new game.

An easy way to test this is by commenting out the call to moveInvaders in the gameLoop function and use the buttons to move the ship. If that's still too hard, then you can also comment out the two calls to killPlayer in the onCollision method.

5. Game Over

Add the following code to gameover.lua to implement the game over scene.

This code is very similar to the start scene so you should be familiar with it by now.

6. Colliding with an Invader

The last collision check we need to perform is a collision between the player and on of the invaders. Add the following code block to the onCollision method we saw earlier.

As usual, we need to check both collision situations. We set the numberOfLives to 0 and call killPlayer. By setting numberOfLives to 0 and invoking killPlayer, the game is over and the game transitions to the start scene.

7. More Features

This completes our game, but I suggest you try to expand the game with a few additional features. For example, you could display the player's lives in a HUD.

I have also included a UFO graphic in the source files. You could try make a UFO randomly appear and if the player hits it with a bullet give them an extra life.

If you need help with these concepts, then check out my Plane Fighting Game series on Tuts+.

Conclusion

If you've followed this series, then you should now have a fully functional game similar to the original Space Invaders. Expand on it and make it your own. I hope you found this tutorial helpful and have learned some new techniques. Thank you for for reading.

2015-01-14T17:15:41.000Z2015-01-14T17:15:41.000ZJames Tyner

New Course: The Swift Programming Language

$
0
0

At Apple's annual WWDC in 2014, it announced the creation and release of a brand new programming language: Swift. The idea is to use this language going forward when creating apps that target both iOS and OS X operating systems. 

While Swift is not currently required to be used on these platforms, we definitely shouldn't be waiting around to learn about the basic constructs and how to use it. So our new course on The Swift Programming Language lets you dive right in and get your feet wet by learning the basics of the language.

What You'll Learn

In this 27-part video course, Tuts+ instructor Derek Jensen will cover the basic concepts and building blocks associated with Apple's new flagship programming language: Swift. 

You'll learn how the language is constructed, with lessons on variables and constants, loops, conditionals, closures and more. Then you'll learn about the concepts of Object Oriented Programming and how they relate to the Swift programming language. And you'll also discover the building blocks of the Swift language, such as the functionality contained in the Swift Standard Library.

By the end of this course you’ll have a solid grasp of the fundamentals of Swift, so that you can start using it when developing apps for iOS and OS X. 

Watch the Introduction

Start Learning for Just $15

You can take our new course straight away by subscribing to Tuts+. For just $15 a month, you get access to this course and hundreds of others, with new ones added every week.

2015-01-15T10:59:23.000Z2015-01-15T10:59:23.000ZAndrew Blackman

New Course: The Swift Programming Language

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-23058

At Apple's annual WWDC in 2014, it announced the creation and release of a brand new programming language: Swift. The idea is to use this language going forward when creating apps that target both iOS and OS X operating systems. 

While Swift is not currently required to be used on these platforms, we definitely shouldn't be waiting around to learn about the basic constructs and how to use it. So our new course on The Swift Programming Language lets you dive right in and get your feet wet by learning the basics of the language.

What You'll Learn

In this 27-part video course, Tuts+ instructor Derek Jensen will cover the basic concepts and building blocks associated with Apple's new flagship programming language: Swift. 

You'll learn how the language is constructed, with lessons on variables and constants, loops, conditionals, closures and more. Then you'll learn about the concepts of Object Oriented Programming and how they relate to the Swift programming language. And you'll also discover the building blocks of the Swift language, such as the functionality contained in the Swift Standard Library.

By the end of this course you’ll have a solid grasp of the fundamentals of Swift, so that you can start using it when developing apps for iOS and OS X. 

Watch the Introduction

Start Learning for Just $15

You can take our new course straight away by subscribing to Tuts+. For just $15 a month, you get access to this course and hundreds of others, with new ones added every week.

2015-01-15T10:59:23.000Z2015-01-15T10:59:23.000ZAndrew Blackman

Swift from Scratch: Function Parameters, Types, and Nesting

$
0
0

In the previous article, we explored the basics of functions in Swift. Functions, however, have a lot more to offer. In this article, we will continue our exploration of functions and look into function parameters, nesting, and types.

1. Local & External Parameter Names

Local Parameter Names

Let's revisit one of the examples of the previous article. The printMessage function defines one parameter, message.

Even though we give the parameter a name, message, we don't use the name when we call the function. We pass in the value for the message parameter.

The name we define in the function's definition is a local parameter name. The value of the parameter can only be referenced by this name in the body of the function. Function parameters, however, are a bit more flexible than that. Let me explain what I mean by that.

Objective-C is known for its long method names. While this may look clunky and inelegant to outsiders, it makes methods easy to understand and, if chosen well, very descriptive. If you think you lost this benefit when switching to Swift, then you're in for a surprise.

External Parameter Names

When a function accepts several parameters, it isn't always obvious which argument corresponds to which parameter. Take a look at the following example to better understand the problem.

The power function raises the value of a by the exponent b. Both parameters are of type Int. While most people will intuitively pass the base value as the first argument and the exponent as the second argument, this isn't clear from the function's type, name, or signature. As we've seen in the previous article, invoking the function is straightforward.

To avoid confusion, we can give the parameters of a function external names. We can then use these external names when the function is called to unambiguously indicate which argument corresponds to which parameter. Take a look at the updated example below.

Note that the function's body hasn't changed since the local names haven't changed. However, when we invoke the updated function, the difference is clear and the result much less confusing.

While the types of both functions are the same, (Int, Int) -> Int, the functions are different. In other words, the second function isn't a redeclaration of the first function. The syntax to invoke the second function may remind some of you of Objective-C. Not only are the arguments clearly described, the combination of function and parameter names describe the purpose of the function.

In some cases, you want to use the same names for local and external parameter names. This is possible and there's no need to type the parameter name twice. In the following example, we use base and exponent as the local and external parameter names.

By prefixing the parameter name with a # symbol, the parameter name serves as the local and external name of the parameter. This also means that we need to update the body of the function.

It's important to note that by providing an external name for a parameter you are required to use that name when invoking the function. This brings us to default values.

Default Values

We covered default parameter values in the previous article, but there is an important default behavior that you need to be aware of. If you define a default value for a parameter, Swift automatically assigns an external parameter name to the parameter. Let's look at an example of the previous article.

Because the second parameter, format, has a default value, Swift automatically sets the external parameter name of format to format. In other words, the result is the same as if we were to prefix format with a # symbol. You can test this by invoking the above function in your playground. What happens if you pass in the format without using the external parameter name of the second parameter? The answer is shown below.

Swift is pretty clear about what we should do. To summarize, when you define a parameter as optional, Swift automatically sets the external parameter name to the local parameter name. The idea behind this behavior is avoiding confusion and ambiguity.

While this behavior is a good best practice, it is possible to disable it. In the updated function definition below, we add an underscore where we would normally add the external parameter name. This tells Swift that we don't want to set an external parameter name for that particular parameter, despite having a default value.

We can now invoke the formatDate function without providing a name for the second argument.

2. Parameters & Mutability

Let's revisit the first example of this tutorial, the printMessage function. What happens if we change the value of the message parameter inside the function's body?

It doesn't take long for Swift to start complaining.

By default, the parameters of a function are constants. In other words, while we can access the values of function parameters, we cannot change their value. To change this default behavior, add the var keyword to the parameter name in the function definition. Swift will then create a variable copy of the parameter's value for you to work with in the function's body.

Note that this doesn't mean that you can pass in a value, modify it in the function, and use the modified value after the function has done its work. Swift creates a copy of the parameter's value that only exists for the lifetime of the function call. This is also illustrated in the following code block in which we pass a constant to the printMessage function.

3. Variadic Parameters

While the term may sound odd at first, variadic parameters are common in programming. A variadic parameter is a parameter that accepts zero or more values. The values need to be of the same type. Using variadic parameters in Swift is trivial as the following example illustrates.

The syntax is easy to understand. To mark a parameter as variadic, you append three dots to the parameter's type. In the function body, the variadic parameter is accessible as an array. In the above example, args is an array of Int values.

Because Swift needs to know which arguments correspond to which parameters, a variadic parameter is required to be the last parameter. It also implies that a function can have at most one variadic parameter.

The above also applies if a function has parameters with default values. The variadic parameter should always be the last parameter.

4. In-Out Parameters

Earlier in this tutorial, you learned how you can define the mutability of a parameter by using the var keyword. In that section, I emphasized that the value of a variable parameter is only accessible from within the function body. If you want to pass a value into a function, modify it in the function, and pass it back out of the function, in-out parameters are what you're looking for.

The following example shows an example of how in-out parameters work in Swift and what the syntax looks like.

We've defined the first parameter as an in-out parameter by adding the inout keyword. The second parameter is a regular parameter with an external name of withString and a local name of b. Let's see how we invoke this function.

We declare a variable, world, of type String and pass it to the perpendString function. The second parameter is a string literal. By invoking the function, the value of the world variable becomes Hello, world. Note that the first argument is prefixed with an ampersand, &, to indicate that it's an in-out parameter.

It goes without saying that constants and literals cannot be passed in as in-out parameters. Swift will thrown an error when you do as illustrated in the following screenshot.

It's evident that in-out parameters cannot have default values, be variadic, or be defined as var or let. If you forget these details, Swift will kindly remind you with an error.

5. Nesting

In C and Objective-C, functions and methods cannot be nested. In Swift, however, nested functions are quite common. The functions we've seen in this and the previous article are examples of global functions, they are defined in the global scope.

When we define a function inside a global function, we refer to that function as a nested function. A nested function has access to the values defined in its enclosing function. Take a look at the following example to better understand this.

While the functions in this example aren't terribly useful, the example illustrates the idea of nested function and capturing values. The printHelloWorld function is only accessible from within the printMessage function. As illustrated in the example, the printHelloWorld function has access to the constant a. The value is captured by the nested function and is therefore accessible from within that function. Swift takes care of capturing values, including managing the memory of those values.

6. Function Types

In the previous article, we briefly touched upon function types. A function has a particular type, composed of the function's parameter types and its return type. The printMessage function, for example, is of type (String) -> (). Remember that () symbolizes Void, which is equivalent to an empty tuple.

Because every function has a type, it's possible to define a function that accepts another function as a parameter. The following example shows how this works.

The printMessageWithFunction function accepts a string as its first parameter and a function of type (String) -> () as its second parameter. In the function's body, the function that we pass in is invoked with the message argument.

The example also illustrates how we can invoke the printMessageWithFunction function. The myMessage constant is passed in as the first argument and the printMessage function, which we defined earlier, as the second argument. How cool is that?

As I mentioned earlier, it's also possible to return a function from a function. The next example is a bit contrived, but it illustrates what the syntax looks like.

The compute function accepts a boolean and returns a function of type (Int, Int) -> Int. The compute function contains two nested functions that are also of type (Int, Int) -> Int, add and subtract.

The compute function returns a reference to either the add or the subtract function, based on the value of the addition parameter. The example also shows how to use the compute function. We store a reference to the function that is returned by the compute function in the computeFunction constant. We then invoke the function stored in computeFunction, passing in 1 and 2, store the result in result, and print the value of result in the standard output. The example may look complex, but it's actually easy to understand if you know what's going on.

Conclusion

You should now have a good understanding of how functions work in Swift and what you can do with them. Functions are a common theme in Swift and you will use them extensively when working with Swift.

In the next article, we dive head first into closures, a powerful construction that is very reminiscent of blocks in C and Objective-C, closures in JavaScript, and lambdas in Ruby.

2015-01-16T17:45:22.000Z2015-01-16T17:45:22.000ZBart Jacobs

Swift from Scratch: Function Parameters, Types, and Nesting

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-23056

In the previous article, we explored the basics of functions in Swift. Functions, however, have a lot more to offer. In this article, we will continue our exploration of functions and look into function parameters, nesting, and types.

1. Local & External Parameter Names

Local Parameter Names

Let's revisit one of the examples of the previous article. The printMessage function defines one parameter, message.

Even though we give the parameter a name, message, we don't use the name when we call the function. We pass in the value for the message parameter.

The name we define in the function's definition is a local parameter name. The value of the parameter can only be referenced by this name in the body of the function. Function parameters, however, are a bit more flexible than that. Let me explain what I mean by that.

Objective-C is known for its long method names. While this may look clunky and inelegant to outsiders, it makes methods easy to understand and, if chosen well, very descriptive. If you think you lost this benefit when switching to Swift, then you're in for a surprise.

External Parameter Names

When a function accepts several parameters, it isn't always obvious which argument corresponds to which parameter. Take a look at the following example to better understand the problem.

The power function raises the value of a by the exponent b. Both parameters are of type Int. While most people will intuitively pass the base value as the first argument and the exponent as the second argument, this isn't clear from the function's type, name, or signature. As we've seen in the previous article, invoking the function is straightforward.

To avoid confusion, we can give the parameters of a function external names. We can then use these external names when the function is called to unambiguously indicate which argument corresponds to which parameter. Take a look at the updated example below.

Note that the function's body hasn't changed since the local names haven't changed. However, when we invoke the updated function, the difference is clear and the result much less confusing.

While the types of both functions are the same, (Int, Int) -> Int, the functions are different. In other words, the second function isn't a redeclaration of the first function. The syntax to invoke the second function may remind some of you of Objective-C. Not only are the arguments clearly described, the combination of function and parameter names describe the purpose of the function.

In some cases, you want to use the same names for local and external parameter names. This is possible and there's no need to type the parameter name twice. In the following example, we use base and exponent as the local and external parameter names.

By prefixing the parameter name with a # symbol, the parameter name serves as the local and external name of the parameter. This also means that we need to update the body of the function.

It's important to note that by providing an external name for a parameter you are required to use that name when invoking the function. This brings us to default values.

Default Values

We covered default parameter values in the previous article, but there is an important default behavior that you need to be aware of. If you define a default value for a parameter, Swift automatically assigns an external parameter name to the parameter. Let's look at an example of the previous article.

Because the second parameter, format, has a default value, Swift automatically sets the external parameter name of format to format. In other words, the result is the same as if we were to prefix format with a # symbol. You can test this by invoking the above function in your playground. What happens if you pass in the format without using the external parameter name of the second parameter? The answer is shown below.

Swift is pretty clear about what we should do. To summarize, when you define a parameter as optional, Swift automatically sets the external parameter name to the local parameter name. The idea behind this behavior is avoiding confusion and ambiguity.

While this behavior is a good best practice, it is possible to disable it. In the updated function definition below, we add an underscore where we would normally add the external parameter name. This tells Swift that we don't want to set an external parameter name for that particular parameter, despite having a default value.

We can now invoke the formatDate function without providing a name for the second argument.

2. Parameters & Mutability

Let's revisit the first example of this tutorial, the printMessage function. What happens if we change the value of the message parameter inside the function's body?

It doesn't take long for Swift to start complaining.

By default, the parameters of a function are constants. In other words, while we can access the values of function parameters, we cannot change their value. To change this default behavior, add the var keyword to the parameter name in the function definition. Swift will then create a variable copy of the parameter's value for you to work with in the function's body.

Note that this doesn't mean that you can pass in a value, modify it in the function, and use the modified value after the function has done its work. Swift creates a copy of the parameter's value that only exists for the lifetime of the function call. This is also illustrated in the following code block in which we pass a constant to the printMessage function.

3. Variadic Parameters

While the term may sound odd at first, variadic parameters are common in programming. A variadic parameter is a parameter that accepts zero or more values. The values need to be of the same type. Using variadic parameters in Swift is trivial as the following example illustrates.

The syntax is easy to understand. To mark a parameter as variadic, you append three dots to the parameter's type. In the function body, the variadic parameter is accessible as an array. In the above example, args is an array of Int values.

Because Swift needs to know which arguments correspond to which parameters, a variadic parameter is required to be the last parameter. It also implies that a function can have at most one variadic parameter.

The above also applies if a function has parameters with default values. The variadic parameter should always be the last parameter.

4. In-Out Parameters

Earlier in this tutorial, you learned how you can define the mutability of a parameter by using the var keyword. In that section, I emphasized that the value of a variable parameter is only accessible from within the function body. If you want to pass a value into a function, modify it in the function, and pass it back out of the function, in-out parameters are what you're looking for.

The following example shows an example of how in-out parameters work in Swift and what the syntax looks like.

We've defined the first parameter as an in-out parameter by adding the inout keyword. The second parameter is a regular parameter with an external name of withString and a local name of b. Let's see how we invoke this function.

We declare a variable, world, of type String and pass it to the perpendString function. The second parameter is a string literal. By invoking the function, the value of the world variable becomes Hello, world. Note that the first argument is prefixed with an ampersand, &, to indicate that it's an in-out parameter.

It goes without saying that constants and literals cannot be passed in as in-out parameters. Swift will thrown an error when you do as illustrated in the following screenshot.

It's evident that in-out parameters cannot have default values, be variadic, or be defined as var or let. If you forget these details, Swift will kindly remind you with an error.

5. Nesting

In C and Objective-C, functions and methods cannot be nested. In Swift, however, nested functions are quite common. The functions we've seen in this and the previous article are examples of global functions, they are defined in the global scope.

When we define a function inside a global function, we refer to that function as a nested function. A nested function has access to the values defined in its enclosing function. Take a look at the following example to better understand this.

While the functions in this example aren't terribly useful, the example illustrates the idea of nested function and capturing values. The printHelloWorld function is only accessible from within the printMessage function. As illustrated in the example, the printHelloWorld function has access to the constant a. The value is captured by the nested function and is therefore accessible from within that function. Swift takes care of capturing values, including managing the memory of those values.

6. Function Types

In the previous article, we briefly touched upon function types. A function has a particular type, composed of the function's parameter types and its return type. The printMessage function, for example, is of type (String) -> (). Remember that () symbolizes Void, which is equivalent to an empty tuple.

Because every function has a type, it's possible to define a function that accepts another function as a parameter. The following example shows how this works.

The printMessageWithFunction function accepts a string as its first parameter and a function of type (String) -> () as its second parameter. In the function's body, the function that we pass in is invoked with the message argument.

The example also illustrates how we can invoke the printMessageWithFunction function. The myMessage constant is passed in as the first argument and the printMessage function, which we defined earlier, as the second argument. How cool is that?

As I mentioned earlier, it's also possible to return a function from a function. The next example is a bit contrived, but it illustrates what the syntax looks like.

The compute function accepts a boolean and returns a function of type (Int, Int) -> Int. The compute function contains two nested functions that are also of type (Int, Int) -> Int, add and subtract.

The compute function returns a reference to either the add or the subtract function, based on the value of the addition parameter. The example also shows how to use the compute function. We store a reference to the function that is returned by the compute function in the computeFunction constant. We then invoke the function stored in computeFunction, passing in 1 and 2, store the result in result, and print the value of result in the standard output. The example may look complex, but it's actually easy to understand if you know what's going on.

Conclusion

You should now have a good understanding of how functions work in Swift and what you can do with them. Functions are a common theme in Swift and you will use them extensively when working with Swift.

In the next article, we dive head first into closures, a powerful construction that is very reminiscent of blocks in C and Objective-C, closures in JavaScript, and lambdas in Ruby.

2015-01-16T17:45:22.000Z2015-01-16T17:45:22.000ZBart Jacobs

Working With Local Databases on Windows Phone 8

$
0
0

In the previous article, you learned how to store data in your app's isolated storage. In this article, we focus on working with local databases that live in your app's isolated storage. You'll learn about database operations using LINQ, database schemas as well as how to fetch data from a local database.

1. Introduction

You can store relational data in a local database that lives in your app's isolated storage. All database operations on Windows Phone are performed using LINQ to SQL. It is used to define the database schema, select data, and save changes to the underlying database file residing in the local folder. 

The LINQ to SQL object model uses the System.Data.Linq.DataContext namespace to make a proxy call to the local database. The LINQ to SQL runtime acts as a bridge between the data context object and the real data to do manipulations.

When working with local databases on Windows Phone, it's important to keep the following in mind:

  • The local database runs in the Windows Phone app's process. It does not run continuously as a background service.
  • It can be accessed only by the corresponding Windows Phone app.
  • It can be accessed only with LINQ to SQL, Transact-SQL is not supported.
  • To synchronize access to the local folder across different threads, the Mutex class is used.
  • It's not recommended to encrypt the reference database file if you're going to access it exclusively from the installation folder. Doing so prevents the system from performing routine database maintenance operations, such as re-indexing, upon the first connection.

This article shows how you can create a local database and insert, update or delete data from it. We will build a sample application with a User Details table and perform various operations on it. We will segregate the code files for different operations such as insert, update and delete for the sake of convenience. 

2. Building the Data Context

The tables for the database can be defined anywhere in the app as long as it is accessible globally. We create a separate file, DB.cs, for all the tables. In this file we specify an object model that determines the database schema and create the data context.

Step 1: Adding References

Add the following directives at the top of the DB.cs file to reference LINQ to SQL assembly:

Step 2: Creating a Table

Add an entity class named User_details that represents the database table of the app in the local database. The attribute [Table] indicates the LINQ to SQL runtime to map the class to a local database table.

As you can see, the User_details class has three public properties that correspond to three database columns:

  • ID is an identifier column that is automatically populated by the database. It's also the primary key for which a database index is automatically created. These settings and more are specified with the LINQ to SQL column mapping attribute written above the property syntax.
  • user_name is a column to store the name of the user.
  • user_email is a column to store the email address of the user.

Step 1: Defining Data Context

The class UserDataContext inherits from DataContext and is referred to as the data context. This code calls the base constructor and declares the database table named User_details. The local database is stored in the app's isolated storage and in our example it is saved as Databases.sdf

Note that the database connection string is not required to be a static field. We use DBConnectionString in this case just for convenience.

3. Creating the Database

To create the database, open the code behind file of the app, named App.xaml.cs. Add the following code at the end of its constructor, named App.

The database creation code is added here so that the database will be present before the code from the main page runs. The code checks whether the database exists and, if no database is found, a new one is created.

4. Database Operations

Once the data context has been built and the database has been created, we can perform operations on it. You can insert, update, and delete records from the table we just created. We have created separate classes to hold functions for insert, delete, and update operations.

Step 1: Inserting Records

It's convenient to create a separate class file, DatabaseAdd.cs, for adding any records to the database. Define a function AddUser that takes name and email_id as parameters and adds a record to the User_details table.

The AddUser function uses theUserDataContext data context to connect to the database, creates a new instance of the User_details entity class, and inserts a record.

New items that have been added to the data context are not saved to the database until the SubmitChanges function is called. Call the AddUser function to add a record to the database.

Step 2: Fetching Records

Create a separate class file, FetchDatabase.cs, for fetching records from the database. This class contains a GetAllUsers function that returns an IList instance, containing the records fetched from the table.

The connection is set up using the data context after which records are fetched from the User_details table. The LINQ query returns an IList instance containing the fetched records. The IList instance is nothing more than a collection of objects of same type.

In the below code snippet we define a Users class with data members id, name, and email to hold the details from the fetched records.

Create another function, getAllUsers, that returns a list of Users when called. The function creates a new list to hold the details of the fetched users. It iterates through the IList instance named usrs and adds the details of each user to the allUsers instance.

In the sample application of this article, the getUsers function is used to set the ItemSource of the Listbox named allusers as shown below.

Step 3: Updating Records

Updating records is very similar to adding records to a table. Continuing with our modular approach, we create a new class file, DatabaseUpdate.cs, for database updates. Unlike delete operations, there's no function to update multiple records at once.

Add a function UpdateUsers that accepts an id, name, and email_id, and updates the table row for the corresponding id.

The function queries the database and stores the first matched record in the entityToUpdate variable. It then updates the record by assigning the new values and submits the changes to update the database.

The database is not updated until we call the SubmitChanges function. This function will update only the first matched record. The UpdateUser function is called to update existing records in the database as shown below.

To update multiple records, you'll need to iterate through the records that you'd like to update one by one. In the following code snippet, we update the name of every use in the database by making it lowercase.

Step 4: Deleting Records

Create a class file, DatabaseDelete.cs ,for delete operations. In the DatabaseDelete class, add a DeleteUser function that accepts a parameter id and deletes a single user whose id matches the passed-in parameter.

The function calls DeleteOnSubmit, which deletes a single record from the database. The changes are saved when the SubmitChanges function is called. The DeleteUser function deletes a single record from the database as shown below.

The System.Data.Linq assembly provides a function DeleteAllOnSubmit to delete multiple records at once. The following code snippet truncates the User_details table.

This function accepts a list of records and deletes the records in that list. Note that in both cases the changes are saved only when the SubmitChanges function is called.

Conclusion

Windows Phone apps use LINQ to SQL for all database operations. LINQ to SQL is used to define the database schema, select data, and, save changes to the underlying database file residing in the app's isolated storage. LINQ to SQL provides an object-oriented approach for working with data stored in a database and consists of an object model and a runtime. I recommend you read this MSDN article for best practices on using local databases. Feel free to download the tutorial's source files to use as reference.

2015-01-19T15:12:13.000Z2015-01-19T15:12:13.000ZVivek Maskara

Working With Local Databases on Windows Phone 8

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-22799

In the previous article, you learned how to store data in your app's isolated storage. In this article, we focus on working with local databases that live in your app's isolated storage. You'll learn about database operations using LINQ, database schemas as well as how to fetch data from a local database.

1. Introduction

You can store relational data in a local database that lives in your app's isolated storage. All database operations on Windows Phone are performed using LINQ to SQL. It is used to define the database schema, select data, and save changes to the underlying database file residing in the local folder. 

The LINQ to SQL object model uses the System.Data.Linq.DataContext namespace to make a proxy call to the local database. The LINQ to SQL runtime acts as a bridge between the data context object and the real data to do manipulations.

When working with local databases on Windows Phone, it's important to keep the following in mind:

  • The local database runs in the Windows Phone app's process. It does not run continuously as a background service.
  • It can be accessed only by the corresponding Windows Phone app.
  • It can be accessed only with LINQ to SQL, Transact-SQL is not supported.
  • To synchronize access to the local folder across different threads, the Mutex class is used.
  • It's not recommended to encrypt the reference database file if you're going to access it exclusively from the installation folder. Doing so prevents the system from performing routine database maintenance operations, such as re-indexing, upon the first connection.

This article shows how you can create a local database and insert, update or delete data from it. We will build a sample application with a User Details table and perform various operations on it. We will segregate the code files for different operations such as insert, update and delete for the sake of convenience. 

2. Building the Data Context

The tables for the database can be defined anywhere in the app as long as it is accessible globally. We create a separate file, DB.cs, for all the tables. In this file we specify an object model that determines the database schema and create the data context.

Step 1: Adding References

Add the following directives at the top of the DB.cs file to reference LINQ to SQL assembly:

Step 2: Creating a Table

Add an entity class named User_details that represents the database table of the app in the local database. The attribute [Table] indicates the LINQ to SQL runtime to map the class to a local database table.

As you can see, the User_details class has three public properties that correspond to three database columns:

  • ID is an identifier column that is automatically populated by the database. It's also the primary key for which a database index is automatically created. These settings and more are specified with the LINQ to SQL column mapping attribute written above the property syntax.
  • user_name is a column to store the name of the user.
  • user_email is a column to store the email address of the user.

Step 1: Defining Data Context

The class UserDataContext inherits from DataContext and is referred to as the data context. This code calls the base constructor and declares the database table named User_details. The local database is stored in the app's isolated storage and in our example it is saved as Databases.sdf

Note that the database connection string is not required to be a static field. We use DBConnectionString in this case just for convenience.

3. Creating the Database

To create the database, open the code behind file of the app, named App.xaml.cs. Add the following code at the end of its constructor, named App.

The database creation code is added here so that the database will be present before the code from the main page runs. The code checks whether the database exists and, if no database is found, a new one is created.

4. Database Operations

Once the data context has been built and the database has been created, we can perform operations on it. You can insert, update, and delete records from the table we just created. We have created separate classes to hold functions for insert, delete, and update operations.

Step 1: Inserting Records

It's convenient to create a separate class file, DatabaseAdd.cs, for adding any records to the database. Define a function AddUser that takes name and email_id as parameters and adds a record to the User_details table.

The AddUser function uses theUserDataContext data context to connect to the database, creates a new instance of the User_details entity class, and inserts a record.

New items that have been added to the data context are not saved to the database until the SubmitChanges function is called. Call the AddUser function to add a record to the database.

Step 2: Fetching Records

Create a separate class file, FetchDatabase.cs, for fetching records from the database. This class contains a GetAllUsers function that returns an IList instance, containing the records fetched from the table.

The connection is set up using the data context after which records are fetched from the User_details table. The LINQ query returns an IList instance containing the fetched records. The IList instance is nothing more than a collection of objects of same type.

In the below code snippet we define a Users class with data members id, name, and email to hold the details from the fetched records.

Create another function, getAllUsers, that returns a list of Users when called. The function creates a new list to hold the details of the fetched users. It iterates through the IList instance named usrs and adds the details of each user to the allUsers instance.

In the sample application of this article, the getUsers function is used to set the ItemSource of the Listbox named allusers as shown below.

Step 3: Updating Records

Updating records is very similar to adding records to a table. Continuing with our modular approach, we create a new class file, DatabaseUpdate.cs, for database updates. Unlike delete operations, there's no function to update multiple records at once.

Add a function UpdateUsers that accepts an id, name, and email_id, and updates the table row for the corresponding id.

The function queries the database and stores the first matched record in the entityToUpdate variable. It then updates the record by assigning the new values and submits the changes to update the database.

The database is not updated until we call the SubmitChanges function. This function will update only the first matched record. The UpdateUser function is called to update existing records in the database as shown below.

To update multiple records, you'll need to iterate through the records that you'd like to update one by one. In the following code snippet, we update the name of every use in the database by making it lowercase.

Step 4: Deleting Records

Create a class file, DatabaseDelete.cs ,for delete operations. In the DatabaseDelete class, add a DeleteUser function that accepts a parameter id and deletes a single user whose id matches the passed-in parameter.

The function calls DeleteOnSubmit, which deletes a single record from the database. The changes are saved when the SubmitChanges function is called. The DeleteUser function deletes a single record from the database as shown below.

The System.Data.Linq assembly provides a function DeleteAllOnSubmit to delete multiple records at once. The following code snippet truncates the User_details table.

This function accepts a list of records and deletes the records in that list. Note that in both cases the changes are saved only when the SubmitChanges function is called.

Conclusion

Windows Phone apps use LINQ to SQL for all database operations. LINQ to SQL is used to define the database schema, select data, and, save changes to the underlying database file residing in the app's isolated storage. LINQ to SQL provides an object-oriented approach for working with data stored in a database and consists of an object model and a runtime. I recommend you read this MSDN article for best practices on using local databases. Feel free to download the tutorial's source files to use as reference.

2015-01-19T15:12:13.000Z2015-01-19T15:12:13.000ZVivek Maskara

An Introduction to Adaptive Design

$
0
0

Apple has been pushing developers to create universal iOS applications for some time now. At WWDC 12, Auto Layout was released for iOS and improvements followed for it in iOS 7. And now with iOS 8, adaptive design has been introduced, which includes several new APIs and Interface Builder advancements to promote developing universal binaries.

In this tutorial, we will look at what exactly adaptive design means and how to use some of its concepts. By the end of the tutorial, you'll be able to use adaptive design to create universal apps using an intuitive workflow. We'll use the new size classes to create a fictional app for a computer store that works on all devices.

1. What Is Adaptive Design?

Adaptive design encompasses several new ideas and techniques instead of being just one, singular API. Some components of adaptive design include trait collections, size classes, adaptive fonts, Auto Layout, and more. At its core, adaptive design exists to help developers create universal and localized apps easily.

If you've been developing iOS apps for a number of years, you've probably realized first hand why adaptive design can be helpful. Autoresizing masks fall apart quickly, keeping track of orientations can be tedious, and developing different code paths based off of the device type isn't scalable. Adaptive design aims to address all of these issues.

Now that we've identified what adaptive design is and why we should be using it, download the sample project to get started.

2. Size Classes

Size classes are the marquee feature of adaptive design. Using them allows you to eliminate code and logic that addressed multiple screen sizes, orientations, or specific devices. It also makes it easy to have just one interface for all of the devices available.

There are two types of size classes, compact and regular. Each size class can be represented horizontally and vertically, and every device is assigned a size class for both orientations. A regular size represents a "large" amount of screen real estate, such as on an iPad. Also included are interface paradigms that provide the illusion of excess space, such as scroll views on an iPhone.

On the other hand, a "compact" screen size denotes a smaller amount of room available. iPhones or iPod Touches generally will fit into this category. That's certainly not a rule, however. For instance, the iPhone 6 Plus supports the regular size class horizontally. The following table lists iOS devices and their respective size class:


VerticallyHorizontally
iPhone PortraitRegularCompact
iPhone LandscapeCompactCompact
iPhone 6 Plus LandscapeCompactRegular
iPad PortraitRegularRegular
iPad LandscapeRegularRegular

Step 1: Choosing a Size Class in Interface Builder

Open up Main.storyboard inside the project. You'll notice that the canvas is shaped like a rectangle. While jarring at first, this is actually displaying a core component of adaptive design. Looking towards the bottom of interface builder, you'll notice a button that says wAny hAny.

This stands for Any Width, Any Height, which is indicating that any changes to the user interface here apply to every size class. If you click the button, a grid appears that allows you to toggle between different size classes:

In the example above, Compact Width | Compact Height is selected and there is a green dot in the blue grid. The green dot shows which size classes are represented. In this case, changes only apply to 3.5, 4, and 4.7 inch iPhones in landscape.

Notice that there is a bit of a difference in the wording, as Interface Builder uses the terms width and height whereas size classes use the terms horizontal and vertical. Width corresponds to horizontal and height corresponds to vertical.

If you changed the currently selected size class, be sure to switch back to Any Width | Any Height.

Step 2: Adding an Image

Drag an image view onto the view controller's canvas from the Object Library. Using the Size Inspector, set its X position to 0 points and its Y position to 72 points. Set the width to 600 points and the height to 218 points. Open the Attributes Inspector and change the view's mode to aspect fit and image to "Laptop". Your canvas should look like the image below:

Step 3: Adding a Label

Open up the Object Library once more and drag a label onto the canvas. Open up the Size Inspector and set the label's X position to 16 points and its Y position to 312 points. For the size, set its width to 568 points and its height to 242 points.

In the Attributes Inspector, make the following changes:

  • set Text to "Silver Laptop"
  • change Font Size to System 100.0 points
  • set Alignment to Center
  • set Lines to 0

Step 4: Adding Constraints

Now we'll add constraints for the label and the image view. At the bottom of Interface Builder, click Reset to Suggested Constraints under the All Views in View Controller section. If the option is greyed out, then make sure one of the views in the canvas is selected.

Since the image view has the same white background as its containing view, we'll change the view's background color to make it easy to differentiate between the two. Select View from the document outline and change its background color to Group Table View Background Color.

Step 5: Build and Run

At the top of Xcode, select iPad Retina to use for the iOS Simulator. Build and run the app by pressing Command + R. The app seems to look fine for the iPad, but we want to ensure it displays properly on every device.

3. Live Preview

Building and running your app just to see how your user interface behaves can be a tedious task. Luckily, Xcode 6 has added the ability to get a live rendering of your user interface on any device in any orientation. This helps us resolve any auto layout issues much faster than running the app in the iOS Simulator every time.

Step 1: Enabling Preview Assistant

At the top of Xcode, click the Assistant Editor button.

This splits Xcode's editor in two panes. In the right pane, select Automatic > Preview > Main.storyboard in the jump bar.

Step 2: Adding Devices to Preview

Interface Builder now shows a live preview of the user interface on a 4 inch iPhone. As expected, the user interface is less than ideal on the iPhone. If you aren't seeing anything on the preview, then click the view controller in the left pane to refresh it.

In the right pane, clicking the + button at the bottom lets you add more devices to preview. Go ahead and add the iPad to preview as well.

Step 3: Switching Orientations

Hover over the iPhone in the assistant editor towards the bottom. To the left of the name of the device, there is a button that switches the current orientation. Click it once to switch the iPhone preview to landscape orientation.

With the orientation in landscape, the user interface looks even worse. The image view isn't showing at all and the label's text is far too big.

4. Installing Size Class Specific Constraints

To fix the user interface, we'll add some constraints that are specific to a certain size class. This is another advantage of adaptive design. We can to tell the user interface how it should lay out its views for certain size classes, using the same storyboard. Before, this would usually require using two different storyboards and loading the correct one at runtime.

Step 1: Adding Image View Base Constraints

We'll first add constraints that should work for most devices and refine them from there. Start by removing the constraints added earlier by clicking any view in the canvas and selecting Editor > Resolve Auto Layout Issues > All Views in View Controller - Clear Constraints.

Select the image view, click the Align button, choose Horizontal Center in Container, and click Add 1 Constraint.

Open the constraint we just added in the Size Inspector on the right and double-click it to edit it.

The constraint has the superview's center equal to the image view's center, but we want the opposite. Click Second Item and choose Reverse First And Second Item to correct the issue.

Next, press Control and drag from the image view to View inside the document outline on the left, and select Equal Heights. Select the constraint in the Size Inspector and change the constraint's multiplier to 0.4. This will force the image view's height to be equal either the superview's height or at least 40 percent of it—whichever ends up being shorter.

Next, click the Pin button and choose the top and bottom spacing to nearest neighbor. For the bottom spacing, enter 18 points. The top spacing should already be set to 0 points. Make sure Constrain to margins is unchecked since we don't want padding around the view. Click Add 2 Constraints at the bottom to add the constraints.

Double-click the Bottom Space constraint in the Size Inspector to edit it. Change the Relation to Greater Than or Equal. To finish up the image view's constraints, Control and drag from the image view to the label and choose Equal Heights.

The constraints for the image view should look like this:

Step 2: Adding Label Base Constraints

Due to the constraints added to the image view, the label already has its height and vertical spacing from the image view added. Select the label and click the Pin button to add a leading, trailing, and vertical spacing constraint as shown in the image below.

If you preview the app now in the assistant editor, the constraints have made things much better. However, there's still a problem when the app is using the compact horizontal size class as you can see below (middle).

In this case, it would be nice to have the image view and label side by side instead of on top of one another. 

Step 3: Adding Compact Horizontal Constraints

Using the size class toggle button at the bottom, select Compact Width | Compact Height. The bar turns into a shade of blue to indicate you are now editing the user interface for a specific size class.

Select the image view, open the Size Inspector, and update its frame as shown in the image below.

Next, select the label and update its frame in the Size Inspector as shown below.

With the label still selected and the Size Inspector open, select the label's constraints and remove them by pressing Delete. You can select multiple constraints by holding down the Shift key. This will remove the constraints we've added so far, but only for this size class.

Do the same for the image view by selecting it, opening the Size Inspector, selecting its constraints, and pressing Delete. We can now add constraints to ensure the image view and label are positioned side by side.

Fortunately, Xcode can easily figure these constraints out for us. With either the image view or the label selected, choose Editor > Resolve Auto Layout Issues > All Views in View Controller - Reset to Suggested Constraints.

Step 5: Preview Updated Constraints

Open the Size Inspector for the image view. You'll see that there are several constraints listed, but some are greyed out and some aren't. This indicates which constraints are active for the current size class.

If you double-click on any of them, the bottom section shows us which size classes the constraints are active for. The image below shows that the constraint is installed for Compact Width | Compact Height and disabled for Regular Width | Regular Height. Clicking the x or button enables or disables the constraint for the given size class.

Open the preview assistant editor again and add a 3.5 inch iPhone in landscape mode if there isn't one already. We can see we've achieved an entirely different layout for certain devices in landscape orientation - all in one storyboard.

5. Dynamic Text

The last thing to address is the font size. While the actual frames of the image view and label are working out nicely, the font can sometimes become truncated. Adaptive design has added new options for developers to handle this type of scenario.

Step 1: Edit the Font Scale

Select the label and open the Attributes Inspector on the right. Under Autoshrink, select Minimum Font Scale and set it to 0.4.

Step 2: Adding Size Class Specific Fonts

Editing the font scale will be sufficient for most cases. In our app, though, the label's contents is readable for the Compact Width | Compact Height size class, but it's not ideal. If you open the preview assistant editor, you'll notice the "p" in the word "laptop" is on its own line.

With the label selected, click the + button next to Font in the Attributes Inspector. This opens a menu to select a size class to apply a particular font to. Choose Compact Width | Compact Height.

Similar to size class specific constraints, a font has been added for the size class we selected. Change the fontsize to 50 points. Now, open the preview assistant editor one more time and verify the font looks perfect on every device.

The ability to add adaptive fonts is incredibly powerful. Localizing apps is trivial when you are able to control font size more precisely with dynamic text.

6. Other Adaptive Design Technologies

While size classes are certainly a premier feature, there are many other adaptive design APIs and advancements that I haven't covered in this tutorial. For example, view controllers now conform to the UITraitEnvironment protocol. This means that view controllers have a traitCollection property that keeps track of what size class is currently displayed.

If you enjoy creating user interfaces in code, the traitCollection property gives you the same capabilities as size classes do in Interface Builder. You can be notified when the size class changes and perform any necessary updates to your constraints or user interface.

Another helpful API is the UIPopoverController. If you've previously developed a universal app, I'm sure you've seen code like this:

As of iOS 8, there's no longer a need to check which device the app is running on when using the UIPopoverController class. The UIPopoverController class now also supports iPhone and iPod Touch.

As far as image assets, notice that there is now a @3x size. This is due to the Retina HD display found on the iPhone 6 Plus. If you open the Images.xcassets file in the project, you'll see it under any of the supplied image sets.

Conclusion

Adaptive design is probably the most important change in iOS development in several years. Prior to adaptive design, universal apps were not easily developed and scalability in such projects could be an issue. Hopefully you've learned enough from this tutorial to avoid those problems and incorporate adaptive design into your own apps.

2015-01-21T15:55:33.000Z2015-01-21T15:55:33.000ZJordan Morgan

An Introduction to Adaptive Design

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-22888

Apple has been pushing developers to create universal iOS applications for some time now. At WWDC 12, Auto Layout was released for iOS and improvements followed for it in iOS 7. And now with iOS 8, adaptive design has been introduced, which includes several new APIs and Interface Builder advancements to promote developing universal binaries.

In this tutorial, we will look at what exactly adaptive design means and how to use some of its concepts. By the end of the tutorial, you'll be able to use adaptive design to create universal apps using an intuitive workflow. We'll use the new size classes to create a fictional app for a computer store that works on all devices.

1. What Is Adaptive Design?

Adaptive design encompasses several new ideas and techniques instead of being just one, singular API. Some components of adaptive design include trait collections, size classes, adaptive fonts, Auto Layout, and more. At its core, adaptive design exists to help developers create universal and localized apps easily.

If you've been developing iOS apps for a number of years, you've probably realized first hand why adaptive design can be helpful. Autoresizing masks fall apart quickly, keeping track of orientations can be tedious, and developing different code paths based off of the device type isn't scalable. Adaptive design aims to address all of these issues.

Now that we've identified what adaptive design is and why we should be using it, download the sample project to get started.

2. Size Classes

Size classes are the marquee feature of adaptive design. Using them allows you to eliminate code and logic that addressed multiple screen sizes, orientations, or specific devices. It also makes it easy to have just one interface for all of the devices available.

There are two types of size classes, compact and regular. Each size class can be represented horizontally and vertically, and every device is assigned a size class for both orientations. A regular size represents a "large" amount of screen real estate, such as on an iPad. Also included are interface paradigms that provide the illusion of excess space, such as scroll views on an iPhone.

On the other hand, a "compact" screen size denotes a smaller amount of room available. iPhones or iPod Touches generally will fit into this category. That's certainly not a rule, however. For instance, the iPhone 6 Plus supports the regular size class horizontally. The following table lists iOS devices and their respective size class:


VerticallyHorizontally
iPhone PortraitRegularCompact
iPhone LandscapeCompactCompact
iPhone 6 Plus LandscapeCompactRegular
iPad PortraitRegularRegular
iPad LandscapeRegularRegular

Step 1: Choosing a Size Class in Interface Builder

Open up Main.storyboard inside the project. You'll notice that the canvas is shaped like a rectangle. While jarring at first, this is actually displaying a core component of adaptive design. Looking towards the bottom of interface builder, you'll notice a button that says wAny hAny.

This stands for Any Width, Any Height, which is indicating that any changes to the user interface here apply to every size class. If you click the button, a grid appears that allows you to toggle between different size classes:

In the example above, Compact Width | Compact Height is selected and there is a green dot in the blue grid. The green dot shows which size classes are represented. In this case, changes only apply to 3.5, 4, and 4.7 inch iPhones in landscape.

Notice that there is a bit of a difference in the wording, as Interface Builder uses the terms width and height whereas size classes use the terms horizontal and vertical. Width corresponds to horizontal and height corresponds to vertical.

If you changed the currently selected size class, be sure to switch back to Any Width | Any Height.

Step 2: Adding an Image

Drag an image view onto the view controller's canvas from the Object Library. Using the Size Inspector, set its X position to 0 points and its Y position to 72 points. Set the width to 600 points and the height to 218 points. Open the Attributes Inspector and change the view's mode to aspect fit and image to "Laptop". Your canvas should look like the image below:

Step 3: Adding a Label

Open up the Object Library once more and drag a label onto the canvas. Open up the Size Inspector and set the label's X position to 16 points and its Y position to 312 points. For the size, set its width to 568 points and its height to 242 points.

In the Attributes Inspector, make the following changes:

  • set Text to "Silver Laptop"
  • change Font Size to System 100.0 points
  • set Alignment to Center
  • set Lines to 0

Step 4: Adding Constraints

Now we'll add constraints for the label and the image view. At the bottom of Interface Builder, click Reset to Suggested Constraints under the All Views in View Controller section. If the option is greyed out, then make sure one of the views in the canvas is selected.

Since the image view has the same white background as its containing view, we'll change the view's background color to make it easy to differentiate between the two. Select View from the document outline and change its background color to Group Table View Background Color.

Step 5: Build and Run

At the top of Xcode, select iPad Retina to use for the iOS Simulator. Build and run the app by pressing Command + R. The app seems to look fine for the iPad, but we want to ensure it displays properly on every device.

3. Live Preview

Building and running your app just to see how your user interface behaves can be a tedious task. Luckily, Xcode 6 has added the ability to get a live rendering of your user interface on any device in any orientation. This helps us resolve any auto layout issues much faster than running the app in the iOS Simulator every time.

Step 1: Enabling Preview Assistant

At the top of Xcode, click the Assistant Editor button.

This splits Xcode's editor in two panes. In the right pane, select Automatic > Preview > Main.storyboard in the jump bar.

Step 2: Adding Devices to Preview

Interface Builder now shows a live preview of the user interface on a 4 inch iPhone. As expected, the user interface is less than ideal on the iPhone. If you aren't seeing anything on the preview, then click the view controller in the left pane to refresh it.

In the right pane, clicking the + button at the bottom lets you add more devices to preview. Go ahead and add the iPad to preview as well.

Step 3: Switching Orientations

Hover over the iPhone in the assistant editor towards the bottom. To the left of the name of the device, there is a button that switches the current orientation. Click it once to switch the iPhone preview to landscape orientation.

With the orientation in landscape, the user interface looks even worse. The image view isn't showing at all and the label's text is far too big.

4. Installing Size Class Specific Constraints

To fix the user interface, we'll add some constraints that are specific to a certain size class. This is another advantage of adaptive design. We can to tell the user interface how it should lay out its views for certain size classes, using the same storyboard. Before, this would usually require using two different storyboards and loading the correct one at runtime.

Step 1: Adding Image View Base Constraints

We'll first add constraints that should work for most devices and refine them from there. Start by removing the constraints added earlier by clicking any view in the canvas and selecting Editor > Resolve Auto Layout Issues > All Views in View Controller - Clear Constraints.

Select the image view, click the Align button, choose Horizontal Center in Container, and click Add 1 Constraint.

Open the constraint we just added in the Size Inspector on the right and double-click it to edit it.

The constraint has the superview's center equal to the image view's center, but we want the opposite. Click Second Item and choose Reverse First And Second Item to correct the issue.

Next, press Control and drag from the image view to View inside the document outline on the left, and select Equal Heights. Select the constraint in the Size Inspector and change the constraint's multiplier to 0.4. This will force the image view's height to be equal either the superview's height or at least 40 percent of it—whichever ends up being shorter.

Next, click the Pin button and choose the top and bottom spacing to nearest neighbor. For the bottom spacing, enter 18 points. The top spacing should already be set to 0 points. Make sure Constrain to margins is unchecked since we don't want padding around the view. Click Add 2 Constraints at the bottom to add the constraints.

Double-click the Bottom Space constraint in the Size Inspector to edit it. Change the Relation to Greater Than or Equal. To finish up the image view's constraints, Control and drag from the image view to the label and choose Equal Heights.

The constraints for the image view should look like this:

Step 2: Adding Label Base Constraints

Due to the constraints added to the image view, the label already has its height and vertical spacing from the image view added. Select the label and click the Pin button to add a leading, trailing, and vertical spacing constraint as shown in the image below.

If you preview the app now in the assistant editor, the constraints have made things much better. However, there's still a problem when the app is using the compact horizontal size class as you can see below (middle).

In this case, it would be nice to have the image view and label side by side instead of on top of one another. 

Step 3: Adding Compact Horizontal Constraints

Using the size class toggle button at the bottom, select Compact Width | Compact Height. The bar turns into a shade of blue to indicate you are now editing the user interface for a specific size class.

Select the image view, open the Size Inspector, and update its frame as shown in the image below.

Next, select the label and update its frame in the Size Inspector as shown below.

With the label still selected and the Size Inspector open, select the label's constraints and remove them by pressing Delete. You can select multiple constraints by holding down the Shift key. This will remove the constraints we've added so far, but only for this size class.

Do the same for the image view by selecting it, opening the Size Inspector, selecting its constraints, and pressing Delete. We can now add constraints to ensure the image view and label are positioned side by side.

Fortunately, Xcode can easily figure these constraints out for us. With either the image view or the label selected, choose Editor > Resolve Auto Layout Issues > All Views in View Controller - Reset to Suggested Constraints.

Step 5: Preview Updated Constraints

Open the Size Inspector for the image view. You'll see that there are several constraints listed, but some are greyed out and some aren't. This indicates which constraints are active for the current size class.

If you double-click on any of them, the bottom section shows us which size classes the constraints are active for. The image below shows that the constraint is installed for Compact Width | Compact Height and disabled for Regular Width | Regular Height. Clicking the x or button enables or disables the constraint for the given size class.

Open the preview assistant editor again and add a 3.5 inch iPhone in landscape mode if there isn't one already. We can see we've achieved an entirely different layout for certain devices in landscape orientation - all in one storyboard.

5. Dynamic Text

The last thing to address is the font size. While the actual frames of the image view and label are working out nicely, the font can sometimes become truncated. Adaptive design has added new options for developers to handle this type of scenario.

Step 1: Edit the Font Scale

Select the label and open the Attributes Inspector on the right. Under Autoshrink, select Minimum Font Scale and set it to 0.4.

Step 2: Adding Size Class Specific Fonts

Editing the font scale will be sufficient for most cases. In our app, though, the label's contents is readable for the Compact Width | Compact Height size class, but it's not ideal. If you open the preview assistant editor, you'll notice the "p" in the word "laptop" is on its own line.

With the label selected, click the + button next to Font in the Attributes Inspector. This opens a menu to select a size class to apply a particular font to. Choose Compact Width | Compact Height.

Similar to size class specific constraints, a font has been added for the size class we selected. Change the fontsize to 50 points. Now, open the preview assistant editor one more time and verify the font looks perfect on every device.

The ability to add adaptive fonts is incredibly powerful. Localizing apps is trivial when you are able to control font size more precisely with dynamic text.

6. Other Adaptive Design Technologies

While size classes are certainly a premier feature, there are many other adaptive design APIs and advancements that I haven't covered in this tutorial. For example, view controllers now conform to the UITraitEnvironment protocol. This means that view controllers have a traitCollection property that keeps track of what size class is currently displayed.

If you enjoy creating user interfaces in code, the traitCollection property gives you the same capabilities as size classes do in Interface Builder. You can be notified when the size class changes and perform any necessary updates to your constraints or user interface.

Another helpful API is the UIPopoverController. If you've previously developed a universal app, I'm sure you've seen code like this:

As of iOS 8, there's no longer a need to check which device the app is running on when using the UIPopoverController class. The UIPopoverController class now also supports iPhone and iPod Touch.

As far as image assets, notice that there is now a @3x size. This is due to the Retina HD display found on the iPhone 6 Plus. If you open the Images.xcassets file in the project, you'll see it under any of the supplied image sets.

Conclusion

Adaptive design is probably the most important change in iOS development in several years. Prior to adaptive design, universal apps were not easily developed and scalability in such projects could be an issue. Hopefully you've learned enough from this tutorial to avoid those problems and incorporate adaptive design into your own apps.

2015-01-21T15:55:33.000Z2015-01-21T15:55:33.000ZJordan Morgan

Swift from Scratch: Closures

$
0
0

If you've worked with blocks in C/Objective-C or lambdas in Ruby, then you won't have a hard time wrapping your head around the concept of closures. Closures are nothing more than blocks of functionality that you can pass around in your code.

As a matter of fact, we've already worked with closures in the previous two articles. That's right. Functions are closures too. Let's start with the basics and inspect the anatomy of a closure.

1. What Is a Closure?

As I said, a closure is a block of functionality that you can pass around in your code. You can pass a closure as an argument of a function or you can store it as a property of an object. Closures have many use cases.

The name closure hints at one of the key characteristics of closures. A closure captures the variables and constants of the context in which it is defined. This is sometimes referred to as closing over those variables and constants. We're going to look at value capturing in more detail at the end of this article.

Flexibility

You've already learned that functions can be incredibly powerful and flexible. Because functions are closures, closures are just as flexible. In this article, you'll discover just how flexible and powerful they are.

Memory Management

The C programming language has a similar concept, blocks. Closures in Swift, however, have a few benefits. One of the key advantages of closures in Swift is that memory management is something you, the developer, don't have to worry about.

Even retain cycles, which aren't uncommon in C/Objective-C, are handled by Swift. This will reduce hard-to-find memory leaks or crashes due to invalid pointers.

2. Syntax

The basic syntax of a closure isn't difficult and it will remind you of global and nested functions, which we covered earlier in this series. Take a look at the following example.

The first thing you'll notice is that the entire closure is wrapped in a pair of curly braces. Closure's parameters are wrapped in a pair of parentheses, separated from the return type by the -> symbol. The above closure accepts one argument, a, of type Int and returns an Int. The body of the closure starts after the in keyword.

Named closures, that is, global and nested functions, look a bit different. The following example should illustrate the differences.

The most prominent differences are the use of the func keyword and the position of the parameters and return type. A closure starts and ends with a curly brace, wrapping the parameters, return type, and closure body. Despite these differences, remember that every function is a closure. Not every closure is a function though.

3. Closures as Parameters

Closures are powerful and the following example illustrates how useful they can be. In the example, we create an array of states. We invoke the map function on the array to create a new array that only contains the first two letters of each state as a capitalized string.

The map function or method is common in many programming languages and libraries, such as Ruby, PHP, and jQuery. In the above example, the map function is invoked on the states array, transforms its contents, and returns a new array that contains the transformed values.

Type Inference

Previously in this series, we learned that Swift is quite smart. Let's see exactly how smart. The array of states is an array of strings. Because we invoke the map function on the array, Swift knows that the state argument is of type String. This means that we can omit the type as shown in the updated example below.

There are a few more things we can omit from the above example, resulting in the following one-liner.

Let me explain what's happening. The compiler can infer that we return a string from the closure that we pass to the map function, which means there's no reason to include it in the closure expression definition. We can only do this if the closure's body includes a single statement though. In that case, we can put that statement on the same line as the closure's definition, as shown in the above example. Because there's no return type in the definition and no -> symbol preceding the return type, we can omit the parentheses enclosing the closure's parameters.

Shorthand Argument Names

It doesn't stop here though. We can make use of shorthand argument names to simplify the above closure expression even more. When using an inline closure expression, as in the above example, we can omit the list of parameters, including the in keyword that separates the parameters from the closure body.

In the closure body, we reference the arguments using shorthand argument names Swift provides us with. The first argument is referenced by $0, the second by $1, etc.

In the updated example below, I have omitted the list of parameters and the in keyword, and replaced the state argument in the closure's body with the shorthand argument name $0. The resulting statement is more concise without compromising readability.

Trailing Closures

The Swift programming language also defines a concept known as trailing closures. The idea is simple. If you pass a closure as the last argument of a function, you can place that closure outside the parentheses of the function call. The following example demonstrates how this works.

If the only argument of the function call is the closure, then it's even possible to omit the parentheses of the function call.

Note that this also works for closures that contain multiple statements. In fact, that is the main reason trailing closures are available in Swift. If a closure is long or complex, and it's the last argument of a function, it is often better to use the trailing closure syntax.

4. Capturing Values

When using closures, you'll often find yourself using or manipulating constants and variables from the closure's surrounding context in the body of the closure. This is possible and often referred to as value capturing. It simply means that a closure can capture the values of constants and variables from the context it is defined in. Take the following example to better understand the concept of value capturing.

I'm sure you agree the above example is a bit contrived, but it clearly shows how value capturing works in Swift. The nested functions, changeToUppercase and changeToLowercase, have access to the outer function's arguments, states, as well as the newStates variable declared in the outer function. Let me explain what happens.

The changeCase function accepts a boolean as its first argument and a variadic parameter of type String as its second parameter. The function returns an array of strings composed of the strings passed to the function as the second argument. In the function's body, we create a mutable array of strings, newStrings, in which we store the manipulated strings.

The nested functions loop over the strings that are passed to the changeCase function and change the case of each string. As you can see, they have direct access to the strings passed to the changeCase function as well as the newStrings array, which is declared in the body of the changeCase function.

We check the value of uppercase, call the appropriate function, and return the newStrings array. The two lines at the end of the example demonstrate how the changeCase function works.

Even though I've demonstrated value capturing with functions, remember that every function is a closure. In other words, the same rules apply to unnamed closures.

Closures

It's been mentioned several times in this article, functions are closures. There are three kinds of closures:

  • global functions
  • nested functions
  • closure expressions

Global functions, such as the println function of Swift's standard library, capture no values. Nested functions, however, have access to and can capture the values of constants and values of the function they are defined in. The previous example illustrates this concept.

Closure expressions, also known as unnamed closures, can capture the values of constants and variables of the context they are defined in. This is very similar to nested functions.

Copying and Referencing

A closure that captures the value of a variable is able to change the value of that variable. Swift is clever enough to know whether it should copy or reference the values of the constants and variables it captures.

Developers that are new to Swift and have little experience with other programming languages will take this behavior for granted. However, it's an important advantage that Swift understands how captured values are being used in a closure and, as a result, can handle memory management for us.

Learn More in Our Swift Programming Course

If you're interested in taking your Swift education to the next level, you can take a look at our full course on Swift development.

Conclusion

Closures are an important concept and you will use them often in Swift. They enable you to write flexible, dynamic code that is both easy to write and understand. In the next article, we will explore object oriented programming in Swift, starting with objects, structures, and classes.

2015-01-23T17:45:16.000Z2015-01-23T17:45:16.000ZBart Jacobs

Swift from Scratch: Closures

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-23138

If you've worked with blocks in C/Objective-C or lambdas in Ruby, then you won't have a hard time wrapping your head around the concept of closures. Closures are nothing more than blocks of functionality that you can pass around in your code.

As a matter of fact, we've already worked with closures in the previous two articles. That's right. Functions are closures too. Let's start with the basics and inspect the anatomy of a closure.

1. What Is a Closure?

As I said, a closure is a block of functionality that you can pass around in your code. You can pass a closure as an argument of a function or you can store it as a property of an object. Closures have many use cases.

The name closure hints at one of the key characteristics of closures. A closure captures the variables and constants of the context in which it is defined. This is sometimes referred to as closing over those variables and constants. We're going to look at value capturing in more detail at the end of this article.

Flexibility

You've already learned that functions can be incredibly powerful and flexible. Because functions are closures, closures are just as flexible. In this article, you'll discover just how flexible and powerful they are.

Memory Management

The C programming language has a similar concept, blocks. Closures in Swift, however, have a few benefits. One of the key advantages of closures in Swift is that memory management is something you, the developer, don't have to worry about.

Even retain cycles, which aren't uncommon in C/Objective-C, are handled by Swift. This will reduce hard-to-find memory leaks or crashes due to invalid pointers.

2. Syntax

The basic syntax of a closure isn't difficult and it will remind you of global and nested functions, which we covered earlier in this series. Take a look at the following example.

The first thing you'll notice is that the entire closure is wrapped in a pair of curly braces. Closure's parameters are wrapped in a pair of parentheses, separated from the return type by the -> symbol. The above closure accepts one argument, a, of type Int and returns an Int. The body of the closure starts after the in keyword.

Named closures, that is, global and nested functions, look a bit different. The following example should illustrate the differences.

The most prominent differences are the use of the func keyword and the position of the parameters and return type. A closure starts and ends with a curly brace, wrapping the parameters, return type, and closure body. Despite these differences, remember that every function is a closure. Not every closure is a function though.

3. Closures as Parameters

Closures are powerful and the following example illustrates how useful they can be. In the example, we create an array of states. We invoke the map function on the array to create a new array that only contains the first two letters of each state as a capitalized string.

The map function or method is common in many programming languages and libraries, such as Ruby, PHP, and jQuery. In the above example, the map function is invoked on the states array, transforms its contents, and returns a new array that contains the transformed values.

Type Inference

Previously in this series, we learned that Swift is quite smart. Let's see exactly how smart. The array of states is an array of strings. Because we invoke the map function on the array, Swift knows that the state argument is of type String. This means that we can omit the type as shown in the updated example below.

There are a few more things we can omit from the above example, resulting in the following one-liner.

Let me explain what's happening. The compiler can infer that we return a string from the closure that we pass to the map function, which means there's no reason to include it in the closure expression definition. We can only do this if the closure's body includes a single statement though. In that case, we can put that statement on the same line as the closure's definition, as shown in the above example. Because there's no return type in the definition and no -> symbol preceding the return type, we can omit the parentheses enclosing the closure's parameters.

Shorthand Argument Names

It doesn't stop here though. We can make use of shorthand argument names to simplify the above closure expression even more. When using an inline closure expression, as in the above example, we can omit the list of parameters, including the in keyword that separates the parameters from the closure body.

In the closure body, we reference the arguments using shorthand argument names Swift provides us with. The first argument is referenced by $0, the second by $1, etc.

In the updated example below, I have omitted the list of parameters and the in keyword, and replaced the state argument in the closure's body with the shorthand argument name $0. The resulting statement is more concise without compromising readability.

Trailing Closures

The Swift programming language also defines a concept known as trailing closures. The idea is simple. If you pass a closure as the last argument of a function, you can place that closure outside the parentheses of the function call. The following example demonstrates how this works.

If the only argument of the function call is the closure, then it's even possible to omit the parentheses of the function call.

Note that this also works for closures that contain multiple statements. In fact, that is the main reason trailing closures are available in Swift. If a closure is long or complex, and it's the last argument of a function, it is often better to use the trailing closure syntax.

4. Capturing Values

When using closures, you'll often find yourself using or manipulating constants and variables from the closure's surrounding context in the body of the closure. This is possible and often referred to as value capturing. It simply means that a closure can capture the values of constants and variables from the context it is defined in. Take the following example to better understand the concept of value capturing.

I'm sure you agree the above example is a bit contrived, but it clearly shows how value capturing works in Swift. The nested functions, changeToUppercase and changeToLowercase, have access to the outer function's arguments, states, as well as the newStates variable declared in the outer function. Let me explain what happens.

The changeCase function accepts a boolean as its first argument and a variadic parameter of type String as its second parameter. The function returns an array of strings composed of the strings passed to the function as the second argument. In the function's body, we create a mutable array of strings, newStrings, in which we store the manipulated strings.

The nested functions loop over the strings that are passed to the changeCase function and change the case of each string. As you can see, they have direct access to the strings passed to the changeCase function as well as the newStrings array, which is declared in the body of the changeCase function.

We check the value of uppercase, call the appropriate function, and return the newStrings array. The two lines at the end of the example demonstrate how the changeCase function works.

Even though I've demonstrated value capturing with functions, remember that every function is a closure. In other words, the same rules apply to unnamed closures.

Closures

It's been mentioned several times in this article, functions are closures. There are three kinds of closures:

  • global functions
  • nested functions
  • closure expressions

Global functions, such as the println function of Swift's standard library, capture no values. Nested functions, however, have access to and can capture the values of constants and values of the function they are defined in. The previous example illustrates this concept.

Closure expressions, also known as unnamed closures, can capture the values of constants and variables of the context they are defined in. This is very similar to nested functions.

Copying and Referencing

A closure that captures the value of a variable is able to change the value of that variable. Swift is clever enough to know whether it should copy or reference the values of the constants and variables it captures.

Developers that are new to Swift and have little experience with other programming languages will take this behavior for granted. However, it's an important advantage that Swift understands how captured values are being used in a closure and, as a result, can handle memory management for us.

Learn More in Our Swift Programming Course

If you're interested in taking your Swift education to the next level, you can take a look at our full course on Swift development.

Conclusion

Closures are an important concept and you will use them often in Swift. They enable you to write flexible, dynamic code that is both easy to write and understand. In the next article, we will explore object oriented programming in Swift, starting with objects, structures, and classes.

2015-01-23T17:45:16.000Z2015-01-23T17:45:16.000ZBart Jacobs
Viewing all 1836 articles
Browse latest View live