3

This question and others discuss how to track a node in SpriteKit using a SKCameraNode.

However, our needs vary.

Other solutions, such as updating the camera's position in update(_ currentTime: CFTimeInterval) of the SKScene, do not work because we only want to adjust the camera position after the node has moved Y pixels down the screen.

In other words, if the node moves 10 pixels up, the camera should remain still. If the node moves left or right, the camera should remain still.

We tried animating the camera's position over time instead of instantly, but running a SKAction against the camera inside of update(_ currentTime: CFTimeInterval) fails to do anything.

Community
  • 1
  • 1
Crashalot
  • 33,605
  • 61
  • 269
  • 439

2 Answers2

5

I just quickly made this. I believe this is what you are looking for? (the actual animation is smooth, just i had to compress the GIF)

enter image description here

This is update Code:

-(void)update:(CFTimeInterval)currentTime {
    /* Called before each frame is rendered */

    SKShapeNode *ball = (SKShapeNode*)[self childNodeWithName:@"ball"];
    if (ball.position.y>100) camera.position = ball.position;

    if (fabs(ball.position.x-newLoc.x)>10) {
        // move x
        ball.position = CGPointMake(ball.position.x+stepX, ball.position.y);
    }

    if (fabs(ball.position.y-newLoc.y)>10) {
        // move y
        ball.position = CGPointMake(ball.position.x, ball.position.y+stepY);
    }
}
GeneCode
  • 7,545
  • 8
  • 50
  • 85
  • Thanks for the effort, but this is effectively what we did before. It resulted in very jerky movement because the node moves fast (drops with gravity). – Crashalot Dec 05 '16 at 20:58
  • If your movement is jerky, it is most probably not due to this, but is it due to the way you move your sprite. Did you implement the timeElapsed*speed to move the sprite? – GeneCode Dec 06 '16 at 02:21
  • Or, maybe, since you are using physics, it is best to put everything related to movements in didsimulatephysics delegate instead? – GeneCode Dec 06 '16 at 02:22
  • Thanks for the fast response. If we don't move the camera, the movement of the sprite is smooth so doesn't seem like it's an issue related to moving the sprite. The jerkiness only occurs when moving the camera to match the sprite's new position, which only happens if the sprite drops 50 pixels or so. – Crashalot Dec 06 '16 at 02:32
  • 1
    I got no more idea. The final suggestion is to try do the camera movement in didsimulatephysics.good luck. – GeneCode Dec 06 '16 at 02:44
3

I would not put this in the update code, try to keep your update section clutter free, remember you only have 16ms to work with.

Instead create a sub class for your character node, and override the position property. What we are basically saying is if your camera is 10 pixels away from your character, move towards your character. We use a key on our action so that we do not get multiple actions stacking up and a timing mode to allow for the camera to smoothly move to your point, instead of being instant.

class MyCharacter : SKSpriteNode
{
    override var position : CGPoint
    {
        didSet
        {

            if let scene = self.scene, let camera = scene.camera,(abs(position.y - camera.position.y) > 10)
            {
                let move = SKAction.move(to: position, duration:0.1)
                move.timingMode = .easeInEaseOut
                camera.run(move,withKey:"moving")
            }
        }
    }
}

Edit: @Epsilon reminded me that SKActions and SKPhysics access the variable directly instead of going through the stored property, so this will not work. In this case, do it at the didFinishUpdate method:

override func didFinishUpdate()
{
    //character should be a known property to the class,  calling find everytime is too slow
    if let character = self.character, let camera = self.camera,(abs(character.position.y - camera.position.y) > 10)
    {
        let move = SKAction.move(to: character.position, duration:0.1)
        move.timingMode = .easeInEaseOut
        camera.run(move,withKey:"moving")
    }
}
Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
  • if the camera only moves down, then take out the abs and make it <= -10 – Knight0fDragon Dec 05 '16 at 12:54
  • 1
    This will only work if you set the character's position directly. If you move the character with an action or by applying a force/impulse to its `physicsBody`, `didSet` won't be called because the position property isn't set directly. – Epsilon Dec 05 '16 at 20:19
  • This is true, you can get around this though by doing character.position = character.position on the didFinishUpdate which puts us back to GeneCodes answer just using a different function, or use customActions to move instead of using the built in one to move your sprite – Knight0fDragon Dec 05 '16 at 21:15
  • Thanks for the detailed answer Knight. @Epsilon do you have other suggestions? – Crashalot Dec 05 '16 at 22:04
  • Running the `SKAction` inside of `didFinishUpdate` appears to have no effect. Does it do something for you? – Crashalot Dec 06 '16 at 03:03
  • it should take affect on the next loops action phase – Knight0fDragon Dec 06 '16 at 03:04
  • how often is the camera going to be moving? it could be the ease in is doing nothing for you – Knight0fDragon Dec 06 '16 at 03:05
  • you could queue up your moves, this gets a little crazy though and I would recommend switching to the customAction instead – Knight0fDragon Dec 06 '16 at 03:07