im having a trouble in scene transition at spritekit application written on swift 4
I have a gameover.swift file declaring EndScene class:
import Foundation
import SpriteKit
class EndScene: SKScene, SKPhysicsContactDelegate {
var RestartButton : UIButton!
var HighScore : Int!
var HighScoreLabel : UILabel!
var GameOverLabel : UILabel!
override func didMove(to view: SKView) {
self.scene?.backgroundColor = SKColor.white
RestartButton = UIButton(frame: CGRect(x:0, y:0, width: view.frame.size.width/3
, height: 30))
RestartButton.titleLabel?.adjustsFontSizeToFitWidth = true
RestartButton.center = CGPoint(x: view.frame.size.width/2 , y: view.frame.size.height/1.5)
RestartButton.setTitle("restart", for: UIControlState.normal)
RestartButton.showsTouchWhenHighlighted = true
RestartButton.setTitleColor(SKColor.black, for: UIControlState.normal)
RestartButton.addTarget(self, action: #selector(EndScene.Restart), for: UIControlEvents.touchUpInside)
self.view?.addSubview(RestartButton)
GameOverLabel = UILabel (frame: CGRect(x:0, y:0, width: view.frame.size.width/3.8, height: 30))
GameOverLabel.center = CGPoint(x: view.frame.size.width/2 , y: view.frame.size.height/10)
GameOverLabel.textColor = SKColor.red
GameOverLabel.text = "Game Over"
self.view?.addSubview(GameOverLabel)
}
func Restart(){
RestartButton.removeFromSuperview()
GameOverLabel.removeFromSuperview()
self.removeAllChildren()
self.view?.presentScene(GameScene(), transition: SKTransition.reveal(with: .up, duration: 0.3))
}
}
GameScene is a class declared in GameScene.swift file. It contains declaration of class describing game process.
The problem is:
when the game starts from GameScene it works correct (all objects are drown and physics work) but when i restart game from EndScene it works incorrect (1 object is drown from time to time but every other objects aren't drown, even background color isn't drown).
What in general can be with it?
You shouldn't just create a GameScene by calling its parameterless initializer. Look at how GameScene is presented in the generated GameViewController.swift file. You will see that it calls (fileNamed:) initializer.
So change this line:
self.view?.presentScene(GameScene(), transition: SKTransition.reveal(with: .up, duration: 0.3))
To
self.view?.presentScene(GameScene(fileNamed: "GameScene"), transition: SKTransition.reveal(with: .up, duration: 0.3))
Related
I'm relatively new to learning the Swift language so I don't know what I'm missing, but I can't seem to see why this would not be working. My goal is to add a background to my scene using SpriteKit, but whenever I try to add one, playgrounds takes a second and then displays an error that says:
There was a problem running this playground.
I already have a scene set up using SpriteKit so when this piece of code is not present I do get a black screen, but for some reason everything seems to fail when this segment is in:
let bg = SKSpriteNode(texture: SKTexture(image: #imageLiteral(resourceName: "IMG_0483.jpg")))
bg.setScale(2.0)
bg.zPosition = -10
bg.position = CGPoint(x: frame.midX, y: frame.midY)
addChild(bg)
Here is the larger context of the script:
import SpriteKit
public class GameScene: SKScene {
var player: SKSpriteNode!
public override func didMove(to view: SKView) {
// Backround
let bg = SKSpriteNode(texture: SKTexture(image: #imageLiteral(resourceName: "IMG_0483.jpg")))
bg.setScale(2.0)
bg.zPosition = -10
bg.position = CGPoint(x: frame.midX, y: frame.midY)
addChild(bg)
}
}
and here is my main where I'm calling it
import UIKit
import SpriteKit
import PlaygroundSupport
let skView = SKView(frame: .zero)
let gameScene = GameScene(size: UIScreen.main.bounds.size)
gameScene.scaleMode = .aspectFill
skView.presentScene(gameScene)
PlaygroundPage.current.liveView = skView
PlaygroundPage.current.wantsFullScreenLiveView = true
Try this:
let bg = SKSpriteNode(imageNamed: "image.jpg")
bg.setScale(2.0)
bg.zPosition = -10
bg.position = CGPoint(x: frame.midX, y: frame.midY)
addChild(bg)
Where you display the scene:
let skView = SKView(frame: UIScreen.main.bounds)
let gameScene = GameScene(fileNamed: "GameScene")
gameScene?.scaleMode = .aspectFill
skView.presentScene(gameScene)
PlaygroundPage.current.liveView = skView
I am creating SKSpriteNode Programmatically with its own SKSpriteNode class. I am wondering how I can add this SKSpriteNode to the scene. My app keeps crashing when I try to addChild() in the didMove() function of my Scene Class.
class ChaosScene: SKScene {
var dragonNode: Dragon!
override func didMove(to view: SKView) {
dragonNode.createDragon()
addChild(dragonNode)
}
}
class Dragon: SKSpriteNode {
var dragonNode: SKSpriteNode!
func createDragon() {
// Create Dragon
dragonNode = SKSpriteNode(imageNamed: "dragon_2_fly_001")
dragonNode.name = "dragon"
dragonNode.physicsBody = SKPhysicsBody(circleOfRadius: 50)
let actionMove = SKAction.move(
to: CGPoint(x: -1000 ,y: dragonNode.position.y),
duration: 2.0)
dragonNode.run(actionMove)
}
}
you're not actually creating anything.
class ChaosScene: SKScene {
var dragonNode: Dragon!
override func didMove(to view: SKView) {
dragonNode = Dragon()
addChild(dragonNode)
}
}
you have to initialize your SpriteNodes before you can add them to the scene
class Dragon: SKSpriteNode {
var dragonNode: SKSpriteNode!
init() {
super.init(texture: nil, color: .clear, size: CGSize.zero)
// Create Dragon
dragonNode = SKSpriteNode(imageNamed: "dragon_2_fly_001")
dragonNode.name = "dragon"
dragonNode.physicsBody = SKPhysicsBody(circleOfRadius: 50)
addChild(dragonNode)
let actionMove = SKAction.move(to: CGPoint(x: -1000 ,y: dragonNode.position.y), duration: 2.0)
dragonNode.run(actionMove)
}
}
When the view is presented, I would like the image named "Player" (set) which is in my images.xcassets to show on the scene.
Currently the scene just loads up blue. Not sure why, as even when adding a color to change the image color did nothing.
import SpriteKit
class CharacterScene: SKScene {
var Circle = SKSpriteNode(imageNamed: "Player")
override func didMoveToView(view: SKView) {
backgroundColor = SKColor.blackColor()
Circle.size = CGSize(width: 40, height: 40)
Circle.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
Circle.color = SKColor.brownColor()
self.addChild(Circle)
}
}
You need to initialize the size of CharacterScene before presenting it on the screen. Here you go:
self.scene!.view!.presentScene(CharacterScene(size: self.scene!.size), transition: SKTransition.pushWithDirection(SKTransitionDirection.Up, duration: 0.3))
When I try to run an action on a sprite I've set a constant for in didMoveToView, I use the same name for it in the touchesBegan function and get a "use of unresolved identifier: "player" error. I have another game where I so the exact same thing and it runs perfectly. Need help! Here is my code:
import SpriteKit
class GameScene: SKScene {
var movingGround : MCTGround!
var fruitGenerator : MCTFruitGen!
var cloudGenerator: MCTCloudGen!
var isStarted = false
override func didMoveToView(view: SKView) {
let player = SKSpriteNode(imageNamed: "koala_idle")
player.position = CGPointMake(95, 150)
addChild(player)
backgroundColor = UIColor(red: 159.0/255.0, green: 201.0/255.0, blue: 244.0/255.0, alpha: 1.0)
movingGround = MCTGround(size: CGSizeMake(view.frame.width, 20))
movingGround.position = CGPointMake(0, view.frame.size.height / 4)
addChild(movingGround)
fruitGenerator = MCTFruitGen(color: UIColor.clearColor(), size: view.frame.size)
fruitGenerator.position = view.center
addChild(fruitGenerator)
let frames = [
SKTexture(imageNamed: "koala_idle"),
SKTexture(imageNamed: "koala_walk01"),
SKTexture(imageNamed: "koala_walk02"),
]
let duration = 1.5 + drand48() * 1.0
let move = SKAction.animateWithTextures(frames, timePerFrame:0.10)
let wait = SKAction.waitForDuration(duration)
let rest = SKAction.setTexture(frames[0])
let sequence = SKAction.sequence([move, rest])
player.runAction(SKAction.repeatActionForever(sequence))
cloudGenerator = MCTCloudGen(color: UIColor.clearColor(), size: view.frame.size)
cloudGenerator.position = view.center
addChild(cloudGenerator)
cloudGenerator.populate(7)
cloudGenerator.startGeneratingWithSpawnTime(1)
}
func start() {
isStarted = true
cloudGenerator.startGeneratingWithSpawnTime(1)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
jumpPlayer()
movingGround.start()
fruitGenerator.startGeneratingFruitEvery(1)
}
override func update(currentTime: CFTimeInterval) {
}
func jumpPlayer() {
let jumpUpAction = SKAction.moveByX(0, y: 40, duration: 0.5)
let jumpDownAction = SKAction.moveByX(0, y: -40, duration: 0.5)
let jumpSequence = SKAction.sequence([jumpUpAction, jumpDownAction])
player.runAction(jumpSequence) // This is where my error is
}
}
Make player a class scope variable (property). Declare it not in a function, but a level above.
var player: SKSpriteNode?
override func didMoveToView(view: SKView) {
player = SKSpriteNode ...
then access it via player?. The safest way.
Your problem is that you are declaring player inside didMoveToView. This makes it private to the didMoveToView method. All you need to do is move let player = SKSpriteNode(imageNamed: "koala_idle") to where you declare movingGround and the other variables with it.
The beginning your code should look like this:
import SpriteKit
class GameScene: SKScene {
var movingGround : MCTGround!
var fruitGenerator : MCTFruitGen!
var cloudGenerator: MCTCloudGen!
let player = SKSpriteNode(imageNamed: "koala_idle")
var isStarted = false
override func didMoveToView(view: SKView) {
player.position = CGPointMake(95, 150)
addChild(player)
Go to File Inspector (right click on the file referenced in the error and select Show File Inspector). In Target Membership make sure your actual app is selected.
In my case only the Test modules were selected.
So as far as I can tell (I'm new to all this), the referenced file was hidden/unregistered with the ViewController.
How do you make a sprite rock back and forth constantly like a boat?
Heres the code i wrote:
import UIKit
import SpriteKit
let boat = SKSpriteNode(imageNamed: "boat_floor")
var rotationVal = CGFloat(-1)
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
backgroundColor = UIColor.whiteColor()
boat.size = CGSize(width: self.frame.size.width, height: self.frame.size.width)
boat.position = CGPoint(x: self.frame.size.width/2, y: 0)
boat.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "boat_floor"), size: boat.size)
boat.physicsBody?.dynamic = false
boat.alpha = 1
self.addChild(boat)
ChangeAngle()
NSTimer.scheduledTimerWithTimeInterval(3, target: self, selector: Selector("ChangeAngle"), userInfo: nil, repeats: true)
}
func ChangeAngle(){
let action = SKAction.rotateByAngle(rotationVal, duration:30)
if rotationVal < 0 {
rotationVal = CGFloat(M_PI)
boat.runAction(action)
}
else if rotationVal > 0 {
rotationVal = -CGFloat(M_PI)
boat.runAction(action)
}
print(rotationVal)
}
}
If I understand you correctly, you can do it like this (just copy&paste the code to see how it works):
import UIKit
import SpriteKit
let boat = SKSpriteNode(color: SKColor.greenColor(), size:CGSize(width: 200, height: 80))
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
backgroundColor = UIColor.whiteColor()
boat.position = CGPoint(x: self.frame.size.width/2, y: 100)
boat.alpha = 1
self.addChild(boat)
let rotate = SKAction.rotateByAngle(-0.6, duration:4)
let sequence = SKAction.repeatActionForever(SKAction.sequence([rotate, rotate.reversedAction()]))
let complete = SKAction.sequence([SKAction.rotateByAngle(0.3, duration:2), sequence])
boat.runAction(complete, withKey:"someKey")
}
}
Using NSTimer is generally bad idea in SpriteKit because it don't respect node's, scene's or view's paused state.