I'm working on a project, and SKNodes aren't resizing dynamically based on device size.
Example:
I'd like what happens on the first image to happen in the second.
Is there anything to make this happen automatically?
Current sizing for image shown:
background.position = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
background.size = CGSize(width: background.size.width / 5.5, height: background.size.height / 5.5)
GameViewController:
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = false
skView.showsNodeCount = false
let scene = GameScene(size: skView.bounds.size)
scene.controller = self
scene.size = skView.bounds.size
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return .AllButUpsideDown
} else {
return .All
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
If you want your whole scene to resize when the game is presented on device with a larger screen you just need to open GameViewController.swift and make sure you are using AspectFill
scene.scaleMode = .AspectFill
Related
I'm pretty new to Swift and I'm having some trouble implementing a leaderboard into my game.
So far, I'm able to authenticate local player and set up leaderboard in iTunes Connect.
However, I'm unable to display the leaderboard itself, if I run the below code, it will abort when I click on GK Leaderboard button in SKScene. So, the question is how can I display the GK leaderboard from SKScene? Thanks!
GameViewController.swift
import SpriteKit
import GameKit
class GameViewController: UIViewController, GKGameCenterControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let scene = SceneMenu(size: view.frame.size)
scene.scaleMode = .aspectFill
scene.backgroundColor = .white
let view = view as! SKView
view.presentScene(scene)
view.showsFPS = true
view.showsNodeCount = true
authenticateLocalPlayer()
}
func authenticateLocalPlayer() {
GKLocalPlayer.local.authenticateHandler = { viewController, error in
}
}
func showLeaderboard() {
let gcVC = GKGameCenterViewController(leaderboardID: "com.generic.leaderboard", playerScope: .global, timeScope: .allTime)
gcVC.gameCenterDelegate = self
present(gcVC, animated: true)
}
func gameCenterViewControllerDidFinish(_ gameCenterViewController: GKGameCenterViewController) {
gameCenterViewController.dismiss(animated: true)
}
}
SceneMenu.swift
import SpriteKit
import GameKit
class SceneMenu: SKScene {
override init(size: CGSize) {
super.init(size: size)
let btnGK = SKLabelNode(text: "GameKit")
btnGK.name = "btn_gk"
btnGK.fontSize = 20
btnGK.fontColor = SKColor.blue
btnGK.fontName = "Avenir"
btnGK.position = CGPoint(x: size.width / 2, y: size.height / 2)
addChild(btnGK)
let btnLeaderboard = SKLabelNode(text: "GK Leaderboard")
btnLeaderboard.name = "btn_leaderboard"
btnLeaderboard.fontSize = 20
btnLeaderboard.fontColor = SKColor.blue
btnLeaderboard.fontName = "Avenir"
btnLeaderboard.position = CGPoint(x: size.width / 2, y: size.height / 2 - 50)
addChild(btnLeaderboard)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = touch.location(in: self)
let action = atPoint(location)
switch action.name {
case "btn_gk":
print("btn_gk")
GKLeaderboard.submitScore(10, context: 0, player: GKLocalPlayer.local, leaderboardIDs: ["com.generic.leaderboard"]) { _ in }
case "btn_leaderboard":
print("btn_leaderboard")
GameViewController().showLeaderboard()
default:
print("nothing")
}
}
}
}
I can’t provide any code right now but what you really should be doing is using something like UIKit to create a UIView for the leader board and then embed that into a SKScene.
There is an interface something like SKView that is backed by a UIView which makes this fairly easy to do.
Keep Sprite Kit for the game stuff. Use UIKit for the UI stuff. 😃
I have this code in my GameScene swift file:
var background = SKSpriteNode(imageNamed: "background")
let blockImage = SKTexture(imageNamed: "block")
let blockSize = CGSize(width: 64, height: 64)
override func didMove(to view: SKView) {
setUpGame()
}
func setUpGame(){
background.position = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
addChild(background)
let block = SKSpriteNode(texture: blockImage, size: blockSize)
block.position.x = block.frame.width/2
block.position.y = frame.height - block.frame.height/2
addChild(block)
}
This is my code in my GameController file:
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
let scene = GameScene(size: self.view.bounds.size)
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
// added to see physics body
view.showsPhysics = true
}
}
why does it take multiple runs for my block node to appear on the simulator except for my background? After the block finally show, it will continue to show after every run until I edit my code. Ive tried removing my background node just in case that might be the issue, but it didn't change anything
Somebody told me in one of my other questions that SpriteKit was easier than UI. I searched online on how to get started with SpriteKit, and I got this: https://www.raywenderlich.com/145318/spritekit-swift-3-tutorial-beginners. I put the images in and everything, I put this code in:
import SpriteKit
class GameScene: SKScene {
// 1
let player = SKSpriteNode(imageNamed: "player")
override func didMove(to view: SKView) {
// 2
backgroundColor = SKColor.white
// 3
player.position = CGPoint(x: size.width * 0.1, y: size.height * 0.5)
// 4
addChild(player)
}
}
(the code they told me to put in), and when I run it, I just see a blank screen. On the tutorial, it had a ninja, but mine is just a blank screen.
Can anyone help with this?
if the screen is white try this :
import SpriteKit
class GameScene: SKScene {
// 1
var player = SKSpriteNode()
override func didMove(to view: SKView) {
// 2
backgroundColor = SKColor.white
// 3
let image = UIImage(named: "player")
let texture = SKTexture(image: image!)
player = SKSpriteNode(texture: texture)
player.position = CGPoint(x: size.width * 0.1, y: size.height * 0.5)
// 4
addChild(player)
}
}
If the screen not white : make sure the scene presented correctly .
If you have the GameScene.sks :
In GameViewController :
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
let scene = SKScene(fileNamed: "GameScene")
scene.scaleMode = .aspectFill
view.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
If you don't have GameScene.sks File
In GameViewController :
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
let scene = GameScene(size : view.frame.size)
scene.scaleMode = .aspectFill
view.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
I would like to create a main menu for my game in swift.
I am using the following code:
import SpriteKit
class menuScene: SKScene {
//Adding Start Button
let startButton = SKSpriteNode(imageNamed: "playButton")
override func didMove(to view: SKView) {
//Temporary Background
backgroundColor = SKColor.darkGray
//Start Button
startButton.position = CGPoint(x: size.width / 2, y: size.height / 2)
addChild(startButton)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self); //Finding location of touch
if atPoint(location) == startButton {
if let scene = GameScene(fileNamed: "GameScene") {
scene.scaleMode = .aspectFill
view!.presentScene(scene, transition: SKTransition.doorsOpenVertical(withDuration: 1))
}
}
}
}
}
When I run this however, My app crashes and highlights if atPoint(location) == startButton {. with "Thread 1, Breakpoint 1.1"
Im not entirely sure what this is but I hope someone can help. Thanks!
Custom SKViews
Let's say, like this M.W.E., you want a menu, a difficulty, and a game scene.
Then you can make a series of custom SKViews to transition between.
GameViewController
This code loads the menuScene:
override func viewDidLoad() {
super.viewDidLoad()
let menuScene = MenuScene(size: view.bounds.size)
let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
menuScene.scaleMode = .resizeFill
skView.presentScene(menuScene)
}
MenuScene
class MenuScene: SKScene {
let playButton = SKLabelNode()
override init(size: CGSize) {
super.init(size: size)
backgroundColor = SKColor.white
playButton.fontColor = SKColor.black
playButton.text = "play"
playButton.position = CGPoint(x: size.width / 2, y: size.height / 2)
addChild(playButton)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.location(in: self)
if playButton.contains(touchLocation) {
let reveal = SKTransition.doorsOpenVertical(withDuration: 0.5)
let difficultyScene = DifficultyScene(size: self.size)
self.view?.presentScene(difficultyScene, transition: reveal)
}
}
}
DifficultyScene
class DifficultyScene: SKScene {
let easyButton = SKLabelNode()
let hardButton = SKLabelNode()
let menuButton = SKLabelNode()
override init(size: CGSize) {
super.init(size: size)
backgroundColor = SKColor.white
easyButton.fontColor = SKColor.black
easyButton.text = "easy"
hardButton.fontColor = SKColor.black
hardButton.text = "hard"
menuButton.fontColor = SKColor.black
menuButton.text = "menu"
easyButton.position = CGPoint(x: size.width / 2, y: size.height / 2)
hardButton.position = CGPoint(x: size.width / 2, y: size.height / 2 - easyButton.fontSize * 2)
menuButton.position = CGPoint(x: size.width / 4 * 3, y: size.height / 4)
addChild(easyButton)
addChild(hardButton)
addChild(menuButton)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.location(in: self)
if easyButton.contains(touchLocation) {
let reveal = SKTransition.doorsOpenVertical(withDuration: 0.5)
let gameScene = GameScene(size: self.size, difficulty: easyButton.text!)
self.view?.presentScene(gameScene, transition: reveal)
}
if hardButton.contains(touchLocation) {
let reveal = SKTransition.doorsOpenVertical(withDuration: 0.5)
let gameScene = GameScene(size: self.size, difficulty: hardButton.text!)
self.view?.presentScene(gameScene, transition: reveal)
}
if menuButton.contains(touchLocation){
let reveal = SKTransition.doorsOpenVertical(withDuration: 0.5)
let menuScene = MenuScene(size: self.size)
self.view?.presentScene(menuScene, transition: reveal)
}
}
}
GameScene
add this to your GameScene:
init(size: CGSize, difficulty: String) {
super.init(size: size)
gameDifficulty = difficulty
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
Storyboards
Alternatively, you can use Storyboards. In the M.W.E. for another S.O. question they have a basic "menu" set up.
In your case, what you would do is:
go to Main.storyboard.
on the right-hand tool bar, find view controller
drag view-controller into Main.storyboard
click on the new view-controller
click - on the right-hand tool bar - the identity inspector (looks like a business card)
change Class to GameViewController
click on view within the hierarchy on the left (under the new view controller)
click the identity inspector
change class to SKView
click on the original view controller
click on the identity inspector
change class to UIViewController
click on the view within the original UIViewController
click on identity inspector
change class to UIView
find button at the bottom of the right-hand side tool bar
drag it onto the first view
right click drag from the button to the second view
on the pop-up menu, under action segue, click show
right click drag from the button up, add horizontally center constraints
right click drag from the button to the right, add vertically center constraints
Images
In GameViewController
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidLayoutSubviews() {
if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
// Configure the view.
let skView = self.view as SKView
var boo = Bool();
boo = true;
skView.showsFPS = boo;
skView.showsNodeCount = boo;
skView.showsPhysics = boo;
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
}
And in didMoveToView
var hero = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: 40, height: 40));
let hero_body = SKPhysicsBody(rectangleOfSize: hero.size);
hero.position = CGPoint(x:self.frame.size.width/2, y:50);
self.addChild(hero)
I dont understand how the position work.. when the Y is 50, the rectangle is not showing. Before in xcode 5 with objective-c in order the node to be in bottom of the screen I would do
-self.frame.size.height/2 + hero.size.height/2
But in here this doesn't work
The comment is right. -self.frame.size.height/2 + hero.size.height/2 worked when your anchor point was CGPointMake(0.5f,0.5f); It seems that in your case the anchor point was never changed from (0,0). To change it, use the self.anchorPoint = CGPointMake(0.5f, 0.5f); method in your scene.