Swift Sprite Kit Physics Body: Ball slows down after applying an impulse - swift

I am quite new to Swift and the Sprite Kit!
I tried to build a Pong game. Everything works well but the ball on which I am applying an impulse slows down really quickly!
I already turned off gravity, friction and damping and set the restitution of the ball and the scene to 1.
Here is my Code:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
    
let player = SKShapeNode(rectOf: CGSize(width: 200, height: 30))
let enemy = SKShapeNode(rectOf: CGSize(width: 200, height: 30))
let ball = SKShapeNode(circleOfRadius: 10)
override func didMove(to view: SKView) {
let border = SKPhysicsBody(edgeLoopFrom: self.frame)
border.restitution = 1
border.friction = 0
border.angularDamping = 0
border.linearDamping = 0
self.physicsBody = border
scene?.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
player.position = CGPoint(x:  0, y: -(scene?.size.height)! * 0.35)
player.fillColor = UIColor.white
player.strokeColor = UIColor.clear
self.addChild(player)
player.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 200, height: 30))
player.physicsBody?.friction = 0
player.physicsBody?.isDynamic = false
player.physicsBody?.angularDamping = 0
player.physicsBody?.linearDamping = 0
player.physicsBody?.restitution = 1
player.physicsBody?.affectedByGravity = false
enemy.position = CGPoint(x: 0, y: (scene?.size.height)! * 0.35)
enemy.fillColor = UIColor.white
enemy.strokeColor = UIColor.clear
self.addChild(enemy)
enemy.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 200, height: 30))
enemy.physicsBody?.friction = 0
enemy.physicsBody?.affectedByGravity = false
enemy.physicsBody?.linearDamping = 0
enemy.physicsBody?.angularDamping = 0
enemy.physicsBody?.isDynamic = false
ball.position = CGPoint(x: 0, y: 0)
ball.fillColor = UIColor.white
ball.strokeColor = UIColor.clear
ball.physicsBody?.angularDamping = 0
ball.physicsBody?.linearDamping = 0
ball.physicsBody?.friction = 0
ball.physicsBody?.restitution = 1
ball.physicsBody?.allowsRotation = false
ball.physicsBody?.affectedByGravity = true
ball.physicsBody = SKPhysicsBody(circleOfRadius: 10)
ball.physicsBody?.isDynamic = true
self.addChild(ball)
ball.physicsBody?.applyImpulse(CGVector(dx: -30, dy: -30))
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let pos = touch.location(in: self)
player.position.x = pos.x
}
}
override func update(_ currentTime: TimeInterval) {
if ball.position.y >  0{
enemy.position.x = ball.position.x
}
}
}
Thank you already!

Be sure to always create your physics body before you change its properties
ball.physicsBody?.angularDamping = 0
ball.physicsBody?.linearDamping = 0
ball.physicsBody?.friction = 0
ball.physicsBody?.restitution = 1
ball.physicsBody?.allowsRotation = false
ball.physicsBody?.affectedByGravity = true
ball.physicsBody = SKPhysicsBody(circleOfRadius: 10) <----Needs to be first
ball.physicsBody?.isDynamic = true
self.addChild(ball)
ball.physicsBody?.applyImpulse(CGVector(dx: -30, dy: -30))

Related

SpriteKit - didBegin contact is called 30 times instead of 1 time

I am making a little FlappyBird clone and have got everything working as it should until I changed the physics body of the bird to be exact to the texture. Now what it does is when it flies through the gap in the pipes it counts 30 points instead of just 1 point.
This only happens when I use the texture exact physics body which I need because the bird isn't round nor rectangular.
How would I go about making the collision so it only collides once with each gap node. I have tried setting the categoryBitBask to 0 after the contact but then all the gaps after don't add to the point count anymore at all.
Here is the full game code:
var score = 0
class GameScene: SKScene, SKPhysicsContactDelegate {
var bird = SKSpriteNode()
var bg = SKSpriteNode()
var ground = SKSpriteNode()
var scoreLabel = SKLabelNode(fontNamed: "Candice")
var gameOverLabel = SKLabelNode(fontNamed: "Candice")
var countbg = SKSpriteNode()
var timer = Timer()
enum ColliderType: UInt32 {
case Bird = 1
case Object = 2
case Gap = 4
}
var gameOver = false
let swooshSound = SKAction.playSoundFileNamed("sfx_swooshing.wav", waitForCompletion: false)
let pointSound = SKAction.playSoundFileNamed("sfx_point.wav", waitForCompletion: false)
let hitSound = SKAction.playSoundFileNamed("sfx_hit.wav", waitForCompletion: false)
#objc func makePipes() {
let movePipes = SKAction.move(by: CGVector(dx: -2 * self.frame.width, dy: 0), duration: TimeInterval(self.frame.width / 150))
let removePipes = SKAction.removeFromParent()
let moveAndRemovePipes = SKAction.sequence([movePipes, removePipes])
let gapHeight = bird.size.height * 2.8
let movementAmount = arc4random() % UInt32(self.frame.height) / 2
let pipeOffset = CGFloat(movementAmount) - self.frame.height / 4
let pipeTexture = SKTexture(imageNamed: "pipe1.png")
let pipe1 = SKSpriteNode(texture: pipeTexture)
pipe1.position = CGPoint(x: self.frame.midX + self.frame.width, y: self.frame.midY + pipeTexture.size().height / 2 + gapHeight / 2 + pipeOffset)
pipe1.zPosition = 2
pipe1.run(moveAndRemovePipes)
pipe1.physicsBody = SKPhysicsBody(rectangleOf: pipeTexture.size())
pipe1.physicsBody!.isDynamic = false
pipe1.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
pipe1.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
pipe1.physicsBody!.collisionBitMask = ColliderType.Object.rawValue
self.addChild(pipe1)
let pipe2Texture = SKTexture(imageNamed: "pipe2.png")
let pipe2 = SKSpriteNode(texture: pipe2Texture)
pipe2.position = CGPoint(x: self.frame.midX + self.frame.width, y: self.frame.midY - pipeTexture.size().height / 2 - gapHeight / 2 + pipeOffset)
pipe2.zPosition = 2
pipe2.run(moveAndRemovePipes)
pipe2.physicsBody = SKPhysicsBody(rectangleOf: pipe2Texture.size())
pipe2.physicsBody!.isDynamic = false
pipe2.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
pipe2.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
pipe2.physicsBody!.collisionBitMask = ColliderType.Object.rawValue
self.addChild(pipe2)
let gap = SKNode()
gap.position = CGPoint(x: self.frame.midX + self.frame.width, y: self.frame.midY + pipeOffset)
gap.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 1, height: gapHeight))
gap.physicsBody!.isDynamic = false
gap.run(moveAndRemovePipes)
gap.physicsBody!.contactTestBitMask = ColliderType.Bird.rawValue
gap.physicsBody!.categoryBitMask = ColliderType.Gap.rawValue
gap.physicsBody!.collisionBitMask = ColliderType.Gap.rawValue
self.addChild(gap)
}
func didBegin(_ contact: SKPhysicsContact) {
if gameOver == false {
if contact.bodyA.categoryBitMask == ColliderType.Gap.rawValue || contact.bodyB.categoryBitMask == ColliderType.Gap.rawValue {
score += 1
scoreLabel.text = String(format: "%05d", score)
run(pointSound)
} else {
self.speed = 0
run(hitSound)
gameOver = true
timer.invalidate()
bird.removeFromParent()
let changeSceneAction = SKAction.run(changeScene)
self.run(changeSceneAction)
}
}
}
//MARK: Change to Game Over Scene
func changeScene(){
let sceneToMoveTo = GameOverScene(size: self.size)
sceneToMoveTo.scaleMode = self.scaleMode
let myTransition = SKTransition.fade(withDuration: 0.5)
self.view!.presentScene(sceneToMoveTo, transition: myTransition)
}
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
setupGame()
}
func setupGame() {
timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(self.makePipes), userInfo: nil, repeats: true)
let groundTexture = SKTexture(imageNamed: "ground.png")
let moveGroundAnimation = SKAction.move(by: CGVector(dx: -groundTexture.size().width, dy: 0), duration: 7)
let shiftGroundAnimation = SKAction.move(by: CGVector(dx: groundTexture.size().width, dy: 0), duration: 0)
let moveGroundForever = SKAction.repeatForever(SKAction.sequence([moveGroundAnimation, shiftGroundAnimation]))
var i: CGFloat = 0
while i < 3 {
ground = SKSpriteNode(texture: groundTexture)
ground.position = CGPoint(x: self.size.width * i, y: self.size.height / 7.65)
ground.zPosition = 3
ground.run(moveGroundForever)
self.addChild(ground)
i += 1
}
let bottom = SKNode()
bottom.position = CGPoint(x: self.frame.midX, y: self.size.height / 7)
bottom.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: self.frame.width, height: 1))
bottom.physicsBody!.isDynamic = false
bottom.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
bottom.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
bottom.physicsBody!.collisionBitMask = ColliderType.Object.rawValue
self.addChild(bottom)
let bgTexture = SKTexture(imageNamed: "bg.png")
bg = SKSpriteNode(texture: bgTexture)
bg.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
bg.size = self.frame.size
bg.zPosition = 1
self.addChild(bg)
let birdTexture = SKTexture(imageNamed: "flappy1.png")
let bird2Texture = SKTexture(imageNamed: "flappy2.png")
let bird3Texture = SKTexture(imageNamed: "flappy3.png")
let bird4Texture = SKTexture(imageNamed: "flappy4.png")
let bird5Texture = SKTexture(imageNamed: "flappy5.png")
let bird6Texture = SKTexture(imageNamed: "flappy6.png")
let animation = SKAction.animate(with: [birdTexture, bird2Texture, bird3Texture, bird4Texture, bird5Texture, bird6Texture], timePerFrame: 0.1)
let makeBirdFlap = SKAction.repeatForever(animation)
bird = SKSpriteNode(texture: birdTexture)
bird.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
bird.setScale(1)
bird.zPosition = 6
bird.run(makeBirdFlap)
self.addChild(bird)
bird.physicsBody = SKPhysicsBody.init(circleOfRadius: birdTexture.size().height / 2)
//bird.physicsBody = SKPhysicsBody(texture: birdTexture, size: birdTexture.size())
bird.physicsBody!.isDynamic = false
bird.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
bird.physicsBody!.categoryBitMask = ColliderType.Bird.rawValue
bird.physicsBody!.collisionBitMask = ColliderType.Bird.rawValue
let countbg = SKSpriteNode(imageNamed: "count_bg.png")
countbg.position = CGPoint(x: self.size.width / 4.8, y: self.size.height * 0.94)
countbg.setScale(0.8)
countbg.zPosition = 4
addChild(countbg)
scoreLabel.fontSize = 80
scoreLabel.text = String(format: "%05d", score)
scoreLabel.fontColor = SKColor(red: 218/255, green: 115/255, blue: 76/255, alpha: 1)
scoreLabel.position = CGPoint(x: self.size.width / 4, y: self.size.height * 0.94)
scoreLabel.zPosition = 5
addChild(scoreLabel)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if gameOver == false {
bird.physicsBody!.isDynamic = true
bird.physicsBody!.velocity = CGVector(dx: 0, dy: 0)
bird.physicsBody!.applyImpulse(CGVector(dx: 0, dy: 280))
//run(swooshSound)
} else {
gameOver = false
score = 0
self.speed = 1
self.removeAllChildren()
setupGame()
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
If you would be using RxSwift, you would be able to easily get rid of those extra events easily by using debounce() or throttle() or distinctUntilChanged(). If you are willing to try this approach, give RxSpriteKit framework a go. Otherwise, store a timestamp of the last contact and ignore the following contacts until some time period elapses.

Spritekit nodes are not colliding even though contact mask are set up

In the code below I have a couple nodes but right now I am just trying to detect collisions between the player and the enemy bullet( I refer to it as "BBullet") but under the function that detects collisions, nothing pops up.
import SpriteKit
import GameplayKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var player = SKSpriteNode()
var firebutton = SKShapeNode()
var bullet = SKSpriteNode()
enum CategoryMask : UInt32 {
case player = 1
case GBullet = 2
case BBullet = 3
case enemyships = 4
}
override func didMove(to view: SKView) {
player = SKSpriteNode(color: .red, size: CGSize(width: 150, height: 150))
player.physicsBody?.affectedByGravity = false
player.position = CGPoint(x: 100, y: 375)
player.physicsBody?.isDynamic = true
player.physicsBody?.restitution = 1
player.physicsBody?.categoryBitMask = CategoryMask.player.rawValue
player.physicsBody?.collisionBitMask = CategoryMask.BBullet.rawValue
player.physicsBody?.contactTestBitMask = CategoryMask.BBullet.rawValue
player.name = "Player"
addChild(player)
firebutton = SKShapeNode(circleOfRadius: 75)
firebutton.position = CGPoint(x: 1000, y: 150)
firebutton.alpha = 0.7
firebutton.physicsBody?.isDynamic = false
firebutton.physicsBody?.affectedByGravity = false
firebutton.physicsBody?.categoryBitMask = 0
firebutton.physicsBody?.collisionBitMask = 100
firebutton.physicsBody?.contactTestBitMask = 100
firebutton.physicsBody?.contactTestBitMask = 0
firebutton.physicsBody?.collisionBitMask = 0
addChild(firebutton)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
spawnenemybullets()
let position = touch.location(in: self)
if firebutton.contains(position){
bullet = SKSpriteNode(color: .orange, size: CGSize(width: 20, height: 10))
bullet.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 20, height: 10))
bullet.physicsBody?.affectedByGravity = false
bullet.physicsBody?.isDynamic = true
bullet.physicsBody?.allowsRotation = false
bullet.position.x = player.position.x + 90
bullet.position.y = player.position.y
bullet.physicsBody?.mass = 0.01
bullet.physicsBody?.categoryBitMask = CategoryMask.GBullet.rawValue
bullet.physicsBody?.collisionBitMask = CategoryMask.enemyships.rawValue
bullet.physicsBody?.contactTestBitMask = CategoryMask.enemyships.rawValue
bullet.name = "FBullet"
addChild(bullet)
bullet.physicsBody?.applyForce(CGVector(dx: 400, dy: 0))
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let position = touch.location(in: self)
if player.contains(position) {
if position.y > 85 && position.y < 665 && position.x > 85 && position.x < 640{
player.position = position
}
}
}
}
func spawnenemybullets () {
bullet = SKSpriteNode(color: .red, size: CGSize(width: 20, height: 10))
bullet.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 20, height: 10))
bullet.physicsBody?.affectedByGravity = false
bullet.physicsBody?.isDynamic = true
bullet.physicsBody?.allowsRotation = false
bullet.position.x = 1300
bullet.position.y = 200
bullet.physicsBody?.mass = 0.01
bullet.physicsBody?.categoryBitMask = CategoryMask.BBullet.rawValue
bullet.physicsBody?.collisionBitMask = CategoryMask.player.rawValue
bullet.physicsBody?.contactTestBitMask = CategoryMask.player.rawValue
bullet.name = "EnemyBullet"
addChild(bullet)
bullet.physicsBody?.applyForce(CGVector(dx: -400, dy: 0))
}
func didBegin(_ contact: SKPhysicsContact) {
print("Contact Happened")
}
}
The two Sprites both have their contact masks set up but for some reason they are not colliding. When I test the project on my phone, they just go right through each other. How do I get them to contact each other?
You haven't created a physicsBody for player (or fireButton).
You also need to make yourself the physics contact delegate:
class GameScene: SKScene, SKPhysicsContactDelegate {
physicsWorld.contactDelegate = self
Edit: my step-by-step guide for collisions and contacts:
https://stackoverflow.com/a/51041474/1430420
A guide to collision and contactTest bit masks:
https://stackoverflow.com/a/40596890/1430420
Manipulating bit masks to turn individual collisions and contacts off and on.
https://stackoverflow.com/a/46495864/1430420

How to make an sprite bounce within an object?

I am trying to make a ball bounce within a circle so it cant get out of the circumference of the circle. Now the ball bounce in self.frame. How can I make the ball bounce within the circle?
let sceneBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
sceneBody.friction = 0
self.physicsBody = sceneBody
var ball = SKShapeNode(circleOfRadius: 9)
ball.fillColor = SKColor.whiteColor()
ball.position = view.center
ball.physicsBody = SKPhysicsBody(circleOfRadius: 9)
ball.physicsBody?.affectedByGravity = true
ball.physicsBody?.restitution = 1
ball.physicsBody?.linearDamping = 0
ball.zPosition = 3
self.addChild(ball)
circulo = SKSpriteNode(imageNamed: "circuloFondo2")
//Circle that I want the ball bounce within
circulo.size = CGSize(width:view.frame.size.width - padding , height: view.frame.size.width - padding)
circulo.color = UIColor(red: 0.15, green: 0.15, blue: 0.15, alpha: 1)
circulo.colorBlendFactor = 1
circulo.alpha = 0.35
circulo.position = view.center
self.addChild(circulo)
circulo.zPosition = 1
I've prepared a simple test project to explain how to do it:
import UIKit
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
enum CollisionTypes: UInt32 {
case Circle = 1
case Ball = 2
//case Enemy1 = 4
//case Enemy2 = 8
//case Enemy3 = 16
//case EnemyBoss = 32
}
var circulo: SKSpriteNode!
var padding: CGFloat = 40.0
var center: CGPoint!
override func didMoveToView(view: SKView) {
self.physicsWorld.gravity = CGVectorMake(0, -6)
self.physicsWorld.contactDelegate = self
self.center = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame))
// Prepare circle
circulo = SKSpriteNode(imageNamed: "circuloFondo2.png")
//Circle that I want the ball bounce within
circulo.size = CGSize(width:view.frame.size.width - padding , height: view.frame.size.width - padding)
let circlePath = UIBezierPath(arcCenter: self.center, radius: (view.frame.size.width - padding*2)/2, startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true)
circulo.color = UIColor(red: 0.15, green: 0.15, blue: 0.15, alpha: 1)
circulo.colorBlendFactor = 1
circulo.alpha = 1
circulo.position = self.center
circulo.zPosition = 1
// Set physics
let circuloBody = SKPhysicsBody.init(edgeLoopFromPath: circlePath.CGPath)
self.physicsBody = circuloBody
self.physicsBody!.affectedByGravity = false
self.physicsBody!.usesPreciseCollisionDetection = true
self.physicsBody!.dynamic = true
self.physicsBody!.mass = 0
self.physicsBody!.friction = 0
self.physicsBody!.linearDamping = 0
self.physicsBody!.angularDamping = 0
self.physicsBody!.restitution = 1
self.physicsBody!.categoryBitMask = CollisionTypes.Circle.rawValue
self.physicsBody!.contactTestBitMask = CollisionTypes.Ball.rawValue
//self.circulo.physicsBody!.collisionBitMask = 0
self.addChild(circulo)
//Prepare ball
let ball = SKShapeNode(circleOfRadius: 9)
ball.fillColor = SKColor.whiteColor()
ball.position = self.center
ball.zPosition = 1
// Set physics
ball.physicsBody = SKPhysicsBody(circleOfRadius: 9)
ball.physicsBody!.affectedByGravity = true
ball.physicsBody!.restitution = 0.8
ball.physicsBody!.linearDamping = 0
ball.physicsBody!.friction = 0.3
ball.physicsBody?.dynamic = true
ball.physicsBody!.mass = 0.5
ball.physicsBody!.allowsRotation = true
ball.physicsBody!.categoryBitMask = CollisionTypes.Ball.rawValue
ball.physicsBody!.contactTestBitMask = CollisionTypes.Circle.rawValue
//ball.physicsBody!.collisionBitMask = 0
self.addChild(ball)
}
func didBeginContact(contact: SKPhysicsContact) {
// elements
if (contact.bodyA.categoryBitMask == CollisionTypes.Circle.rawValue &&
contact.bodyB.categoryBitMask == CollisionTypes.Ball.rawValue) {
print("contact between circle and ball")
}
}
The circuloFondo2 image:
A demo about the project:
In this answer you can see all the code to do it, but if you want you can download the project here

Physics issue: ball is bouncing too high

I am working on game where a ball bounces and hits a platform and then bounces right back. Ideally the ball should bounce to exactly the height that it started at. However, in my game the ball slowly keeps bouncing higher and higher. I've looked at the documentation and tried to change all of the physics properties but nothing seems to work.
Any suggestions?
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
let ballCategory:UInt32 = 0x1 << 0;
let circleCategory:UInt32 = 0x1 << 1;
let platformCategory:UInt32 = 0x1 << 2;
var ball = SKShapeNode(circleOfRadius: 20.0)
var circle = SKShapeNode(circleOfRadius: 200.0)
var platform = SKShapeNode(rectOfSize: CGSizeMake(10, 1))
var circleColor = 2
var ballColor = 3
var scoreLabel: SKLabelNode!
var score = 0
override func didMoveToView(view: SKView) {
setUpLabels()
self.physicsWorld.contactDelegate = self
backgroundColor = (UIColor.whiteColor())
ball.fillColor = SKColor.redColor()
ball.strokeColor = SKColor.clearColor()
ball.position = CGPoint(x: self.size.width/2, y: self.size.height/2+60)
ball.physicsBody = SKPhysicsBody(circleOfRadius: 20)
ball.physicsBody?.categoryBitMask = ballCategory
ball.physicsBody?.collisionBitMask = platformCategory
ball.physicsBody?.contactTestBitMask = platformCategory
ball.physicsBody?.dynamic = true
ball.physicsBody?.restitution = 1.0
ball.physicsBody?.affectedByGravity = true
ball.physicsBody?.linearDamping = 0.0
ball.physicsBody?.friction = 0.0
self.addChild(ball)
circle.fillColor = SKColor.clearColor()
circle.strokeColor = SKColor.redColor()
circle.lineWidth = 5.0
circle.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
circle.physicsBody = SKPhysicsBody(edgeLoopFromPath: circle.path)
circle.physicsBody?.categoryBitMask = circleCategory
self.addChild(circle)
platform.fillColor = SKColor.clearColor()
platform.strokeColor = SKColor.clearColor()
platform.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(10, 1))
platform.position = CGPoint(x: self.size.width/2, y: circle.position.y/2)
platform.physicsBody?.categoryBitMask = platformCategory
platform.physicsBody?.dynamic = false
platform.physicsBody?.friction = 0.0
self.addChild(platform)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
circleColor += 1
if circleColor%3 == 1 {
circle.strokeColor = UIColor.redColor()
}
if circleColor%3 == 2 {
circle.strokeColor = UIColor.greenColor()
}
if circleColor%3 == 3 {
circle.strokeColor = UIColor.yellowColor()
}
if circleColor%3 == 4 {
circle.strokeColor = UIColor.greenColor()
}
if circleColor%3 == 5 {
circle.strokeColor = UIColor.blueColor()
}
if circleColor%3 == 0 {
circle.strokeColor = UIColor.yellowColor()
}
}
func didBeginContact(contact: SKPhysicsContact) {
if ball.fillColor == circle.strokeColor {
score += 1
scoreLabel.text = String("Score \(score)")
}
if ball.fillColor != circle.strokeColor {
let transition = SKTransition.revealWithDirection(SKTransitionDirection.Down, duration: 1.0)
let scene = SecondScene(size: self.scene!.size)
scene.scaleMode = SKSceneScaleMode.AspectFill
self.scene!.view!.presentScene(scene, transition: transition)
}
ballColor = Int(arc4random_uniform(10))
if ballColor%3 == 1 {
ball.fillColor = UIColor.redColor()
}
if ballColor%3 == 2 {
ball.fillColor = UIColor.greenColor()
}
if ballColor%3 == 3 {
ball.fillColor = UIColor.yellowColor()
}
if ballColor%3 == 4 {
ball.fillColor = UIColor.greenColor()
}
if ballColor%3 == 5 {
ball.fillColor = UIColor.blueColor()
}
if ballColor%3 == 0 {
ball.fillColor = UIColor.yellowColor()
}
}
func setUpLabels () {
scoreLabel = SKLabelNode(fontNamed: "Arial")
scoreLabel.position = CGPoint(x: 60, y: self.size.height-30)
scoreLabel.text = String("Score \(score)")
scoreLabel.fontColor = UIColor.blackColor()
scoreLabel.fontSize = 25
self.addChild(scoreLabel)
}
override func update(currentTime: CFTimeInterval) {
}
}
Reduce restitution a little which take control of the bounciness of the physics body. Like this:
ball.physicsBody?.restitution = 0.9
In general numerical differential equation solvers that solve the ode for the next time step will introduce energy into the system, which is why you are seeing what you are seeing. You can mitigate this by introduce a damping force. In the case of SpriteKit this means changing the restitution or linear damping factors.
For more about the drift that occurs see: https://en.wikipedia.org/wiki/Energy_drift or http://www.cs.cmu.edu/~baraff/sigcourse/notesb.pdf.

Use random number (arc4random_uniform) to display random shapes

The purpose for this code is to do random number to display random shapes but the simulator displays them in the same spot which is the bottom left corner of the screen, for some reason the random for the position which is a is not working.
Code:
import UIKit
import SpriteKit
import Darwin
class StartGame: SKScene {
var scoreLabel = SKLabelNode(fontNamed: "cholkDuster")
var square = SKSpriteNode(imageNamed: "square")
var circle = SKSpriteNode(imageNamed: "circle")
var rectangle = SKSpriteNode(imageNamed: "rectangle")
var triangle = SKSpriteNode(imageNamed: "triangle")
let bg = SKSpriteNode(imageNamed: "background.png")
var score = 0
override func didMoveToView(view: SKView) {
//random number for the shapes
var timecreatShapes = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("creatShapes"), userInfo: nil, repeats: true)
//background image
bg.position = CGPoint(x: CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
bg.size.width = self.frame.size.width
bg.size.height = self.frame.size.height
self.addChild(bg)
self.scoreLabel.text = "0"
self.scoreLabel.fontSize = 42
self.scoreLabel.position = CGPoint(x: CGRectGetMidX(self.frame) , y: CGRectGetMidY(self.frame))
self.addChild(scoreLabel)
scoreLabel.zPosition = 2
self.physicsWorld.gravity = CGVectorMake(0, -0.5)
//declaring a square image
square.size = CGSize(width: 150, height: 100)
square.color = SKColor.redColor()
square.physicsBody = SKPhysicsBody(circleOfRadius: square.size.height / 2)
square.physicsBody?.dynamic = true
square.physicsBody?.allowsRotation = false
//declaring a circle image
circle.size = CGSize(width: 150, height: 100)
circle.physicsBody = SKPhysicsBody(circleOfRadius: square.size.height / 2)
circle.physicsBody?.dynamic = true
circle.physicsBody?.allowsRotation = false
//declaring a triangle
triangle.size = CGSize(width: 150, height: 100)
triangle.physicsBody = SKPhysicsBody(circleOfRadius: square.size.height / 2)
triangle.physicsBody?.dynamic = true
triangle.physicsBody?.allowsRotation = false
//declaring rectangle
rectangle.size = CGSize(width: 150, height: 100)
rectangle.physicsBody = SKPhysicsBody(circleOfRadius: square.size.height / 2)
rectangle.physicsBody?.dynamic = true
rectangle.physicsBody?.allowsRotation = false
}
func creatShapes () {
var x = Int ( arc4random_uniform(4) + 1)
var a = CGFloat ( arc4random_uniform(1000) + 1)
switch(x){
case 1:
circle.position = CGPoint (x: a , y: self.frame.size.height)
self.addChild(SKSpriteNode(imageNamed:"circle"))
case 2:
square.position = CGPoint(x: a , y: self.frame.size.height)
self.addChild(SKSpriteNode(imageNamed:"square"))
case 3:
rectangle.position = CGPoint(x: a , y: self.frame.size.height)
self.addChild(SKSpriteNode(imageNamed:"rectangle"))
case 4:
triangle.position = CGPoint(x: a , y: self.frame.size.height)
self.addChild(SKSpriteNode(imageNamed:"triangle"))
default:
break
}
println(x)
println(a)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if (self.nodeAtPoint(location) == self.square || self.nodeAtPoint(location) == self.triangle || self.nodeAtPoint(location) == self.circle || self.nodeAtPoint(location) == self.rectangle){
self.score++
}
self.scoreLabel.text = String(self.score)
}
}