Reputation: 211
I'm creating a simple game with Swift
and SpriteKit
.
I want to add an endless background (vertically), I only found answers for background with images but I need to do it without image, only background color.
I thought about checking if the player is in the frame.maxY
, if so, to move it back to the starting point, but I was wondering if there is a better idea.
//Does not matter which ring we chose as all ring's 'y' position is the same.
func moveBackgroundUp(){
if ((mPlayer.position.y >= self.frame.maxY) || (mRingOne.position.y >= self.frame.maxY)) {
mPlayer.position.y = 150 //mPlayers original starting point.
for ring in mRings {
ring.position.y = 350
}
}
}
Thanks in advance!
Upvotes: 3
Views: 118
Reputation: 3158
Don't just move a background up the screen, that' really isn't the way to go about it. What you should do is detect the position of the camera (assuming it moves with the player), and when it's position is about to occupy space outside of the occupied space of your current background sprite, add a new background sprite to the scene where the last one left off. Here is an example of how to do that with just a red sprite:
First add a property to the scene to track level position:
// To track the y-position of the level
var levelPositionY: CGFloat = 0.0
Now create a method to update your background:
func updateBackground() {
let cameraPos = camera!.position
if cameraPos.y > levelPositionY - (size.height * 0.55) {
createBackground()
}
}
func createBackground() {
// Create a new sprite the size of your scene
let backgroundSprite = SKSpriteNode(color: .red, size: size)
backgroundSprite.anchorPoint = CGPoint(x: 0.5, y: 0)
backgroundSprite.position = CGPoint(x: 0, y: levelPositionY)
// Replace backgroundNode with the name of your backgroundNode to add the sprite to
backgroundNode.addChild(backgroundSprite)
levelPositionY += backgroundSprite.size.height
}
Now you want to call updateBackground
inside your overridden update(_:)
method:
override func update(_ currentTime: TimeInterval) {
// All your other update code
updateBackground()
}
Also, make sure to create an initial background when you first create the scene:
override func didMove(to view: SKView) {
createBackground()
}
NOTE! - It's important to set the custom anchor point for the background sprite for this code to work properly. An anchor of (0.5, 0) allows the background sprite to be anchored in the middle of the scene on the x-axis, but at the bottom of the scene on the y-axis. This allows you to easily stack one on top of the other.
EDIT - I forgot to mention that it's also a good idea to conserve resources and remove any background nodes that are outside the viewable area and won't be coming back in (i.e. a continuous scrolling game where you can't go backwards). You could do that by updating your updateBackground
method above:
func updateBackground() {
let cameraPos = camera!.position
if cameraPos.y > levelPositionY - (size.height * 0.55) {
createBackground()
}
// Make sure to change 'backgroundNode' to whatever the name of your backgroundNode is.
for bgChild in backgroundNode.children {
// This will convert the node's coordinates to scene's coordinates. See below for this function
let nodePos = fgNode.convert(fgChild.position, to: self)
if !isNodeVisible(bgChild, positionY: nodePos.y) {
// Remove from it's parent node
bgChild.removeFromParent()
}
}
}
func isNodeVisible(_ node: SKNode, positionY: CGFloat) -> Bool {
if !camera!.contains(node) {
if positionY < camera!.position.y - size.height * 2.0 {
return false
}
}
return true
}
So above you just loop through all the children inside your background node and detect if they are out of view, and if so remove them from the parent. Make sure to change my generic backgroundNode
to whatever the name of your background node is.
Upvotes: 3