I am creating a game and I set up the background already. Now when I put in the code to add the character to the scene it does not appear. This is the code I used to try and get the character to appear on the screen. Apparently my character shows up behind the background. Is there another way to get the character to show in front of the background?
func createPlayer() -> SKNode {
let playerNode = SKNode()
playerNode.position = CGPoint(x: self.size.width / 2, y: 80.0)
let sprite = SKSpriteNode(imageNamed: "Pig")
playerNode.addChild(sprite) return playerNode }
In order to make the character appear in front of the background image you need to use zposition:
//You need to choose a high zposition number to make sure it shows up in front.
playerNode.zPosition = 1
// you should set the background images z position using the same method to something below 1
I would also recommend using this to add your character to the scene:
self.addChild(playerNode)
I'm trying to make a game where the sprite will always move to the right when hit by an object. However since the Sprite rotates constantly and the zero radians rotates with the Sprite causes my calculated magnitude to go the opposite direction if the sprite is facing left and hits the object. Is there a way to keep the direction of the magnitude always pointing to the right even if the zero is facing left?
// referencePoint = upper right corner of the frame
let rightTriangleFinalPoint:CGPoint = CGPoint(x: referencePoint.x, y: theSprite.position.y)
let theSpriteToReferenceDistance = distanceBetweenCGPoints(theSprite.position, b: referencePoint)
let theSpriteToFinalPointDistance = distanceBetweenCGPoints(theSprite.position, b: rightTriangleFinalPoint)
let arcCosineValue = theSpriteToFinalPointDistance / theSpriteToReferenceDistance
let angle = Double(acos(arcCosineValue))
let xMagnitude = magnitude * cos(angle)
let yMagnitude = (magnitude * sin(angle)) / 1.5
Not sure if this works for you:
I would use an orientation constraint to rotate the sprite. The movement can be done independent from the orientation in that case.
I made an tutorial some time ago: http://stefansdevplayground.blogspot.de/2014/09/howto-implement-targeting-or-follow.html
So I figured out what was going on.
It seems like the angle doesn't rotate with the Sprite like I originally thought and the vector that I am making is working with the code above. THE problem that I had was that I also set the collision bit for the objects which is wrong. If I only set the contact bit for the objects against the sprite the my desired outcome comes true.
I need to fire a "shot" from a static SKSpriteNode towards another dynamic node. I've created a shot as a sprite node as the shot and moved it to by SKAction to the main sprite node, like so:
let node = info["node"] as SKSpriteNode // The static node
let shot = SKSpriteNode(color: UIColor.blueColor(), size: CGSize(width:node.frame.width / 3, height: node.frame.height / 1.2))
shot.physicsBody = SKPhysicsBody(edgeLoopFromRect: shot.frame)
shot.position = node.position
shot.physicsBody?.categoryBitMask = shotMask
shot.physicsBody?.contactTestBitMask = spriteMask
shot.physicsBody?.collisionBitMask = 0
shot.physicsBody?.usesPreciseCollisionDetection = true
self.addChild(shot)
shot.runAction(SKAction.moveTo(sprite.position, duration: 1.0))
My problem is that the shot stops after it reaches the point. Is there a way to make the shot continue moving in it's direction, or is there another way of doing what I need? Thanks!
Don't use a SKAction to move the shot. Instead change the shot's position by directly modifying it's position.
shot.position = CGPointMake(shot.position.x+1, shot.position.y);
Run the above in your update method. To speed up the shot, change the +1 to whatever value you need. Obviously you will need to remove the shot node from parent once it leaves the screen, hits the target, etc...
You'll need to calculate the vector from the shot's origin to it's destination. Then extend the vector until the shot will be off screen, possibly by finding the unit vector (a vector of length 1) and multiplying it by 3000 or so. As you have a definite endpoint now, you could still use an SKAction.
I'm still playing around with learning SpriteKit in iOS & have been doing lots of reading & lots of experimenting. I'm confused by something else I've found* regarding coordinates, frames & child nodes.
Consider this snippet of code, in which I'm trying to draw a green box around my spaceship sprite for debugging purposes:
func addSpaceship()
{
let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png")
spaceship.name = "spaceship"
// VERSION 1
spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
let debugFrame = SKShapeNode(rect: spaceship.frame)
debugFrame.strokeColor = SKColor.greenColor()
spaceship.addChild(debugFrame)
// VERSION 2
// spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
spaceship.setScale(0.50)
self.addChild(spaceship)
}
If I add the set the spaceship sprite with the line marked "VERSION 1" above, I get this:
which is clearly wrong. But if I comment out the line marked "VERSION 1" above, and instead use the line marked "VERSION 2", I get what I want:
Notice that the actual code for the lines marked Version 1 & Version 2 is identical:
spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
So why does it matter when I set the position of the spaceship sprite?
To my way of thinking, the position of the spaceship sprite is irrelevant to the placement of the the debugFrame, because the debugFrame is a child of the spaceship sprite & thus, it's coordinates should be relative to the spaceship sprite's frame - right?
Thanks
WM
*This is somewhat related to a question I asked yesterday:
In SpriteKit on iOS, scaling a textured sprite produces an incorrect frame?
but a) I understand that one now, and b) this is a different enough that it deserves its own question.
UPDATE:
Hmmm - thanks, guys for the ideas below, but I still don't get it & maybe this will help.
I modified my code to print out the relavant positions & frames:
func addSpaceship()
{
let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png")
spaceship.name = "spaceship"
println("Spaceship0 Pos \(spaceship.position) Frame = \(spaceship.frame)")
// VERSION 1 (WRONG)
spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
println("Spaceship1 Pos \(spaceship.position) Frame = \(spaceship.frame)")
let debugFrame = SKShapeNode(rect: spaceship.frame)
println("DEBUG Pos \(debugFrame.position) Frame = \(debugFrame.frame)")
debugFrame.strokeColor = SKColor.greenColor()
spaceship.addChild(debugFrame)
// VERSION 2 (RIGHT)
// spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
// println("Spaceship2 Pos \(spaceship.position) Frame = \(spaceship.frame)")
spaceship.setScale(0.50)
self.addChild(spaceship)
}
Then, I ran it both ways got these results. Since I understand Version 2, let's start there.
Running with the "VERSION 2 (RIGHT)" code, I got:
Spaceship0 Pos (0.0,0.0) Frame = (-159.0,-300.0,318.0,600.0)
DEBUG Pos (0.0,0.0) Frame = (-159.5,-300.5,319.0,601.0)
Spaceship2 Pos (384.0,512.0) Frame = (225.0,212.0,318.0,600.0)
The spaceship node starts, by default, with its position at the bottom left of the screen (Spaceship0). Its frame is also expressed in terms of its anchor point (center) being set in the bottom left of the screen, hence the negative numbers for the origin of its frame rect.
The debug frame is then created with its position set to 0, 0 by default & its frame set to be the same as the spaceship's.
The code (Spaceship2) then moves the spaceship node to a position in the view's coordinates (384.0,512.0), and its frame's origin is moved by adding the new position to the old origin (i.e. 384 + -159 = 225).
All is well.
Unfortunately, I still don't get Version 1.
When I run with the "VERSION 1 (WRONG)," code, I get
Spaceship0 Pos (0.0,0.0) Frame = (-159.0,-300.0,318.0,600.0)
Spaceship1 Pos (384.0,512.0) Frame = (225.0,212.0,318.0,600.0)
DEBUG Pos (0.0,0.0) Frame = (0.0,0.0,543.5,812.5)
As above, the spaceship node starts, by default, with its position at the bottom left of the screen (Spaceship0). Its frame is also expressed in terms of its anchor point (center) being set in the bottom left of the screen, hence the negative numbers for the origin of its frame rect.
The code (Spaceship1) then moves the spaceship node to a position in the view's coordinates (384.0,512.0), and its frame's origin is moved by adding the new position to the old origin (i.e. 384 + -159 = 225).
The debug frame is then created with its position set to 0, 0 by default & its frame set to have a strange width (543.5) & a strange height (812.5). Since I'm initializing the debugFrame.frame with spaceship.frame (i think that's what the default initializer does), I would expect the new debugFrame.frame to be the same as the spaceship's frame - but it isn't! The debug frame width & height values apparently come from adding the actual width & height to the origin of the spaceship node frame (543.5 = 225 + 318.5). But if that is the case, why is t's frame rect origin still 0, 0 & not the same adding (225.0 + 0 = 225.0)???
I don't get it.
You are creating the shape node using the sprite's frame, which is in scene coordinates. Because the shape will be a child of the sprite, you should create the node in the sprite's coordinates. For example, if you create the SKShapeNode with spaceship's size
let debugFrame = SKShapeNode(rectOfSize: spaceship.size)
instead of using the spaceship's frame, debugFrame will be centered on the spaceship regardless of when you set the ship's position. Also, debugFrame will scale/move appropriately with the ship.
In response to your 'I don't get it'.
Your code is ok but has a logical problem. The 'frame' is counted relative to the parent coordinates. Please realize that the parent of the spaceship and the parent of the debug window are different in your code.
Two ways to resolve your problem:
Add a zero offset for the debug window and use the spaceship as the parent.
The advantage of this is that the debug window will move, scale with the spaceship:
let rectDebug = CGRectMake( 0, 0, spaceship.frame.size.width, spaceship.frame.size.height)
let debugFrame = SKShapeNode(rect:rectDebug)
spaceship.addChild(debugFrame)
Add the debug window with the spaceship 'frame' coordinates to the parent of the spaceship (which is 'self'). The disadvantage of this, is that you have to move, scale the debug window yourself in the code, since it will not be attached to the spaceship.:
let debugFrame = SKShapeNode(rect:spaceship.frame)
self.addChild(debugFrame)
Both solutions are widely used. You should chose whichever is better for you in your case.
Three other problems might come up:
1.There might be code errors in my code, I just typed these into the web window directly without xcode syntax checking.
2.The anchor points of the two objects could be different. So you might need alignment in your code for this.
3.The zPosition of the objects should also be taken into consideration, so these objects will not be hidden under some other objects.
In response to the problem you are trying to solve, perhaps showPhysics would help:
skView.showsFPS = YES;
skView.showsNodeCount = YES;
skView.showsPhysics = YES;
This is almost the same problem as in the other question you mentioned. frame is a property that contains a position and a size. Both of them are subject to scaling of their ancestor node. Read section "A Node Applies Many of Its Properties to Its Descendants" in https://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Nodes/Nodes.html#//apple_ref/doc/uid/TP40013043-CH3-SW13
Again : never apply scaling to a node, never move a node before having fully constructed its hierarchy, except if you want some special or weird effect.
I'm developing a game on Iphone and Ipad like a space invaders.
Balloons to destroy are falling from the top of the screen in a straight line.
Here my codes to add them :
func addBalloonv(){
var balloonv:SKSpriteNode = SKSpriteNode (imageNamed: "ballonvert.png")
balloonv.physicsBody = SKPhysicsBody (circleOfRadius: balloonv.size.width/2)
balloonv.physicsBody.dynamic = true
balloonv.physicsBody.categoryBitMask = balloonCategory | greenCategory
balloonv.physicsBody.contactTestBitMask = flechetteCategory
balloonv.physicsBody.collisionBitMask = balloonCategory
balloonv.physicsBody.mass = 1
balloonv.physicsBody.restitution = 1
balloonv.physicsBody.allowsRotation = true
let minX = balloonv.size.width/2
let maxX = self.frame.size.width - balloonv.size.width/2
let rangeX = maxX - minX
let position:CGFloat = CGFloat(arc4random()) % CGFloat(rangeX) + CGFloat(minX)
balloonv.position = CGPointMake(position, self.frame.size.height+balloonv.size.height)
self.addChild(balloonv)
I have one func by balloon color.
So for the moment they move in straight line and I'm looking for random movements (with turbulences like balloon in air) from the top and both sides.
How can I do that?
Thank you very much !!
This is exactly what the new Physics Fields feature in SpriteKit (as of iOS 8 / OS X Yosemite) is for. These let you apply different kinds of forces to all physics bodies in region, like gravity, drag, and turbulence. See the SKFieldNode class docs for details.
Fields are a kind of node, so to get what you're after, you'd add one noise (or turbulence) field to your scene, covering the area that the balloons fall through, and it'll perturb the path of each balloon that passes. The simplest way to do it goes something like this:
let field = SKFieldNode.noiseFieldWithSmoothness(0.5, animationSpeed: 0.1)
scene.addChild(field)
You'll want to tweak the smoothness, animation speed, and field.strength till you get just the level of noise you want. You might also look into whether you want just a noise field, which applies random forces in random directions, or a turbulence field, which does the same thing, but with forces that get stronger when bodies are moving faster.
The above code gets you a field whose region of effect is infinite. You might want to limit it to a specific area (for example, so it doesn't keep knocking your balloons around after they land). I did this to make a field that covers only the top 3/4 of a 300x200 scene:
field.region = SKRegion(size: CGSize(width: 300, height: 100))
field.position = CGPoint(x: 150, y: 150)