Vertical endless scrolling background in sprite kit - ios

I'm making a game and I'd like to have my background scroll vertically endlessly but I have no clue how to start. I'm pretty new to coding and sprite kit especially so any help would be greatly appreciated.
Anyone know how I could go about doing this?

You want to have two nodes, one to start with and one that follows it. Lastly, loop forever.
func createGroundForward() {
let groundTexture = SKTexture(imageNamed: "Track")
for i in 0 ... 1 {
let ground = SKSpriteNode(texture: groundTexture)
ground.zPosition = -4
ground.position = CGPoint(x: 0, y: -groundTexture.size().height + (groundTexture.size().height + (groundTexture.size().height * CGFloat(i))))
addChild(ground)
let moveLeft = SKAction.moveBy(x:0 , y: -groundTexture.size().height, duration: 5)
let moveReset = SKAction.moveBy(x:0 , y: groundTexture.size().height, duration: 0)
let moveLoop = SKAction.sequence([moveLeft, moveReset])
let moveForever = SKAction.repeatForever(moveLoop)
ground.run(moveForever)
}
}
Then add the function to your didMove function (which is like viewDidLoad for Sprite).
override func didMove(to view: SKView) {
self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
createGroundForward()
}

I will give you an answer conceptually to give you a place to start since you have not provided any code.
You will need multiple images that are the size of the screen and stack them on top of each other vertically.
You then want to move these images down point by point. When the top of one of the images reaches the bottom of the screen, put it back on top of your stack of images. This will cause a never ending scrolling of your background.
Best of luck!

Related

SpriteKit scrolling background image showing line between images

I'm learning how to make games in iOS, so I decided to replicate the first level of Mario Bros using my own assets, just to learn how to make them as well.
The issue I'm having right now is that, when creating the scrolling background, using this formula I found on Hacking with Swift, I keep getting a line in between my images.
I've checked that my images have no border in the AI file. (The images are the ones above)
import SpriteKit
import GameplayKit
class GameScene: SKScene {
private var player = SKSpriteNode()
private var bg = SKSpriteNode()
override func didMove(to view: SKView) {
let playerTexture = SKTexture(imageNamed: "player")
player = SKSpriteNode(texture: playerTexture)
player.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
addBackground()
self.addChild(player)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
// MARK: UTILITY FUNCTIONS
func addBackground() {
let bgTexture = SKTexture(imageNamed: "bg")
for i in 0 ... 1 {
bg = SKSpriteNode(texture: bgTexture)
//bg.position = CGPoint(x: (i == 0 ? bgTexture.size().width : bgTexture.size().width - 1) * CGFloat(i), y: self.frame.midY)
bg.position = CGPoint(x: (bgTexture.size().width * CGFloat(i)) - CGFloat(1 * i), y: 0)
bg.size.height = self.frame.height
//bg.anchorPoint = CGPoint.zero
bg.zPosition = -10
self.addChild(bg)
let moveLeft = SKAction.moveBy(x: -bgTexture.size().width, y: 0, duration: 5)
let moveReset = SKAction.moveBy(x: bgTexture.size().width, y: 0, duration: 0)
let moveLoop = SKAction.sequence([moveLeft, moveReset])
let moveForever = SKAction.repeatForever(moveLoop)
bg.run(moveForever)
}
}
}
Just create a new project, copy-paste it and you should see it running
I also changed my GameScene.sks size to: 2688 x 1242
And one last change I made to make the background appear in full screen was to set the LaunchScreen as stated in this answer which seems to be an issue in Xcode 12
I understand that the formula from Hacking with Swift post is making the images overlap by 1px, I've tried removing the 1 * i part from it, yet results are not different.
Other thing I did was to verify the images were "joining" perfectly together, and they do, the lines you can see in the image below are from the AI canvas, both images join in between "cactuses".
I also tried running it into a device in case it might be a bug in the simulator:
Your image has a thin black border on the left handside and along the top, 1 pixel wide. It's black. Remove that and try again.

Nodes not appearing

So I'm trying to get a Node in xcode to appear, but it doesnt... here's the code.
import SpriteKit
import GameplayKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
let levelLabelNode = SKLabelNode(fontNamed: "Arial")
levelLabelNode.text = "Level"
levelLabelNode.fontSize = 30
levelLabelNode.fontColor = SKColor.green
levelLabelNode.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height*0.75)
self.addChild(levelLabelNode)
}
}
This had me stuck for a while. The coordinate system of the programme (assuming you are running from the default) has point (0, 0) at the centre of the screen. self.frame.size.width refers to the entire width of the screen. Therefore, positioning a node at self.frame.size.width/2 would position a node at the rightmost edge of the screen. If you want to position your node centred horizontally and 3/4 up the screen try:
levelLabelNode.position = CGPoint(x: 0, y: self.frame.height/4)
Hope this helped!
Remember: The coordinate system starts with (0, 0) in the centre and self.frame.size.width is the entire width of the screen.

SKSpriteNode not scalling properly

I'm developing a small game using Swift & SpriteKit. When I add a SKSpriteNode for Restart button, it doesn't scale properly.
The size of Restart button is 100px in height and width. If I don't set scale , it covers the whole screen and make the screen appear white. I figured out that if I setScale to 0.005 only than it appears on screen, but not in proper size.
import Foundation
import SpriteKit
class EndScene: SKScene {
var restartBtn = SKSpriteNode()
override func didMoveToView(view: SKView) {
background()
restartGame()
}
func restartGame() {
restartBtn = SKSpriteNode(imageNamed: "restartBtn")
restartBtn.setScale(0.005)
restartBtn.position = CGPoint(x: self.size.width / 2, y: self.size.height / 4)
restartBtn.zPosition = 1
self.addChild(restartBtn)
}
func background() {
let bkg = SKSpriteNode(imageNamed: "Background")
bkg.size = self.frame.size
bkg.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2)
bkg.zPosition = -2
self.addChild(bkg)
}
}
Here is the output of this code,
Restart Button Output
UPDATE
I put scene!.scaleMode = .AspectFill right inside didMoveToView function and it helped in rendering the shape of the SpriteNode properly. But still I have to setScale(0.001) to make the size of Restart button fit in the screen. Can anyone assist me what line of code I'm still missing?
Instead of using .setScale try using restartBtn.size = CGSize(Width: 50, Height: 50)
This uses the Sprite Kit's resize formula.
I ran into this as well. It happened when I forgot to specify the size of the scene. Instead of calling initWithSize I just wrote init and the scene started to scale down all nodes by x1000. Nodes were visible, but they required a scale of 0.001

How to make objects move?

This is my code I wrote in Xcode using Sprite Kit, Swift. I'm trying to make a game like ComboQuest. The game consists of a moving bar that moves left and right trying to hit objects. As I'm trying to recreate that left and right movement here is my code:
func rightSprite(){
let actionR = SKAction.moveByX(0.001, y: 0, duration: 0.01)
Sprite.runAction(SKAction.repeatActionForever(actionR))
}
func leftSprite(){
let actionR = SKAction.moveByX(-0.001, y: 0, duration: 0.01)
Sprite.runAction(SKAction.repeatActionForever(actionR))
}
These two functions are then activate in the TouchesBegan override func, but there is a small flaw. When you touch the screen to change the direction there is not a complete reaction.
How would you guys code this?
First off, make sure you have a valid instance of a SKSpriteNode. It would be helpful to see more of your code to see where you are creating the bar sprite you would like to move. For example, below I created a red rectangle sprite.
let bar = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: 50, height: 10))
As far as your actions, you need to call them on your instance of a sprite. I used the same bar sprite from the example above. Also, since you are setting an action to repeat forever, you will need to remove that action to get it to stop. It appears you want the bar to move left and right. You can either remove all actions as I have done, or you could name your actions, and just remove a certain one. For simplicity, I just removed all actions.
func rightSprite(){
let actionR = SKAction.moveByX(0.001, y: 0, duration: 0.01)
bar.removeAllActions()
bar.runAction(SKAction.repeatActionForever(actionR))
}
func leftSprite(){
let actionL = SKAction.moveByX(-0.001, y: 0, duration: 0.01)
bar.removeAllActions()
bar.runAction(SKAction.repeatActionForever(actionL))
}
Take a look a this :
override func didMoveToView(view: SKView) {
let sprite = SKSpriteNode(color: UIColor.purpleColor(), size: CGSize(width: 20, height:50))
var startPoint:CGPoint = CGPoint(x: 100, y: CGRectGetMidY(frame))
var endPoint:CGPoint = CGPoint(x: 300, y: CGRectGetMidY(frame))
let moveLeft = SKAction.moveTo(endPoint, duration:3)
let moveRight = SKAction.moveTo(startPoint, duration:3)
let sequence = SKAction.sequence([moveLeft,moveRight])
sprite.position = startPoint
addChild(sprite)
sprite.runAction(SKAction.repeatActionForever(sequence), withKey:"moving")
}
I assume that your scene and view are initialized and sized correctly (eg that you done something like this scene.size = skView.bounds.size ) so when you try this example, sprite will show up on screen (instead of possible off-screen because you probably loading a scene from a .sks file).
IMO this is the natural way when using SKAction to move a sprite from point A to point B continuously (like from a Combo Quest) and that is:
Create starting and ending point
Make separate actions for moving sprite left and right
Make a sequence to run those two actions one after another
Repeat that action forever
Run that action with key to give your self a way to stop an action
When you want to stop action, you should do something like this:
if(sprite.actionForKey("moving") != nil){
sprite.removeActionForKey("moving")
}

Swift - Trouble with SKAction sequence

I'm trying to move my background image down and then after a 3 second delay, move it back up the screen. And I want this to occur forever.
It slides down the screen perfectly fine, but then nothing else happens. Can anyone see what I'm doing wrong here?
override func didMoveToView(view: SKView) {
background.anchorPoint = CGPoint(x: 0, y: 0)
background.size = CGSize(width: frame.size.width, height: frame.size.height)
background.name = "bg"
addChild(background)
let moveBG1 = SKAction.moveToY(-(size.height), duration: 3.0)
let moveBGback = SKAction.moveToY(size.height, duration: 3.0)
runAction(SKAction.repeatActionForever(
SKAction.sequence([
SKAction.runAction(moveBG1, onChildWithName: "bg"),
SKAction.waitForDuration(3.0),
SKAction.runAction(moveBGback, onChildWithName: "bg")
])
))
According with your anchorPoint, the first action is correct. As nickfalk write to you, the second action must to be:
let moveBGback = SKAction.moveToY(0, duration: 3.0)
if you want to see your BG come back, so you have wrong the Y position, otherwise your BG is putted at the TOP of the screen (so not visible)

Resources