I need to make something like a Gravity Point in Swift.
The SpriteNode is in the middle of the screen, and by Left or Right Gestures it can move along the x-axis.
But after for e.g. a 'RightSwipe', it should come back to his starting point. You could say it should look like a jump along the x-axis.
The World Gravity cant be a specific point, so how can I 'Force' it to come back to his original point?
I tried it with SKFieldNode's RadialGravityField, but after the Nodes impulse is made, it goes back to his original point and disappears.
How can I avoid that?
My Code:
{
.......
Node = SKSpriteNode(texture: Node1)
Node.size = CGSize(width: 100, height: 140)
Node.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height / 4)
Node.zPosition = 3
Node.runAction(RunAnimation)
Node.physicsBody = SKPhysicsBody(rectangleOfSize: Node.size)
Node.physicsBody?.dynamic = true
Node.physicsBody?.allowsRotation = false
Node.physicsBody?.usesPreciseCollisionDetection = true
Node.physicsBody?.restitution = 0
Node.physicsBody?.velocity = CGVectorMake(0, 0)
self.addChild(Node)
let swipeRight:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: Selector("SwipeRight:"))
swipeRight.direction = .Right
view.addGestureRecognizer(swipeRight)
let swipeLeft:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: Selector("SwipeLeft:"))
swipeLeft.direction = .Left
view.addGestureRecognizer(swipeLeft)
}
func SwipeRight(recognizer:UISwipeGestureRecognizer) {
Node.physicsBody?.applyImpulse(CGVectorMake(10,0))
}
func SwipeLeft(recognizer:UISwipeGestureRecognizer) {
Node.physicsBody?.applyImpulse(CGVectorMake(-10,0))
}
override func update(currentTime: CFTimeInterval) {
if(Node.position.x > self.frame.size.width / 1.6)
{
fieldNode = SKFieldNode.radialGravityField()
fieldNode.enabled = true
fieldNode.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height / 4)
fieldNode.strength = 0.4
addChild(fieldNode)
}
if(Node.position.x < self.frame.size.width / 2.6)
{
fieldNode = SKFieldNode.radialGravityField()
fieldNode.enabled = true
fieldNode.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height / 4)
fieldNode.strength = 0.4
addChild(fieldNode)
}
Sounds like a job for a radial gravity SKFieldNode. link
Related
It's my very first post in coding forum - it means i'm REEAAAAALLLY stuck (I've searched everywhere and tested many options).
Creating a simple bouncing ball on my ipad screen, coding the app using SpriteKit.
The below code prevent the ball to move at all BUT when i remove the SKPhysicsBody created out the frame.edge : the ball falls.
I've got the feeling that the self.physicsBody is ultimately made as a volume despite I ask it to be made from an edge...
Can you please help ?
override func didMove(to view: SKView) {
self.physicsWorld.gravity = CGVector(dx: 0,dy: -6)
self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame) // ball's cage
self.physicsBody?.friction = 0;
let fbound = SKShapeNode(rect: self.frame)
fbound.lineWidth = 1
fbound.strokeColor = .red
addChild(fbound)
let path = CGMutablePath()
path.addArc(center: CGPoint(x: view.bounds.width / 2, y: view.bounds.height / 2),
radius: 15,
startAngle: 0,
endAngle: CGFloat.pi * 2,
clockwise: true)
let ball = SKShapeNode(path: path)
ball.lineWidth = 1
ball.fillColor = .red
ball.strokeColor = .black
ball.glowWidth = 0.5
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.frame.size.width/2)
ball.physicsBody?.friction = 0
ball.physicsBody?.restitution = 1
ball.physicsBody?.mass = 0.6
ball.physicsBody?.linearDamping = 0
ball.physicsBody?.allowsRotation = false
ball.physicsBody?.isDynamic = true
addChild(ball)
}
Please let me know if you need more details
Thanks a mil in advance
Rgds
I have a pong game in a Swift Playground that I made by following a tutorial online but my assistant editor won't show anything! Where is my pong game!? My code is below the image, which shows that nothing is showing up.
import SpriteKit
import PlaygroundSupport
// Declare some global constants
let width = 800 as CGFloat
let height = 1200 as CGFloat
let racketHeight = 150 as CGFloat
let ballRadius = 20 as CGFloat
// Three types of collision objects possible
enum CollisionTypes: UInt32 {
case Ball = 1
case Wall = 2
case Racket = 4
}
// Racket direction
enum Direction: Int {
case None = 0
case Up = 1
case Down = 2
}
// Make a SpriteKit scene
class gameScene: SKScene, SKPhysicsContactDelegate {
let racketSpeed = 500.0
var direction = Direction.None
var score = 0
var gameRunning = false
// Screen elements
var racket: SKShapeNode?
var ball: SKShapeNode?
let scoreLabel = SKLabelNode()
// Initialize objects during first start
override func sceneDidLoad() {
super.sceneDidLoad()
scoreLabel.fontSize = 40
scoreLabel.position = CGPoint(x: width/2, y: height - 100)
self.addChild(scoreLabel)
createWalls()
createBall(position: CGPoint(x: width / 2, y: height / 2))
createRacket()
startNewGame()
self.physicsWorld.contactDelegate = self
}
// Create the ball sprite
func createBall(position: CGPoint) {
let physicsBody = SKPhysicsBody(circleOfRadius: ballRadius)
ball = SKShapeNode(circleOfRadius: ballRadius)
physicsBody.categoryBitMask = CollisionTypes.Ball.rawValue
physicsBody.collisionBitMask = CollisionTypes.Wall.rawValue | CollisionTypes.Ball.rawValue | CollisionTypes.Racket.rawValue
physicsBody.affectedByGravity = false
physicsBody.restitution = 1
physicsBody.linearDamping = 0
physicsBody.velocity = CGVector(dx: -500, dy: 500)
ball!.physicsBody = physicsBody
ball!.position = position
ball!.fillColor = SKColor.white
}
// Create the walls
func createWalls() {
createWall(rect: CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: ballRadius, height: height)))
createWall(rect: CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: width, height: ballRadius)))
createWall(rect: CGRect(origin: CGPoint(x: 0, y: height - ballRadius), size: CGSize(width: width, height: ballRadius)))
}
func createWall(rect: CGRect) {
let node = SKShapeNode(rect: rect)
node.fillColor = SKColor.white
node.physicsBody = getWallPhysicsbody(rect: rect)
self.addChild(node)
}
// Create the physics objetcs to handle wall collisions
func getWallPhysicsbody(rect: CGRect) -> SKPhysicsBody {
let physicsBody = SKPhysicsBody(rectangleOf: rect.size, center: CGPoint(x: rect.midX, y: rect.midY))
physicsBody.affectedByGravity = false
physicsBody.isDynamic = false
physicsBody.collisionBitMask = CollisionTypes.Ball.rawValue
physicsBody.categoryBitMask = CollisionTypes.Wall.rawValue
return physicsBody
}
// Create the racket sprite
func createRacket() {
racket = SKShapeNode(rect: CGRect(origin: CGPoint.zero, size: CGSize(width: ballRadius, height: racketHeight)))
self.addChild(racket!)
racket!.fillColor = SKColor.white
let physicsBody = SKPhysicsBody(rectangleOf: racket!.frame.size, center: CGPoint(x: racket!.frame.midX, y: racket!.frame.midY))
physicsBody.affectedByGravity = false
physicsBody.isDynamic = false
physicsBody.collisionBitMask = CollisionTypes.Ball.rawValue
physicsBody.categoryBitMask = CollisionTypes.Racket.rawValue
physicsBody.contactTestBitMask = CollisionTypes.Ball.rawValue
racket!.physicsBody = physicsBody
}
// Start a new game
func startNewGame() {
score = 0
scoreLabel.text = "0"
racket!.position = CGPoint(x: width - ballRadius * 2, y: height / 2)
let startLabel = SKLabelNode(text: "Game Over")
startLabel.position = CGPoint(x: width / 2, y: height / 2)
startLabel.fontSize = 160
self.addChild(startLabel)
// Animated countdown
let fadeIn = SKAction.fadeIn(withDuration: 0.5)
let fadeOut = SKAction.fadeOut(withDuration: 0.5)
startLabel.text = "3"
startLabel.run(SKAction.sequence([fadeIn, fadeOut]), completion: {
startLabel.text = "2"
startLabel.run(SKAction.sequence([fadeIn, fadeOut]), completion: {
startLabel.text = "1"
startLabel.run(SKAction.sequence([fadeIn, fadeOut]), completion: {
startLabel.text = "0"
startLabel.run(SKAction.sequence([fadeIn, fadeOut]), completion: {
startLabel.removeFromParent()
self.gameRunning = true
self.ball!.position = CGPoint(x: 30, y: height / 2)
self.addChild(self.ball!)
})
})
})
})
}
// Handle touch events to move the racket
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if location.y > height / 2 {
direction = Direction.Up
} else if location.y < height / 2{
direction = Direction.Down
}
}
}
// Stop racket movement
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
direction = Direction.None
}
// Game loop:
var dt = TimeInterval(0)
override func update(_ currentTime: TimeInterval) {
if gameRunning {
super.update(currentTime)
checkGameOver()
if dt > 0 {
moveRacket(dt: currentTime - dt)
}
dt = currentTime
}
}
// Move the racket up or down
func moveRacket(dt: TimeInterval) {
if direction == Direction.Up && racket!.position.y < height - racketHeight {
racket!.position.y = racket!.position.y + CGFloat(racketSpeed * dt)
} else if direction == Direction.Down && racket!.position.y > 0 {
racket!.position.y = racket!.position.y - CGFloat(racketSpeed * dt)
}
}
// Check if the ball is still on screen
// Game Over animation
func checkGameOver() {
if ball!.position.x > CGFloat(width) {
gameRunning = false
ball!.removeFromParent()
let gameOverLabel = SKLabelNode(text: "Game Over")
gameOverLabel.position = CGPoint(x: width / 2, y: height / 2)
gameOverLabel.fontSize = 80
self.addChild(gameOverLabel)
// Game Over animation
let rotateAction = SKAction.rotate(byAngle: CGFloat(M_PI), duration: 1)
let fadeInAction = SKAction.fadeIn(withDuration: 2)
gameOverLabel.run(SKAction.repeat(rotateAction, count: 2))
gameOverLabel.run(SKAction.scale(to: 0, duration: 2.5), completion: {
gameOverLabel.removeFromParent()
self.startNewGame()
})
}
}
// Detect collisions between ball and racket to increase the score
func didBegin(_ contact: SKPhysicsContact) {
if contact.bodyA.categoryBitMask == CollisionTypes.Racket.rawValue || contact.bodyB.categoryBitMask == CollisionTypes.Racket.rawValue {
score += 1
scoreLabel.text = String(score)
}
}
}
//Initialize the playground and start the scene:
let skView = SKView(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: width, height: height)))
let scene = gameScene(size: skView.frame.size)
skView.presentScene(scene)
PlaygroundPage.current.liveView = skView
This happens to me sometimes. Playgrounds with SpriteKit just would not show anything in the Timeline view - you do have the Timeline view open, right? If you don't, tap the "Show the Assistant editor" button on the toolbar to open the Timeline view.
If you have the Timeline view open and nothing shows, try shutting down Xcode and restarting it. That generally resolves this issue for me.
I'm trying to create a scenario where there's a radial gravity field. In this scene, there's also an object built by two physics bodies with a different mass.
When I run this code, the radial gravity field is created correctly and the body goes to gravityCenter.
I'm expecting that the body rotates too because the head is heavier than the tail but this doesn't happend.
Why?
class GameScene: SKScene {
let object = SKSpriteNode(imageNamed: "myobj")
let myCategory : UInt32 = 0x1 << 0
override func didMove(to view: SKView) {
self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
let gravityCenter = SKFieldNode.radialGravityField()
gravityCenter.isEnabled = true
gravityCenter.position = CGPoint(x: size.width, y: size.height * 0.5)
gravityCenter.strength = 0.5
addChild(gravityCenter)
object.position = CGPoint(x: size.width * 0.1, y: size.height * 0.9)
object.scale(to: CGSize(width: 100, height: 25))
let head = SKPhysicsBody(circleOfRadius: object.size.width/5, center: CGPoint(x: object.size.width/2, y: 0))
let tail = SKPhysicsBody(circleOfRadius: object.size.width/50, center: CGPoint(x: -object.size.width/2, y: 0))
head.mass = 500
head.categoryBitMask = myCategory
head.allowsRotation = true
head.isDynamic = true
head.angularDamping = 0
head.affectedByGravity = true
tail.mass = 2
tail.categoryBitMask = myCategory
tail.allowsRotation = true
tail.isDynamic = true
tail.angularDamping = 0
tail.affectedByGravity = true
object.physicsBody = SKPhysicsBody(bodies: [head, tail])
object.physicsBody?.categoryBitMask = myCategory
object.physicsBody?.allowsRotation = true
object.physicsBody?.isDynamic = true
object.physicsBody?.angularDamping = 0
object.physicsBody?.affectedByGravity = true
addChild(object)
}
}
Well, from a physics standpoint SpriteKit is behaving correctly. If you think about it, more mass does mean more gravitational force, but it also means more inertia, which exactly cancels out the increased force. Perhaps introduce a little bit of linearDamping into the tail? That would get the body to rotate by making the head drag the tail a little bit.
I awant to add SKSpriteNode's after something repositioned therefore I want to add the nodes through the update method in Swift Sprite Kit.
There are Objects ( platforms ) that move downwards the y axis, once they are out of screen they appear on the top side again ( like an infinite loop ). I visualize this in the update method. Note that the platforms dont really move, rather then I centered a camera on my Player node that moves up.
After the reposition of the platform node, I want to add an Enemy again on top of the platforms, however because I try it through the update method, it adds sometimes more than 1 node on top of it.
I cant reposition the Enemy like I do with the platforms, because it should be a random enemy node.
Any way to call the SpawnEnemy method in the update method, and check if it was called only once?
My Code:
override func didMoveToView(view: SKView) {
/* Setup your scene here */
self.World = SKNode()
self.World.name = "World"
addChild(World)
self.WorldCamera = SKNode()
self.WorldCamera.name = "Camera"
self.World.addChild(WorldCamera)
....
SpawnPlatforms()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform2.position.y + 30))
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform3.position.y + 30))
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform4.position.y + 30))
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform5.position.y + 30))
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform6.position.y + 30))
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform7.position.y + 30))
}
func SpawnPlatforms() {
Platform0 = SKSpriteNode (color: SKColor.greenColor(), size: CGSize(width: self.frame.size.width * 2 , height: 25))
Platform0.position = CGPoint(x: self.frame.size.width / 2, y: -36)
Platform0.zPosition = 1
Platform0.physicsBody = SKPhysicsBody(rectangleOfSize:Platform0.size)
Platform0.physicsBody?.dynamic = false
Platform0.physicsBody?.allowsRotation = false
Platform0.physicsBody?.restitution = 0.0
Platform0.physicsBody?.usesPreciseCollisionDetection = true
Platform0.physicsBody?.velocity = CGVectorMake(0, 0)
Platform0.physicsBody?.categoryBitMask = Platform0Category
Platform0.physicsBody?.collisionBitMask = PlayerCategory | EnemyCategory
Platform0.physicsBody?.contactTestBitMask = PlayerCategory | EnemyCategory
World.addChild(Platform0)
Platform1 = SKSpriteNode (color: SKColor.redColor(), size: CGSize(width: self.frame.size.width * 2 , height: 25))
Platform1.position = CGPoint(x: self.frame.size.width / 2, y: Platform0.position.y + self.frame.size.height / 4.5)
Platform1.zPosition = 1
Platform1.physicsBody = SKPhysicsBody(rectangleOfSize:Platform1.size)
Platform1.physicsBody?.dynamic = false
Platform1.physicsBody?.allowsRotation = false
Platform1.physicsBody?.restitution = 0
Platform1.physicsBody?.usesPreciseCollisionDetection = true
Platform1.physicsBody?.categoryBitMask = Platform1Category
Platform1.physicsBody?.collisionBitMask = PlayerCategory | EnemyCategory
Platform1.physicsBody?.contactTestBitMask = PlayerCategory | EnemyCategory
World.addChild(Platform1)
....a.s.o. for the other 6 platform nodes
}
func SpawnEnemy(position: CGPoint!){
let random = arc4random_uniform(4)
switch (random) {
case 0:
let node1 = SpawnNode1(position)
self.addChild(node1)
break
case 1:
let node2 = SpawnNode2(position)
self.addChild(node2)
break
case 2:
let node3 = SpawnNode3(position)
self.addChild(node3)
break
case 3:
break
default:
break
}
}
override func didSimulatePhysics() {
WorldCamera.position = CGPoint(x: Player.position.x, y: Player.position.y)
self.centerOnNode(WorldCamera!)
}
func centerOnNode(node: SKNode) {
let cameraPositionInScene: CGPoint = WorldCamera.scene!.convertPoint(WorldCamera.position, fromNode: World)
World.runAction(SKAction.moveTo(CGPoint(x:World.position.x , y:World.position.y - cameraPositionInScene.y), duration: 1.0))
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if(Platform1.position.y < (Player.position.y - self.frame.size.height / 2)){
Platform1.position = CGPointMake(self.frame.size.width / 2, Platform7.position.y + self.frame.size.height / 4.5)
Platform1.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform1.position.y + 30))
}
if(Platform2.position.y < (Player.position.y - self.frame.size.height / 2)){
Platform2.position = CGPointMake(self.frame.size.width / 2, Platform1.position.y + self.frame.size.height / 4.5)
Platform2.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform2.position.y + 30))
}
if(Platform3.position.y < (Player.position.y - self.frame.size.height / 2)){
Platform3.position = CGPointMake(self.frame.size.width / 2, Platform2.position.y + self.frame.size.height / 4.5)
Platform3.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform3.position.y + 30))
}
if(Platform4.position.y < (Player.position.y - self.frame.size.height / 2)){
Platform4.position = CGPointMake(self.frame.size.width / 2, Platform3.position.y + self.frame.size.height / 4.5)
Platform4.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform4.position.y + 30))
}
if(Platform5.position.y < (Player.position.y - self.frame.size.height / 2)){
Platform5.position = CGPointMake(self.frame.size.width / 2, Platform4.position.y + self.frame.size.height / 4.5)
Platform5.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform5.position.y + 30))
}
if(Platform6.position.y < (Player.position.y - self.frame.size.height / 2)){
Platform6.position = CGPointMake(self.frame.size.width / 2, Platform5.position.y + self.frame.size.height / 4.5)
Platform6.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform6.position.y + 30))
}
if(Platform7.position.y < (Player.position.y - self.frame.size.height / 2)){
Platform7.position = CGPointMake(self.frame.size.width / 2, Platform6.position.y + self.frame.size.height / 4.5)
Platform7.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: Platform7.position.y + 30))
}
}
Your problem is you do not create any kind of check that moving the platform has already spawned an enemy. Sure, you move the platform, but until your player moves, it will constantly spawn enemies. I do not see where this is happening, but you should spawn enemy when you move the platform, not on your update
Edit:
yikes, I see it now, this is some ugly code lol, In all those ifs that move the platform, you should spawn the enemy. But this needs to be worked to also check if the previous platform is below the current, not above
Edit++:
Upon further review and added details, try something like this instead:
First, give all Platforms a name "Platform"
Then
override func update(currentTime: CFTimeInterval) {
for node in scene.children
{
if (node.name == "Platform" && !node.intersectsNode(scene) && node.position.y < player.y - (self.frame.size.height / 4.5))
{
let platform = node as! SKSpriteNode
platform.position.y += (7 * (self.frame.size.height / 4.5))
platform.color = SKColor.redColor()
SpawnEnemy(CGPoint(x: self.frame.size.width / 2, y: platform.position.y + 30))
}
}
}
Question: How does this even work, I would just check if a platform hits a certain point in the scene, recycle it, instead of having to check every single platform and moving it's previous one
so you're spawning an enemy on every frame.. thats going to be way too many enemies.. I'm still not totally following the exact architecture of your game, but this might help you out.
get delta time to see how much time has passed.. and every 10 seconds (or whatever) call your spawn enemy code instead of calling it on every frame
// time values
var delta = NSTimeInterval(0)
var last_update_time = NSTimeInterval(0)
let spawnTimerMax = NSTimeInterval(10)
var spawnTimer = NSTimeInterval(0)
override func update(currentTime: NSTimeInterval) {
if last_update_time == 0.0 {
delta = 0
} else {
delta = currentTime - last_update_time
}
last_update_time = currentTime
// ten seconds elapsed, spawn enemy and restart.
spawnTimer += delta
if spawnTimer >= spawnTimerMax {
// your spawn code goes here
spawnTimer = 0
}
}
I'm creating a SpriteKit game with Swift. I'm using the NSTimer, schedule timer with time interval with the target and the selector. Although repeats is set to true, the pipe comes and goes only once. Here is my timer:
let timer = NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: "makePipes", userInfo: nil, repeats: true)
The pipe moves only once although repeats if true. I have declared the function (makePipes) in the didMoveToView.
Here is my full code:
import SpriteKit
class GameScene: SKScene {
func makePipes()
{let action = SKAction.moveToX(self.frame.size.width - 1000, duration: 3)
pipe.runAction(SKAction.repeatActionForever(action))}
var mainPlayer = SKSpriteNode(imageNamed: "Ball")
var ground = SKSpriteNode(imageNamed: "ground.png")
var pipe = SKSpriteNode(imageNamed: "pipe.png")
var barrier = SKSpriteNode(imageNamed: "Barrier.png")
override func didMoveToView(view: SKView) {
/* Setup your scene here */
backgroundColor = UIColor.whiteColor()
self.physicsWorld.gravity = CGVector(dx: 0, dy: -5)
mainPlayer.position = CGPoint(x: self.size.width / 2 , y: self.frame.height / 2)
mainPlayer.color = UIColor.grayColor()
mainPlayer.colorBlendFactor = 1.0
ground.size.width = 1000
barrier.size.width = 1000
// physics for the main palyer
mainPlayer.physicsBody = SKPhysicsBody(circleOfRadius: mainPlayer.size.height / 2)
self.addChild(mainPlayer)
ground.position = CGPoint(x: self.frame.size.width - 500, y: self.frame.size.height - 750)
ground.setScale(5)
ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: self.ground.size.width , height: self.ground.size.height))
ground.physicsBody?.dynamic = false
pipe.position = CGPoint(x: self.frame.width , y: self.frame.size.height - self.frame.height + 178)
pipe.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: pipe.size.width, height: pipe.size.height))
pipe.physicsBody?.dynamic = true
pipe.physicsBody?.affectedByGravity = false
self.addChild(pipe)
self.addChild(ground)
barrier.setScale(5)
barrier.position = CGPoint(x: frame.width / 2 , y: frame.height / 2 + 40)
barrier.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: barrier.size.width, height: barrier.size.height))
barrier.physicsBody?.dynamic = false
barrier.size.height = 200
self.addChild(barrier)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
self.physicsWorld.gravity = CGVector(dx: 0, dy: -1)
if (mainPlayer.size.height < self.frame.height / 5.5) {
mainPlayer.physicsBody?.velocity = CGVectorMake(0.0, 0.0)
mainPlayer.physicsBody?.applyImpulse(CGVectorMake(0, 10))
let timer = NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: "makePipes", userInfo: nil, repeats: true)
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
I don't see the pipe recreated anywhere. It looks to me like the function is in fact called repeatedly, but because you are not recreating pipes and simply using the same pipe object it just moving farther and farther down. Instead of using only one pipe object, you could try to keep generating pipes within that function like this:
fun makePipes()
{
//create pipe
var Pipe = SKSpriteNode(imageNamed:"pipe.png")
pipe.position = CGPoint(x: self.frame.width , y: self.frame.size.height - self.frame.height + 178)
pipe.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: pipe.size.width, height: pipe.size.height))
pipe.physicsBody?.dynamic = true
pipe.physicsBody?.affectedByGravity = false
self.addChild(pipe)
//move pipe
let action = SKAction.moveToX(self.frame.size.width - 1000, duration: 3)
pipe.runAction(action, completion: {() -> Void in
//completed action, can remove pipe
pipe.removeFromParent()
})
}
also remove the instance variable from your class so it doesn't conflict and take out your initialization from viewDidLoad. Lastly, I'd recommend to use the SKAction perform selector which will do the same thing. However, it is integrated in SpriteKit (you avoid memory leaks and can have much more control over timing!)