I am using xCode 6 beta 4 to build a game. In iOS 8 , everything works fine but in iOS 7.0 simulator, the player object isn't displayed.
EDIT: Thanks to the comments, I changed background.zPosition to -100 and now I can see the player object. It is still weird why this wasn't required at iOS 8.0 .
My Code:
class PlayScene : SKScene{
let background = SKSpriteNode(imageNamed: "background1")
let player = SKSpriteNode(imageNamed: "ball")
var ForceX = CGVectorMake(250, 0)
let Gravity = CGVectorMake(0, -15)
var bgVelocity = CGFloat(0)
var maxBgY = CGFloat(0)
var origRunningBGPosition = CGFloat(0)
var isJumping=false
var startedJump = false
override func didMoveToView(view: SKView!) {
self.player.position=CGPointMake(150, 150)
self.player.physicsBody=SKPhysicsBody(rectangleOfSize: self.player.size)
self.player.physicsBody.affectedByGravity=false
self.player.physicsBody.mass=CGFloat(1)
self.background.size=CGSizeMake(self.frame.width, self.frame.height*3)
self.background.anchorPoint=CGPointMake(0, 0)
self.background.position=CGPointMake(0, 0)
bgVelocity+=2.5
self.maxBgY=self.background.size.height-self.frame.height
maxBgY*=CGFloat(-1)
self.origRunningBGPosition=CGRectGetMinY(self.frame)
self.addChild(self.background)
self.addChild(self.player)
}
What I found out is that when I don't use background , I can see the player, and I can't understand why it is happening and why in iOS 7.0 only?
When you define your skView in your viewDidLoad in your viewController that holds the skScenes put this and everything will act as it use to
skView.ignoresSiblingOrder = NO;
Related
I'm making a game using spritekit. I'm using a joystick in my game which is declared in a separate SKNode class called 'joystick'.
In this class, I add a UIGesturerecongiser to the view from the class. In the constructor method, one of the parameters is a SKView which is passed from the game scene.
Constructor Method in Joystick class:
init(colour: UIColor, position: CGPoint, skView: SKView) {
//constructor method
self.colour = colour;
self.parentposition = position;
self.view = skView;
super.init();
//setup properties
//user interaction is needed to allow touches to be detected
self.isUserInteractionEnabled = true;
//setup
setup();
}
In the games scene, I initialise the class like this:
class GameScene: SKScene {
func setupJoyStick() {
let joystick1 = Joystick(colour: UIColor.red, position: CGPoint(x: screenwidth / 3, y: screenwidth / 10 * 1.5), skView: self.view!)
self.addChild(joystick1)
}
}
Error:
When I run my app, I get an error because the 'self.view' return nil and because it is forced to unwrap, it causes a fatal error.
Where View is defined:
if let scene = GKScene(fileNamed: "GameScene") {
// Get the SKScene from the loaded GKScene
if let sceneNode = scene.rootNode as! GameScene? {
// Copy gameplay related content over to the scene
sceneNode.entities = scene.entities
sceneNode.graphs = scene.graphs
// Set the scale mode to scale to fit the window
sceneNode.scaleMode = .aspectFill
sceneNode.size = view.bounds.size
// Present the scene
if let view = self.view as! SKView? {
view.presentScene(sceneNode)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
}
Additional Info:
I'm using:
Xcode 9.2
Swift 4
Sprite Kit
I'm testing it on:
Iphone 6s
Latest version of IOS (non-beta), latest public release.
Can someone please explain why this is happening and how to fix this problem.
Thanks in advance, any help would be appreciated.
Looks like you're trying to get view property of SKScene but it's nil. It's because you didn't presented SKScene.
Unfortunately I haven't worked with SpriteKit but you can find info about view property here and about SKScene here.
I'm testing the possibility of the tile editor that comes with Xcode 8 (8.2.2). And I've created a PacMan-like map as shown above. There's a game character at the top-left corner in a rectangle. I wonder if there's an easy way of making the game character staying inside the blue borders? So far, I've set a (red) wall to the left like the following through the scene editor. And I have the following lines of code.
struct PhysicsCategory {
static let None: UInt32 = 0
static let Player: UInt32 = 0b1 // 1
static let Edge: UInt32 = 0b10 // 2
static let Wall: UInt32 = 0b100 // 4
}
class GameScene: SKScene {
// MARK: - Variables
var background: SKTileMapNode! // background
var player: SKNode! // player
// MARK: - DidMove
override func didMove(to view: SKView) {
setupNodes()
}
func setupNodes() {
background = self.childNode(withName: "World") as! SKTileMapNode
background.physicsBody = SKPhysicsBody(edgeLoopFrom: background.frame)
background.physicsBody?.categoryBitMask = PhysicsCategory.Edge
let wall = self.childNode(withName: "Wall")
wall?.physicsBody = SKPhysicsBody(rectangleOf: (wall?.frame.size)!)
wall?.physicsBody?.isDynamic = false
wall?.physicsBody?.categoryBitMask = PhysicsCategory.Wall
player = self.childNode(withName: "Player")
player.physicsBody = SKPhysicsBody(circleOfRadius: 32)
player.physicsBody?.categoryBitMask = PhysicsCategory.Player
player.physicsBody?.collisionBitMask = 4
player.physicsBody?.allowsRotation = false
}
}
The user will get to control the player position with CoreMotion. For now, the game character does respect the left edge. But if the map gets complicated, I could end up placing a lot of walls here and there. And that kind of kills the fun as it could be time-consuming. So, again, is there a simplier way of making the game character collide the map borders?
Take a look at GameplayKit's pathfinding classes, specifically GKGridGraph and GKGridGraphNode which allow you to specify a graph that only has these kind of rectilinear paths.
There is a good tutorial from Apple here: https://developer.apple.com/library/content/documentation/General/Conceptual/GameplayKit_Guide/Pathfinding.html
And a demo app here: https://developer.apple.com/library/content/samplecode/Pathfinder_GameplayKit/Introduction/Intro.html#//apple_ref/doc/uid/TP40016461
I've added an SKView as a subview in my Sprite Kit game to display the game nodes and content.
let skView = SKView()
class GameViewController: UIViewController, CLLocationManagerDelegate {
self.view.addSubview(skView)
The SKView is added as a subview instead of the default way suggested in Sprite Kit projects (the commented code below), because I also have an MKMapView that is displayed behind the mostly transparent SKView, and otherwise the MapView would obscure the game scene.
//let skView = self.view as! SKView
The Game Scene is then presented on the SKView:
if let scene = GameScene(fileNamed:"GameScene") {
// Configure the view.
skView.allowsTransparency = true
skView.showsFPS = false
skView.showsNodeCount = false
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
scene.backgroundColor = .clearColor()
skView.presentScene(scene)
}
In the main Game Scene, I have a main worldnode, to which I add a bunch of character nodes in a separate function, which is called when the scene is presented (code below). This function also applies rotate and move actions to the character nodes. If I set up the SKView that presents the scene using the default Sprite Kit method (let skView = self.view as! SKView), this works perfectly, but if I add the presenting scene to the view controller as a subview (let skView = SKView() and self.view.addSubview(skView)), then the actions do not work properly - the character nodes twitch instead of rotating properly, and do not move at all.
Can anyone help me understand why the actions seem not to be functioning when the scene is presented on an SKView that is a subview of the view controller? (But function fine when the SKView is set as self.view as! SKView)? I've checked the nodes with hasActions() (they do), and everything seems to be in the proper view hierarchy, so I'm a bit stumped.
I'm running the latest iOS 9.0 beta, and Xcode 7.0 beta.
Thanks.
func moveCharacters() {
if characterDic.count > 0 {
for i in 1...characterDic.count {
if let characterKey = characterDic["P" + "\(i)"] {
let characterStatus = Int(characterKey["active"] as! NSNumber)
if characterStatus == 1 || characterStatus == 2 {
if worldNode.childNodeWithName("P" + "\(i)") != nil {
worldNode.childNodeWithName("P" + "\(i)")?.removeFromParent()
}
let characterXPos = CGFloat(characterDic["P" + "\(i)"]!["curX"] as! Double)
let characterYPos = CGFloat(characterDic["P" + "\(i)"]!["curY"] as! Double)
let characterTexture = SKTexture(imageNamed: "character1.png")
let character = SKSpriteNode(texture: characterTexture)
character.position = CGPoint(x: characterXPos, y: characterYPos)
character.xScale = 0.2
character.yScale = 0.2
worldNode.addChild(character)
/////////
let characterXDest = CGFloat(characterDic["P" + "\(i)"]!["destX"] as! Double)
let characterYDest = CGFloat(characterDic["P" + "\(i)"]!["destY"] as! Double)
let destLoc = CGPoint(x: characterXDest, y: characterYDest)
let distToGo = sqrt(pow((characterXDest - characterXPos),2) + pow((characterYDest - characterYPos),2))
let moveNode = SKAction.moveTo(destLoc, duration: Double(distToGo/50))
let angle = atan2(((destLoc.y - (character.position.y))), ((destLoc.x - (character.position.x))))
let Pi = CGFloat(M_PI)
let DegreesToRadians = Pi / 180
let rotate = SKAction.rotateToAngle(angle - 90 * DegreesToRadians, duration: 0)
character.runAction(rotate)
character.runAction(moveNode)
}
}
}
}
}
I am adding sklabelnodes and skspritenodes to the scene with these functions:
var levelnode = SKSpriteNode()
var labelLevel = SKLabelNode(fontNamed: "Courier-Bold")
func addlevels(){
var level = score + 1
if (level > 0){
sprite()
levelnode.position = CGPointMake(frame.size.width / 2.2, -frame.size.height/15.6 - frame.size.height/17.6)
levelnode.name = "1"
addChild(levelnode)
sklabel()
labelLevel.text = ("1")
labelLevel.position.x = levelnode.position.x - (levelnode.size.width/40)
labelLevel.position.y = levelnode.position.y - (levelnode.size.width/6)
labelLevel.name = "1"
addChild(labelLevel)
}
if (level > 1){
sprite()
levelnode.position = CGPointMake(frame.size.width / 1.42 - frame.size.width/100, -frame.size.height/10 - frame.size.height/17.6)
levelnode.name = "2"
addChild(levelnode)
sklabel()
labelLevel.text = ("2")
labelLevel.position.x = levelnode.position.x - (levelnode.size.width/40)
labelLevel.position.y = levelnode.position.y - (levelnode.size.width/6)
labelLevel.name = "2"
addChild(labelLevel)
}
// this goes on and on till level 25
}
func sprite(){
levelnode = SKSpriteNode(imageNamed: "levelnode")
levelnode.size.width = frame.size.width / 8
levelnode.size.height = levelnode.size.width
levelnode.zPosition = 1
}
func sklabel(){
labelLevel = SKLabelNode(fontNamed: "Courier-Bold")
labelLevel.zPosition = 2
labelLevel.fontColor = SKColor.blackColor()
labelLevel.fontSize = frame.size.height / 35
}
When I am changing the scene, the sprites and labels are removed from the willmovefromview function:
override func willMoveFromView(view: SKView) {
removeAllChildren()
}
but this is taking too slow if I compare it with other scenes where even more skspritenodes are added..
I think It has to do with the functions where I add the sprites and labels, but what is wrong about it?
EDIT:
the function that takes me back too the menu:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
errint = false
for touch: AnyObject in touches {
let location: CGPoint! = touch.locationInNode(self)
let nodeAtPoint = self.nodeAtPoint(location)
if (nodeAtPoint.name != nil) {
if nodeAtPoint.name == "menu" {
removeallAction()
removeAllChildren()
var scene1 = GameMenuScene(size: self.size)
scene1.button = self.button
scene1.button2 = self.button2
scene1.button3 = self.button3
scene1.viewController = self.viewController
let transition = SKTransition.moveInWithDirection(SKTransitionDirection.Left, duration: 0.75)
self.view?.presentScene(scene1, transition: transition)
}
}
}
}
Doesn't transitioning to another scene deallocate the current scene?
And if that scene is deallocated, then there's no need for the nodes and such to be removed...
Could you do me a favor, and transition out without removing the children and actions, then transition back in and see if it matters??
Anyway, speed is trivial if you're testing on the simulator... the simulator really only simulates opengl, the core of SpriteKit.
Please try it on your device.
BTW, I'm not sure of stuff but nobody seemed to have answered you so I tried...
EDIT:
HOLY MOTHER OF GOD WHY DIDN'T I SEE THE TIMESTAMP IT WAS ASKED TWO MONTHS AGO.
Too late now I guess... but to anybody reading this, don't answer questions at 2 am.
I am trying to make a mouse down event, but keep getting the error "Use of undeclared type 'NSEvent'" on the "override func mouseDown( theEvent: NSEvent!) { " line. After researching and trying different things, I still got nothing. Anyone had this problem before?
import UIKit
import SpriteKit
let BallCategoryName = "ball"
let MainBallCategoryName = "mainBall"
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
// 1. Create a physics body that borders the screen
let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
// 2. Set the friction of that physicsBody to 0
borderBody.friction = 0
// 3. Set physicsBody of scene to borderBody
self.physicsBody = borderBody
physicsWorld.gravity = CGVectorMake(0, 0)
let ball = childNodeWithName(BallCategoryName) as SKSpriteNode
var mainBall = childNodeWithName(MainBallCategoryName) as SKSpriteNode
ball.physicsBody!.applyImpulse(CGVectorMake(10, -10))
ball.physicsBody!.allowsRotation = false
ball.physicsBody!.friction = 0
ball.physicsBody!.restitution = 1
ball.physicsBody!.linearDamping = 0
ball.physicsBody!.angularDamping = 0
}
override func mouseDown( theEvent: NSEvent!) {
let action = SKAction.moveTo(
CGPoint(x:theEvent.locationInWindow.x,y:theEvent.locationInWindow.y),
duration:2
);
MainBallCategoryName.runAction(action)
}
}
iOS devices don't have mice, and iOS doesn't have an NSEvent class. It has a UIEvent class, but there's nothing special about a function named mouseDown on iOS. iOS events report touches, not mouse buttons.
If you copied this code from a tutorial, the tutorial was for OS X, not iOS. You should find an iOS tutorial instead.
In an OS X app you should not:
import UIKit
but instead use
import AppKit