Gravity property not working in SpriteKit Scene - ios

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)

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.

Sprite Kit stop Impulse

I want to increase a CGFloat every time while the Screen is tapped.
The float has a set maximum and minimum value.
I tried to go through this suggestion: StackOverflow
However, this only increases the CGFloat after the touch is made, or the maximum is reached. I want to increase the CGFloat during the touch, meaning the longer you touch the higher the Jump/CGFloat.
The problem probably lies within the impulse, that you cant change it after it was applied. That means, after the 'Player' gets an impulse of 20, and the screen is longer touched, the Float may increase, but the impulse won't.
If you look at my current code, the impulse is set at maximum while the screen is touched, but if released the action should be removed. However, it doesn't work, the impulse does not stop.
I know that you can set the velocity of the body at a value after the press is made, and if the press has ended the velocity back to 0 so it stops it 'jump', but that doesn't look quite smooth as it would be with an impulse.
Has anybody a solution?
struct Constants {
static let minimumJumpForce:CGFloat = 20.0
static let maximumJumpForce:CGFloat = 60.0
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var force: CGFloat = 20.0
func longPressed(longPress: UIGestureRecognizer) {
if (longPress.state == UIGestureRecognizerState.Began) {
println("Began")
self.pressed = true
let HigherJump = SKAction.runBlock({Player.physicsBody?.applyImpulse(CGVectorMake(0, Constants.maximumJumpForce))})
self.runAction(HigherJump , withKey:"HighJump")
}else if (longPress.state == UIGestureRecognizerState.Ended) {
println("Ended")
self.pressed = false
self.removeActionForKey("HighJump")
}
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
1.Create ‘Game’ from Xcode template based on SpriteKit
2.Copy paste listed code to GameScene class
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var location = CGPoint()
var floorSize = CGSize()
var floorColor = UIColor()
var player = SKSpriteNode()
override func didMoveToView(view: SKView) {
view.showsFPS = true;
view.showsNodeCount = true;
view.showsDrawCount = true;
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody?.categoryBitMask = 1
self.physicsBody?.contactTestBitMask = 1
self.physicsWorld.gravity = CGVectorMake(0, 0)
self.physicsWorld.contactDelegate = self;
location = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
player = SKSpriteNode(imageNamed:"Spaceship")
player.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: 320, height: 320))
player.physicsBody?.categoryBitMask = 1
player.physicsBody?.collisionBitMask = 1
player.physicsBody?.contactTestBitMask = 1
player.physicsBody?.linearDamping = 0;
player.xScale = 1
player.yScale = 1
player.position = location
self.addChild(player)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.physicsWorld.gravity = CGVectorMake(0, 0)
let direction = Float(1.5708)//Float(player.zRotation) + Float(M_PI_2)
player.physicsBody?.applyForce(CGVector(dx: 150000*CGFloat(cosf(direction)), dy: 150000*CGFloat(sinf(direction))))
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.physicsWorld.gravity = CGVectorMake(0, -7.9)
}
}
3.Run the app
This should give you start point for you 'Jump' game :)
Try changing this:
if(self.pressed){
let HigherJump = SKAction.runBlock({if(self.force < Constants.maximumJumpForce){
self.force += 2.0
}else{
self.force = Constants.maximumJumpForce
}})
self.runAction(HigherJump)
}
to this:
if(self.pressed){
if(self.force < Constants.maximumJumpForce) {
self.force += 2.0
}
else {
self.force = Constants.maximumJumpForce
}
}
Theres no need to use a runBlock SKAction here.

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)

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

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.

Resources