Category Archives: Swift

Getting Started with iOS for a C# Programmer – Part 6 – Graphics

In this post I set out to create a series of posts that would walk through creating a basic game in Swift. In the post preceding this one I covered collision, and now we are moving on to graphics.

Add Assets

The secret to graphics in Swift seems to be creating assets. If you look to the left hand side of your project, you should see an asset store:

This can be added to:

Create a new image here (in fact, we’ll need two):

Then drag and drop your icons. Mine were kindly provided by my daughter:

Use SKSpriteNode

Once you have an image, it’s a straight-forward process to map it to the game sprite (for which we are currently using a rectangle). As you can see in GameScene.swift, very little actually changes:

    func createAlien(point: CGPoint) -> SKSpriteNode {
        let size = CGSize(width: 40, height: 30)
        
        //let alien = SKShapeNode(rectOf: size)
        let alien = SKSpriteNode(imageNamed: "alienImage")
        alien.size = size
        
        //print(self.frame.minY, self.frame.maxY, self.frame.minX, self.frame.maxX, self.frame.width, self.frame.height)
        alien.position = point
        //alien.strokeColor = SKColor(red: 0.0/255.0, green: 200.0/255.0, blue: 0.0/255.0, alpha: 1.0)
        //alien.lineWidth = 4
        
        alien.physicsBody = SKPhysicsBody(rectangleOf: size)
        
        alien.physicsBody?.affectedByGravity = false
        alien.physicsBody?.isDynamic = true
        
        alien.physicsBody?.categoryBitMask = collisionAlien
        alien.physicsBody?.collisionBitMask = 0
        alien.physicsBody?.contactTestBitMask = collisionPlayer
        
        alien.name = "alien"
        
        return alien

    }
    

It’s worth bearing in mind that this will simply replace the existing rectangles with graphics. As you can probably see from the images above, mine are neither straight, trimmed, nor centered, and so it looks a little skewed in the game. Nevertheless, we’re now in the territory of a playable game:

We’re not there yet, though. The next post is the final one, in which we’ll add a score, deal with the overlapping aliens and probably reduce the size of the ship. Also, if you run this, you’ll see that after a short amount of time, it uses a huge amount of memory tracking all the aliens, so we’ll limit the number of aliens.

References

https://www.raywenderlich.com/49695/sprite-kit-tutorial-making-a-universal-app-part-1

https://developer.apple.com/library/content/documentation/Xcode/Reference/xcode_ref-Asset_Catalog_Format/

https://developer.apple.com/documentation/spritekit/skspritenode

Getting Started With iOS for a C# Programmer – Part Five – Collision

In the previous post in this series, we covered moving an object around the screen. The next thing to consider to how to shoot the aliens, and how they can defeat the player.

Aliens

The first stage is to create something to collide with. As with other game objects, our aliens will simply be rectangles at this stage. Let’s start with a familiar looking function:

    func createAlien(point: CGPoint) -> SKShapeNode {
        let size = CGSize(width: 40, height: 30)
        
        let alien = SKShapeNode(rectOf: size)
    
        alien.position = point
        alien.strokeColor = SKColor(red: 0.0/255.0, green: 200.0/255.0, blue: 0.0/255.0, alpha: 1.0)
        alien.lineWidth = 4
        
        alien.physicsBody = SKPhysicsBody(rectangleOf: size)
        
        alien.physicsBody?.affectedByGravity = false
        alien.physicsBody?.isDynamic = true
        
        alien.name = "alien"
        
        return alien

    }

So, that will create us a green rectangle – let’s cause them to appear at regular intervals:

    override func didMove(to view: SKView) {
        createScene()
        
        createAlienSpawnTimer()
    }

    func createAlienSpawnTimer() {
        var timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.timerUpdate), userInfo: nil, repeats: true)
        
    }

The scheduleTimer calls self.timerUpdate:

    @objc func timerUpdate() {
        let xSpawn = CGFloat(CGFloat(arc4random_uniform(1334)) - CGFloat(667.0))
        let ySpawn = CGFloat(250)
        
        print (xSpawn, ySpawn)
        
        let spawnLocation = CGPoint(x: xSpawn, y: ySpawn)
        let newAlien = createAlien(point: spawnLocation)
        self.addChild(newAlien)
    }

So, every second, we’ll get a new alien… But they will just sit there at the minute; let’s get them to try and attack our player:

    override func update(_ currentTime: TimeInterval) {
        // Called before each frame is rendered
        player?.position.x += playerSpeed!
        
        self.enumerateChildNodes(withName: "bullet") {
            (node, _) in
            node.position.y += 1
        }
        
        moveAliens()
    }
    
    func moveAliens() {
        self.enumerateChildNodes(withName: "alien") {
            (node, _) in
            node.position.y -= 1
            if (node.position.x < (self.player?.position.x)!) {
                node.position.x += CGFloat(arc4random_uniform(5)) - 1 // Veer right
            } else if (node.position.x > (self.player?.position.x)!) {
                node.position.x += CGFloat(arc4random_uniform(5)) - 4 // Veer left
            }
        }
    }

Collision

The SpriteKit game engine actually handles most of the logic around collisions for you. There’s a few changes that are needed to our game at this stage, though.

SKPhysicsContactDelegate

This is the parent class that actually handles the collision logic, so your GameScene class now needs to look more like this:

class GameScene: SKScene, SKPhysicsContactDelegate {

The game engine needs to be told where this SKPhysicsContactDelegate implementation is; in our case, it’s the same class:

    func createScene(){
        self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
        self.physicsBody?.isDynamic = false
        self.physicsBody?.affectedByGravity = false
        
        self.physicsWorld.contactDelegate = self
        self.backgroundColor = SKColor(red: 255.0/255.0, green: 255.0/255.0, blue: 255.0/255.0, alpha: 1.0)

Contact and Colision Masks

The next thing, is that you need to tell SpriteKit how these objects interact with each other. There are three concepts here: contact, collision and category.

Category

This allows each object to adhere to a type of behaviour; for example, the aliens need to pass through each other, but not through bullets; likewise, if we introduced a different type of alien (maybe a different graphic), it might need the same collision behaviour as the existing ones.

Contact

The idea behind contact is that you get notified when two objects intersect each other; in our case, we’ll need to know when aliens intersect bullets, and when aliens intersect the player.

Collision

Collision deals with what happens when the objects intersect. Unlike contact, this isn’t about getting notified, but the physical interaction. Maybe we have a game where blocks are pushed out of the way – in which case, we might only need collision, but not contact; or, in our case, we don’t have any physical interaction, because contact between two opposing entities results in one of them being removed.

Code

So, the result of all that is that we need three new properties setting for each new object:

        alien.physicsBody?.categoryBitMask = collisionAlien
        alien.physicsBody?.collisionBitMask = 0
        alien.physicsBody?.contactTestBitMask = collisionPlayer
        
        alien.name = "alien"

. . .

        bullet.physicsBody?.categoryBitMask = collisionBullet
        bullet.physicsBody?.collisionBitMask = 0
        bullet.physicsBody?.contactTestBitMask = collisionAlien
        
        bullet.name = "bullet"

. . .

        player.physicsBody?.categoryBitMask = collisionPlayer
        player.physicsBody?.collisionBitMask = 0
        player.physicsBody?.contactTestBitMask = 0
        
        player.name = "player"

didBegin

One this is done, you have access to the didBegin function; which, bizarrely named as it is, is the function that handles contact. Before we actually write any code in here, let’s create a helper method to determine if two nodes have come into contact:

    func AreTwoObjectsTouching(objA: String, nodeA: SKNode, objB: String, nodeB: SKNode, toRemove: String) -> Bool {
        if (objA == nodeA.name && objB == nodeB.name) {
            if (toRemove == objA) {
                RemoveGameItem(item: nodeA)
            } else if (toRemove == objB) {
                RemoveGameItem(item: nodeB)
            }
            return true
        } else if (objB == nodeA.name && objA == nodeB.name) {
            if (toRemove == objA) {
                RemoveGameItem(item: nodeB)
            } else if (toRemove == objB) {
                RemoveGameItem(item: nodeA)
            }
            return true
        } else {
            return false
        }
    }

Since the accepted standard for iOS is bad naming, I felt it my duty to continue the tradition. This helper method is effectively all the logic that occurs. As you can see, as we don’t know what has touched what, we have reversed checks and then simply remove the stated item (in our case, that is just a game rule). The didBegin function simply calls this:

    func didBegin(_ contact: SKPhysicsContact) {
        print ("bodyA", contact.bodyA.node?.name)
        print ("bodyB", contact.bodyB.node?.name)
        
        // If player and alien collide then the player dies
        if (AreTwoObjectsTouching(objA: "alien", nodeA: contact.bodyA.node!,
                                  objB: "player", nodeB: contact.bodyB.node!, toRemove: "player")) {
        
        } else if (AreTwoObjectsTouching(objA: "bullet", nodeA: contact.bodyA.node!,
                                         objB: "alien", nodeB: contact.bodyB.node!, toRemove: "alien")) {
            RemoveGameItem(item: contact.bodyB.node!)
            RemoveGameItem(item: contact.bodyA.node!)
        }
     
    }

The debug statements at the top are clearly not necessary; however, they do give some insight into what is happening in the game.

Summary

We now have a vaguely working game:

You can control the ship, fire, and the aliens are removed when they are hit, along with the player being removed when it is hit. The next stage is to replace the rectangles with images.

References

https://stackoverflow.com/questions/46494701/understanding-spritekit-collisionbitmask

Getting Started With iOS for a C# Programmer – Part Four – Controlling an Object

In this post, we covered how to move an object on the screen; this time, we’re going to control it. However, before we do, let’s change the game orientation to landscape only, as that’s really the only thing that makes sense on an iPhone for this type of game.

Landscape

The first thing to do is to change the code in the GameViewController to force the orienetation to landscape:

    override var shouldAutorotate: Bool {
        return true
    }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if UIDevice.current.userInterfaceIdiom == .phone || UIDevice.current.userInterfaceIdiom == .pad {
            return .landscape
        } else {
            return .all
        }
    }

When you run the simulator, the game will now appear on its side; to rectify that, select Hardware -> Rotate Left*:

Control

As you may have noticed from the previous post, we do have a modicum of control over the rectangle; let’s now change that so that we can press to the left and have it move left, or on the right and have it move right.

Left and Right

It turns out that this is pretty easy once you understand how the co-ordinates work in Swift:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for t in touches {
            self.touchDown(atPoint: t.location(in: player!))
        }
    }

And the touchDown function:

func touchDown(atPoint pos : CGPoint) {
        print (pos.x, pos.y)
        
        var halfWidth = (player?.frame.width)! / 2;
        
        if (pos.x < -halfWidth) {
            playerSpeed? -= CGFloat(1.0);
        } else if (pos.x > halfWidth) {
            playerSpeed? += CGFloat(1.0);
        }
}

Finally, we need the update event to do something with the playerSpeed:

    override func update(_ currentTime: TimeInterval) {
        // Called before each frame is rendered
        player?.position.x += playerSpeed!
    }

Now we have a game where we can move the player left and right.

Tidy up

To clean up the screen before we get into firing, it would be nice if the player was lower down the screen, and a slightly different colour:

func CreatePlayer() -> SKShapeNode {
        
        let playerSize = CGSize(width: 100, height: 10)
        
        let player = SKShapeNode(rectOf: playerSize)
        print(self.frame.minY, self.frame.maxY, self.frame.minX, self.frame.maxX, self.frame.width, self.frame.height)
        player.position = CGPoint(x:self.frame.midX, y:-150)
        player.strokeColor = SKColor(red: 0.0/255.0, green: 0.0/255.0, blue: 200.0/255.0, alpha: 1.0)
        player.lineWidth = 1
        
        player.physicsBody = SKPhysicsBody(rectangleOf: playerSize)
        
        player.physicsBody?.affectedByGravity = false
        player.physicsBody?.isDynamic = true
            
        return player
    }
    

Remember, this is a landscape only game.

Fire

Okay – so firing is just an extra clause in our touchDown function:

    
    func touchDown(atPoint pos : CGPoint) {
        print (pos.x, pos.y)
        
        var halfWidth = (player?.frame.width)! / 2;
        
        if (pos.x < -halfWidth) {
            playerSpeed? -= CGFloat(1.0);
        } else if (pos.x > halfWidth) {
            playerSpeed? += CGFloat(1.0);
        } else {
            Fire()
        }
    }

    func Fire() {
        let bullet = CreateBullet(point: (player?.position)!)
        self.addChild(bullet)
    }

    func CreateBullet(point : CGPoint) -> SKShapeNode {
        
        let bulletSize = CGSize(width: 1, height: 10)
        
        let bullet = SKShapeNode(rectOf: bulletSize)
        //print(self.frame.minY, self.frame.maxY, self.frame.minX, self.frame.maxX, self.frame.width, self.frame.height)
        bullet.position = point
        bullet.strokeColor = SKColor(red: 0.0/255.0, green: 0.0/255.0, blue: 200.0/255.0, alpha: 1.0)
        bullet.lineWidth = 4
        
        bullet.physicsBody = SKPhysicsBody(rectangleOf: bulletSize)
        
        bullet.physicsBody?.affectedByGravity = false
        bullet.physicsBody?.isDynamic = true
        
        bullet.name = "bullet"
        
        return bullet
    }

All we’ve actually done here is to create a new rectangle, and sourced it right at the centre of the player. We’ve added it to the self construct, so the automatic rendering will pick it up; next, we need to move it:

    override func update(_ currentTime: TimeInterval) {
        // Called before each frame is rendered
        player?.position.x += playerSpeed!
        
        self.enumerateChildNodes(withName: "bullet") {
            (node, _) in
            node.position.y += 1
        }
    }

Footnotes

* Remember, when holding an iPhone or iPad, the button should always be on the right hand side – without wishing to judge, anyone that feels different is wrong, and very possibly evil.

References

https://stackoverflow.com/questions/475553/how-can-i-test-landscape-view-using-the-iphone-simulator

Getting Started With iOS for a C# Programmer – Part Three – Moving an Object

In the first post in this series, I described how to set-up an account and create a very basic program. I also laid out a timeline for getting a very basic game up and running on an iPhone. In this post, I follow on from here where I describe how to run an application in the simulator.

This time, we’re going to create a different type of project and start the game. In the first post, I described the target of this post to make an object move across the screen; we’re actually going to go slightly further and allow a small amount of control.

Create a new Game Project

This time, when we create a new project, we’ll select “Game”:

The next screen is vaguely familiar; for this particular example, we want Swift as the language, and SpriteKit as the game framework:

This should create you a new project that looks something like this:

It also gives you some codeā€¦ which causes the program to do this out of the box:

Clear Default Game Code

There’s quite a lot of code generated by default in order to create this magnificent application. A lot of it needs deleting; let’s start with the text. In GameScene.sks, select the “Hello, World” text and delete it:

Most of the rest of the code is in GameScene.Swift; you can simply clear that; although, unless your target is to create the exact same game as this series of posts describes, you might want to comment out what’s there, so you can revisit later.

Create Object

The first step to making an object move across the screen is to create an object. Our object is going to be a rectangle:

    func createScene(){
        self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
        self.physicsBody?.isDynamic = false
        self.physicsBody?.affectedByGravity = false
        
        //self.physicsWorld.contactDelegate = self
        self.backgroundColor = SKColor(red: 255.0/255.0, green: 255.0/255.0, blue: 255.0/255.0, alpha: 1.0)
        
        let player = CreatePlayer()
        self.addChild(player)

    }
    
    // Returns SKShapeNode
    func CreatePlayer() -> SKShapeNode {
        
        let playerSize = CGSize(width: 100, height: 50)
        
        let player = SKShapeNode(rectOf: playerSize)
        player.position = CGPoint(x:self.frame.midX, y:self.frame.midY)
        player.strokeColor = SKColor(red: 0.0/255.0, green: 0.0/255.0, blue: 0.0/255.0, alpha: 1.0)
        
        player.physicsBody = SKPhysicsBody(rectangleOf: playerSize)
        
        player.physicsBody?.affectedByGravity = false
        player.physicsBody?.isDynamic = true
            
        return player
    }

There are two functions in the code above. ‘createScene()’ establishes the game environment: background colour, physics rules, etc. This, in turns, calls ‘CreatePlayer()’ and adds the result to ‘self’.

A Quick not on `Self`

What is ‘self’? As you can see from the class definition, the GameScene class inherits from SKScene:

class GameScene: SKScene {

In C# terms, ‘self’ translates to ‘this’, so we’re referring to the instance of a class that inherits from SKScene.

We now have a couple of functions to set the game up, but haven’t yet called them; that’s where the didMove event comes in. This fires after the scene is loaded and rendered:

override func didMove(to view: SKView) {
            createScene()
    }

And we have our box:

Move Game Object

But the target wasn’t just to draw something on the screen, but to move it. Let’s make it move when you touch the screen. First, we’ll need to declare a couple of variables to hold the player object and the speed they are travelling (BTW, there’s a reason the variable is called playerSpeed and not speed – speed is a variable that exists in the SpriteKit namespace – although you wouldn’t know it from the error!):

class GameScene: SKScene {
    
    private var player : SKShapeNode?
    private var playerSpeed : CGFloat? = 0

There’s a series of events that handle when the user touches the screen, but let’s use ‘touchesBegan’ for now:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        playerSpeed! += CGFloat(1.0)
    }

Finally, the update function allows the change of game variables before they are rendered:

    override func update(_ currentTime: TimeInterval) {
        // Called before each frame is rendered
        player?.position.x += playerSpeed!
    }

As far as I can establish, anything inside the SKScene object is automatically rendered each frame by virtue of being there. So, if we were relating this to a C# game engine such as MonoGame, the Draw function is automated.

References

http://sweettutos.com/2017/03/09/build-your-own-flappy-bird-game-with-swift-3-and-spritekit/

https://developer.apple.com/documentation/spritekit/skscene/1519607-didmove

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Methods.html

Getting Started With iOS for a C# Programmer – Part Two – Running the Simulator

The purpose of this post is to take the code that we created here and run it in the simulator.

Leaving the Playground

To a .Net programmer, this seems like an alien concept but, depending on the mode that you run Xcode in, it results in a different IDE. If, instead of selecting Plaground, we select “Create an Xcode Project”, the whole app experience changes:

There are a lot more options available now; but let’s stick to the most basic:

The created Single View App should look like this in structure:

The target of this post is simply to take the few lines of code that we wrote in part one, and have them run on a simulator.

The first thing it does is launch the ViewController, so let’s take the code that we created in the first part, and add it directly to the ViewController; the new controller will look like this:

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        let x = UILabel()
        x.text = "test"
        x.textColor = UIColor.black
        x.frame = CGRect(x: 5, y: 5, width: 80, height: 20)
        
        let v = UIView()
        v.frame = CGRect(x: 0, y: 0, width: 100, height: 100);
        v.backgroundColor = UIColor.white
        v.addSubview(x)
        
        self.view = v
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

There are a couple of changes – firstly, we no longer reference Playground, and secondly, the active view is set here:

self.view = v

When we run this, we get the simulator appearing, and the text appears (as we might expect):

Getting Started With iOS for a C# Programmer – Part One

I’ve never programmed with XCode before; I’ve never even owned a Mac, so since I now have access to one, I thought I’d see if I could create a basic game. In order to motivate me to complete this, I thought I’d document my efforts, and try to put at least one post up every two weeks. As I knew absolutely nothing about this to begin with, I’m going to start from there.

The Basics

The first thing that you’ll need is an Apple account. You can use one that you might have set-up for your iPhone; otherwise, you can set one up here. It’s free to register, and there’s no need to sign up for a developer account immediately; although, should you wish to, it will cost you $99.

The next stage is to install Xcode; which can be found here. Xcode is the IDE, so it’s the equivalent of Visual Studio – it is not a language in its own right. The language we’re dealing with here is called Swift.

Your first program

When you initially run Xcode, you’ll be faced with a screen like this:

Since we don’t know what we’re doing, let’s select “Get started with a playground”:

And let’s select a Blank playground.

We then get an (almost) blank text editor:

The examples given seem to introduce a new level of complexity by including controllers; however, this is the simplest example of a working “Hello, world” program that I could come up with:

import UIKit
import PlaygroundSupport

let x = UILabel()
x.text = "test"
x.textColor = UIColor.black
x.frame = CGRect(x: 5, y: 5, width: 80, height: 20)

let v = UIView()
v.frame = CGRect(x: 0, y: 0, width: 100, height: 100);
v.backgroundColor = UIColor.white
v.addSubview(x)

PlaygroundPage.current.liveView = v

To break down that code

import UIKit
import PlaygroundSupport

Playground support is the library that allows you to visualise the preview of what the app will look like when it’s eventually on the device.

let x = UILabel()
x.text = "test"
x.textColor = UIColor.black
x.frame = CGRect(x: 5, y: 5, width: 80, height: 20)

The UILabel object has to live within a frame; otherwise it will not appear on the screen. The default colour is black, but as I’ve specified the colour of the view, I thought it made sense to specify all colours.

let v = UIView()
v.frame = CGRect(x: 0, y: 0, width: 100, height: 100);
v.backgroundColor = UIColor.white
v.addSubview(x)

PlaygroundPage.current.liveView = v

This sets up the view; which seems to map to a form in WinForms, or a view in WPF. Again, the view needs a frame; and, in this case, it does need a colour (as the default is black).

The x, y, height and width variables are just guesses – so these may need changing later. Finally, we set the current Live View on the playground so that it knows which view to display.

Running the Code

If you run that initially, you’ll see that, whilst it compiles, nothing actually happens; the trick is here:

Summary and Target

Once you’ve established the basic syntax, the code suddenly seems much more familiar. There are some things that appear foreign to the eyes of a .Net developer; for example, “let” establishes a constant. In the case that it’s used here, it’s a constant pointer.

The target game that I have in mind is a very basic space invaders style game. I’ve already written a similar one in WinJS for the Windows Store so this is kind of a coding kata for me.

As a very loose plan, I intend to do the following:

Step 2: How does this code run on a simulator and on a device?
Step 3: Make an object move across the screen
Step 4: Allow control of said object
Step 5: Collision
Step 6: Graphics
Step 7: Score

Some of these steps may be spread over more than one post – it depends how hard they end up being.