locationInNode returning erroneous results - ios

I have a subclass of SKNode called Player which pretty much consists of this: http://hub.ae/blog/2014/03/26/soft-body-physics-jellyusing-spritekit/ converted to swift (With a few changes). I've allowed the user to move the player node with his finger with the following code:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
player.runAction(SKAction.moveTo(touch.locationInNode(world), duration: 1))
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
player.runAction(SKAction.moveTo(touch.locationInNode(world), duration: 1))
}
override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
player.removeAllActions()
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
player.removeAllActions()
}
*As a note, the 'world' var you see is just another SKNode. 'player' is a child of this node.
This looks like it should work, however the node moves in very strange directions. This is an example of how it looks:
http://gyazo.com/87b0d09101bbbfd3ac0f2a3cdbf42e4c
How can I fix this? I found that settings the anchor point of the scene to 0.5 fixes this issue, however then the physics body of 'player' node gets messed up.

I had same problem but i can not remember if it is how i fixed it. Try changing this:
world > self
player.runAction(SKAction.moveTo(touch.locationInNode(world), duration: 1))
To:
player.runAction(SKAction.moveTo(touch.locationInNode(self), duration: 1))
If i am wrong let me know :)
EDIT
set anchor point to (0.5,0.5) and write those 2 methods to center on your node.
override func didSimulatePhysics() {
camera.position = CGPointMake(player.position.x, player.position.y);
centerOnNode(camera)
}
func centerOnNode(node: SKNode){
var positionInScene : CGPoint = convertPoint(node.position, fromNode: node.parent)
world.position = CGPointMake(world.position.x - positionInScene.x, world.position.y - positionInScene.y)
}

Related

Exceeding the maximum number of touches makes the program not to call the touchesEnded method?

Ive just started learning programming in general and ran into a problem:
I have read some articles about that the iPhones are only capable of tracking 5 touches or so... But I realised that when I touch the screen with e.g. 7 fingers at once, my program-let stops working.
So, anyone knows, which parts of the code malfunctions when I am touching the screen way too many times at once?
(I am a newbie.)
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first!
touchLocation = touch.locationInNode(self)
nrTouches += touches.count
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
nrTouches -= touches.count
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first!
touchLocation = touch.locationInNode(self)
}
override func update(currentTime: CFTimeInterval) {
if nrTouches > 0 {
touchingLabel.text = "touching"
} else {
touchingLabel.text = "not touching"
}
}
So, in the case I am touching with 7 fingers at once, "touching" will be displayed all the time.
tankyuu
You're missing touchesCancelled, which gets called when the 6th finger is put down:
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
if let touches = touches {
nrTouches -= touches.count // same logic as touchesEnded
}
}
An interesting note: The iPad can handle 11 touch events. More on that here.

Moving objects according to touchesMoved

So I'm trying to move an object using the touches moved function, however I'm not sure how to do that when the coordinates are not predetermined. This is what I've got going :
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
var touch: AnyObject? = touches.anyObject()
var point = touch?.locationInView(self.view)
}
So basically I'm making the point variable the coordinates (points).
Then what needs to happen is that i move an object (in this case Label1) to that location:
func MoveObject(point) {
Label1.frame.origin = ( /* Here would the ´point´ be */ )
}
Also keep in mind that later when this problem is out of the way I'm going to change the location so its not where you touch but it moves accordingly. I don't know if that matters really but I'm just saying in case it does ;)
What about
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
var touch: AnyObject? = touches.anyObject()
var point = touch?.locationInView(self.view)
moveObject(point)
}
...
func MoveObject(point) {
Label1.center = point
}

touchesMoved: How to know when the touch ended?

I have a ball that I want to move around (Spritekit) and I want to set a velocity so when the player move the ball then he moves his finger from the screen the ball will move and it will have it's own velocity depinding on some calculations
the question :
this is my code , how can I know when the player is moving his finger from the screen ?!
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
if let touch = touches.first as? UITouch{
var location = touch.locationInNode(self)
ball6.position = location
}
Use this method:
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
//your code
}

SpriteKit custom UIScrollView with acceleration

Basically I need to create a UIScrollView in my SpriteKit project but i'm having a lot of problem adding SKButtons (custom SKNode class for button management). So I proceeded to create a scrollable SKNode with touch gesture but, obviously, this bar won't have the native UIScrollView acceleration: the feature I was looking for.
So tried to overtake this problem by adding a native UIScrollView and catch every change of position, like this:
using this code:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[blueNode setPosition:CGPointMake(blueNode.position.x, scrollerUI.contentOffset)];
}
This works right but foolishly I forgot that if I add buttons, the touch gesture won't recognize the button's touch event! (The UIScrollView has the priority).
Maybe is just a stupid question but I don't really know how to figure it out. Maybe programming my own acceleration methods?
I think I came up with a solution to handle touches. Since the UIScrollView eats all the touches to allow it to scroll you need to pass them to the SKScene. You can do that by subclassing UIScrollView:
class SpriteScrollView: UIScrollView {
var scene: SKScene?
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
scene?.touchesBegan(touches, withEvent: event)
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
scene?.touchesMoved(touches, withEvent: event)
}
override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
scene?.touchesCancelled(touches, withEvent: event)
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
scene?.touchesEnded(touches, withEvent: event)
}
}
Then your scene needs to see if the touch hits any nodes and appropriately send the touches to those nodes. So in your SKScene add this:
var nodesTouched: [AnyObject] = []
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
super.touchesBegan(touches, withEvent: event)
let location = (touches.first as! UITouch).locationInNode(self)
nodesTouched = nodesAtPoint(location)
for node in nodesTouched as! [SKNode] {
node.touchesBegan(touches, withEvent: event)
}
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
super.touchesMoved(touches, withEvent: event)
for node in nodesTouched as! [SKNode] {
node.touchesMoved(touches, withEvent: event)
}
}
override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
super.touchesCancelled(touches, withEvent: event)
for node in nodesTouched as! [SKNode] {
node.touchesCancelled(touches, withEvent: event)
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
super.touchesEnded(touches, withEvent: event)
for node in nodesTouched as! [SKNode] {
node.touchesEnded(touches, withEvent: event)
}
}
Note this is for single touches and does not handle errors well, you'll need to wrap some of the forced down casting in if statements if you want to do this properly
I hope this helps someone even though the question is months old.
One possible solution would be to add tap gesture to scene:
override func didMoveToView(view: SKView) {
let tap : UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: Selector("tapped:"))
view.addGestureRecognizer(tap)
}
func tapped(tap : UITapGestureRecognizer) {
let viewLocation = tap.locationInView(tap.view)
let location = convertPointFromView(viewLocation)
let node = nodeAtPoint(location)
if node.name == "lvlButton" {
var button = node as! SKButton
button.touchBegan(location)
}
}

Overriding touchesBegan in Swift

I am overriding:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent)
in Swift.
I am wondering, is this correct for getting one touch point:
var touchPoint: CGPoint! = event.touchesForView(self)?.anyObject()?.locationInView(self)
Thanks in advance!
As of iOS 8.3, touchesBegan takes a touches parameter which is a Set<NSObject>. It's now Set<UITouch>. So, you would:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let point = touches.first?.location(in: view) else { return }
// use `point` here
}
In previous iOS versions, touchesBegan was defined as a NSSet parameter, as outlined in the question, so you would:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
if let touch = touches.anyObject() as? UITouch {
let touchPoint = touch.locationInView(view)
...
}
}

Resources