I'm trying to create my User SpriteNode with the following Methode. The texture is Kladde and the Image is not empty too.
func spawnPlayer() {
if didFirstTap == true && isGameOver == false {
let collisionMask = CollisionCategory.Surrounding.rawValue | CollisionCategory.Platform.rawValue
let x = self.frame.size.width / 4
let y = CGRectGetMidY(self.frame)
let node = SKNode()
node.position = CGPointMake(frame.size.width + playerTexture!.size().width, 0)
playerNode = SKSpriteNode(texture: playerTexture)
playerNode!.setScale(1.0)
playerNode!.position = CGPointMake(x, y)
playerNode!.speed = 1.0
playerNode!.zRotation = 0.0
playerNode!.physicsBody = SKPhysicsBody(circleOfRadius: playerNode!.size.height / 2)
playerNode!.physicsBody?.dynamic = true
playerNode!.physicsBody?.allowsRotation = false
playerNode!.physicsBody?.categoryBitMask = CollisionCategory.Player.rawValue
playerNode!.physicsBody?.contactTestBitMask = collisionMask
playerNode!.physicsBody?.collisionBitMask = collisionMask
playerNode!.physicsBody!.velocity = CGVectorMake( 0, 0 )
node.addChild(playerNode!)
addChild(node)
}
}
I Hope someone knows, why my Node is invisible?
Look at where the node is spawning:
node.position = CGPointMake(frame.size.width + playerTexture!.size().width, 0)
Then on top of that you move the player in the position of the node
let x = self.frame.size.width / 4
let y = CGRectGetMidY(self.frame)
playerNode!.position = CGPointMake(x, y)
This poor guy is way outside of the screen space.
Related
How to display distance value plane surface between two points in measurement ARKit/SceneKit? Same as on image.
Here's a simple principle how to place a label with 3D text between two points.
let p1 = SCNNode() // POINT 1
p1.geometry = SCNSphere(radius: 0.3)
p1.position = SCNVector3(-1, -2, -3)
p1.geometry?.firstMaterial?.diffuse.contents = NSColor.red
scene.rootNode.addChildNode(p1)
let p2 = SCNNode() // POINT 2
p2.geometry = SCNSphere(radius: 0.2)
p2.position = SCNVector3(4, 5, 6)
p2.geometry?.firstMaterial?.diffuse.contents = NSColor.red
scene.rootNode.addChildNode(p2)
let x = (p1.position.x + p2.position.x) / 2
let y = (p1.position.y + p2.position.y) / 2
let z = (p1.position.z + p2.position.z) / 2
let label = SCNNode()
let text = SCNText(string: "label", extrusionDepth: 5)
label.geometry = text
// Shifting text's pivot to its center.
// Default pivot's position is lower left corner.
label.simdPivot.columns.3.x = Float((text.boundingBox.min.x +
text.boundingBox.max.x) / 2)
label.simdPivot.columns.3.y = Float((text.boundingBox.min.y +
text.boundingBox.max.y) / 2)
label.scale = SCNVector3(0.02, 0.02, 0.02)
label.position = SCNVector3(x, y, z)
label.geometry?.firstMaterial?.diffuse.contents = NSColor.red
scene.rootNode.addChildNode(label)
let constraint = SCNBillboardConstraint()
label.constraints = [constraint]
let plane = SCNNode()
plane.geometry = SCNPlane(width: 2, height: 1)
plane.position = SCNVector3(x, y, z)
plane.geometry?.firstMaterial?.diffuse.contents = NSColor.white
scene.rootNode.addChildNode(plane)
plane.constraints = [constraint]
The same way you may add ARAnchor and attach any label to it.
All this code in my project works fine, but I am having some problems. When the plane touches the border of the screen it starts to spin after contact. I can't figure out how to make it so it doesn't spin when it hits the border of the screen. It only has this problem when I use:
plane.physicsBody = SKPhysicsBody(texture: plane.texture!, size: plane.size)
Other forms of definition I have no problem, but I need it to be the size of the texture.
plane = SKSpriteNode(imageNamed: sett.store() as! String)
plane.size = CGSize(width: 80, height: 80)
plane.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 4)
// scorenode collison off, makes images spin on any contact
plane.physicsBody = SKPhysicsBody(texture: plane.texture!, size: plane.size)
plane.physicsBody?.categoryBitMask = Physics.Plane
plane.physicsBody?.collisionBitMask = Physics.Bird
plane.physicsBody?.contactTestBitMask = Physics.Bird | Physics.Score | Physics.Coin
plane.physicsBody?.affectedByGravity = true
plane.physicsBody?.dynamic = true
plane.zPosition = 2
self.addChild(plane)
// screen boarder so cant leave screen
let boredBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
boredBody.friction = 0
self.physicsBody = boredBody
My other problem is again with the the plane
plane.physicsBody = SKPhysicsBody(texture: plane.texture!, size: plane.size)
but as well I need this so it's the size of the texture. When it hits my score node on the screen it should only add 1 point but it varies 1-about 60 points when it crosses the scoreNode. How would i fix this?
let scoreNode = SKSpriteNode()
scoreNode.size = CGSize(width: 800, height: 1)
scoreNode.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 + 350)
scoreNode.physicsBody = SKPhysicsBody(rectangleOfSize: scoreNode.size)
scoreNode.physicsBody?.affectedByGravity = false
scoreNode.physicsBody?.dynamic = false
scoreNode.physicsBody?.categoryBitMask = Physics.Score
scoreNode.physicsBody?.collisionBitMask = 0
scoreNode.physicsBody?.contactTestBitMask = Physics.Plane
scoreNode.color = SKColor.whiteColor()
// when scoreNode and plane touch && initates score and highScore
if firstBody.categoryBitMask == Physics.Score && secondBody.categoryBitMask == Physics.Plane || firstBody.categoryBitMask == Physics.Plane && secondBody.categoryBitMask == Physics.Score {
score += 1
if score >= highScore{
highScore = score
scoreLabel.text = "SCORE: \(score)"
highScoreLabel.text = "HIGH SCORE: \(highScore)"
let highScoreDefault = NSUserDefaults.standardUserDefaults()
highScoreDefault.setValue(highScore, forKey: "highScore")
highScoreDefault.synchronize()
} else {
scoreLabel.text = "SCORE: \(score)"
highScoreLabel.text = "HIGH SCORE: \(highScore)"
}
}
It's spining because the collision has imparted angular velocity on the physics body. This is as it should be. If you really never want an object to have angular velocity you can do that by setting the node physics body
allowsRotation property to false.
in this case it would be something like:
scoreNode.physicsBody?.allowsRotation = false
https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKPhysicsBody_Ref/index.html#//apple_ref/occ/instp/SKPhysicsBody/allowsRotation
I have this line of code, to make 3 spriteNodes, i would like them to jump up the screen when I tap anywhere on the screen, but not to follow where the screen is tapped, i can get a single spriteNode to do it, using
applyImpluse in touchBegan, i will be using the accelerometer to move x axis, any help will be greatly appreciated,
let numberOfBalls = 3
let ballWidth = SKSpriteNode(imageNamed: "ball6").size.width
let totalBallWidth = ballWidth * CGFloat(numberOfBalls)
ball6.size = CGSize(width: 50, height: 50)
let xOffset = (CGRectGetWidth(frame) - totalBallWidth)/2
for i in 0..<numberOfBalls{
let ball6 = SKSpriteNode(imageNamed: "ball6")
ball6.position = CGPoint(x: xOffset + CGFloat(CGFloat(i) / 2) * ballWidth, y: CGRectGetHeight(frame) / 2)
self.addChild(ball6)
ball6.physicsBody = SKPhysicsBody(circleOfRadius: ball6.frame.size.width/2)
ball6.physicsBody?.friction = 0.5
ball6.physicsBody?.restitution = 0.8
ball6.physicsBody?.mass = 0.2
ball6.physicsBody?.allowsRotation = true
ball6.physicsBody?.dynamic = true
ball6.physicsBody?.affectedByGravity = true
Swift 2
SpriteKit
So I'm using the following code to spawn enemies randomly and then to move them towards the player. But for some reason, only the first enemy moves towards the player, the rest do nothing. I'm new to this so all details would help.
Under didmovetoview:
let wait = SKAction.waitForDuration(3, withRange: 2)
let spawn = SKAction.runBlock {
let Enemy = SKSpriteNode(imageNamed: "Enemy.png")
Enemy.size.height = (70) //138
Enemy.size.width = (49) //99
Enemy.position = CGPointMake(CGRectGetWidth(self.frame) - 100 , CGRectGetHeight(self.frame) - 100)
Enemy.physicsBody = SKPhysicsBody (rectangleOfSize: Enemy.size)
Enemy.physicsBody!.dynamic = true
Enemy.physicsBody!.allowsRotation = false
Enemy.physicsBody!.friction = 0
Enemy.physicsBody!.restitution = 0
Enemy.physicsBody!.linearDamping = 1
Enemy.physicsBody!.angularDamping = 1
Enemy.name = "Enemy"
Enemy.zPosition = 3
self.addChild(Enemy)
self.EnemyExists=true
}
let sequence = SKAction.sequence([wait, spawn])
self.runAction(SKAction.repeatActionForever(sequence))
Under update func:
let Enemy = childNodeWithName("Enemy") as! SKSpriteNode
let Player = childNodeWithName("Player") as! SKSpriteNode
if EnemySpeed == OriginalEnemySpeed {
let impulseVector = CGVector(dx: (Player.position.x - Enemy.position.x)/200, dy: (Player.position.y - Enemy.position.y)/200)
Enemy.physicsBody?.applyImpulse(impulseVector)
}
if Enemy.position.x + Enemy.size.width / 4 > size.width {
Enemy.position.x = Enemy.size.width / 4
}
else if Enemy.position.x + Enemy.size.width / 4 < 0 {
Enemy.position.x = size.width - Enemy.size.width / 4
}
if Enemy.position.y + Enemy.size.height / 4 > size.height {
Enemy.position.y = Enemy.size.height / 4
}
else if Enemy.position.y + Enemy.size.height / 4 < 0 {
Enemy.position.y = size.height - Enemy.size.height / 4
}
EnemySpeed-=1
if EnemySpeed < 1 {
EnemySpeed = OriginalEnemySpeed
}
childNodeWithName("Enemy") will only pick up the first sprite in the scene called Enemy.
You need to loop over all sprites called enemy with enumerateChildNodesWithName:
enumerateChildNodesWithName("Enemy") {
node, stop in
let Enemy = node as! SKSpriteNode
// Your enemy movement/update code here
}
You'll have to do something about your EnemySpeed variable if it's supposed to refer to the speed of the sprite you are currently processing, as it's just a single instance variable and not a property of that sprite. You'll probably want to use Enemy.physicsBody.velocity, which is a CGVector, so to convert this to a speed you need:
enemySpeedX = enemy.physicsbody.velocity.dx
enemySpeedY = enemy.physicsbody.velocity.dy
enemySpeed = sqrt(enemySpeedX* enemySpeedX + enemySpeedY* enemySpeedY)
Also check your naming standards; most things should be camel-case so Enemy should be enemy, OriginalEnemySpeed should be originalEnemySpeed etc.
So I created a parent node named planet, that has to two children one of which is a 'landingPad'. I'm trying to detect collision between this child and another node named 'lander'. I've tried a lot of options but nothing seems to work. Thanks in advance.
func createPlanet() {
var planet = SKSpriteNode()
planet.zPosition = 1
planet.name = "mars"
redPlanet = SKSpriteNode(imageNamed: "redPlanet")
redPlanet.name = "red"
redPlanet.zPosition = 2
planet.addChild(redPlanet)
landingPad = SKSpriteNode(imageNamed: "landingPad")
landingPad.name = "pad"
landingPad.zPosition = 3
landingPad.position = CGPoint(x: 0, y: redPlanet.size.height / 2 - 60)
landingPad.physicsBody = SKPhysicsBody(texture: landingPad.texture!, size: size)
landingPad.physicsBody!.dynamic = false
landingPad.physicsBody!.categoryBitMask = landingPadMask
landingPad.physicsBody!.collisionBitMask = landerMask
landingPad.physicsBody!.contactTestBitMask = 0
planet.addChild(landingPad)
planet.position = CGPoint(x: frame.size.width / 2, y: -redPlanet.size.height / 6)
planet.physicsBody = SKPhysicsBody(circleOfRadius: redPlanet.size.height / 2)
planet.physicsBody!.dynamic = false
planet.physicsBody!.categoryBitMask = planetMask
planet.physicsBody!.contactTestBitMask = 0
let spinner = SKAction.rotateByAngle(CGFloat(M_PI), duration: 3)
planet.runAction(SKAction.repeatActionForever(spinner))
addChild(planet)
}
And the lander code...
func createLander() {
var randomX = RandomInt(min: 10, max: 400)
lander = SKSpriteNode(imageNamed: "lander")
lander.position = CGPoint(x: CGFloat(randomX), y: frame.size.height + 20)
lander.name = "lander"
lander.zPosition = 10
lander.physicsBody = SKPhysicsBody(texture: lander.texture!, size: lander.size)
lander.physicsBody!.dynamic = true
lander.physicsBody!.affectedByGravity = true
lander.physicsBody!.friction = 0.2
lander.physicsBody!.restitution = 0.75
lander.physicsBody!.linearDamping = 0.208
lander.physicsBody!.angularDamping = 0.1
lander.physicsBody!.categoryBitMask = landerMask
lander.physicsBody!.collisionBitMask = landingPadMask | cometMask
addChild(lander)
}
you are missing:
lander.physicsBody!.contactTestBitMask = landingPadMask | cometMask
and
landingPad.physicsBody!.contactTestBitMask = landerMask
And for the delegate:
self.physicsWorld.contactDelegate = self;
Then you get the collision with:
didBeginContact and didEndContact