Node not moving once Physics added to scene: swift, SpriteKit - ios

every time I add the following code:
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
the physics body for my "ball" item stops moving. It worked before adding the previous line.
here is all my code:
class GameScene: SKScene {
// creaTE nODE/Sprite
let ball = SKSpriteNode(imageNamed: "ball.png")
override func didMoveToView(view: SKView) {
// set up scene here
self.backgroundColor = SKColor.whiteColor()
//add physics to scene
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
//create cg piont for sprite
ball.position = CGPointMake(size.width / 2, size.height / 2)
//give it some real life physics!
ball.physicsBody = SKPhysicsBody(circleOfRadius: size.height / 2)
addChild(ball)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}

This line is causing the problem:
ball.physicsBody = SKPhysicsBody(circleOfRadius: size.height / 2)
You need to use
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.height / 2)
The physicsBody being created in the previous line was the size of the scene, hence it did not have space to move!
You can check the physicsBody being created by setting the showsPhysics property to YES in the SKView. Check here for more details.

Related

SpriteKit Physics - Nodes not staying in bounds of screen

Simple code below creates a ball (on touch) and set physics body to make it fall and bounce. I set the bounds to match the frame, wanting the ball to remain 100% within the screen. However when running the code, the ball will move off the screen out of view left and right. How can I keep the sprite within the bounds of the screen?
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
physicsBody = SKPhysicsBody(edgeLoopFromRect: frame)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
if let touch = touches.first {
let location = touch.locationInNode(self)
let ball = SKShapeNode(circleOfRadius: 20)
ball.physicsBody = SKPhysicsBody(circleOfRadius: 20)
ball.physicsBody!.restitution = 0.4
ball.position = location
addChild(ball)
}
}
}

Sprites not contacting properly

There's a ball and a paddle, the ball should be on the paddle and touching it but the ball never touches the paddle and stops before reaching the paddle, can anyone help me out?
import SpriteKit
class GameScene: SKScene ,SKPhysicsContactDelegate {
let ballCategory:UInt32 = 0x1 << 0
let bottomCategory:UInt32 = 0x1 << 1
let paddleCategory:UInt32 = 0x1 << 2
override init(size: CGSize){
super.init(size: size)
physicsWorld.contactDelegate = self
let ball = SKSpriteNode(imageNamed: "ball")
ball.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
addChild(ball)
ball.physicsBody = SKPhysicsBody(circleOfRadius: self.frame.size.width / 2)
ball.physicsBody?.dynamic = true
ball.physicsBody?.allowsRotation = false
ball.physicsBody?.friction = 0
// ball.physicsBody?.applyImpulse(CGVectorMake(2,-2))
ball.physicsBody?.categoryBitMask = ballCategory
ball.physicsBody?.contactTestBitMask = paddleCategory
ball.physicsBody?.collisionBitMask = paddleCategory
ball.physicsBody?.affectedByGravity = true
let paddle = SKSpriteNode(imageNamed: "paddle")
paddle.position = CGPointMake(CGRectGetMidX(self.frame), paddle.frame.size.height * 2)
addChild(paddle)
paddle.physicsBody = SKPhysicsBody(rectangleOfSize: paddle.frame.size)
paddle.physicsBody?.affectedByGravity = false
paddle.physicsBody?.dynamic = false
paddle.physicsBody?.categoryBitMask = paddleCategory
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
}
func didBeginContact(contact: SKPhysicsContact) {
print("touched")
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
The best way to determine where your nodes are making contact is to turn on Physics.
Open GameViewController.swift and enter the following code:
skView.showsPhysics = true
You are experiencing this issue because of this line:
ball.physicsBody = SKPhysicsBody(circleOfRadius: self.frame.size.width / 2)
self is a scene here.
You need this:
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.frame.size.width / 2)
Turn on physics visual representation in your GameViewController like this:
skView.showsPhysics = true
and you will see what is going on.

Gravity property not working in SpriteKit Scene

import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch in touches {
let location = touch.locationInNode(self)
let sprite = SKSpriteNode(imageNamed:"Beach Ball-100")
self.addChild(sprite)
sprite.xScale = 0.5
sprite.yScale = 0.5
sprite.position = location
sprite.color = UIColor.redColor()
sprite.physicsBody = SKPhysicsBody(edgeLoopFromRect:self.frame)
sprite.physicsBody?.affectedByGravity = true
var action = SKAction.rotateByAngle(CGFloat(M_PI), duration:1)
}
}
}
The code above is present in my scene class. When I run it, the ball object is not falling as expected since the gravity property is set to true. Please explain what I am doing wrong.
The Physicsbody is wrong. You need the frame of the sprite and not of the world:
sprite.physicsBody = SKPhysicsBody(rectangleOfSize: sprite.frame.size)
Add SKPhysicsContactDelegate:
class GameScene: SKScene, SKPhysicsContactDelegate
Define your physicsWorld in didMoveToView or in touchesBegan(like you did in example)
physicsWorld.gravity = CGVectorMake(0, -1.0)
physicsWorld.contactDelegate = self
Give your node proper SKPhysicsBody size
sprite.physicsBody = SKPhysicsBody(circleOfRadius: frame.size.width / 2)

How do I make my character move sideways? Xcode 6 Sprite Kit

I am making a simple side scrolling game using apple's swift programming language and I want to make my character move left when the left half of the screen is touched and right when the other half is touched. I have done this using this code:
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if location.x < CGRectGetMidX(self.frame){
character.position.x -= 30
} else if location.x > CGRectGetMidX(self.frame){
character.position.x += 30
} else {
println("jump")
}
}
but he stops moving immediately after he moves 30 px over. my question is, can someone explain how to make him keep moving until the user lifts their finger?
This is my GameScene.swift file:
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
let character = SKSpriteNode(texture: SKTexture(imageNamed: "character"))
override func didMoveToView(view: SKView) {
/* Setup your scene here */
//world
self.physicsWorld.gravity = CGVectorMake(0.0, -5.0)
//background
var background = SKSpriteNode(imageNamed: "background")
background.size.height = self.frame.size.height
background.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
self.addChild(background)
//character
character.position = CGPointMake(self.frame.size.width * 0.6, self.frame.size.height * 0.6)
character.setScale(0.015)
character.physicsBody = SKPhysicsBody(circleOfRadius: CGFloat(character.size.width / 2))
var charPos = character.position
character.physicsBody?.dynamic = true
self.addChild(character)
//platform 1
var platformTexture = SKTexture(imageNamed: "platform")
var platform = SKSpriteNode(texture: platformTexture)
platform.position = CGPointMake(self.frame.size.width * 0.6, CGRectGetMidY(self.frame))
platform.physicsBody = SKPhysicsBody(rectangleOfSize: platform.size)
platform.physicsBody?.dynamic = false
platform.setScale(0.25)
self.addChild(platform)
//platform 2
var platformTexture2 = SKTexture(imageNamed: "platform")
var platform2 = SKSpriteNode(texture: platformTexture2)
platform2.position = CGPointMake(self.frame.size.width * 0.4, self.frame.size.height * 0.3)
platform2.physicsBody = SKPhysicsBody(rectangleOfSize: platform2.size)
platform2.physicsBody?.dynamic = false
platform2.setScale(0.25)
self.addChild(platform2)
//platform main
var platformTexture3 = SKTexture(imageNamed: "platform")
var platform3 = SKSpriteNode(texture: platformTexture2)
platform3.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMinY(self.frame) + platform3.size.height / 3)
platform3.physicsBody = SKPhysicsBody(rectangleOfSize: platform3.size)
platform3.physicsBody?.dynamic = false
platform3.setScale(1)
platform3.size.width = platform3.size.width * CGFloat(2.0)
self.addChild(platform3)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
}
You have to apply force constantly to character in every update: call in order to move it without stopping. You can also apply impulses in order to move character, or make it jump. Here is an example based on you code, to give you a basic idea how you can move characters using physics (or by changing velocity vector of a character manually). Look through the comments to find what is important.
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
let character = SKSpriteNode(texture: SKTexture(imageNamed: "pauseButton"))
//Boolean variable to store information about move signal (updated in touchesBegan and touchesEnded method)
var move = false
override func didMoveToView(view: SKView) {
/* Setup your scene here */
//world
self.physicsWorld.gravity = CGVectorMake(0.0, -5.0)
self.physicsWorld.contactDelegate = self; //don't forget to set contact delegate if you want to use contact detection and methods like didBeginContact and didEndContact
//background
//just a physical border so that character can't escape from us :)
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
//character
character.position = CGPointMake(self.frame.size.width * 0.6, self.frame.size.height * 0.6)
character.setScale(0.415)
character.physicsBody = SKPhysicsBody(circleOfRadius: CGFloat(character.size.width / 2))
var charPos = character.position
character.physicsBody?.dynamic = true
self.addChild(character)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
//Hold finger at upper area to move character constantly to the right.
if location.y > 400{
//moving allowed, force is applied in update method. read the docs about applyImpulse and applyForce methods and the differences between those two.
move = true
}else{
if location.x < CGRectGetMidX(self.frame){
character.physicsBody?.applyImpulse(CGVector(dx: -30, dy: 0))
//tap somewhere above this to make character jump
if(location.y > 250) {
character.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 50))
}
} else if location.x > CGRectGetMidX(self.frame){
character.physicsBody?.applyImpulse(CGVector(dx: 30, dy: 0))
//tap somewhere above this to make character jump
if(location.y > 250) {
character.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 50))
}
}
}
}
}
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
move = false
//character.physicsBody?.velocity = CGVector(dx: 0, dy: 0) //you can make character to stop by manually setting its velocity vector to (0,0)
}
override func update(currentTime: CFTimeInterval) {
if(move){character.physicsBody?.applyForce(CGVector(dx: 30, dy: 0))}
//if(move){character.position = CGPoint(x: character.position.x+1, y:character.position.y)} //not recommended if you need physics simulation (eg. collisions)
}
}
Note that you can change node's position in every update call to achieve what you want, like this :
if(move){character.position = CGPoint(x: character.position.x+1, y:character.position.y)}
But this way you will pull the node out of physics simulation and you can experience unexpected results. Search SO about this topic, there are some good posts about all this.
Hope this helps a bit.

Swift: SKSpriteNode not recognising boundaries of physicsBody

I have this object that is a SKSpriteNode created from an image. The whole scene area itself is the boundary from where this object should not escape. Top and bottom boundaries are recognised but not the sides? Any help appreciated. Thanks
import SpriteKit
var ship = SKSpriteNode()
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
self.backgroundColor = SKColor.blackColor()
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsWorld.gravity = CGVectorMake(0.0, -9.8)
ship = SKSpriteNode(imageNamed: "spark")
ship.position = CGPointMake(200, 400)
ship.physicsBody.linearDamping = 0
ship.physicsBody.restitution = 0.95
ship.physicsBody.friction = 0
self.addChild(ship)
var myVector = CGVectorMake(20, 20)
ship.physicsBody.applyImpulse(myVector)
let emitter = SKEmitterNode(fileNamed: "myExhaust")
emitter.position = CGPointMake(0.0, -ship.size.height / 2.0)
ship.addChild(emitter)
emitter.targetNode = self
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
var touch = touches.anyObject() as UITouch
// ship.position = [touch locationInNode:self];
ship.position = touch.locationInNode(self)
}
}
Try using the SKScene's size to create a CGRect and don't use SKScene.frame directly. SKScene.size determines the size of the visible portion of the SKScene and may be different from SKScene.frame.size.
override func didMoveToView(view: SKView) {
physicsBody = SKPhysicsBody(edgeLoopFromRect: CGRectMake(0, 0, size.width, size.height))
// ...
}
(Side Note: with Swift you don't need to use self there)

Resources