Define map bounds and center on player node?

2020-03-06 06:53发布

I'm working on a sidescroller with Spritekit and Swift. I don't understand how to define a playable area bigger than the screen and center the camera on the player. How can this be done?

This is my current code, I tried to create a "world node" which I could move around to simulate the camera, however it's somehow disassociated from it's shape and I haven't been able to get the player inside it.

override func didMoveToView(view: SKView) {
    self.anchorPoint = CGPointMake(0.5, 0.5)
    self.physicsWorld.contactDelegate = self
    self.size = CGSizeMake(view.bounds.size.width, view.bounds.size.height)

    // Add world
    let r : CGRect = CGRectMake(0, 0, 500, 500)
    world = SKShapeNode(rectOfSize: r.size)
    world.physicsBody = SKPhysicsBody(edgeLoopFromRect: r)
    world.strokeColor = SKColor.blackColor()
    world.position = CGPointMake(0, 0)
    self.addChild(world)

    // Add player
    player = SKShapeNode(rectOfSize: CGSize(width: 50, height: 50))
    player.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: 50, height: 50))
    player.fillColor = SKColor.blackColor()
    player.position = CGPointMake(0, 0)
    world.addChild(player)

    // Accelerometer updates
    motionManager.startAccelerometerUpdates()
}

2条回答
够拽才男人
2楼-- · 2020-03-06 07:45

The example in Apple's documentation is in the Advanced Scene Processing section. Apple suggests making a "World" SKNode as a child of the Scene, and a "Camera" SKNode as a child of the world.

They suggest constantly moving the world so that it centers on the Camera during the didSimulatePhysics step. This method allows you to perform actions or simulate physics on the Camera itself, if you so choose. If you center the camera prior to this step, you won't be able to use physics to affect the Camera Node.

If you specifically only want left and right scrolling, simply restrict the movement to the X-axis.

Edit: The current problem is because of your creation of the world and the physicsBody from a Rect that has its position predetermined. This is causing trouble with your anchorPoint setting (the world & physicsBody are being created with their lower left corners starting at the Scene's anchor point).

This can be fixed by creating the World and Player without using a Rect with position set. SKShapeNode's shapeNodeWithRectOfSize works, as does SKSpriteNode's spriteNodeWithColor:size: PhysicsBody is a bit trickier, and should likely use bodyWithEdgeLoopFromPath: world.path

EDIT: For future persons interested in creating a side-scroller with a camera always focused on the player, this is probably the simplest way to get one to work:

var player = SKShapeNode()
var world = SKShapeNode()

override func didMoveToView(view: SKView) {
    self.anchorPoint = CGPointMake(0.5, 0.5)
    self.size = CGSizeMake(view.bounds.size.width, view.bounds.size.height)

    // Add world
    world = SKShapeNode(rectOfSize: CGSizeMake(300, 300))
    world.physicsBody = SKPhysicsBody(edgeLoopFromPath: world.path)
    world.fillColor = SKColor.blackColor()
    self.addChild(world)

    // Add player
    player = SKShapeNode(rectOfSize: CGSize(width: 50, height: 50))
    player.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: 50, height: 50))
    player.fillColor = SKColor.blackColor()
    world.addChild(player)
}

override func update(currentTime: CFTimeInterval) {
    world.position.x = -player.position.x
    world.position.y = -player.position.y
}
查看更多
Ridiculous、
3楼-- · 2020-03-06 07:55

I followed Ray Wenderlich's tutorial on a side scrolling game Super Koalio (or something like that). That game is a side scroller where the game map is larger sideways than the screen. The following code is for my game which is a vertical scrolling game.

In the update method I call a method called setViewPointCenter.

-(void)update:(CFTimeInterval)currentTime
  {
    // Other things are called too
    [self setViewPointCenter:self.player.position];
  }

Then in that method you just update the view

- (void)setViewPointCenter:(CGPoint)position
{
  NSInteger x = MAX(position.x, self.size.width / 2);
  NSInteger y = MAX(position.y, self.size.height /2);
  x = MIN(x, (self.map.mapSize.width * self.map.tileSize.width) - self.size.width / 2);
  y = MIN(y, (self.map.mapSize.height * self.map.tileSize.height) - self.size.height / 2);
  CGPoint actualPostion = CGPointMake(x, y);
  CGPoint centerOfView = CGPointMake(self.size.width/2, self.size.height/2);
  CGPoint viewPoint = CGPointSubtract(centerOfView, actualPostion);
  self.map.position = viewPoint;
}

Now my character is always in the center of the screen. I did change some items from horizontal to vertical, but at least you get an idea. Also, I used a tile map that is why you see mapSize and tileSize. You might want to take a look at Ray's tutorial. And of course you will need to convert into the methods into Swift!!

查看更多
登录 后发表回答