SceneKit SCNNode follow touch movement









up vote
0
down vote

favorite












I'm trying to have a Sphere node follow the movement of my finger on the screen on it's x axis only, without affecting the y or z values of the sphere. I'm not sure if I should be applying a force to the physics body or moving it with an SCNAction. The sphere will be bouncing on a cube node that takes up the width of the screen. My biggest problem as of now is figuring out what to put inside the pangesture function. Here is an example of what I'm trying to replicate, where the user slides their finger across the screen and the ball mirrors its location.



override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) 

for t in touches

let touchLocation = t.location(in: self.view)
let touchCoordinatesX = (touchLocation.x - self.scnView.frame.width / 2)
ballNode.position.x = Float(touchCoordinatesX/75)




The code above works somewhat, when I drag my finger across the screen the y-position freaks out, and lags up and down really quickly even though my code never edits the y-value of the ball. Everytime I drag across the screen, the y-position of the ball is reset to its original value when it was added to the scene's root node.
Hop



Based off your answer this is what I used and does exactly what I need it to.



@objc func handlePan(recognizer: UIPanGestureRecognizer)

currentLocation = recognizer.location(in: self.view)

let touchCoordinatesX = (currentLocation.x - self.scnView.frame.width / 2)



if recognizer.state == .changed



ballNode.position.x = Float(touchCoordinatesX/75)
ballNode.position.y = ballNode.presentation.position.y













share|improve this question



























    up vote
    0
    down vote

    favorite












    I'm trying to have a Sphere node follow the movement of my finger on the screen on it's x axis only, without affecting the y or z values of the sphere. I'm not sure if I should be applying a force to the physics body or moving it with an SCNAction. The sphere will be bouncing on a cube node that takes up the width of the screen. My biggest problem as of now is figuring out what to put inside the pangesture function. Here is an example of what I'm trying to replicate, where the user slides their finger across the screen and the ball mirrors its location.



    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) 

    for t in touches

    let touchLocation = t.location(in: self.view)
    let touchCoordinatesX = (touchLocation.x - self.scnView.frame.width / 2)
    ballNode.position.x = Float(touchCoordinatesX/75)




    The code above works somewhat, when I drag my finger across the screen the y-position freaks out, and lags up and down really quickly even though my code never edits the y-value of the ball. Everytime I drag across the screen, the y-position of the ball is reset to its original value when it was added to the scene's root node.
    Hop



    Based off your answer this is what I used and does exactly what I need it to.



    @objc func handlePan(recognizer: UIPanGestureRecognizer)

    currentLocation = recognizer.location(in: self.view)

    let touchCoordinatesX = (currentLocation.x - self.scnView.frame.width / 2)



    if recognizer.state == .changed



    ballNode.position.x = Float(touchCoordinatesX/75)
    ballNode.position.y = ballNode.presentation.position.y













    share|improve this question

























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I'm trying to have a Sphere node follow the movement of my finger on the screen on it's x axis only, without affecting the y or z values of the sphere. I'm not sure if I should be applying a force to the physics body or moving it with an SCNAction. The sphere will be bouncing on a cube node that takes up the width of the screen. My biggest problem as of now is figuring out what to put inside the pangesture function. Here is an example of what I'm trying to replicate, where the user slides their finger across the screen and the ball mirrors its location.



      override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) 

      for t in touches

      let touchLocation = t.location(in: self.view)
      let touchCoordinatesX = (touchLocation.x - self.scnView.frame.width / 2)
      ballNode.position.x = Float(touchCoordinatesX/75)




      The code above works somewhat, when I drag my finger across the screen the y-position freaks out, and lags up and down really quickly even though my code never edits the y-value of the ball. Everytime I drag across the screen, the y-position of the ball is reset to its original value when it was added to the scene's root node.
      Hop



      Based off your answer this is what I used and does exactly what I need it to.



      @objc func handlePan(recognizer: UIPanGestureRecognizer)

      currentLocation = recognizer.location(in: self.view)

      let touchCoordinatesX = (currentLocation.x - self.scnView.frame.width / 2)



      if recognizer.state == .changed



      ballNode.position.x = Float(touchCoordinatesX/75)
      ballNode.position.y = ballNode.presentation.position.y













      share|improve this question















      I'm trying to have a Sphere node follow the movement of my finger on the screen on it's x axis only, without affecting the y or z values of the sphere. I'm not sure if I should be applying a force to the physics body or moving it with an SCNAction. The sphere will be bouncing on a cube node that takes up the width of the screen. My biggest problem as of now is figuring out what to put inside the pangesture function. Here is an example of what I'm trying to replicate, where the user slides their finger across the screen and the ball mirrors its location.



      override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) 

      for t in touches

      let touchLocation = t.location(in: self.view)
      let touchCoordinatesX = (touchLocation.x - self.scnView.frame.width / 2)
      ballNode.position.x = Float(touchCoordinatesX/75)




      The code above works somewhat, when I drag my finger across the screen the y-position freaks out, and lags up and down really quickly even though my code never edits the y-value of the ball. Everytime I drag across the screen, the y-position of the ball is reset to its original value when it was added to the scene's root node.
      Hop



      Based off your answer this is what I used and does exactly what I need it to.



      @objc func handlePan(recognizer: UIPanGestureRecognizer)

      currentLocation = recognizer.location(in: self.view)

      let touchCoordinatesX = (currentLocation.x - self.scnView.frame.width / 2)



      if recognizer.state == .changed



      ballNode.position.x = Float(touchCoordinatesX/75)
      ballNode.position.y = ballNode.presentation.position.y










      ios swift4 uigesturerecognizer scenekit uipangesturerecognizer






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 12 at 23:48

























      asked Nov 12 at 3:14









      Tiptonix Beats

      82114




      82114






















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          1
          down vote



          accepted










          Try handlePan and setting/saving a dragMode state variable. The code below is something I used to select a panel and strafe the screen, so there is some extra code in for those things, but I think you could modify it to fit your needs. In your case, my "strafing the screen" should be similar to your need to drag the ball towards your fingertip.



          If you set your ball object to currentLocation.x in dragChanges(), then it should line up exactly on your finger tip and the response should happen quickly. My guess based on your picture is that you'd want a slight delay so that it's more realistic. If that's the case, I'd suggest adding a timer and processing a small queue of saved X positions so that it comes towards your finger tip in small increments.



          Hope that helps.



          //**************************************************************************
          @objc func handlePan(recognizer: UIPanGestureRecognizer)

          //**************************************************************************
          func dragBegins(vRecognizer: UIPanGestureRecognizer)

          if(data.gameState == .run)

          if(vRecognizer.numberOfTouches == 2) dragMode = .strafe


          //**************************************************************************
          func dragChanges(vRecognizer: UIPanGestureRecognizer)

          if(data.gameState == .run)

          if(dragMode == .strafe && vRecognizer.numberOfTouches == 1)

          dragMode = .none
          return


          switch(dragMode)

          case .strafe:
          gNodes.camera.strafe(vX: Float(currentLocation.x), vY: Float(currentLocation.y))
          break
          case .none:
          break
          default:
          break



          //**************************************************************************
          func dragEnds(vRecognizer: UIPanGestureRecognizer)

          if(data.gameState == .run)

          switch(dragMode)

          case .strafe:
          break
          default:
          break


          dragMode = .none






          share|improve this answer




















          • This helped me out a lot, thanks. What should I put inside of the handlePan function that prevents the user from moving the ball unless it's within x amount of distance from the ball? If I pan on the far right side of the screen, and the ball is positioned on the far left, it "teleports" to the gesture location. I don't want it to do that.
            – Tiptonix Beats
            Nov 12 at 23:50











          • I think I'd try the timer route. Put a timer in so that position.x only sets when the timer goes off. Then it should reduce the "teleport" affect. Save the last X (in mine its data.lastMouseX) value somewhere that it can be shared between the timer and call to it.
            – Voltan
            Nov 12 at 23:59










          • You could also use a lerp to get several points between x and far right pan drag
            – Voltan
            Nov 13 at 17:58










          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53255523%2fscenekit-scnnode-follow-touch-movement%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          1
          down vote



          accepted










          Try handlePan and setting/saving a dragMode state variable. The code below is something I used to select a panel and strafe the screen, so there is some extra code in for those things, but I think you could modify it to fit your needs. In your case, my "strafing the screen" should be similar to your need to drag the ball towards your fingertip.



          If you set your ball object to currentLocation.x in dragChanges(), then it should line up exactly on your finger tip and the response should happen quickly. My guess based on your picture is that you'd want a slight delay so that it's more realistic. If that's the case, I'd suggest adding a timer and processing a small queue of saved X positions so that it comes towards your finger tip in small increments.



          Hope that helps.



          //**************************************************************************
          @objc func handlePan(recognizer: UIPanGestureRecognizer)

          //**************************************************************************
          func dragBegins(vRecognizer: UIPanGestureRecognizer)

          if(data.gameState == .run)

          if(vRecognizer.numberOfTouches == 2) dragMode = .strafe


          //**************************************************************************
          func dragChanges(vRecognizer: UIPanGestureRecognizer)

          if(data.gameState == .run)

          if(dragMode == .strafe && vRecognizer.numberOfTouches == 1)

          dragMode = .none
          return


          switch(dragMode)

          case .strafe:
          gNodes.camera.strafe(vX: Float(currentLocation.x), vY: Float(currentLocation.y))
          break
          case .none:
          break
          default:
          break



          //**************************************************************************
          func dragEnds(vRecognizer: UIPanGestureRecognizer)

          if(data.gameState == .run)

          switch(dragMode)

          case .strafe:
          break
          default:
          break


          dragMode = .none






          share|improve this answer




















          • This helped me out a lot, thanks. What should I put inside of the handlePan function that prevents the user from moving the ball unless it's within x amount of distance from the ball? If I pan on the far right side of the screen, and the ball is positioned on the far left, it "teleports" to the gesture location. I don't want it to do that.
            – Tiptonix Beats
            Nov 12 at 23:50











          • I think I'd try the timer route. Put a timer in so that position.x only sets when the timer goes off. Then it should reduce the "teleport" affect. Save the last X (in mine its data.lastMouseX) value somewhere that it can be shared between the timer and call to it.
            – Voltan
            Nov 12 at 23:59










          • You could also use a lerp to get several points between x and far right pan drag
            – Voltan
            Nov 13 at 17:58














          up vote
          1
          down vote



          accepted










          Try handlePan and setting/saving a dragMode state variable. The code below is something I used to select a panel and strafe the screen, so there is some extra code in for those things, but I think you could modify it to fit your needs. In your case, my "strafing the screen" should be similar to your need to drag the ball towards your fingertip.



          If you set your ball object to currentLocation.x in dragChanges(), then it should line up exactly on your finger tip and the response should happen quickly. My guess based on your picture is that you'd want a slight delay so that it's more realistic. If that's the case, I'd suggest adding a timer and processing a small queue of saved X positions so that it comes towards your finger tip in small increments.



          Hope that helps.



          //**************************************************************************
          @objc func handlePan(recognizer: UIPanGestureRecognizer)

          //**************************************************************************
          func dragBegins(vRecognizer: UIPanGestureRecognizer)

          if(data.gameState == .run)

          if(vRecognizer.numberOfTouches == 2) dragMode = .strafe


          //**************************************************************************
          func dragChanges(vRecognizer: UIPanGestureRecognizer)

          if(data.gameState == .run)

          if(dragMode == .strafe && vRecognizer.numberOfTouches == 1)

          dragMode = .none
          return


          switch(dragMode)

          case .strafe:
          gNodes.camera.strafe(vX: Float(currentLocation.x), vY: Float(currentLocation.y))
          break
          case .none:
          break
          default:
          break



          //**************************************************************************
          func dragEnds(vRecognizer: UIPanGestureRecognizer)

          if(data.gameState == .run)

          switch(dragMode)

          case .strafe:
          break
          default:
          break


          dragMode = .none






          share|improve this answer




















          • This helped me out a lot, thanks. What should I put inside of the handlePan function that prevents the user from moving the ball unless it's within x amount of distance from the ball? If I pan on the far right side of the screen, and the ball is positioned on the far left, it "teleports" to the gesture location. I don't want it to do that.
            – Tiptonix Beats
            Nov 12 at 23:50











          • I think I'd try the timer route. Put a timer in so that position.x only sets when the timer goes off. Then it should reduce the "teleport" affect. Save the last X (in mine its data.lastMouseX) value somewhere that it can be shared between the timer and call to it.
            – Voltan
            Nov 12 at 23:59










          • You could also use a lerp to get several points between x and far right pan drag
            – Voltan
            Nov 13 at 17:58












          up vote
          1
          down vote



          accepted







          up vote
          1
          down vote



          accepted






          Try handlePan and setting/saving a dragMode state variable. The code below is something I used to select a panel and strafe the screen, so there is some extra code in for those things, but I think you could modify it to fit your needs. In your case, my "strafing the screen" should be similar to your need to drag the ball towards your fingertip.



          If you set your ball object to currentLocation.x in dragChanges(), then it should line up exactly on your finger tip and the response should happen quickly. My guess based on your picture is that you'd want a slight delay so that it's more realistic. If that's the case, I'd suggest adding a timer and processing a small queue of saved X positions so that it comes towards your finger tip in small increments.



          Hope that helps.



          //**************************************************************************
          @objc func handlePan(recognizer: UIPanGestureRecognizer)

          //**************************************************************************
          func dragBegins(vRecognizer: UIPanGestureRecognizer)

          if(data.gameState == .run)

          if(vRecognizer.numberOfTouches == 2) dragMode = .strafe


          //**************************************************************************
          func dragChanges(vRecognizer: UIPanGestureRecognizer)

          if(data.gameState == .run)

          if(dragMode == .strafe && vRecognizer.numberOfTouches == 1)

          dragMode = .none
          return


          switch(dragMode)

          case .strafe:
          gNodes.camera.strafe(vX: Float(currentLocation.x), vY: Float(currentLocation.y))
          break
          case .none:
          break
          default:
          break



          //**************************************************************************
          func dragEnds(vRecognizer: UIPanGestureRecognizer)

          if(data.gameState == .run)

          switch(dragMode)

          case .strafe:
          break
          default:
          break


          dragMode = .none






          share|improve this answer












          Try handlePan and setting/saving a dragMode state variable. The code below is something I used to select a panel and strafe the screen, so there is some extra code in for those things, but I think you could modify it to fit your needs. In your case, my "strafing the screen" should be similar to your need to drag the ball towards your fingertip.



          If you set your ball object to currentLocation.x in dragChanges(), then it should line up exactly on your finger tip and the response should happen quickly. My guess based on your picture is that you'd want a slight delay so that it's more realistic. If that's the case, I'd suggest adding a timer and processing a small queue of saved X positions so that it comes towards your finger tip in small increments.



          Hope that helps.



          //**************************************************************************
          @objc func handlePan(recognizer: UIPanGestureRecognizer)

          //**************************************************************************
          func dragBegins(vRecognizer: UIPanGestureRecognizer)

          if(data.gameState == .run)

          if(vRecognizer.numberOfTouches == 2) dragMode = .strafe


          //**************************************************************************
          func dragChanges(vRecognizer: UIPanGestureRecognizer)

          if(data.gameState == .run)

          if(dragMode == .strafe && vRecognizer.numberOfTouches == 1)

          dragMode = .none
          return


          switch(dragMode)

          case .strafe:
          gNodes.camera.strafe(vX: Float(currentLocation.x), vY: Float(currentLocation.y))
          break
          case .none:
          break
          default:
          break



          //**************************************************************************
          func dragEnds(vRecognizer: UIPanGestureRecognizer)

          if(data.gameState == .run)

          switch(dragMode)

          case .strafe:
          break
          default:
          break


          dragMode = .none







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 12 at 21:41









          Voltan

          155110




          155110











          • This helped me out a lot, thanks. What should I put inside of the handlePan function that prevents the user from moving the ball unless it's within x amount of distance from the ball? If I pan on the far right side of the screen, and the ball is positioned on the far left, it "teleports" to the gesture location. I don't want it to do that.
            – Tiptonix Beats
            Nov 12 at 23:50











          • I think I'd try the timer route. Put a timer in so that position.x only sets when the timer goes off. Then it should reduce the "teleport" affect. Save the last X (in mine its data.lastMouseX) value somewhere that it can be shared between the timer and call to it.
            – Voltan
            Nov 12 at 23:59










          • You could also use a lerp to get several points between x and far right pan drag
            – Voltan
            Nov 13 at 17:58
















          • This helped me out a lot, thanks. What should I put inside of the handlePan function that prevents the user from moving the ball unless it's within x amount of distance from the ball? If I pan on the far right side of the screen, and the ball is positioned on the far left, it "teleports" to the gesture location. I don't want it to do that.
            – Tiptonix Beats
            Nov 12 at 23:50











          • I think I'd try the timer route. Put a timer in so that position.x only sets when the timer goes off. Then it should reduce the "teleport" affect. Save the last X (in mine its data.lastMouseX) value somewhere that it can be shared between the timer and call to it.
            – Voltan
            Nov 12 at 23:59










          • You could also use a lerp to get several points between x and far right pan drag
            – Voltan
            Nov 13 at 17:58















          This helped me out a lot, thanks. What should I put inside of the handlePan function that prevents the user from moving the ball unless it's within x amount of distance from the ball? If I pan on the far right side of the screen, and the ball is positioned on the far left, it "teleports" to the gesture location. I don't want it to do that.
          – Tiptonix Beats
          Nov 12 at 23:50





          This helped me out a lot, thanks. What should I put inside of the handlePan function that prevents the user from moving the ball unless it's within x amount of distance from the ball? If I pan on the far right side of the screen, and the ball is positioned on the far left, it "teleports" to the gesture location. I don't want it to do that.
          – Tiptonix Beats
          Nov 12 at 23:50













          I think I'd try the timer route. Put a timer in so that position.x only sets when the timer goes off. Then it should reduce the "teleport" affect. Save the last X (in mine its data.lastMouseX) value somewhere that it can be shared between the timer and call to it.
          – Voltan
          Nov 12 at 23:59




          I think I'd try the timer route. Put a timer in so that position.x only sets when the timer goes off. Then it should reduce the "teleport" affect. Save the last X (in mine its data.lastMouseX) value somewhere that it can be shared between the timer and call to it.
          – Voltan
          Nov 12 at 23:59












          You could also use a lerp to get several points between x and far right pan drag
          – Voltan
          Nov 13 at 17:58




          You could also use a lerp to get several points between x and far right pan drag
          – Voltan
          Nov 13 at 17:58

















          draft saved

          draft discarded
















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53255523%2fscenekit-scnnode-follow-touch-movement%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          這個網誌中的熱門文章

          How to read a connectionString WITH PROVIDER in .NET Core?

          In R, how to develop a multiplot heatmap.2 figure showing key labels successfully

          Museum of Modern and Contemporary Art of Trento and Rovereto