Attach SKSpriteNode to another SKSpriteNode - ios

I have a Player SkSpriteNode that needs to pickup an Object. Once the Object is picked up, it should be attached to the player. I don't really care where the object is (to a side, above, center, etc), but it needs to stick to the player and not move from it's position.
With the code below I can get it to stick, but once the Player falls from a platform, the Object lags behind it, almost like it's lighter than the Player. I've tried pinning it, but that affects how high my Player jumps. Setting dynamic or gravity to false doesn't seem to help either.
The code below is in the Player Class.
func pickedUpObject(object: ObjectClass) {
object.removeFromParent()
object.position = CGPoint(x: -20, y: -5)
object.zPosition = 0
self.addChild(pollen)
}

Related

Fix the camera to a distance from a spritenode

I am trying to fix the camera to a sprite node “players.first!” and I managed to do so using SKConstraints as follows
func setupWorld(){
let playerCamera = SKCameraNode()
let background = SKSpriteNode(imageNamed: platformType + "BG")
var cameraFollow = [SKConstraint]()
cameraFollow.append(SKConstraint.distance(SKRange(constantValue: 0), to: players.first!))
playerCamera.constraints = cameraFollow
background.zPosition = layers().backgroundLayer
background.constraints = cameraFollow
background.size = self.size
self.addChild(playerCamera)
self.camera = playerCamera
self.addChild(background)
physicsWorld.contactDelegate = self
addEmitter()
}
But this keeps the camera fixed to the exact location of the node, I want the camera to be shifted to the right of the node “players.first!” (only in X dimension) and I couldn’t manage to do so with SKConstraints, note that the node is moving fast so updating the position of the camera in the update function makes the camera jitter.
This image is explaining my issue
Constrain the camera to an empty SKNode and make it a child node of the first player which is offset to the right in the frame of the player. This can be accomplished in the scene editor or programmatically by setting this dummy node's position to something like CGPoint(x: 100, y: 0). When the player moves, this node will also move, dragging the camera along with it; and since the camera is focused on this node, the nodes in the same 'world' of the player will appropriately appear to move in the opposite direction while maintaining the look you want for the player.
EDIT: If the player rotates
If the player needs to rotate, the above configuration will result in the entire node world revolving around the fixed empty node. To prevent this, instead place an empty SKNode that acts as the fixed camera point which will be called "cameraLocation" and the player node into another empty SKNode which will be called "pseudoPlayer". Constrain the camera to "cameraLocation". Moving the "pseudoPlayer" node will then move both the camera's fixed point (so that the camera moves) and the player node while only resulting in the rotation of the player and not the entire world.
NOTE: The only potential drawback is that in order to move the player correctly through the world, you must move the "pseudoPlayer" instead.

How to use SKConstraint in swift

I have a moving camera in my scene, which always follows my player. But I also have some other content(On screen controls) which I want to stay in a single place on the screen, but when the camera moves, The controls are moving away to. How would I go about doing this. I have searched a lot, and found the SKConstraint, but I couldn't find any tutorials to use it in swift 3.
Should I be using the SKConstraint? If yes, how can I use it, if no, how do I keep the controls at a certain position on the screen at all times.
I also know that I could change the position of the controls in the update method, but I do not want to do that as there are many on screen controls, and I try to refrain from writing code in the update method as much as possible.
Any help would be appreciated, thanks!
You can use an SKConstraint to cause a camera to follow a character.
First, create a camera node and a hero and add them to the scene
let cameraNode = SKCameraNode()
let hero = SKSpriteNode(imageNamed: "Spaceship")
addChild(hero)
camera = cameraNode
addChild(cameraNode)
Next, create a constraint and assign it to the camera node's constraints property
let range = SKRange(constantValue:0)
let constraint = SKConstraint.distance(range, to: hero)
cameraNode.constraints = [constraint]
Lastly, if you have controls or labels that need to be at fixed locations relative to the camera, you can add them to the camera node
let label = SKLabelNode(text: "Score: 123")
// Position the label relative to the camera node
label.position = CGPoint(x: 100, y: 100)
cameraNode.addChild(label)

infinite scrolling background - how to make objects move with ground

I have an infinitely scrolling background and a character 'walking' on the ground plane.
I want to drop objects from above and have them land on the ground - so far so good. But the objects don't move with the ground.
Can't find any examples where this is taken care of.
my 'ground' is just an edge at the correct height with regard to my graphics background.
let Edge = SKNode()
Edge.physicsBody = SKPhysicsBody(edgeFromPoint: CGPointZero, toPoint: CGPointMake(self.frame.width + 1, 0))
Edge.position = CGPointMake(0, bottomShelf_ItemStartPosition.y)
self.addChild(Edge)
I've tried giving my ground SKSriteNode physical properties, but this didn't make any difference.
What would be the best approach for this? Must be a simple way to make the moving ground effect objects.
adding scroll routine:
func backgroudScrollUpdate1(){
back.position = CGPoint(x: back.position.x - scrollPerFrameAmount, y: back.position.y)
back2.position = CGPoint(x: back2.position.x - scrollPerFrameAmount, y: back2.position.y)
if (back.position.x < -(back.size.width / 2)) {
back.position = CGPointMake(back2.position.x + back.size.width, back.position.y)
}
if (back2.position.x < -(back.size.width / 2)) {
back2.position = CGPointMake(back.position.x + back2.size.width, back2.position.y)
}
}
update - some progress
i have set up a physics world, where my ground is infinitely scrolling. I've got some items that fall out of the 'sky' and land on the ground. I can move the things around by applying impulse directly or one thing hitting another.
But, what i expected is that the scrolling ground would 'pull' things along with it if they are on the ground?
I have played around with different friction levels of both the ground at the items touching the ground, but it doesn't seem to matter.
one thing that did sort of work is if i set the phsyics body of an item to a circle, then the ground does influence the item, turning it around in the opposite direction of the scrolling - but when it hits an edge it just stops, rather than spinning at the edge.
If that part is working, then why wouldn't a rectangle be dragged along by the ground ?
would love to see example code of a phsyics world that does have the ground effecting other nodes..

Centering Camera on Velocity Applied Node Not Working

I have a subclass of SKNode which consists of a few sprites that make up a player. I would like the "camera" to center on this node (Always have the player in the center). Now before you down vote this for it being a duplicate, hear me out. The Apple documents suggest making the player node completely static, and instead moving around a camera node. However in my case I'm applying multiple properties of physics to my character, including velocity impulses. My first thought would be to just apply these impulses to the camera node itself, however this has become impossible due to the fact that the character has a small soft-body physics engine on it. I'm applying velocity to it like so:
player.primaryCircle.physicsBody!.velocity = CGVector(dx: player.primaryCircle.physicsBody!.velocity.dx+relVel.dx*rate, dy: player.primaryCircle.physicsBody!.velocity.dy+relVel.dy*rate)
I managed to get it to partially work with the following code:
override func didSimulatePhysics() {
self.player.position = player.primaryCircle.position
self.camera.position = player.position
centerOnNode(camera)
}
func centerOnNode(node: SKNode) {
let cameraPositionInScene: CGPoint = node.scene!.convertPoint(node.position, fromNode: node.parent!)
node.parent!.position = CGPoint(x:node.parent!.position.x - cameraPositionInScene.x, y:node.parent!.position.y - cameraPositionInScene.y)
}
However that didn't 100% work, as seen here: (It should be focused on the red circle)
http://gyazo.com/b78950e6cc15b60f390cd8bfd407ab56
As you can see, the world/map is moving, however it doesn't seem to be moving fast enough to center the player in the middle. (And note that the "Unamed" text is at a fixed spot on the screen -- That's why it seems to always be in the center)
I think this should still work with physics unless I am not truly understanding the question. We did something similar with our SKATiledMap with that Auto Follow Feature. What you need to do is make sure the player is added to a node you can move (usually a map) as a child and then in the update function you do something like this...(sorry it isn't in swift)
-(void)update
{
if (self.autoFollowNode)
{
self.position = CGPointMake(-self.autoFollowNode.position.x+self.scene.size.width/2, -self.autoFollowNode.position.y+self.scene.size.height/2);
//keep map from going off screen
CGPoint position = self.position;
if (position.x > 0)
position.x = 0;
if (position.y > 0)
position.y = 0;
if (position.y < -self.mapHeight*self.tileWidth+self.scene.size.height)
position.y = -self.mapHeight*self.tileWidth+self.scene.size.height;
if (position.x < -self.mapWidth*self.tileWidth+self.scene.size.width)
position.x = -self.mapWidth*self.tileWidth+self.scene.size.width;
self.position = CGPointMake((int)(position.x), (int)(position.y));
}
}
Map being the node that the player is added to. Hopefully that helps. Also here is the link to the git hub project we have been working on. https://github.com/SpriteKitAlliance/SKAToolKit

How to simulate a world larger than the screen in SpriteKit?

I'm looking for the proper SpriteKit way to handle something of a scrollable world. Consider the following image:
In this contrived example, the world boundary is the dashed line and the blue dot can move anywhere within these boundaries. However, at any given point, a portion of this world can exist off-screen as indicated by the image. I would like to know how I can move the blue dot anywhere around the "world" while keeping the camera stationary on the blue dot.
This is Adventure, a sprite kit game by apple to demonstrate the point I made below. Read through the docs, they explain everything
Theres a good answer to this that I can't find at the moment. The basic idea is this:
Add a 'world' node to your scene. You can give it a width/height that is larger than the screen size.
When you 'move' the character around (or blue dot), you actually move your world node instead, but in the opposite direction, and that gives the impression that you're moving.
This way the screen is always centered on the blue dot, yet the world around you moves
below is an example from when I was experimenting a while ago:
override func didMoveToView(view: SKView) {
self.anchorPoint = CGPointMake(0.5, 0.5)
//self.size = CGSizeMake(600, 600)
// Add world
world = SKShapeNode(rectOfSize: CGSize(width: 500, height: 500))
world.fillColor = SKColor.whiteColor()
world.position = CGPoint(x: size.width * 0.5, y: size.height * 0.5)
world.physicsBody?.usesPreciseCollisionDetection = true
self.addChild(world)
}
override func update(currentTime: CFTimeInterval) {
world.position.x = -player.position.x
world.position.y = -player.position.y
}
override func didSimulatePhysics() {
self.centerOnNode(self.camera)
}
func centerOnNode(node: SKNode) {
if let parent = node.parent {
let nodePositionInScene: CGPoint = node.scene!.convertPoint(node.position, fromNode: parent)
parent.position = CGPoint(
x: parent.position.x - nodePositionInScene.x,
y: parent.position.y - nodePositionInScene.y)
}}
If you create a "camera" node which you add to your "world" node, a couple of simple functions (above) allow you to "follow" this camera node as it travels through the world, though actually you are moving the world around similar to Abdul Ahmad's answer.
This method allows you to use SpriteKit functionality on the camera. You can apply physics to it, run actions on it, put constraints on it, allowing effects like:
camera shaking (an action),
collision (a physics body, or matching the position of another node with a physics body),
a lagging follow (place a constraint on the camera that keeps it a certain distance from a character, for example)
The constraint especially adds a nice touch to a moving world as it allows the "main character" to move around freely somewhat while only moving the world when close to the edges of the screen.

Resources