Swift SpriteKit 3D Touch and touches moved
Asked Answered
C

1

2

I have recently send out a version of my game to TestFlight for internal testing. My friend noticed that on his iPhone 6S Plus the controls to shoot do not work correctly.

The controls are as follow

1) left half of screen = jump

2) right half of screen = shoot

3) Slide and hold on right half of screen = start slow motion

Now in my touches began method I have a slight delay for the shooting, so if touches moved is called it cancels the shooting and starts slow mo. This seems to be causing the problem on 3D Touch enabled phones.

Digging further into this I came across this post

iOS 9 Spritekit Double Tap Not Working on iPhone 6S

where it basically states that on 3D Touch enabled devices the touches moved method gets called automatically.

  On 3D Touch capable devices, touch pressure changes cause     
   touchesMoved:withEvent: to be called for all apps running on iOS   
   9.0. When running iOS 9.1, the method is called only for apps  
   linked with the iOS 9.0 (or later) SDK.

    Apps should be prepared to receive touch move events with no   
    change in the x/y coordinates. "

This seems to make sense of why my friend has problems, if touches moved is always called it will cancel the shooting and start slow mo, even though he is not sliding on the screen.

So my questions is

1) Can you disable 3D Touch in SpriteKit games?

2) Is this a bug?

3) any other way to use touches moved correctly on 3D Touch devices?

4) alternatively can I use gesture recognisers to simulate a slide and hold feature that I am currently doing in touches moved.

Thanks for any help

Codi answered 17/3, 2016 at 12:20 Comment(5)
Just a quick suggestion to take a look at Demo Bots sample app and see, whether same kind of issue happens in that sample on iPhone 6S.Jemison
Thanks for you suggestion. I use the DemoBots sample a lot for my projects. I have just checked and they use the "touchesMoved.." methods twice. However both are in subclasses of SKSpriteNodes, so I wonder if that makes the difference. I dont have a 3d touch device so it sucks to test.Codi
Me neither. You could distribute Demo Bots to your friend via OTA distribution (e.g. TestFlight) for tests as a last resort.Jemison
Yeah thanks I might try that. The way this is described in the list seems like its a bug. I am playing around with alternatives for now. Thanks againCodi
Incase you are interested I posted an answer to my own question on how to solve this. Thanks again for your helpCodi
C
4

After trying various other things that didnt work, including UISwipeGestureRecognizer subclasses, I finally figured it out.

The answer was actually staring me right in the face in that same stackOverflow post I linked in my question

iOS 9 Spritekit Double Tap Not Working on iPhone 6S

The solution is to create a property

var startingTouchLocation: CGPoint?

than in touches Began you set that property

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    for touch in touches {
        let location = touch.locationInNode(self)

        /// Set starting touch. this is for 3d touch enabled devices, see touchesMoved method below
        startingTouchLocation = location


        ....
     }
 }

and than add a check in touchesMoved to return from the method until the touch has actually moved.

 override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    for touch in touches {
        let location = touch.locationInNode(self)

        /// WAY 1 - Check if touch moved because on 3d touch devices this method gets called on a force touch.
        guard location != startingTouchLocation else { return }

        // Your code
        ...

        /// WAY 2 - Add a min distance for the finger to travel in any direction before calling touches moved code
        let minValue: CGFloat = 30
        guard let startingLocation = startingLocation else { return }

        guard currentLocation.y < startingLocation.y - minValue ||
        currentLocation.y > startingLocation.y + minValue ||
        currentLocation.x < startingLocation.x - minValue ||
        currentLocation.x > startingLocation.x + minValue else { return  false }

       // Your code 
       ....
     }
  }
Codi answered 20/3, 2016 at 16:33 Comment(2)
I got the same issue with you. On iPhone 6S, the touchesMoved method was called as soon as touchesBegan was called. We need to take care this.Alsoran
Yeah same problem, this fixes it! iPhone X and up works fine, but on 8 and lower it fires touchMoved several times blocking my logic.Humankind

© 2022 - 2024 — McMap. All rights reserved.