How to Make a Game Like Monster Island Tutorial

Learn how to make a game like Monster Island. By Brian Broom.

Leave a rating/review
Save for later
Share

Update 10/7/16: This tutorial has been updated for Xcode 8 and Swift 3.

In this how to make a game like Monster Island tutorial, you will level up your knowledge of the SpriteKit physics system by creating a game named ZombieCat. Your goal as a zombie, is to defeat evil cats by throwing beakers of zombie goo at them—turning them into zombie cats. To do that, you’ll implement one of the major UI features of Monster Island: A large power meter showing the strength and direction of your throw.

Zombies AND cats—what could be better!

In case you’ve never played it, Monster Island is a fun physics-based puzzle game by Miniclip in which you defeat monsters by flinging bombs at them.

If you haven’t used Apple’s SpriteKit framework before, check out Sprite Kit Swift 2 Tutorial for Beginners. This tutorial assumes you’re familiar with actions, the physics system and the scene editor.

Let’s dive in!

Getting Started

This project uses Swift 3 and requires, at a minimum, Xcode beta 4. Once you have that, go ahead and download a copy of the starter project, and look through it.

Open GameScene.sks to see the basic elements of a physics puzzle level already set up.

The walls, cats and obstacles all have physics bodies defined for them, as well as their Category Mask values set in the Attributes Inspector.

Evil cats up to no good.

Make a game like Monster Island tutorial. Evil cats up to no good.

Creating the Projectile

At this point, all you can do in the game is watch the cats quietly plotting to take over the world. Scary, right? You need a way to fight back. That way, of course, is zombie goo. :]

In GameScene.swift, add these properties just before didMove(to:)

var pinBeakerToZombieArm: SKPhysicsJointFixed?
var beakerReady = false

Add a method to create the node for your beaker of goo.

func newProjectile () {
  let beaker = SKSpriteNode(imageNamed: "beaker")
  beaker.name = "beaker"
  beaker.zPosition = 5
  beaker.position = CGPoint(x: 120, y: 625)
  let beakerBody = SKPhysicsBody(rectangleOf: CGSize(width: 40, height: 40))
  beakerBody.mass = 1.0
  beakerBody.categoryBitMask = PhysicsType.beaker
  beakerBody.collisionBitMask = PhysicsType.wall | PhysicsType.cat
  beaker.physicsBody = beakerBody
  addChild(beaker)
  
  if let armBody = childNode(withName: "player")?.childNode(withName: "arm")?.physicsBody {
    pinBeakerToZombieArm = SKPhysicsJointFixed.joint(withBodyA: armBody, bodyB: beakerBody, anchor: CGPoint.zero)
    physicsWorld.add(pinBeakerToZombieArm!)
    beakerReady = true
  }
}

Add the following line to didMove(to:):

newProjectile()

This is a fairly standard example of creating a new SKSpriteNode, setting its properties, adding a SKPhysicsBody and adding it to the scene. Two properties you might not be familiar with are categoryBitMask and collisionBitMask. These mask values are how the physics system identifies which sprites interact with each other.

Each physics body has a categoryBitMask property you set to one of the values defined in the PhysicsType struct located at the top of GameScene.swift. Sprites will only collide with or bounce off objects where the categoryBitMask matches the other object’s collisionBitMask.

The beaker is attached to the zombie with a SKPhysicsJoint. A fixed joint keeps two physics bodies in the same relative position. In this case, the beaker will move with the arm body, until the joint is removed.

Note: The physics simulation uses two types of body interactions, collision and contact.

Collision: In this type of interaction, the two sprites bounce off of each other like a ball off a wall. The physics simulation automatically takes care of the collision calculation, so you don’t have to deal with angles or differences in mass.

Contact: This interaction alerts you when two objects touch or overlap. The moving object will continue to move through the other object, unless you change its motion manually. You’d use contacts to be informed when an event happens, such as a ball crossing a goal line, without changing the object’s motion.

For more details about these interactions, or bit masks in general, the Making Contact section of How To Create a Breakout Game with Sprite Kit and Swift gives a great explanation.

Build and run to see your new beaker of zombie goo. You’re almost ready to attack those cats!

bloop

New beaker appears on screen

Throwing the Beaker

Now that you’ve got the beaker in the game, you need to be able to use it as a weapon.

Meow.

You have to beaker-ful with zombie goo. It could create a cat-atrophy.

To throw the beaker, all you have to do is remove the SKSKPhysicsJointFixed and give it an impulse in the physics system. An impulse is like a kick, represented by a vector that has both an X and a Y component.

Add the following methods to GameScene.swift:

func tossBeaker(strength: CGVector) {
  if beakerReady == true {
    if let beaker = childNode(withName: "beaker") {
      if let arm = childNode(withName: "player")?.childNode(withName: "arm") {
        let toss = SKAction.run() {
        self.physicsWorld.remove(self.pinBeakerToZombieArm!)
        beaker.physicsBody?.applyImpulse(strength)
        beaker.physicsBody?.applyAngularImpulse(0.1125)
        self.beakerReady = false
      }
      let followTrough = SKAction.rotate(byAngle: -6*3.14, duration: 2.0)
          
      arm.run(SKAction.sequence([toss, followTrough]))
    }
        
    // explosion added later
    }
  }
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
  tossBeaker(strength: CGVector(dx: 1400, dy: 1150))
}

When using the physics system, you change the motion of a sprite through its physics body, not the sprite itself. SKPhysicsBody has two methods you could use to throw the beaker, applyForce and applyImpulse. Since you want the change to be instantaneous, use applyImpulse. Usually, thrown objects spin while in the air, and applyAngularImpulse simulates that. You can adjust the angular impulse to get the desired amount of spin, or even change its direction by using a negative number.

Don’t forget to remove the SKPhysicsJoint, or the beaker will stay attached to the zombie hand.

Build and run the game. When you tap on the screen, the beaker should fly around. Notice how the beaker bounces off of the walls and cats.

Wheeee!

Make a game like Monster Island tutorial. A beaker is in flight.

But despite all that spinning and bouncing, there’s no explosion. For that, you need the explosion effect.

Adding the Explosion Animation

To display the explosion image, you’ll need a SKSpriteNode. You may be wondering where the best place is to position the explosion. There are several answers, but one of the simplest is to add it as a child of the beaker.

Add the following to the end of newProjectile():

let cloud = SKSpriteNode(imageNamed: "regularExplosion00")
cloud.name = "cloud"
cloud.setScale(0)
cloud.zPosition = 1
beaker.addChild(cloud)

This creates a new sprite and adds it as a child node of the beaker, meaning the two will move and rotate together. You set the scale to zero to hide the sprite, since the explosion happens later. Setting the zPosition ensures the cloud appears on top of the beaker instead of underneath.

To see the explosion, add the following to tossBeaker(strength:) replacing the explosion added later comment:

if let cloud = beaker.childNode(withName: "cloud") {
  
  // 1
  let fuse = SKAction.wait(forDuration: 4.0)
  let expandCloud = SKAction.scale(to: 3.5, duration: 0.25)
  let contractCloud = SKAction.scale(to: 0, duration: 0.25)
  
  // 2
  let removeBeaker = SKAction.run() {
    beaker.removeFromParent()
  }
  let boom = SKAction.sequence([fuse, expandCloud, contractCloud, removeBeaker])
  
  // 3
  let respawnBeakerDelay = SKAction.wait(forDuration: 1.0)
  let respawnBeaker = SKAction.run() {
    self.newProjectile()
  }
  let reload = SKAction.sequence([respawnBeakerDelay, respawnBeaker])
  
  // 4
  cloud.run(boom) {
    self.run(reload)
  }
}

Taking this step-by-step:

  1. The first three actions wait 4 seconds before making the cloud grow and shrink in the form of an explosion. Feel free to experiment with these values for different effects.
  2. Normally, this would be a simple removeFromParent action, but these actions run on the cloud node. You need to remove the beaker node instead, so you define a runBlock action. Then you combine the actions in a sequence.
  3. These actions give you another beaker to toss at the cats.
  4. Finally, you run the sequence of actions from Step 2 on the cloud node. While you could have the reload actions in the main sequence action, the completion block will come in handy later.

Build and run to see how dangerous zombie goo can be.

Down with the ferocious felines!

Make a game like Monster Island tutorial. boom
Brian Broom

Contributors

Brian Broom

Author

Over 300 content creators. Join our team.