Hacking with Swift – Challenge 14

New day, new challenge!

No seriously, I have taken the decision to slow down a bit.

I didn’t have two and half hours to dedicate to coding before starting this initiative and I certainly do not have them now that work is—thankfully—flowing in at a steady pace.

I will continue to practice at least 1 hr a day but as now that it is Day 60 I am only facing Day 56 there is really no point in rushing and destroying my health … and then, for what? Am I getting a better job because of this? No! Not now and not for the next few years in any case so better be realistic and very, very calm!


Review

Here is a summary of some of the things we learned during this project:

  • GCD’s asyncAfter() takes an absolute time rather than an offset relative to now. Well… I am not sure I agree with this because in code we wrote deadline: .now() + 1, that is an absolute time (now) plus an offset relative to …well, now… so it is an infinite-brain-loop. The absolute time we pass and the now are the same thing, right? Bah…
  • SpriteKit nodes may or may not have a name property set. In this project we have always set a name for it but we have not really used it. Why? Who knows…
  • Every SKNode has a parent property. This question was the sister of the previous one as the other option was “every node must have a unique name”.
  • y: 0 is the bottom of the screen in SpriteKit. …and thank goodness to this, come on, all school formation brings that y grows vertically from the bottom up and only UIKit wants to reinvent the wheel. I would really like to know why this happens.
  • SpriteKit actions sequences are made from arrays. That is, we create more than a single action separately, then we create an array that includes all of them, then run that array…
  • Objects are sorted by Z position, where higher numbers are placed on top of lower numbers. By now we have only encountered 1 and -1 so I do not know what the other possible positions are. zPosition seems to be a CGFloat so I guess many possibilities are available but I wonder if -1 and 1 are the min and max of them. Again, mystery!
  • We can create custom subclasses of SKNode. Yes, we can!
  • An xScale value of 1.0 means “100% of its regular size”.
  • SpriteKit creates particles using SKEmitterNode, and I dread the moment when I will have to go and lose myself in that world.
  • SpriteKit has actions that move objects, wait for a period of time, play sounds, and more.
  • Any part of the mask of an SKCropNode that has color is not cropped. This was really hard to understand but, well, I will have just to live with my ignorance because the documentation does not explain it in any better way and, especially, it is in Objective-C so… no luck there…
  • SKCropNode only crops nodes that are placed inside it.

Challenges

Can I say that when I read what the challenges were for today I just wanted to quit Xcode and say goodbye to all this? I feel all of these challenges as a huge burden because even if yes, they stretch my knowledge… yes, they require me to go and browse countless pages of material to find what I need. The reason why I follow a course is to get the knowledge I need, not to lose my time looking for it… Always the same story again and again… Really not enjoying it but I committed so, fine, I will go on… I will probably end up with Day140 instead of 100 for the same program…

Challenge 1: record your own voice saying “Game over!” And have it play when the game ends.

I recorded the voice over using the new Voice Memo app on Mojave but … so frustrating … no way to send it to MYSELF apart from emailing it to me. There is no iCloud dedicated folder for that, it doesn’t show in iTunes… where the hell is that?

Anyway… then, I imported the file into the app and added the following line to createEnemy():

run(SKAction.playSoundFileNamed("GameOver.m4a", waitForCompletion: false))

Challenge 2: When showing “Game Over” add an SKLabelNode showing the final score.

Always inside createEnemy(), just under the code for the sound I just added, I set gameScore.isHidden = true as there is no point in showing both the score label and the final score message, right?

I then initialised an SKLabelNode(fontNamed: "Chalkduster"), set its text property to “Your final score is (score)!”, set its position (after a few trial and errors) to (x: 512, y: 312), its zPosition to 1 and, finally, added the child to the parent scene.

Challenge 3: Use SKEmitterNode to create a smoke-like effect when penguins are hit, and a separate mud-like effect when they go into or come out of a hole.

Very interesting thing.

I managed to create a smoke-like effect and added it to the node but, of course, when I went on to create another effect for the showing and hiding, a problem occurred. The console told me this:

Attempted to add a SKNode which already has a parent

The app then crashes when I hit a penguin… mumble mumble…


After a whole lot of mumbling it is not really clear to me why that crash was happening. It was clear, though, that I was writing the whole thing in a non-optimised way so I changed my approach.

For the smoke-like effect I created a SpriteKit particle and then set it inside the hit() method (in case I will ever need it in another place I will create a separate method). Here is the method as it is now.

if let smokeParticle = SKEmitterNode(fileNamed: "smoke") {
    smokeParticle.position = charNode.position
    
    let smokeSequence = SKAction.sequence([
        SKAction.run { [weak self] in self?.addChild(smokeParticle) },
        SKAction.wait(forDuration: 3.0),
        SKAction.run { smokeParticle.removeFromParent() }
    ])
    
    run(smokeSequence)
}

The important part here is the sequence, otherwise we get infinite nodes added to our scene, something that we hopefully do not want.

The mud-like effect required quite more thinking because even if the idea was the same, we have two states for the penguin: inside the hole or outside it so we need to switch over the isVisible property to see where the mud gets created. This can be done with a method like this:

func sprayMud() {
    if let mudParticle = SKEmitterNode(fileNamed: "mud") {
        switch isVisible {
            case true: mudParticle.position = CGPoint(x: 0, y: 0)
            case false: mudParticle.position = CGPoint(x: 0, y: charNode.position.y + 80)
        }
        
        let mudSequence = SKAction.sequence([
            SKAction.run { [weak self] in self?.addChild(mudParticle) },
            SKAction.wait(forDuration: 3.0),
            SKAction.run { mudParticle.removeFromParent() }
            ])
        
        run(mudSequence)
    }
}

We then call the sprayMud() method inside the hide() method and inside the show() one.

That’s it!

The third challenge was harder because I got that strange crash but I am happy nonetheless that I managed to finish them.

The mud particle was a big challenge because I didn’t know what to base the model on so I eventually copied a friend’s one (no shame in that, really, I cannot know everything beforehand if I’m not getting a thorough explanation on that and if the available resources assume you already know 90% of the subject).

So, a big thank you to Rob Baldwin (@isSwifty on Twitter) for helping me out on this.

If you are interested in my solutions you can find it here.

Please don’t forget to drop a hello and a thank you to Paul for all his great work (you can find him on Twitter) and don’t forget to visit the 100 Days Of Swift initiative page.

Thanks for reading!

Till the next one!


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 )

Twitter picture

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

Facebook photo

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

Connecting to %s

%d bloggers like this: