Swift: How to fill view with a SK Sprite Node? - ios

I am trying to learn Swift by creating my own game (app), but I am having a problem.
I have a SKSpriteNode which I use as the background for the game. It's an image I've made. My problem is that my background won't fill the view so I get these grey bars outside of the Node.
What is wrong in my code?
override func didMoveToView(view: SKView) {
/* Setup your scene here */
Hintergrund = SKSpriteNode(imageNamed: "PenaltyLocker_BG1")
Hintergrund.size = CGSize(width: view.frame.width, height: view.frame.height)
Hintergrund.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2)
Hintergrund.zPosition = 1
Hintergrund.name = "Hintergrund"
addChild(Hintergrund)
Now when I start the simulator for iPhone it looks like this: http://imgur.com/a/mBOWn

Change to use the size of the SKScene.
self.scene.size.width / self.scene.size.height
Hintergrund.size = CGSize(width: self.scene.size.width, height: self.scene.size.height)
Hintergrund.position = CGPoint(x: self.scene.size.width/2, y: self.scene.size.height/2)
You can also check this tutorial for more info.

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.

How to create a physics body for an SKSpriteNode with an interior in Sprite Kit (Swift)

I am currently making an iOS game in which a ball must bounce within a frame defined by the below image:
The game relies on the below method to automatically create and assign a physics body to the frame surrounding the game.
frame.physicsBody = SKPhysicsBody(texture: frameTexture, size: frame.size)
This code, however, assigns a body that encompasses the outside of the image, rather than the interior, and thus treats the blank interior as a solid object. This, in turn, means that the ball cannot be inside the frame and is forced off the screen immediately after being spawned.
Is there any way to give a physics body an interior?
Another post here: SpriteKit SKPhysicsBody with Inner Edges aims to do something similar, but does not involve automatic wrapping around a texture (hence the new question)
You can use init(edgeLoopFrom:) initializer to achieve inner edge friction. you can use this code below:
override func didMove(to view: SKView) {
//Setup scene's physics body (setup the walls)
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
let back = SKSpriteNode(imageNamed: "1")
back.position = CGPoint(x: frame.midX, y: frame.midY)
back.size = CGSize(width: 500, height: 600)
back.zPosition = -3
let rect = CGRect(origin: CGPoint(x: -back.size.width/2, y: -back.size.height/2), size: back.size)
back.physicsBody = SKPhysicsBody(edgeLoopFrom: rect)
addChild(back)
//Add Red ball "inside" the back sprite
let red = SKShapeNode(circleOfRadius: 20)
red.fillColor = .red
red.strokeColor = .clear
red.position = back.position
red.physicsBody = SKPhysicsBody(circleOfRadius: 20)
red.physicsBody?.restitution = 1
red.physicsBody?.friction = 0
red.zPosition = 1
red.physicsBody?.affectedByGravity = false
addChild(red)
red.physicsBody?.applyImpulse(CGVector(dx: 20, dy: 15))
}
please follow this Question and have a look to the answer given below.
i am providing a screenshot of my project

Spritekit - Spritenode in front of Tableview

I have this tableview that is added to my scene by a subclass and it is added like so to the scene
override func didMove(to view: SKView) {
gameTableView.frame = CGRect(x:14,y:70, width: frame.maxX / 1.08, height: frame.maxY/0.9)
self.scene?.view?.addSubview(gameTableView)
gameTableView.reloadData()
universalBackButton = SKSpriteNode(color: SKColor.orange, size: CGSize(width: 100, height: 100))
universalBackButton.position = CGPoint(x:frame.midX - universalBackButton.size.width * 0.7, y: -frame.maxY + universalBackButton.size.height)
universalBackButton.zPosition = 100001
self.scene?.addChild(universalBackButton)
itemShopMenu = SKSpriteNode(color: SKColor.orange, size: CGSize(width: 75, height: 50))
itemShopMenu.position = CGPoint(x:frame.midX + universalBackButton.size.width * 0.7, y: -frame.maxY + itemShopMenu.size.height)
itemShopMenu.zPosition = 100001
self.scene?.addChild(itemShopMenu)
}
But when I go to add buttons so I can leave the tableview scene they're behind the tableview and not in front of it. I have had little to no experience using subviews with scenes and don't know how to get the spritenodes to be in front of the tableview instead of behind it so they can be tapped to execute a function. is there anyway I can add the spritenodes in front of the tableview so they can be pressed?
SpriteKit is optimized for layering sprites within an SKView - not for placing above other UIViews. Why not achieve the same effect by creating UI buttons and layering them on top instead of using sprites as buttons?
let universalBackButton = UIButton()...

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

SKEffectNode, SpriteKit invert color in Swift

I want to invert the color from the part of the HelloLable which is outside of the boxSprite. I know that it is possible with SKEffectNode but I don't know how.
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
let box = SKSpriteNode()
box.position = CGPoint(x: size.width/2-100, y: size.height/2)
box.color = UIColor.blackColor()
box.size = CGSize(width: 200, height: 200)
addChild(box)
let HelloLable = SKLabelNode()
HelloLable.text = "Hello"
HelloLable.position = CGPoint(x: size.width/2, y: size.height/2)
HelloLable.fontColor = UIColor.whiteColor()
HelloLable.fontSize = 50
addChild(HelloLable)
}
If I understand you correctly, you'd like to make something like this:
I don't think there is a standard solution to do this (maybe you could try blending modes or shaders).
Maybe the easiest solution could be to make 2 labels, one white in the box, and one black under the box, with similar properties, and clip the white one with the box.

Resources