Saturday, January 31, 2015

Code Jam : Particle Effects




For today's post, we will see about graceful entry and exit for the spaceship, enemies trembling when a hit happens, audio player introduction, and display of explosion effect using Emitter Node. 

Fade In :
In Update, where each new enemy spawns: 
            FrameCount = 0
            /* Called before each frame is rendered */
            let sprite = SKSpriteNode(imageNamed: "Spaceship")
            sprite.xScale = 0.15
            sprite.yScale = 0.15
            sprite.position = CGPoint(x: Int(arc4random_uniform(1000)), y: Int(arc4random_uniform(700)))
            sprite.alpha = 0.1;
            var spriteActionArray = Array<SKAction>()
            spriteActionArray.append(SKAction.fadeInWithDuration(0.3))
            
            spriteActionArray.append(SKAction.moveTo(
                CGPoint(
                    x: Int(arc4random_uniform(1000)), y: Int(arc4random_uniform(1000))
                ), duration: 60))
            let seq = SKAction.sequence(spriteActionArray)
            sprite.runAction(seq)
            ...

The lines highlighted with blue color indicate fade in transition for the enemies. The alpha has to be set to 0.1 because fadeInWithDuration increases current alpha value to 1.0 in the number of seconds mentioned in the argument (0.3 seconds) in our case. 

Note: The fadeInWithDuration has to be added as first in the sequence of actions, otherwise, the spaceships move to the destination and then fade in, because the actions in the sequence are executed one by one. Which means only when the first action ends, the next action will begin. If you had imagined the spaceship gradually gaining visibility as it moves to the destination, you would be wrong as well.

Fade Out:
When enemies are hit, they have to fade out gradually so that the transition is smooth. For this purpose we use the function fadeOutWithDuration() as indicated by the blue line. Again as name indicates, this reduces the alpha value from the current value to 0.

In Touches Began:

for (i,e) in enumerate(Enemies){
                var x = CGFloat(location.x - e.position.x)
                var y  = CGFloat(location.y - e.position.y)
                var d2 = CGFloat(x*x + y*y)
                if(d2 < 500){
                    e.runAction(SKAction.fadeOutWithDuration(0.5));
                    Hits++
                }     
 }

Since we are not removing the destroyed enemy in the same frame, it has to be carried out separately in update() . Here we check the alpha value of each enemy, and if it is 0, then remove it from the scene and from the Enemies array. 

For - in enumerate syntax is used to iterate through the Array.

for(i,e) in enumerate(Enemies){
        if e.alpha == 0 {
              self.removeChildrenInArray([e])
              Enemies.removeAtIndex(i)
        }
}

Audio:

Now comes the interesting new part.  Adding audio to be played during each hit. 
I downloaded scream.aiff file from http://www.bigsoundbank.com . This is not what I had in mind, but for testing purposes, this should suit just fine. 
First we need to add the file to Resources section of the game. For this, go to Target->BuildPhases->Copy Resources subsection. 


Ignore the red colored files for now. I myself am trying to figure out a way to fix them. 
Once the file has been browsed and added, you can verify if the file was indeed added by going to the place where the .app bundle was created, and opening package contents (control + click on .app). For me the .app file was stored in /Users/<username>/Library/Developer/Xcode/DerivedData/SwiftGame-axdwdnvxnbxhlebvxgkasiyslagc/Build/Products/Debug-iphonesimulator/ . Don't worry about the bunch of letters after SwiftGame. 

Next let NSBundle find the path to the scream aiff file. NSBundle represents location in filesystem that groups code and resources together. This is what official doc says.  They help location resource files like scream.aiff, in the code, and allows loading and unloading executable dynamically and help in localization. 

Here we would be using NSBundle to get the absolute path for the resource :scream.aiff
NSBundle.mainBundle() is used to get the main application bundle object. mainBundle returns back NSBundle object that corresponds to the application from where the current executable is running. 
If unsure, you have to verify the returned Bundle object. Currently we are not verifying it for simplicity purpose. In short it returns the bundle object for the .app bundle from where the current exe file is running. It is available in OS 10.0 or later. 

Now that we have the main bundle, we have to get the absolute path to scream.aiff. This is done by using pathForResource(). All it needs is file name, and type of file (ofType parameter).

In didMoveToView:
let AudioDestruction = (NSBundle.mainBundle().pathForResource("scream", ofType: "aiff"))

Note: If name of the file is given as "scream.aiff", it returns nil object. 


 if let ad = AudioDestruction {
            GameAudioPlayer = AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: ad), fileTypeHint: "aiff", error: nil)
        }

In this line: if let ad = AudioDestruction { ,  Since AudioDestruction is an optional parameter, it could be nil as well. In that case, shortest code to verify if not nil would be to set its value to a constant by using "let" keyword, and if it is not nil, then the execution enters the if block.Inside the if block, GameAudioPlayer is a AVAudioPlayer object declared inside the class like so:   ...
AVAudioPlayer is a class that provides methods to control audio playback from a file or memory. Programmer can tune volume, panning, channels etc using AVAudioPlayer's instance.
GameAudioPlayer is set to a new instance of the class AVAudioPlayer, whose initializer requires an URL of the sound file path. contentsOfURL parameter contains URL that has the path to local resource file. NSURL also can contain path to data on a remote server. When NSURL is used to indicate path of the local file, then it can be used to change file's last modification date.
So why can't we use simple strings instead of URL? First because AVAudioPlayer requires URL in its initializer parameter. Second, for Apple related code, URL seems to be preferred way of accessing local disk files. You can load contents of file from URL into NSString object using stringWithContentsOfURL method or you can load contents of file from URL into NSData using dataWithContentsOfURL.
Second parameter in AVAudioPlayer initializer is fileTypeHint, which indicates the UTI(Unique Transaction Identifier) string for file type. Swift supports many audio types including AIFF, AIFC, WAV, etc.
Third and last parameter for the initializer is Error object which gets set if there is error in loading the file. Currently it is set to nil, since we are not worried about error handling today.
When enemy is hit, play the audio :

Code Jam 1: New to Swift - Part 2

Continuing Part 1. 

Last week I ended with enemy spaceships being added to the Array, to be iterated over later.
This week, I am going to cover the part where touch coordinates are checked for collision with the spaceships using Circle-Point collision test and display score on the screen.


In GameScene.swift :
In the function "touchesBegan" (function used to track beginning of touch. Complements touchesEnded, and touchesMoved), we get a Set of touches to deal with.

override func touchesBegan(touches: NSSet, withEvent event: UIEvent){

Inside this functionswift :

In the function a for loop is used to iterate through all the touches.
for loops follow the syntax of 

"for item: TYPE in ARRAY/SET{"

Here, AnyObject type is used to denote an instance of any Type. I am drawing parallels with "auto" keyword of C++ where auto takes on the type of the value. For e.g in C++ we could write the same range based for loop as 

for (auto i : touches)

Inside the for loop, location of the touch is obtained using locationInNode() function for the SKScene (Game's main and only scene)


for touch: AnyObject in touches {
 let location = touch.locationInNode(self)

Inside this for loop, Iterate through the enemies, and if the touch location falls inside the bounding circle for the enemy spaceship, then consider it a hit, remove the spaceship from the SKScene, remove it from the Array, and increment Score.

Here e.position indicates the center of the sprite, because the anchor position "anchorPoint" is left to  its default value (0.5,0.5) which means the sprite  is centered on its position. 

If the distance square is less than 500( Trial and error value), then remove the child from the SKScene, and remove from the custom Array, and increment Hits count. 

for (i,e) in enumerate(Enemies){ 
    var x = CGFloat(location.x - e.postion.x)
    var y = CGFloat(location.y - e.position.y)
    var d2 = CGFloat(x*x + y*y) // Formula : (DistanceSquare = (X1 - X2) ^ 2 + (Y1 - Y2) ^ 2)
    if(d2 < 500){
        self.removeChildrenInArray([e])
        Enemies.removeAtIndex(i) 
        Hits++
        
       }
    }
}

Get the child node with name "score" and verify if it is SKLabelNode, and change its text based on format "Score: %d" where %d denotes format specifier for int

if let node = self.childNodeWithName("score") as? SKLabelNode {
                 node.text = NSString(format: "Score: %d", Hits)

This should cover the collision detection.


Now moving on to initialization : this sets the basic properties of the label which is used to display score of the game.

in override func didMoveToView(view: SKView){
  let ScoreLabel = SKLabelNode(fontNamed:"Chalkduster")
ScoreLabel.name = "score"
ScoreLabel.text = "Score : 0"
ScoreLabel.fontSize = 20
ScoreLabel.position = CGPoint(x:400, y:200)
self.addChild(ScoreLabel)
}








This is the code jam of the week starting with Jan 12 2015.

Saturday, January 24, 2015

Code Jam 1: New to Swift - Part 1



I came across the Ebook "Swift Development with Cocoa: Developing for Mac and iOS App" by "Jonathan Manning, Paris Buttfield" in Amazon, and downloaded its sample to my Kindle (Original version) Ereader 6".

As I started reading the sample this weekend, I tried out the instructions in the first chapter about Xcode, and started an empty game project in Xcode with Swift language.  Here are the details about that game snippet. 

Since I work with C++ mainly, most of my technical knowledge is based off of C++ standards. So I might find myself using C++ jargons automatically. I will try my best to stick to Swift jargons, and add comparison with C++ standards wherever possible. Also I am assuming you have a fairly good knowledge about C++ language and a decent knowledge about Xcode IDE. Focus of this blog is mainly on Swift Programming Language and comparisons with C++

P.S:
I am writing these blogs to help anyone else who might be looking for similar explanations, and to deepen my understanding of the language. Hence I have provided as many explanations and code snippets as possible. 

Also I got this idea of code jam a week from Jayenkai and Adriel Wallace, hence I would like to contribute this blog series to their brilliant and dedicated "games a week" idea. I am naming this blog code jam a week, because the game snippets I think will be done each week are not complete games. But parts of the game, that will build up to be a complete game(s).
About the Game: 
Its a simple one, where spaceships arrive on the screen at random coordinates, and when user touches a spaceship, his/her score increases. 

I used iOS simulator, setting the game up for iPhone 5. 

ScreenShots:




Game Mechanics:
- Enemy spaceships appear randomly on screen
- They move to random destinations
- User has to touch them to destroy them
- Each spaceship destroyed, increases score by 1.

There are no:
- Time limits
- no poof during spaceship destruction
- no transparent transition or other animations during appearance or disappearance

This game is as simple as a "hello world" example. 

Implementation Details
Now lets get to the main part. Since I am new to swift, I will try to explain as much as I can. Feel free to correct me if I am wrong in any of the technicalities. 

Create a Project:
- Create a new Xcode project : iOS -> Application -> Game. Provide Product Name, chose Swift as language, SpriteKit as Game Technology and other details, and save it to a convenient location on your device. 

-SpriteKit is a framework to render animated sprites on screen. They are the easiest and fastest way to bring animated 2d objects on screen. 

-Swift is a iOS and OS X programming language introduced by Apple of course, in 2014. It aims at providing an enhanced language, to shift from Objective C, and works at eliminating Objective C's demerits like null pointers, etc. 

Now that we have covered the definitions, lets move to actual code. More information on these two topics are available online in abundant quantities.

Make a spaceship appear on the screen at random location: