(Swift SpriteKit) Rotate sprite in the direction of touch - ios

On the screenshot provided, the red arrow and cross are just for demonstration purposes and are not in the game. I would like the sprite of the spaceship to face the direction of the ball it shoots.
Link to image
Here is my current code for touch location
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch in touches {
let location = touch.locationInNode(self)
var bullet = SKSpriteNode(imageNamed: "bullet")
bullet.position = cannon.position
bullet.size = CGSize(width: 35, height: 35)
//physics
bullet.physicsBody = SKPhysicsBody(circleOfRadius: bullet.size.width/2)
bullet.physicsBody?.categoryBitMask = PhysicsCategory.bullet
bullet.physicsBody?.collisionBitMask = PhysicsCategory.enemy
bullet.physicsBody?.contactTestBitMask = PhysicsCategory.enemy
bullet.name = "bullet"
bullet.physicsBody?.affectedByGravity = false
self.addChild(bullet)
var dx = CGFloat(location.x - cannon.position.x)
var dy = CGFloat(location.y - cannon.position.y)
let magnitude = sqrt(dx * dx + dy * dy)
dx /= magnitude
dy /= magnitude
let vector = CGVector(dx: 120.0 * dx, dy: 120.0 * dy) //adjust constant to increase impluse.
bullet.physicsBody?.applyImpulse(vector)
// I found this code bellow this comment, but it just moves the cannon's y position
let direction = SKAction.moveTo(
CGPointMake(
400 * -cos(bullet.zRotation - CGFloat(M_PI_2)) + bullet.position.x,
400 * -sin(bullet.zRotation - CGFloat(M_PI_2)) + bullet.position.y
),
duration: 0.8)
cannon.runAction(direction)
}
}

Here is the code I found which works perfectly.
Rotate a sprite to sprite position not exact in SpriteKit with Swift
let angle = atan2(location.y - cannon.position.y , location.x - cannon.position.x)
cannon.zRotation = angle - CGFloat(M_PI_2)

I had been working some time ago in something like what you want so, here is my results
first you need to use VectorMath.swift created by Nick Lockwood and this is my code to make my spider move towards user touch
import SpriteKit
import SceneKit
class GameScene: SKScene {
let sprite = SKSpriteNode(imageNamed:"Aranna")
var velocity = Vector2(x: 0, y: 0)
var positionV2D = Vector2(x: 0, y: 0)
var headingVector = Vector2(x: 0, y: 1)
override func didMoveToView(view: SKView) {
/* Setup your scene here */
let myLabel = SKLabelNode(fontNamed:"Chalkduster")
myLabel.text = "Hello, World!";
myLabel.fontSize = 45;
myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
sprite.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
positionV2D = Vector2(point:sprite.position);
let testVector = Vector2(x: 10, y: 14);
velocity += testVector;
print(velocity.toString());
velocity += Vector2(x: 1, y: 1);
//velocity = velocity + testVector;
print(velocity.toString());
velocity *= 0.5;
velocity.printVector2D();
velocity = Vector2(x: 2, y: 2);
velocity.normalized();
velocity.printVector2D();
self.addChild(sprite)
}
func ToRad(grados:CGFloat) ->CGFloat
{
return ((CGFloat(M_PI) * grados) / 180.0)
}
func ToDeg(rad:CGFloat) ->CGFloat
{
return (180.0 * rad / CGFloat(M_PI))
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch in touches {
let location = touch.locationInNode(self)
let toTarget = Vec2DNormalize(Vector2(point:location) - positionV2D);
let angle2 = headingVector.angleWith(toTarget);
print(ToDeg(CGFloat(angle2)));
headingVector.printVector2D();
self.sprite.runAction(SKAction.rotateToAngle(CGFloat(angle2), duration: 0.1))
self.sprite.runAction(SKAction.moveTo(location, duration: 0.5))
positionV2D = Vector2(point: location);
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
I hope this helps you

If you want to rotate only you shouldn't call the moveTo action.
Calculate the angle between touch location and location of the cannon and call action rotateToAngel
here is the code
let angle = atan2(dy, dx) - CGFloat(M_PI_2)
let direction = SKAction.rotateToAngle(angle, duration: 0.4, shortestUnitArc: true)
cannon.runAction(direction)

I found that with the answer submitted by James that this caused it to rotate in the wrong way, fine if you have something like a canonball but as it was used on my game which had a mage and a fireball with a trail it caused an issue, this can be easily fixed with
let angle = atan2(touchlocation.x - cannon.position.x , touchlocation.y -
cannon.position.y)
cannon.zRotation = -(angle - CGFloat(Double.pi/2))
use Double.pi / 2 and M_PI_2 is depriciated now

Related

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 to run a SKAction in the direction of a joystick's degree

i am creating a game and i am having trouble making my bullets spawn in the direction of my joystick. here is the method for my bullets
func spawnBullets(){
let bullet = SKSpriteNode(imageNamed: "bullet.png")
bullet.zPosition = -5
bullet.position = CGPointMake(hero.position.x, hero.position.y)
bullet.xScale = 0.25
bullet.yScale = 0.25
bullet.physicsBody = SKPhysicsBody(rectangleOfSize: bullet.size)
bullet.physicsBody?.categoryBitMask = PhysicsCategory.bullet
bullet.physicsBody?.contactTestBitMask = PhysicsCategory.enemy
bullet.physicsBody?.affectedByGravity = false
bullet.physicsBody?.dynamic = false
let action = SKAction.moveToY(self.size.height + 30, duration: 1.0)
let actionDone = SKAction.removeFromParent()
bullet.runAction(SKAction.sequence([action, actionDone]))
self.addChild(bullet)
}
here is how i am calling the method in my
override func didMoveToView(view: SKView) {
_ = NSTimer.scheduledTimerWithTimeInterval(0.25, target: self,
selector: Selector ("spawnBullets"), userInfo: nil, repeats: true)
}
and here is how i coded my touches moved function (i believe that is the method that i need to edit)
override func touchesMoved(touches: Set<UITouch>, withEvent event:
UIEvent?) {
for touch in touches {
let location = touch.locationInNode(self)
let v = CGVector(dx: location.x - joystickBase.position.x, dy:
location.y - joystickBase.position.y)
let angle = atan2(v.dy, v.dx)
let deg = angle * CGFloat(180 / M_PI)
let length: CGFloat = joystickBase.frame.size.height / 2
let xDist:CGFloat = sin(angle - 1.5709633) * length
let yDist:CGFloat = cos(angle - 1.5709633) * length
print(deg + 180)
if (stickActive == true) {
if (CGRectContainsPoint(joystickBase.frame, location)) {
joystick.position = location
}else{
joystick.position = CGPointMake(joystickBase.position.x -
xDist, joystickBase.position.y + yDist)
}
}
}
}
You are only moving the bullets in a vertical direction:
let action = SKAction.moveToY(self.size.height + 30, duration: 1.0)
Not sure if this is a twin stick game or not.
To get sprites to go based on the joystick, just do the following
let accel = 10 //accel is the # of pixels the sprite moves per frame, do not use moveTo, because moveTo will change the speeds of your sprite based on distance
let action = SKAction.moveByX(joystick.x * accel,y:joystick.y * accel,duration:1)
This of course is based on the understanding that your joystick coordinates go from -1.0 to 1.0 on each axis, and that point up or right gets you a 1.0 result
I would not even do this approach though, SKActions are not a good choice for things that are not automated. You should be updating the position of the sprite at some point in your update phase
sprite.position.x += joystick.x * accel
sprite.position.y += joystick.y * accel

How to create a separation between two SpriteKit objects

I have a circle and triangles inside and outside. I was looking through my character if it is not in a circle outside the circle touching triangles and vice versa.
It does not matter if my character out of my circle it still happens.
In fact if I'm in my circle and triangles outside my circle so my character should not touch them.
How do I solve this?
Does anyone have an idea?
My Code :
func AddCharacter() {
BooCharacter.size = CGSize(width: 30, height: 30)
BooCharacter.anchorPoint.y = 0
BooCharacter.zRotation = CGFloat(-M_PI_2)
//BooCharacter.position.y += circleRadius
BooCharacter.position = CGPoint(x:0.0, y:circleRadius)
BooCharacter.physicsBody = SKPhysicsBody(texture:BooCharacterSKT, size: CGSize(width: 30, height: 30))
BooCharacter.physicsBody = SKPhysicsBody(circleOfRadius: 15);
BooCharacter.physicsBody?.categoryBitMask = heroCategory
BooCharacter.physicsBody?.contactTestBitMask = triangleCategory
BooCharacter.physicsBody?.collisionBitMask = triangleCategory;
}
func AddCircle() {
Circle = SKShapeNode(circleOfRadius: circleRadius)
Circle.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
Circle.strokeColor = UIColor.whiteColor()
self.addChild(Circle)
Circle.addChild(BooCharacter)
self.AddTriangleToCircle(Circle, Location: CGFloat(random(1...90)), Inside: true)
self.AddTriangleToCircle(Circle, Location: CGFloat(random(90...280)), Inside: false)
self.AddTriangleToCircle(Circle, Location: CGFloat(random(280...360)), Inside: false)
//self.AddTriangleToCircle(Circle, Location: 90)
//self.AddTriangleToCircle(Circle, Location: 180)
//self.AddTriangleToCircle(Circle, Location: 240)
//self.AddTriangleToCircle(Circle, Location: 300)
}
func AddPointsLable() {
pointsLabel = PointsLabel(num: 0)
pointsLabel.position = CGPoint(x: self.size.width/2, y: self.size.height/2 - 35)
pointsLabel.name = "pointsLabel"
addChild(pointsLabel)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
BooCharacter.zRotation += CGFloat(M_PI)
//for touch in touches {
//let location = touch.locationInNode(self)
let TapLable = childNodeWithName("tap")
TapLable?.removeFromParent()
//}
}
override func update(currentTime: NSTimeInterval) {
angleRelatedToCircle -= rotationSpeed
//BooCharacter.zRotation -= rotationSpeed
let newLocation = CGPointMake(circleRadius * cos(angleRelatedToCircle), circleRadius * sin(angleRelatedToCircle));
// BooCharacter.position.x = circleRadius * cos(angleRelatedToCircle)
// BooCharacter.position.y = circleRadius * sin(angleRelatedToCircle)
BooCharacter.runAction(SKAction.rotateByAngle(-rotationSpeed, duration: 0));
BooCharacter.runAction(SKAction.moveTo(newLocation, duration: 0));
//SKAction.moveTo(CGP, duration: <#T##NSTimeInterval#>)
//NSLog("x = %f, y = %f, r = %f",BooCharacter.position.x,BooCharacter.position.y,BooCharacter.zRotation);
}
func AddTriangleToCircle(Circle: SKShapeNode, Location: CGFloat, Inside: Bool) {
let Triangle: SKSpriteNode = SKSpriteNode(imageNamed: "Triangle")
Triangle.size = CGSize(width: 30, height: 30)
Triangle.anchorPoint.y = 0
if Inside == true {
// Inside Triangle
Triangle.zRotation = CGFloat(M_PI_2)
} else {
// Outside Triangle
Triangle.zRotation = CGFloat(-M_PI_2)
}
Triangle.position = CGPoint(x:0.0, y:circleRadius)
let rotationSpeed1 = rotationSpeed + Location;
var angleRelatedToCircle1 = angleRelatedToCircle;
angleRelatedToCircle1 -= rotationSpeed1
Triangle.zRotation -= rotationSpeed1
Triangle.position.x = circleRadius * cos(angleRelatedToCircle1)
Triangle.position.y = circleRadius * sin(angleRelatedToCircle1)
//Triangle.name = "Triangle";
Triangle.physicsBody = SKPhysicsBody(texture:TriangelSKT, size: CGSize(width: 30, height: 30))
//TODO: Make this a polygon body
Triangle.physicsBody?.categoryBitMask = triangleCategory
Triangle.physicsBody?.contactTestBitMask = heroCategory
Triangle.physicsBody?.collisionBitMask = heroCategory
Circle.addChild(Triangle);
}
func didBeginContact(contact: SKPhysicsContact) {
// ---------------------------------------------
// Hero Hit Triangle
// ---------------------------------------------
if (contact.bodyA.categoryBitMask == triangleCategory) {
// Play Sound Effect
// Remove Triangle
//contact.bodyA.node?.removeFromParent();
// Update Score
NSLog("Hero hit Triangle");
}
}
func random(range: Range<Int> ) -> Int
{
var offset = 0
if range.startIndex < 0 // allow negative ranges
{
offset = abs(range.startIndex)
}
let mini = UInt32(range.startIndex + offset)
let maxi = UInt32(range.endIndex + offset)
return Int(mini + arc4random_uniform(maxi - mini)) - offset
}
}
What you probably want is to set character's physics body like this:
BooCharacter.physicsBody = SKPhysicsBody(circleOfRadius: 15);
because currently, character size is a 30x30 rectangle and its body is a circle with a diameter of 60 (d=2r). You need a body with diameter of 30.
Also, you are changing characters anchor point but keep in mind that physics body is not affected with that action. It stays centered on node's position... Read more in this example.
And about triangle node. Currently it has a physics body with a rectangular shape even if it's a triangle. Not sure if you want that, but it may cause the problems you are experiencing. You have a few options to solve this:
Create physics body manually, like pointed in one of your previous questions, or
Create a physics body from a texture. Keep in mind that this might be performance intensive, but it will probably be fine for your game because you don't have many objects on the scene.

SpriteKit friction not seeming to working properly

On a project in Xcode 7 I have a few SKSpriteNodes that move back and forth on the screen and another one, called user, that is meant to jump from sprite to sprite, progressively up the screen. However, when user lands on one of the moving sprites the moving sprite just slides right out from under it and user falls back down. I thought that this meant that I needed to increase the friction property on the nodes so that user would "stick" to the nodes, but this just makes it bounce on the other nodes. My problem is that the nodes moving back and forth seem to "slippery," and user just doesn't stay on them.
Here's my code:
My class for user:
class UserNode: SKSpriteNode
{
class func newNode(position position: CGPoint) -> UserNode
{
let position = position
let sprite = UserNode(imageNamed: "userImage")
sprite.position = position
sprite.size = CGSize(width: sprite.size.width * 2, height: sprite.size.height * 2)
sprite.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "userImage"), size: sprite.size)
sprite.physicsBody?.affectedByGravity = true
sprite.physicsBody?.dynamic = true
sprite.physicsBody?.allowsRotation = false
sprite.physicsBody?.friction = 0.2
return sprite
}
}
and for moving user (the methods in my gamescene)
let scale: CGFloat = 2.0
let damping: CGFloat = 0.98
var point = CGPoint?()
func moveNodeToPoint(sprite: SKSpriteNode, point: CGPoint)
{
let dx = (point.x - sprite.position.x) * scale
let dy = (point.y - sprite.position.y) * scale
sprite.physicsBody?.velocity = CGVectorMake(dx, dy)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
{
/* Called when a touch begins */
for _: AnyObject in touches
{
if !welcomeNode.hidden
{
let fadeAway = SKAction.fadeOutWithDuration(0.3)
welcomeNode.runAction(fadeAway)
directionsNode.runAction(fadeAway)
touchStartNode.runAction(fadeAway)
welcomeNode.hidden = true
directionsNode.hidden = true
touchStartNode.hidden = true
}
//////////
point = CGPointMake(self.frame.midX, user.position.y + 300)
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?)
{
point = nil
}
override func update(currentTime: CFTimeInterval)
{
/* Called before each frame is rendered */
if (point != nil)
{
moveNodeToPoint(user, point: point!)
}
else
{
let dx = user.physicsBody!.velocity.dx * damping
let dy = user.physicsBody!.velocity.dy * damping
user.physicsBody?.velocity = CGVectorMake(dx, dy)
}
}
and for moving the platforms:
let screenSize = UIScreen.mainScreen().bounds
let width = screenSize.size.width * 2
let firstAction = SKAction.moveBy(CGVector(dx: width, dy: 0), duration: 2)
let secondAction = SKAction.moveBy(CGVector(dx: -width, dy: 0), duration: 2)
let actions = [firstAction, secondAction]
let barAction = SKAction.sequence(actions)
let mainBarAction = SKAction.repeatActionForever(barAction)
platform.runAction(mainBarAction)

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