100 Days of Swift – Day 75

Reflections on Day 74

After the countless humiliation that has been yesterday’s challenge I am changing the title of my articles here as what I am doing is just a diary of this initiative which, in one way or another, I will bring to the end so that I can start anew doing it my way.

I will keep following Paul’s teachings but I will not get crazy if the challenges are too much beyond me. Once more I want to be clear: those challenges are great and should be there, but if the only way to solve them is to go out on the web and spend hours and hours looking for different resources on where to learn what was not taught in the lessons the challenges are about, then I’m sorry but I’m out.

A teacher should teach something and then give the students a good number of exercise where their new and fresh knowledge could be tested (that is, with the same exact difficulty as the subject just taught) and then one, maximum two exercise that should stretch their imagination to 110%, maximum 120%… not, 350%!

I mean, yesterday I spent again three hours trying to understand what was being asked, browsing past code, looking on the Internet for suggestions, solutions, but this just is not fun at all. The knowledge to solve these challenges should be in what we have already learnt, nothing more. Then, of course, they can be hard as a math exercise can be harder than another one, but that’s it.

This way of proposing the challenges is just not fun and then the way I got rebuked yesterday evening on the official Slack channel when I asked for an official solution was just outrageous. In short, he is creating a community around this 100 days thing and then, if someone is having any real issue, as in my case, he has no time for that. I mean, one just needs to be clear, I have really nothing against that and, especially after one night of sleep over it I see everything more clearly now: we can ask for his help at any time but no answer is ever guaranteed, especially if we are asking for solutions to problems he created in the first place.

As a non-English native speaker I find it very difficult to follow the videos so, after each one of them, I just go back and read the accompanying text which, in theory, should be the same. This has been true for the first 30 or so days while now many things are not the same, increasing my confusion by ten times or more. So I am really feeling in a trap now, where I cannot go back because I committed and going forward is really heavy on my psyche.

I have asked for help to other people on the Slack channel, explaining what the issue with this project was but no one answered apart from saying to look to their code which, once copied (or straight downloaded from GitHub), just doesn’t work. So which road is the right one?

Anyway, enough ranting for today, let’s get back to work…

Hacking with Swift – Learning Project 20

Today I will be tackling a new SpriteKit game taken from Paul Hudson’s best-selling book Hacking with Swift. I had already read the first 8 projects last year before taking this challenging initiative. Be sure to give a look at it if you have never done so before.

Setting Up

By now we should know the drill. If not, please refer to some of my previous articles where I showed how to set up the projects for SpriteKit. In short:

  1. Delete Action.sks
  2. Edit GameScene.sks (erase the label, change the size and anchor points)
  3. Clean up GameScene.swift (leave only didMove(to:)

Import the files for Project 20 (images in the assets catalog, .sks files in the Project Navigator.

Ready… aim… fire: Timer and follow().

This was a complex part but here is a summary of what was done and, possibly, learned:

  1. two main properties were created, an optional Timer and an array of SKNodes. It is said that this array is created to avoid accidental taps. I am not understanding why this is a problem right now but I guess it will be explained later down the road.
  2. Three integer properties were created to indicate the starting point for the fireworks. The only thing I do not understand is why rightEdge is 1024+22 and not 1046
  3. A score property was created and was left to us to fill in later. No complaints!
  4. Inside didMove(to:) the background was set to the appropriate image, fixed in the center of the screen, given a .replace blend mode, a -1 zPosition and added to the parent node.
  5. The gameTimer property was initialised with a scheduled timer set to fire every 6 seconds calling the launchFireworks method.
  6. The createFirework(xMovement:x:y:) method was created. Here it is with comments explaining what it does:
// Create Firework: three parameters, the x-movement speed, then x,y position for creation
func createFirework(xMovement: CGFloat, x: Int, y: Int) {
    // create an SKNode as firework container
    let node = SKNode()
    node.position = CGPoint(x: x, y: y)
    
    // create a rocket sprite node, name it "firework", adjust its colorBlendFactor, then add it to the container node
    let firework = SKSpriteNode(imageNamed: "rocket")
    firework.colorBlendFactor = 1 // we want to color that fully
    firework.name = "firework"
    node.addChild(firework)
    
    // give the firework sprite node a random color out of three
    switch Int.random(in: 0...2) {
    case 0:
        firework.color = .cyan
    case 1:
        firework.color = .green
    default:
        firework.color = .red
    }
    
    // create a UIBezierPath to represent the movement of the firework
    let path = UIBezierPath()
    path.move(to: .zero)
    path.addLine(to: CGPoint(x: xMovement, y: 1000))
    
    // make the container node follow that path, turning as needed
    let move = SKAction.follow(path.cgPath, asOffset: true, orientToPath: true, speed: 200)
    node.run(move)
    
    // create particles behind the node
    if let emitter = SKEmitterNode(fileNamed: "fuse") {
        emitter.position = CGPoint(x: 0, y: -22)
        node.addChild(emitter)
    }
    
    // add the firework to the array and to the scene
    fireworks.append(node)
    addChild(node)
}
  1. The launchFireworks() method was created, creating a movementAmount constant and switching over 4 possibilities to create five fireworks either straight up, in a fan, from left to right and from right to left. Each of the switch case would call the createFirework method five times, changing either the x or the y parameter according to what is needed.

Swipe to select

After my usual cleaning and organising of the code page a touch handling method was created called checkTouches. This would check for the first touch on the multi-touch enabled screen and capture both its location and the nodes found at that location.

Then, using the new for case let syntax, we would loop over each node in those found nodes only if they could be downcast to SKSpriteNodes. Once that could have been verified, the node’s name would be checked and if it would not be “firework” this iteration of the loop would be skipped.

Assuming this would succeed (because all nodes we added had the “firework” name tag) we would loop over each element of the fireworks array and check for first child of that node to be an SKSpriteNode. If that child-node name would already be “selected” (something that would be set up later in this method) and its color not equal to our firstly selected node’s color, its name would be changed back to “firework” and its color blend factor changed back to 1 (i.e.: it’s original color set up in the createFirework method).

After this loop the node’s name would be changed to “selected” and its color blend factor be set to 0 (that is, its default texture color, i.e.: white).

I am not sure I understand why this works: we check for the nodes in a point where we touched, check that its name is “firework” and then we the nodes inside the fireworks array. Why? I mean, why does this even work? It checks for the sprite-node name and color for each one … ok … fine … I see some light at the end of the tunnel but I wonder how much will I be able to reproduce this code if such a situation presents me in the future.

Two base methods get override and passed this checkTouches method: touchesBegan and touchesMoved which handle the beginning of touches on the screen and the swiping. As usual even if this is perhaps the third time we use the touchesBegan method we did not receive a proper explanation of what this method is and does so here it is:

One or more new touches occurred.
One or more new touches occurred.

…and here is the touchesMoved one, which is completely new:

Similar method to the touchesBegan one
Similar method to the touchesBegan one

Making things go bang: SKEmitterNode.

The last thing to be done in this project is to make the fireworks explode when touched. The explode(firework:) method is quite simple as it just declares and instantiates an SKEmitterNode with the proper file name, sets it at the firework’s position and add it to the parent node. Then it removes the firework. Still it is not clear to me how the computer figures out the order of things in which to perform these actions: does it explode and then removes the node or the other way around?

The next method is the explodeFireworks one which keeps track of the amount of fireworks removed and then loops over the fireworks array in its .enumerated().reversed() state destroying every firework named “selected” (which we took care of before) and adding 1 to the amount. It then switches over that amount and gives a sensible score to the player.

Final thing, in GameViewController.swift we need to configure the shake gesture which is handled by the motionBegan method. Two thirds of the method are taken by some safety checks to be sure that our view is an SKView and that the scene in that view is our GameScene. Once that is determined, we call the explodeFireworks method on our game scene.

That’s it.


As always you can find the code for this app here on GitHub.

Whatever you think of the way this series is handled, Paul still needs to be thanked and respected for all the work he is doing for the community so please don’t forget to drop a hello and a thank you to him for all his great work (you can find him on Twitter) and don’t forget to visit the 100 Days Of Swift initiative page. If you would like to give a look at his SpriteKit book, you can check this link. He has about 20 great books on Swift, all of which you can check about here.


If you like what I’m doing here please consider liking this article and sharing it with some of your peers. If you are feeling like being really awesome, please consider making a small donation to support my studies and my writing (please appreciate that I am not using advertisement on my articles).

If you are interested in my music engraving and my publications don’t forget visit my Facebook page and the pages where I publish my scores (Gumroad, SheetMusicPlus, ScoreExchange and on Apple Books).

You can also support me by buying Paul Hudson’s books from this Affiliate Link.

Anyways, thank you so much for reading!

Till the next one!

Published by Michele Galvagno

Professional Musical Scores Designer and Engraver Graduated Classical Musician (cello) and Teacher Tech Enthusiast and Apprentice iOS / macOS Developer Grafico di Partiture Musicali Professionista Musicista classico diplomato (violoncello) ed insegnante Appassionato di tecnologia ed apprendista Sviluppatore iOS / macOS

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: