Ios Simulator in Xcode 6 running at 0.0 fps - ios

I know other people have asked questions about slow ios simulators before. But my problem is not the the simulator is slow. It is that the simulator runs at 0.0 fps (according to the text at the bottom) and I can't test any of my code. I am very confused and any help would be appreciated. Don't have enough reputation to post an image. But at the bottom it says 3 nodes 0.0 fps.
UPDATE
I deleted the following code from my code and it started working like normal again.
while left {
var leftMove = SKAction.moveByX(1, y: 0, duration: 0.1)
person.runAction(leftMove)
}
while !left{
var rightMove = SKAction.moveByX(-1, y: 0, duration: 0.1)
person.runAction(rightMove)
}
that was taken from my update() method
here is the whole thing...
import SpriteKit
class GameScene: SKScene {
var person = SKSpriteNode(imageNamed: "guyLeft_1.png")
var left = true
override func didMoveToView(view: SKView) {
self.backgroundColor = SKColor.whiteColor()
var ground = SKShapeNode(rectOfSize: CGSizeMake(self.frame.size.width, self.frame.size.height * 0.2))
ground.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height * 0.1)
ground.fillColor = SKColor.blueColor()
self.addChild(ground)
person.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height * 0.2)
self.addChild(person)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
!left
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
while left {
var leftMove = SKAction.moveByX(1, y: 0, duration: 0.1)
person.runAction(leftMove)
}
while !left{
var rightMove = SKAction.moveByX(-1, y: 0, duration: 0.1)
person.runAction(rightMove)
}
}
}

It says 0fps because it is not able to render the scene just once.
Just change it to
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if left {
var leftMove = SKAction.moveByX(1, y: 0, duration: 0.1)
person.runAction(leftMove)
}
if !left { // or use an if-else construct
var rightMove = SKAction.moveByX(-1, y: 0, duration: 0.1)
person.runAction(rightMove)
}
}
There is really not much to explain here - the while just caused an infinite loop. If you have no break statements and the while body does not alter the evaluated condition left the program will be stuck forever inside the while loop.
Additionally:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
left = false // either
left = !left // or
}
The previous code just evaluates !left and ignores the result - effectively does nothing.

Related

Swift SpriteKit: Creating a realistic driving experience 2D

How would I go by creating a realistic driving experience?
I'm using iOS Swift 3 with SpriteKit using the functions applyForce to accelerate when I click the gas button and when braking I add friction to the physicsBody, also I can't seem to turn right, no idea on how to do it.
Right now for turning I'm splitting the screen using the left and right to turn but I'm using applyForce but its very bad because it turns when the car is stopped and in a very unrealistic way.
When I apply force its only to go up so if I do create a turning mechanism and I do a uturn the car will still go up.
Also side note: Multitouch doesn't work?
Any help? Thanks
override func didMove(to view: SKView) {
// Multi Touch
self.view?.isMultipleTouchEnabled = true
car.carNode.position = CGPoint(x: 0, y: 0)
car.carNode.physicsBody = SKPhysicsBody(rectangleOf: car.carNode.size)
car.carNode.physicsBody?.affectedByGravity = false
car.carNode.physicsBody?.angularDamping = 0.1
car.carNode.physicsBody?.linearDamping = 0.1
car.carNode.physicsBody?.friction = 0.1
car.carNode.physicsBody?.mass = 1
self.addChild(car.carNode)
// HUD Display
gas.gasButton.position = CGPoint(x: 300, y: -500)
self.addChild(gas.gasButton)
brake.brakeButton.position = CGPoint(x: 150, y: -500)
self.addChild(brake.brakeButton)
}
override func update(_ currentTime: TimeInterval) {
if touching {
car.carNode.physicsBody?.applyForce(CGVector(dx: 0, dy: 180))
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if location.x < self.frame.size.width / 2 {
// Left side of the screen
car.carNode.physicsBody?.applyForce(CGVector(dx: -100, dy: 0))
} else {
// Right side of the screen
car.carNode.physicsBody?.applyForce(CGVector(dx: 100, dy: 0))
}
// Gas Button
if (gas.gasButton.contains(location)) {
touching = true
}
// Brake Button
else if (brake.brakeButton.contains(location)) {
car.carNode.physicsBody?.friction = 1
}
}
}
Integration of the comment
for touch in touches {
let location = touch.location(in: self)
let velY = car.carNode.physicsBody?.velocity.dy
let factor:CGFloat = 100
let maxFactor:CGFloat = 300
//limit
let dxCalc = factor * velY > maxFactor ? maxFactor : factor * velY
if location.x < self.frame.size.width / 2 {
// Left side of the screen
car.carNode.physicsBody?.applyForce(CGVector(dx: -dxCalc, dy: 0))
} else {
// Right side of the screen
car.carNode.physicsBody?.applyForce(CGVector(dx: dxCalc, dy: 0))
}
// Gas Button
//etc
}
}

Simulate zero gravity style player movement

I am having a little trouble modelling the correct way to move my player node in the way
that I want.
This is my first foray into Spritekit and I have the basics up and running (I have a static background, added player node and have a playable bounds rectangle with bounds checking)
The way I have added my player movement is to track the beginning touch position and
store this in scene class scoped variable (Called beginningTouchPosition) and to also store the current touch position (Called currentTouchPosition).
I also track the players sprite node position (currentPlayerPosition)
What I do is onTouchesBegan I update 'beginningTouchPosition' and then within onTouchesMoved I update 'currentTouchPosition', this way I can know the direction the user wants his ship to move by getting the direction relative to the 'beginningTouchPosition' as he/she moves their finger around. Also the distance of 'currentTouchPosition' from 'beginningTouchPosition' determines how fast the ship moves.
I move the player in the update by creating a CGVector using the above points and using this with an SKAction.MoveBy call.
I did it this way as I wanted the user to be able to touch anywhere on the screen to be able to control movement.
How I wanted the player to move. I'd rather have the ship move by applying a certain set velocity with a set acceleration in a certain direction. So that the player will accelerate from zero to say 1 in the space of 1/2 second when the finger is moved and to continue in that direction until the finger is either moved again or lifted.
If the finger is lifted then the ship should continue moving in the last direction but to start decelerate until the velocity is back to zero.
I am basically trying to simulate how a object would move in zero gravity, with the obvious non-realistic feature of deceleration.
I've found tutorials that show how to move an object towards a finger touch but this isnt what I want as I am trying to make a game that is a side scrolling space shooter where the player can go anywhere within the playable area, as opposed to simply up and down. Similar to the old retro game 'Nemesis', see screen below:
I've attached my player class code and scene code for better visualization of how I am currently doing it all.
Any pointers to literature on how to apply velocities with acceleration in a specified direction would be helpful :)
Scene file - Level_1.swift
import SpriteKit
// Global
/*
Level_1 set up and control
*/
class Level_1: SKScene {
// Instance variables
var lastUpdateTime:NSTimeInterval = 0
var dt:NSTimeInterval = 0
var player = Player() // Sub classed SKSpriteNode for all player related stuff
var currentTouchPosition: CGPoint!
var beginningTouchPosition:CGPoint!
var currentPlayerPosition: CGPoint!
let playableRectArea:CGRect
override init(size: CGSize) {
// Constant - Max aspect ratio supported
let maxAspectRatio:CGFloat = 16.0/9.0
// Calculate playable height
let playableHeight = size.width / maxAspectRatio
// Determine margin on top and bottom by subtracting playable height
// from scene height and then divide by 2
let playableMargin = (size.height-playableHeight)/2.0
// Calculate the actual playable area rectangle
playableRectArea = CGRect(x: 0, y: playableMargin,
width: size.width,
height: playableHeight)
super.init(size: size)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func didMoveToView(view: SKView) {
/* Setup your scene here */
currentTouchPosition = CGPointZero
beginningTouchPosition = CGPointZero
let background = SKSpriteNode(imageNamed: "background1")
background.position = CGPoint(x: size.width/2, y: size.height/2)
background.zPosition = -1
self.addChild(background)
currentPlayerPosition = CGPoint(x: 100, y: size.height/2)
player.position = currentPlayerPosition
self.addChild(player)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
currentTouchPosition = touch.locationInNode(self)
}
let dxVectorValue = (-1) * (beginningTouchPosition.x - currentTouchPosition.x)
let dyVectorValue = (-1) * (beginningTouchPosition.y - currentTouchPosition.y)
player.movePlayerBy(dxVectorValue, dyVectorValue: dyVectorValue, duration: dt)
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
player.removeAllActions()
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch: AnyObject in touches {
beginningTouchPosition = touch.locationInNode(self)
currentTouchPosition = beginningTouchPosition
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
currentPlayerPosition = player.position
if lastUpdateTime > 0 {
dt = currentTime - lastUpdateTime
}else{
dt = 0
}
lastUpdateTime = currentTime
player.boundsCheckPlayer(playableRectArea)
}
}
Player node - Player.swift
import Foundation
import SpriteKit
struct PhysicsCategory {
static let None : UInt32 = 0
static let All : UInt32 = UInt32.max
static let Player : UInt32 = 0b1 // 1
static let Enemy : UInt32 = 0b10 // 2
}
class Player: SKSpriteNode{
init(){
// Initialize the player object
let texture = SKTexture(imageNamed: "ship1")
super.init(texture: texture, color: UIColor.clearColor(), size: texture.size())
self.xScale = 2
self.yScale = 2
self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
self.zPosition = 1
// Player physics
self.physicsBody?.allowsRotation = false
self.physicsBody?.dynamic = false
self.physicsBody?.categoryBitMask = PhysicsCategory.Player
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// Check if the player sprite is within the playable area bounds
func boundsCheckPlayer(playableArea: CGRect){
let bottomLeft = CGPoint(x: 0, y: CGRectGetMinY(playableArea))
let topRight = CGPoint(x: playableArea.size.width, y: CGRectGetMaxY(playableArea))
if(self.position.x <= bottomLeft.x){
self.position.x = bottomLeft.x
// velocity.x = -velocity.x
}
if(self.position.x >= topRight.x){
self.position.x = topRight.x
// velocity.x = -velocity.x
}
if(self.position.y <= bottomLeft.y){
self.position.y = bottomLeft.y
// velocity.y = -velocity.y
}
if(self.position.y >= topRight.y){
self.position.y = topRight.y
// velocity.y = -velocity.y
}
}
/*
Move the player in a certain direction by a specific amount
*/
func movePlayerBy(dxVectorValue: CGFloat, dyVectorValue: CGFloat, duration: NSTimeInterval)->(){
let moveActionVector = CGVectorMake(dxVectorValue, dyVectorValue)
let movePlayerAction = SKAction.moveBy(moveActionVector, duration: 1/duration)
self.runAction(movePlayerAction)
}
}
Basically we need a scene with zero gravity and a player where the touches cause force type physics actions. This is instead of moveBy type digital actions that simple move a character on the screen by such and such.
I went ahead and tested the code to try and get you something similar to what you describe. I altered some of your code a tad... to get it to work with my own set-up, as you didn't provide your GameViewController code so ask if you have any questions.
I've provided the code at the end with comments that say // IMPORTANT CODE with a # beside.
Here's details on why you use each piece of "IMPORTANT CODE
We need physics to accomplish what you describe so first ensure the player class will have a physics body. The body will be dynamic and affected by gravity (Zero Gravity), however you may want to fiddle with the gravity slightly for gameplay sake.
let body:SKPhysicsBody = SKPhysicsBody(texture: texture, alphaThreshold: 0, size: texture.size() )
self.physicsBody = body
self.physicsBody?.allowsRotation = false
self.physicsBody?.dynamic = true
self.physicsBody?.affectedByGravity = true
Since you want zero gravity we need to change our physics worlds gravity in our scene
scene?.physicsWorld.gravity = CGVectorMake(0, 0)
Next we change your movePlayerBy() to work with forces instead of simple digital movement. We do this with SKAction.applyForce.
This gives you a set-up based on force that's correlated with the swipe.
However, you may want a constant velocity no matter how hard the swipe. You can do that by normalizing the vector.. See here for somehow who asked that question and how it may apply here
(http://www.scriptscoop2.com/t/adc37b4f2ea8/swift-giving-a-physicsbody-a-constant-force.html)
func movePlayerBy(dxVectorValue: CGFloat, dyVectorValue: CGFloat, duration: NSTimeInterval)->(){
print("move player")
let moveActionVector = CGVectorMake(dxVectorValue, dyVectorValue)
let movePlayerAction = SKAction.applyForce(moveActionVector, duration: 1/duration)
self.runAction(movePlayerAction)
}
If you want the player to decelerate , we must add a function to set the player's velocity to 0. I've made it so this happens 0.5 seconds after the function is initially called.. otherwise the "floating through gravity" effect isn't really noticed as the movement would end with touchesEnded().
You can experiment with other ways to de-accelerate like a negative force of what was used initially, before the pause action in the sequence below.
There's many other ways to make it more of a true deceleration ... like a second sequence that subtracts -1 from velocity at a set time interval until it hits 0, before we hard code velocity to 0.
But, that's up to you from a gameplay standpoint.
So this should be enough to give you an idea.
func stopMoving() {
let delayTime: NSTimeInterval = 0.5 // 0.5 second pause
let stopAction: SKAction = SKAction.runBlock{
self.physicsBody?.velocity = CGVectorMake(0, 0)
}
let pause: SKAction = SKAction.waitForDuration(delayTime)
let stopSequence: SKAction = SKAction.sequence([pause,stopAction])
self.runAction(stopSequence)
}
We alter touchesEnded() to call stopMoving() .. But, try it without this to see it without that "deceleration".
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
player.removeAllActions()
player.stopMoving()
}
Other Notes.
Currently the bounds only catch the player on the left and right with the code I created... I'm not sure if that will happen in your set-up. But, as that's another question to figure out, I didn't further look into it.
Here's my code I used ... I'm providing it since I made a few other minor alterations for the sake of testing. I wouldn't worry about anything other than where I place the new important pieces of code.
GameScene.Swift
import SpriteKit
// Global
/*
Level_1 set up and control
*/
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
class Level_1: GameScene {
// Instance variables
var lastUpdateTime:NSTimeInterval = 0
var dt:NSTimeInterval = 0
var player = Player() // Sub classed SKSpriteNode for all player related stuff
var currentTouchPosition: CGPoint = CGPointZero
var beginningTouchPosition:CGPoint = CGPointZero
var currentPlayerPosition: CGPoint = CGPointZero
var playableRectArea:CGRect = CGRectZero
override func didMoveToView(view: SKView) {
/* Setup your scene here */
// IMPORTANT CODE 2 //
scene?.physicsWorld.gravity = CGVectorMake(0, 0)
// Constant - Max aspect ratio supported
let maxAspectRatio:CGFloat = 16.0/9.0
// Calculate playable height
let playableHeight = size.width / maxAspectRatio
// Determine margin on top and bottom by subtracting playable height
// from scene height and then divide by 2
let playableMargin = (size.height-playableHeight)/2.0
// Calculate the actual playable area rectangle
playableRectArea = CGRect(x: 0, y: playableMargin,
width: size.width,
height: playableHeight)
currentTouchPosition = CGPointZero
beginningTouchPosition = CGPointZero
let background = SKSpriteNode(imageNamed: "Level1_Background")
background.position = CGPoint(x: size.width/2, y: size.height/2)
background.zPosition = -1
self.addChild(background)
// CHANGED TO Put my own texture visible on the screen
currentPlayerPosition = CGPoint(x: size.width/2, y: size.height/2)
player.position = currentPlayerPosition
self.addChild(player)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
currentTouchPosition = touch.locationInNode(self)
}
let dxVectorValue = (-1) * (beginningTouchPosition.x - currentTouchPosition.x)
let dyVectorValue = (-1) * (beginningTouchPosition.y - currentTouchPosition.y)
player.movePlayerBy(dxVectorValue, dyVectorValue: dyVectorValue, duration: dt)
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
player.removeAllActions()
// IMPORTANT CODE 5 //
player.stopMoving()
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
print("touch")
for touch: AnyObject in touches {
beginningTouchPosition = touch.locationInNode(self)
currentTouchPosition = beginningTouchPosition
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
currentPlayerPosition = player.position
if lastUpdateTime > 0 {
dt = currentTime - lastUpdateTime
}else{
dt = 0
}
lastUpdateTime = currentTime
player.boundsCheckPlayer(playableRectArea)
}
}
GameViewController.swift
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene(fileNamed:"GameScene") {
// Configure the view.
let skView = self.view as! SKView
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)
}
}
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
}
}
Player.swift
import Foundation
import SpriteKit
struct PhysicsCategory {
static let None : UInt32 = 0
static let All : UInt32 = UInt32.max
static let Player : UInt32 = 0b1 // 1
static let Enemy : UInt32 = 0b10 // 2
}
class Player: SKSpriteNode{
init(){
// Initialize the player object
let texture = SKTexture(imageNamed: "Player1")
super.init(texture: texture, color: UIColor.clearColor(), size: texture.size())
self.xScale = 2
self.yScale = 2
self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
self.zPosition = 1
// Player physics
// IMPORTANT CODE 1 //
let body:SKPhysicsBody = SKPhysicsBody(texture: texture, alphaThreshold: 0, size: texture.size() )
self.physicsBody = body
self.physicsBody?.allowsRotation = false
self.physicsBody?.dynamic = true
self.physicsBody?.affectedByGravity = true
self.physicsBody?.categoryBitMask = PhysicsCategory.Player
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
// Check if the player sprite is within the playable area bounds
func boundsCheckPlayer(playableArea: CGRect){
let bottomLeft = CGPoint(x: 0, y: CGRectGetMinY(playableArea))
let topRight = CGPoint(x: playableArea.size.width, y: CGRectGetMaxY(playableArea))
if(self.position.x <= bottomLeft.x){
self.position.x = bottomLeft.x
// velocity.x = -velocity.x
}
if(self.position.x >= topRight.x){
self.position.x = topRight.x
// velocity.x = -velocity.x
}
if(self.position.y <= bottomLeft.y){
self.position.y = bottomLeft.y
// velocity.y = -velocity.y
}
if(self.position.y >= topRight.y){
self.position.y = topRight.y
// velocity.y = -velocity.y
}
}
/*
Move the player in a certain direction by a specific amount
*/
// IMPORTANT CODE 3 //
func movePlayerBy(dxVectorValue: CGFloat, dyVectorValue: CGFloat, duration: NSTimeInterval)->(){
print("move player")
let moveActionVector = CGVectorMake(dxVectorValue, dyVectorValue)
let movePlayerAction = SKAction.applyForce(moveActionVector, duration: 1/duration)
self.runAction(movePlayerAction)
}
// IMPORTANT CODE 4 //
func stopMoving() {
let delayTime: NSTimeInterval = 0.5 // 0.5 second pause
let stopAction: SKAction = SKAction.runBlock{
self.physicsBody?.velocity = CGVectorMake(0, 0)
}
let pause: SKAction = SKAction.waitForDuration(delayTime)
let stopSequence: SKAction = SKAction.sequence([pause,stopAction])
self.runAction(stopSequence)
}
}

How do I move one node from one position to another position?

I have a file where I move a square from one side to a point near the middle of the screen.
After that, I want to move it to another position, but I am unsure of how to do that.
This is my code so far. When you run it, it moves to one point and then stops.
What I want it to do is it moves to that one point and immediately goes to a point with the same x value but a y value touching the top of the screen.
override func didMoveToView(view: SKView) {
self.physicsWorld.contactDelegate = self
createEnemies()
}
deinit{
print("deinit called")
}
func randomBetweenNumbers(firstNum: CGFloat, secondNum: CGFloat) -> CGFloat{
return CGFloat(arc4random()) / CGFloat(UINT32_MAX) * abs(firstNum - secondNum) + min(firstNum, secondNum)
}
//Helper method for spawning a point along the screen borders. This will not work for diagonal lines.
func randomPointBetween(start:CGPoint, end:CGPoint)->CGPoint{
return CGPoint(x: randomBetweenNumbers(start.x, secondNum: end.x), y: randomBetweenNumbers(start.y, secondNum: end.y))
}
func createEnemies(){
//Randomize spawning time.
//This will create a node every 0.5 +/- 0.1 seconds, means between 0.4 and 0.6 sec
let wait = SKAction .waitForDuration(0.5, withRange: 0.2)
weak var weakSelf = self //Use weakSelf to break a possible strong reference cycle
let spawn = SKAction.runBlock({
var random = arc4random() % 4 + 1
var position = CGPoint()
var moveTo = CGPoint()
var offset:CGFloat = 40
switch random {
//Left
case 1:
position = weakSelf!.randomPointBetween(CGPoint(x: 0, y: weakSelf!.frame.height/2), end: CGPoint(x: 0, y: weakSelf!.frame.height/2))
//Move to opposite side
moveTo = CGPoint(x: weakSelf!.frame.width/4, y: weakSelf!.frame.height/2)
//moveTo2 = CGPoint(x: weakSelf!.frame.width/4, y: weakSelf!.frame.height)
break
default:
break
}
weakSelf!.spawnEnemyAtPosition(position, moveTo: moveTo)
})
let spawning = SKAction.sequence([wait,spawn])
self.runAction(SKAction.repeatActionForever(spawning), withKey:"spawning")
}
func spawnEnemyAtPosition(position:CGPoint, moveTo:CGPoint){
let enemy = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 40, height: 40))
enemy.position = position
enemy.physicsBody = SKPhysicsBody(rectangleOfSize: enemy.size)
enemy.physicsBody?.affectedByGravity = false
enemy.physicsBody?.dynamic = true
enemy.physicsBody?.collisionBitMask = 0 // no collisions
//Here you can randomize the value of duration parameter to change the speed of a node
let move = SKAction.moveTo(moveTo,duration: 2.5)
//let remove = SKAction.removeFromParent()
enemy.runAction(SKAction.sequence([move]))
/*if enemy.position = CGPoint(x: weakSelf!.frame.width/4, y: weakSelf!.frame.height/2) {
let move2 = SKAction.moveTo(moveTo2,duration: 2.5)
enemy.runAction(SKAction.sequence([move2]))
}*/
self.addChild(enemy)
print("\(enemy.position)")
}
func didBeginContact(contact: SKPhysicsContact) {
}
/*
Added for debugging purposes
override func touchesBegan(touches: NSSet, withEvent event: UIEvent?) {
//Just make a transition to the other scene, in order to check if deinit is called
//You have to make a new scene ... I named it WelcomeScene
var scene:WelcomeScene = WelcomeScene(fileNamed: "WelcomeScene.sks")
scene.scaleMode = .AspectFill
self.view?.presentScene(scene )
}
*/
Run a sequence for example.
moveTo = CGPoint(x: weakSelf!.frame.width/4, y: weakSelf!.frame.height/2)
moveTo2 = CGPoint(x: weakSelf!.frame.width/4, y: weakSelf!.frame.height)
let move = SKAction.moveTo(moveTo,duration: 2.5)
let move2 = SKAction.moveTo(moveTo2,duration: 2.5)
let moveToSequence = SKAction.sequence([move, move2])
enemy.runAction(moveToSequence)

How do I move a ball up and down depending on a tap using SpriteKit?

My code for my touches began function is this:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
let moveBall = SKAction.moveToY(380, duration: 0.4)
let moveBalldown = SKAction.moveToY(293, duration: 0.4)
if ball.position.y == 293 {
ball.runAction(moveBall)
}
if ball.position.y == 380 {
ball.runAction(moveBalldown)
}
When I tap the screen, nothing happens.
I want the ball to move up and down depending on the tap.
The ball should move up on the first tap and then back down once it is at y = 380, and the screen is tapped again.
Here is the rest of the code that affects the ball.
var ball = SKSpriteNode(imageNamed: "ball")
self.ball.position = CGPoint(x:40, y:293)
self.addChild(self.ball)
self.ball.yScale = 0.17
self.ball.xScale = 0.17
self.physicsWorld.gravity = CGVectorMake(0, 0)
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.height * 0.08)
ball.physicsBody?.dynamic = true
var degreeRotation = CDouble(self.SBEBSpeed) * M_PI / 180
self.ball.zRotation -= CGFloat(degreeRotation)
let moveBall = SKAction.moveToY(380, duration: 0.4)
let moveBalldown = SKAction.moveToY(293, duration: 0.4)
if ball.position.y == 293 {
ball.runAction(moveBall)
}
if ball.position.y == 380 {
ball.runAction(moveBalldown)
}
I haven't touched SpriteKit in some time but I wanted to test your code. I'm currently running XCode Version 6.3.1, and I see they've updated the touchesBegan function to now take a Set of NSObjects. But your actual code inside the method runs just fine, so as long as you have set your "ball" to the right coordinates when it is initially rendered. Here is my working example:
import SpriteKit
class GameScene: SKScene {
var ball = SKSpriteNode()
override func didMoveToView(view: SKView) {
var ballTexture = SKTexture(imageNamed: "ball.png")
ball = SKSpriteNode(texture: ballTexture)
ball.position = CGPoint(x: CGRectGetMidX(self.frame), y: 293)
self.addChild(ball)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
let moveBall = SKAction.moveToY(380, duration: 0.4)
let moveBalldown = SKAction.moveToY(293, duration: 0.4)
if ball.position.y == 293 {
ball.runAction(moveBall)
}
if ball.position.y == 380 {
ball.runAction(moveBalldown)
}
}
EDIT: (Because I can't comment yet, and I didn't want to make a new answer) I ran your code after you updated it and the ball does not even appear on my screen. Is that happening to you when you say nothing is happening? The only problem was the x-position. I would recommend using coordinates that are relative of self.frame

How do I make my character move sideways? Xcode 6 Sprite Kit

I am making a simple side scrolling game using apple's swift programming language and I want to make my character move left when the left half of the screen is touched and right when the other half is touched. I have done this using this code:
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if location.x < CGRectGetMidX(self.frame){
character.position.x -= 30
} else if location.x > CGRectGetMidX(self.frame){
character.position.x += 30
} else {
println("jump")
}
}
but he stops moving immediately after he moves 30 px over. my question is, can someone explain how to make him keep moving until the user lifts their finger?
This is my GameScene.swift file:
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
let character = SKSpriteNode(texture: SKTexture(imageNamed: "character"))
override func didMoveToView(view: SKView) {
/* Setup your scene here */
//world
self.physicsWorld.gravity = CGVectorMake(0.0, -5.0)
//background
var background = SKSpriteNode(imageNamed: "background")
background.size.height = self.frame.size.height
background.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
self.addChild(background)
//character
character.position = CGPointMake(self.frame.size.width * 0.6, self.frame.size.height * 0.6)
character.setScale(0.015)
character.physicsBody = SKPhysicsBody(circleOfRadius: CGFloat(character.size.width / 2))
var charPos = character.position
character.physicsBody?.dynamic = true
self.addChild(character)
//platform 1
var platformTexture = SKTexture(imageNamed: "platform")
var platform = SKSpriteNode(texture: platformTexture)
platform.position = CGPointMake(self.frame.size.width * 0.6, CGRectGetMidY(self.frame))
platform.physicsBody = SKPhysicsBody(rectangleOfSize: platform.size)
platform.physicsBody?.dynamic = false
platform.setScale(0.25)
self.addChild(platform)
//platform 2
var platformTexture2 = SKTexture(imageNamed: "platform")
var platform2 = SKSpriteNode(texture: platformTexture2)
platform2.position = CGPointMake(self.frame.size.width * 0.4, self.frame.size.height * 0.3)
platform2.physicsBody = SKPhysicsBody(rectangleOfSize: platform2.size)
platform2.physicsBody?.dynamic = false
platform2.setScale(0.25)
self.addChild(platform2)
//platform main
var platformTexture3 = SKTexture(imageNamed: "platform")
var platform3 = SKSpriteNode(texture: platformTexture2)
platform3.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMinY(self.frame) + platform3.size.height / 3)
platform3.physicsBody = SKPhysicsBody(rectangleOfSize: platform3.size)
platform3.physicsBody?.dynamic = false
platform3.setScale(1)
platform3.size.width = platform3.size.width * CGFloat(2.0)
self.addChild(platform3)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
}
You have to apply force constantly to character in every update: call in order to move it without stopping. You can also apply impulses in order to move character, or make it jump. Here is an example based on you code, to give you a basic idea how you can move characters using physics (or by changing velocity vector of a character manually). Look through the comments to find what is important.
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
let character = SKSpriteNode(texture: SKTexture(imageNamed: "pauseButton"))
//Boolean variable to store information about move signal (updated in touchesBegan and touchesEnded method)
var move = false
override func didMoveToView(view: SKView) {
/* Setup your scene here */
//world
self.physicsWorld.gravity = CGVectorMake(0.0, -5.0)
self.physicsWorld.contactDelegate = self; //don't forget to set contact delegate if you want to use contact detection and methods like didBeginContact and didEndContact
//background
//just a physical border so that character can't escape from us :)
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
//character
character.position = CGPointMake(self.frame.size.width * 0.6, self.frame.size.height * 0.6)
character.setScale(0.415)
character.physicsBody = SKPhysicsBody(circleOfRadius: CGFloat(character.size.width / 2))
var charPos = character.position
character.physicsBody?.dynamic = true
self.addChild(character)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
//Hold finger at upper area to move character constantly to the right.
if location.y > 400{
//moving allowed, force is applied in update method. read the docs about applyImpulse and applyForce methods and the differences between those two.
move = true
}else{
if location.x < CGRectGetMidX(self.frame){
character.physicsBody?.applyImpulse(CGVector(dx: -30, dy: 0))
//tap somewhere above this to make character jump
if(location.y > 250) {
character.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 50))
}
} else if location.x > CGRectGetMidX(self.frame){
character.physicsBody?.applyImpulse(CGVector(dx: 30, dy: 0))
//tap somewhere above this to make character jump
if(location.y > 250) {
character.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 50))
}
}
}
}
}
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
move = false
//character.physicsBody?.velocity = CGVector(dx: 0, dy: 0) //you can make character to stop by manually setting its velocity vector to (0,0)
}
override func update(currentTime: CFTimeInterval) {
if(move){character.physicsBody?.applyForce(CGVector(dx: 30, dy: 0))}
//if(move){character.position = CGPoint(x: character.position.x+1, y:character.position.y)} //not recommended if you need physics simulation (eg. collisions)
}
}
Note that you can change node's position in every update call to achieve what you want, like this :
if(move){character.position = CGPoint(x: character.position.x+1, y:character.position.y)}
But this way you will pull the node out of physics simulation and you can experience unexpected results. Search SO about this topic, there are some good posts about all this.
Hope this helps a bit.

Resources