Swift - SpriteKit how do I do infinite background scrolling with two unique backgrounds? - swift

My code works perfectly fine for one common background but I am unable to figure out the required logic have it working perfectly fine if the backgrounds were unique.
override func didMove(to view: SKView)
{
createBackground()
}
func createBackground ()
{
var texture1 = SKTexture(imageNamed: "card1")
let texture2 = SKTexture(imageNamed: "card2")
for i in 0...1
{
let background = SKSpriteNode(texture: texture1)
background.anchorPoint = CGPoint.zero
background.position = CGPoint(x: 0, y: texture1.size().height * CGFloat(i))
addChild(background)
let moveDown = SKAction.moveBy(x: 0, y: -background.size.height, duration: 5)
let reset = SKAction.moveBy(x: 0, y: background.size.height, duration: 0)
let sequence = SKAction.sequence([moveDown, reset])
let forever = SKAction.repeatForever(sequence)
background.run(forever)
texture1 = texture2
}
}
}

Related

Trail of nodes along a path as in hello world

hi I have a node traveling back and forth along a path. I am trying to integrate the moving shapeNode as in the hello world example to trail my moving node. I'm using a trigger from frame update to trigger the copying of the shape node. And using the position of the travelling node.
The problem is that the trail has some sort of offset and i don't know where its coming from. I have tried to compensate but to no avail. I'm wondering if it might have anything to do with the actions. Thanks for reading.
I have tried looking at this link but i cannot translate
Here is my code so far
spriteKit xcode 9 swift 4 iPad Air
// GameScene.swift
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var borderBody = SKPhysicsBody()
var myMovingNode = SKSpriteNode()
var trailNode : SKShapeNode?
override func didMove(to view: SKView) {
//Define Border
borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
borderBody.friction = 0
self.physicsBody = borderBody
physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)
physicsWorld.contactDelegate = self
//Define myMovingNode
myMovingNode = SKSpriteNode(imageNamed: "greenball")
myMovingNode.size.width = 50
myMovingNode.size.height = 50
let myMovingNodeBody:CGSize = CGSize(width: 50, height: 50)
myMovingNode.physicsBody = SKPhysicsBody.init(rectangleOf: myMovingNodeBody)
myMovingNode.zPosition = 2
addChild(myMovingNode)
//Make Path for myMovingNode to travel
let myPath = CGMutablePath()
myPath.move(to: CGPoint(x: 30, y: 30))
myPath.addLine(to: CGPoint(x: 500, y: 500))
/*This is another path to try*/
// myPath.addCurve(to: CGPoint(x: 800, y: 700), control1: CGPoint(x: 500, y: 30), control2: CGPoint(x: 50, y: 500))
/*This draws a line along myPath*/
let myLine = SKShapeNode(path: myPath)
myLine.lineWidth = 10
myLine.strokeColor = .green
myLine.glowWidth = 0.5
myLine.zPosition = 2
addChild(myLine)
/*This sets myMovingNode running along myPath*/
let actionForward = SKAction.follow(myPath, asOffset: false, orientToPath: true, duration: 10)
let actionReverse = actionForward.reversed()
let wait = SKAction.wait(forDuration: 1)
let actionSequence = SKAction.sequence([actionForward, wait, actionReverse, wait])
myMovingNode.run(SKAction.repeatForever(actionSequence))
/*This defines TrailNode and its actions*/
trailNode = SKShapeNode.init(rectOf: CGSize.init(width: 20, height: 20), cornerRadius: 10)
if let trailNode = trailNode {
trailNode.lineWidth = 1
trailNode.fillColor = .cyan
trailNode.run(SKAction.sequence([SKAction.wait(forDuration: 5),
SKAction.fadeOut(withDuration: 3),
SKAction.removeFromParent()]))
}//Eo if Let
}//eo overdrive
func timeFunction (){/*This is controlled by func update*/
let n = trailNode?.copy() as! SKShapeNode?
/*this is where i'm trying to compensate*/
let movingNodeX = myMovingNode.position.x
let movingNodeY = myMovingNode.position.y
let movingNodeOffSet = CGPoint(x: movingNodeX - 0, y: movingNodeY - 0)
n?.position = movingNodeOffSet
myMovingNode.addChild(n!)
}
var frameCounter = 0
override func update(_ currentTime: TimeInterval) {
// print( "Called before each frame is rendered")
if frameCounter == 10{frameCounter = 0; timeFunction()}
frameCounter = frameCounter + 1
}
}//class GameScene
hi in answer to my own question. It was the simplest. On the last line change from
myMovingNode.addChild(n!) to addChild(n!)

Swift 3 - Background loop not working properly

I am trying to make a Flappy Bird like game and have to make my background loop infinitely. I found some tutorials online but it is just not working for me and I can't figure out why.
This is my code so far
var Background = SKSpriteNode()
var txtBG = SKTexture(imageNamed: "Background")
var txtLand = SKTexture(imageNamed: "Ground")
var Ground = SKSpriteNode()
var moving:SKNode!
// Cena
override func didMove(to view: SKView) {
scene?.anchorPoint = CGPoint(x: 0, y: 0)
moving = SKNode()
self.addChild(moving)
//Ground
Ground = SKSpriteNode(texture: txtLand)
Ground.position = CGPoint(x:0, y: txtLand.size().height * 1.3)
Ground.setScale(2.5)
self.addChild(Ground)
//Background
Background = SKSpriteNode(texture: txtBG)
Background.setScale(2.0)
Background.position = CGPoint(x: self.size.width, y: txtLand.size().height * 5.2 )
let BGmove = SKAction.moveBy(x: -txtBG.size().width * 2.0, y: txtLand.size().height * 5.2 , duration: TimeInterval(15))
let BGRepo = SKAction.moveBy(x: txtBG.size().width * 2.0, y: txtLand.size().height * 5.2, duration: 0.0)
let BGLoop = SKAction.repeatForever(SKAction.sequence([BGmove,BGRepo]))
for i in 0 ..< 2 + Int(self.frame.size.width / ( txtBG.size().width * 2 )) {
let i = CGFloat(i)
Background = SKSpriteNode(texture: txtBG)
Background.setScale(2.0)
Background.position = CGPoint(x:txtBG.size().width/2 + txtBG.size().width * i * 2.0, y: txtLand.size().height * 5.2)
Background.run(BGLoop)
self.addChild(Background)
}
What happens is the background starts moving horizontally but also moving upwards and I don't understand why.
Any help will be much appreciated!
Your Background Move actions have the background moving by x and by y. If you want to use SKAction.moveBy(x: CGFloat, y: CGFloat, duration: TimeInterval) then set y to 0 or you can use SKAction.moveTo(x: CGFloat, duration: TimeInterval) to only move the x value.

Move a sprite randomly using Swift 3

I was trying to make a game where the dragon moves around randomly and the hero has to avoid it. I can make the dragon appear at a random location and move once or twice but to make it continuously move from point to point and then move some more has given me trouble. I think it might be because I'm not waiting for the action to complete before generating all of the random numbers. I tried the following code including labels to prove to myself that the random numbers are generating, at least up to 20...
import SpriteKit
import GameplayKit
class GameScene: SKScene {
private let greenDragonNode = GreenDragonSprite.newInstance()
private var lastUpdateTime : TimeInterval = 0
private var i = 0
override func sceneDidLoad() {
self.lastUpdateTime = 0
let xOrigin = CGFloat(arc4random()).truncatingRemainder(dividingBy: size.width)
let yOrigin = CGFloat(arc4random()).truncatingRemainder(dividingBy: size.height)
let dragonOrigin = CGPoint(x: xOrigin, y: yOrigin)
greenDragonNode.position = dragonOrigin
greenDragonNode.setScale(0.1)
addChild(greenDragonNode)
}
override func didMove(to view: SKView) {
for i in 1...20 {
let xDestination = CGFloat(arc4random()).truncatingRemainder(dividingBy: size.width)
let yDestination = CGFloat(arc4random()).truncatingRemainder(dividingBy: size.height)
let dragonDestination = CGPoint(x: xDestination, y: yDestination)
let xDestination2 = CGFloat(arc4random()).truncatingRemainder(dividingBy: size.width)
let yDestination2 = CGFloat(arc4random()).truncatingRemainder(dividingBy: size.height)
let dragonDestination2 = CGPoint(x: xDestination2, y: yDestination2)
let dragonNodeTravel = SKAction.move(to:dragonDestination, duration: 3.0)
let dragonNodeReturn = SKAction.move(to: dragonDestination2, duration: 3.0)
greenDragonNode.run(SKAction.sequence([dragonNodeTravel, dragonNodeReturn]))
// i += 1
let label = SKLabelNode(text: "\(i)")
label.position = dragonDestination2
addChild(label)
}
}
}
That is happening because only the last action from the for loop is executed. You have to make a queue of actions. So you should append them to an array, and run them in a sequence, like this:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
private let greenDragonNode = SKSpriteNode(color: .green, size: CGSize(width: 20, height: 20))
func getRandomPoint(withinRect rect:CGRect)->CGPoint{
let x = CGFloat(arc4random()).truncatingRemainder(dividingBy: rect.size.width)
let y = CGFloat(arc4random()).truncatingRemainder(dividingBy: rect.size.height)
return CGPoint(x: x, y: y)
}
override func didMove(to view: SKView) {
greenDragonNode.position = self.getRandomPoint(withinRect: frame)
addChild(greenDragonNode)
var actions:[SKAction] = []
for i in 1...20 {
let destination = getRandomPoint(withinRect: frame)
let move = SKAction.move(to:destination, duration: 1.0)
actions.append(move)
let label = SKLabelNode(text: "\(i)")
label.position = destination
addChild(label)
}
let sequence = SKAction.sequence(actions)
greenDragonNode.run(sequence)
}
}

Getting different colour backgrounds to scroll up

I am coding for my A2 coursework project, and making a well-known game 'Fall Down'. However i am trying to get the background to change every cycle while it scrolls - so it changes from blue to red to yellow etc. However when I run it, this only works for the first two colours, then flashes back to the first colour. Here is the code i currently have
var background = SKSpriteNode()
override func didMoveToView(view: SKView) {
let blueTexture = SKTexture(imageNamed: "BlueBackground")
let redTexture = SKTexture(imageNamed: "RedBackground")
let yellowTexture = SKTexture(imageNamed: "YellowBackground")
let greenTexture = SKTexture(imageNamed: "GreenBackground")
let purpleTexture = SKTexture(imageNamed: "PurpleBackground")
let TextureArray = [blueTexture, redTexture, yellowTexture, greenTexture, purpleTexture]
let levelProgress = SKAction.moveByX(0, y:blueTexture.size().height, duration: 5)
let newLevel = SKAction.moveByX(0 , y: -blueTexture.size().height, duration: 0)
let sequenceForever = SKAction.repeatActionForever(SKAction.sequence([ levelProgress, newLevel]))
var a = 0
for var i: CGFloat = 0; i<5; i++ {
let currentBG = TextureArray[a]
a++
background = SKSpriteNode(texture: currentBG)
background.position = CGPoint(x: CGRectGetMidX(self.frame), y: -blueTexture.size().height/2 + blueTexture.size().height * i)
background.size.width = self.frame.width
background.runAction(sequenceForever)
self.addChild(background)
}
if anyone could point me in the right direction or if any more information is needed let me know! This is my first post so any posting advice would be great too.
It might by because of this:
let levelProgress = SKAction.moveByX(0, y:blueTexture.size().height, duration: 5)
let newLevel = SKAction.moveByX(0 , y: -blueTexture.size().height, duration: 0)
let sequenceForever = SKAction.repeatActionForever(SKAction.sequence([ levelProgress, newLevel]))
background.position = CGPoint(x: CGRectGetMidX(self.frame), y: -blueTexture.size().height/2 + blueTexture.size().height * i
you always use the blueTexture.size. try to change it to a constant value.

Issue with scrolling background vertically with sprite kit

I am trying to scroll game background vertically and it works for some time and later background become empty. this is what I have tried:
var background = SKSpriteNode(imageNamed: "bgPlayScene")
func addBG() {
let backgroundTexture = SKTexture(imageNamed: "bgPlayScene")
let shiftBackground = SKAction.moveToY(-backgroundTexture.size().height, duration: 9)
let replaceBackground = SKAction.moveToY(backgroundTexture.size().height, duration: 0)
let movingAndReplacingBackground = SKAction.repeatActionForever(SKAction.sequence([shiftBackground,replaceBackground]))
for var i = 0; i<3; i++ {
println(i)
//defining background; giving it height and moving width
background=SKSpriteNode(texture:backgroundTexture)
background.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
background.size.width = self.frame.width
background.runAction(movingAndReplacingBackground)
self.addChild(background)
}
}
This is what I am getting: http://gyazo.com/3da3a267aeb030225fdb8c0d563276aa
I don't know what I am missing.Please let me know if there is another better way to do this.
As suggested by iAnum I got answer from that post and here is my code:
This way I add 2 backgrounds.
func addScrollingBG() {
bg1 = SKSpriteNode(imageNamed: "bgPlayScene")
bg1.anchorPoint = CGPointZero
bg1.position = CGPointMake(0, 0)
bg1.size = CGSize(width: frame.size.width, height: frame.size.height)
addChild(bg1)
bg2 = SKSpriteNode(imageNamed: "bgPlayScene")
bg2.anchorPoint = CGPointZero
bg2.position = CGPointMake(0, bg1.size.height + 1)
bg2.size = CGSize(width: frame.size.width, height: frame.size.height)
self.addChild(bg2)
}
And this is my update method:
override func update(currentTime: NSTimeInterval) {
bg1.position = CGPointMake(bg1.position.x, bg1.position.y-4)
bg2.position = CGPointMake(bg2.position.x, bg2.position.y-4)
if bg1.position.y < -bg1.size.height {
bg1.position = CGPointMake(bg1.position.x, bg2.position.y + bg2.size.height)
}
if bg2.position.y < -bg2.size.height {
bg2.position = CGPointMake(bg2.position.x, bg1.position.y + bg1.size.height)
}
}