Unable to swing the cat's tail like a boss (Chapter 7)

Hi,

Following the instructions up to page 179 in the latest pdf, when I deploy CatNap to either a simulator or to my iPad, the animation for swinging the cat’s tail doesn’t seem to be triggered.

I have noticed the following, which may be relevant:

  • The cat’s tail does swing when I press animate in the Cat.sks action editor.
  • The cat’s tail does not swing when I press animation in GameScene.sks editor.
  • Changing the startup up scene to Cat.sks shows the swing action as expected.
  • The provided “final” project works fine - but I can’t see any differences!
  • Adding an action (or even editing one) break things - no actions are then being run on deploy. Deleting the new action doesn’t fix the problem!
  • No errors reported on the console.

It looks like a problem with Xcode - but if anyone has any suggestions - greatly appreciated!

1 Like

Seems to be that isPaused is set to true, which is quirk of Xcode 9

Changing isPaused = false (e.g. as part of CatNode.didMoveToScene()) resolves!

2 Likes

Thank you! I was struggling with this for awhile.

I’m having same problem - but not sure where I’m supposed to change isPaused from true to false.

1 Like

When you get to pages 216-217 and add create the CatNode.swift file you can add
isPaused=false
either before or after
print("cat added to scene")
in didMoveToScene

2 Likes

@blindfreddy Thank you very much!

Actually I had the same problem for catCurl and catAwake, both in the CatNode.swift file.
I found in both cases adding isPaused = false after the move(toParent: self) worked.

catAwake.move(toParent: self)
catAwake.isPaused = false

catCurl.move(toParent: self)
catCurl.isPaused = false

Would really like to know why it doesn’t work without the extra code.

I wish I had looked here first before spending hours on this issue.

After reading this thread, I ended up enumerating the nodes in the didMove override in GameScene.swift:

  enumerateChildNodes(withName: "//*") { (node, stop) in
    print("\(String(describing: node.name)) paused: \(node.isPaused)")
    if node.isPaused {node.isPaused = false}
  }

It showed that all the nodes in the cat reference had isPaused = true. Changing the cat_body node changed its child nodes as well, so it is the only one that needs to be changed.

4 Likes

Was there ever a fix for the Xcode glitch? I am not at the catNode.swift file creation yet and am trying to see if I can get this to work before heading into the next section.

1 Like

I have to admit this is a problem for me too. I also noticed that along with the tail not swinging the cat wouldn’t actually purr until one of the blocks had been removed. The mouth would move and all that but there was no sound. Once a block had been removed the purring sound kicked in. Weird.

I’m very green when it comes to all this but if Xcode is setting isPaused to true then is there a way to change it to false earlier than at catNode?

Edit: Spelling.

I’m in the same boat @airtower, haven’t yet gotten to the point where I write a .swift file for this. I’m blown away that there’s no “isPaused” option in the Properties Inspector or anywhere in the Scene Editor for that matter… That you actually need to fix this with code.

I’m with @airtower and @gdubz and don’t see a solution for those who aren’t past page 179, meaning we’re not to the coding part yet.

Since I know there is a coding solution coming up I will keep going, but a solution for this would be appreciated.

@sgerrard @airtower and @gdubz

I figured out the issue. When I created my project, I had the “Integrate GameplayKit” selected. As a result Xcode setup viewDidLoad() in GameViewController with the code with GKScene and subsequently sceneNode instead of SKScene and scene (shown below). Once I corrected viewDidLoad() to match the Challenge viewDidLoad(), the tail wags when running as it should in Chapter 7.

EDIT:
The difference lies in the isPaused property of the SpriteNodes.
And this property seems to set itself depending on whether or not you moved/altered a referenced Sprite since you last build/ran CatNap.

I figured out a way to be able to modify Sprites between builds, it’s a pain but it works.

How to keep the Sprite Nodes from Pausing

The Key is to not move a Sprite that you just placed in, until AFTER it’s first build.

  1. In Cat.sks file - (or any sks file you want to reference)
    Set up scene size. 380 x 440 points
    Save.
    Page 167 details how to set it up.

  2. In GameScene.sks
    Place a Reference object anywhere in the scene.
    Save.
    Page 169 has instructions

  • Name cat_shared
  • Reference Cat
  • Position 1030, 1045
  • zPosition 10
  1. In Cat.sks
    Place a Colour Sprite object into the scene
    Important! Don’t move it once you drop it in the scene - that will cause the Sprite’s isPaused property to insta be set to true!
    If you moved the Sprite: delete it and drop a new one in.

  2. Set it’s colour to System Green Colour (or any colour except red to avoid confusion)

  3. Place a Rotate Action object in the timeline for that Sprite and have it repeat via ∞ infinity loop.
    Page 177 has details.

image

  1. Build/Run - the green square Sprite should rotate. :+1: isPaused = false

Temp Cat Body

image

  1. Drag in 4 more Colour Sprites into the scene.

image

  1. Build / Run - the Green Sprite should still be rotating.

image

  1. These 4 Red Sprites will be
  • A Temporary Cat Body
    name it temp_body, texture cat_body, X 22, Y -112
  • Cat Head
    Name cat_head, Parent temp_body, texture cat_head, X 18, Y 192
  • Cat Mouth
    Name mouth, Parent cat_head, texture cat_mouth, X 6, Y -67
  • Cat Eyes
    Name eyes, Parent cat_head, texture cat_eyes, X 6, Y 2
    Page 167 - 168 details their properties.

image

  1. Build / Run - Green Sprite should still be rotating, and all the Sprites should not be Paused. Now’s a great time to commit changes to your Git repository.

Tail

  1. Place a Colour Sprite object into the scene - it will be Red.

  2. Place RotateToAngle Action on the Sprite
    Page 173 has details.
    Duration: 2, Degrees: 5

  3. Place another RotateToAngle Action on the Sprite’s timeline
    Duration: 1.5

  4. Select Both and repeat them forever via an ∞ infinity loop
    Page 177 has details.

  5. Set the Sprite’s Anchor Point to (0, 0)

  1. Build/Run

image
If Green Sprite stops spinning now or at any point, it’s a good indicator that your other nodes will no longer animate - that’s probably going to happen, which is why we made a temp_body from the get go.

  1. Name the Red Sprite tail, set it’s texture to cat_tail.

  2. Build and Run, the tail should look like a tail and be swinging.

image

  1. Set the tail’s parent to temp_body, Position -206, -70, zPosition -1

  2. Build/Run - the Tail will probably stop moving. That’s ok.
    If it’s swinging You’re done!

Cat Body

  1. If the tail stopped swinging - Set the tail’s parent back to SKScene_0.

You can stop here if you don’t mind that the tail’s parent isn’t the cat_body.
The last few steps address this.

image

  1. Delete the Rotate Action on the Green Sprite, because this Sprite is going to be the cat_body.
    Note: Only use this Green Sprite if it has been spinning up until this point.
    If your Green Sprite had stopped spinning a few steps above, replace it with a new Colour Sprite.

  2. Set the name of the Green Sprite to cat_body, texture cat_body, X 22, Y -112

  3. Set tail’s parent to cat_body,

  4. Set cat_head’s parent to cat_body

  5. Build/Run

That tail should still be swinging like a boss.

Things should be easier from here on out because it seems this bug only happened when modifying the Sprites in the file referenced, meaning I could freely move the SKEditorReferenceNode to Cat in GameScene without issue.

Cheers!
Rebecca

1 Like

After reading through the various solutions and googling similar behaviour in general when using scene builder in Xcode, the simplest solution that I found to work was simply to set the .isPaused property to false. HOWEVER, I did find from Googling, that for some, this only works after setting the property to true. So,

scene.isPaused = true
scene.isPaused = false

I also found that for some, you might need to set the property on the view rather than the scene

view.isPaused = true
view.isPaused = false

1 Like

I had the same problem and typed view.isPaused = true, and then
view.isPaused = false, in the viewDidLoad() , in GameViewController.swift and it
WORKED!

I was getting stressed out trying to figure out what I did wrong! This book really needs an update to fix the code!

1 Like

Hey everyone! This issue still seems to occur in 2020. For those of you that don’t want to skip ahead and add stuff in the CatNode file you can add this is in the didMove(to view:) function in your GameScene.swift:

    if let cat = childNode(withName: "cat_shared") { // 1
        for item in cat.children { // 2
            item.isPaused = true // 3
            item.isPaused = false
        }
    }
  1. get’s your cat item from the childnodes
  2. loops over every childnode from the cat node
  3. first sets the isPaused to true, then to false.
2 Likes

Did anyone ever figure this out? It’s still a problem as of XCode 11.5 and it’s driving me crazy! The only way I can get it to work is to set isPaused = true and then isPaused = false. Why on earth would you need to do that? It has to be a bug somewhere? :slight_smile:

1 Like

@iraisethebar Thank you for sharing your solution - much appreciated!