【问题标题】:swift/scenekit problems getting touch events from SCNScene and overlaySKScene从 SCNScene 和 overlaySKScene 获取触摸事件的 swift/scenekit 问题
【发布时间】:2017-03-23 15:58:33
【问题描述】:

下午好,我正试图弄清楚如何从 SCNNode 和 SKSpriteNode 从 SCNScene 中获取触摸通知,并与 SKScene 叠加。

import UIKit
import SceneKit
class GameViewController: UIViewController {
var scnView:SCNView!
var scnScene:SCNScene!
var sprite: spritekitHUD!
var cameraNode: SCNNode!
var shape: SCNNode!


override func viewDidLoad() {
    super.viewDidLoad()
    setupScene()
     }

func setupScene() {
    scnView = self.view as! SCNView
    scnView.delegate = self
    scnView.allowsCameraControl = true
    scnScene = SCNScene(named: "art.scnassets/scene.scn")
    scnView.scene = scnScene
    sprite=spritekitHUD(size: self.view.bounds.size, game: self)
    scnView.overlaySKScene=sprite
    cameraNode = scnScene.rootNode.childNode(withName: "camera",
                                              recursively: true)!
    shape=scnScene.rootNode.childNode(withName: "shape", recursively: true)
    shape.name="ThreeDShape"
    }

 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
 let touch = touches.first!
 let location = touch.location(in: scnView)
 let hitResults = scnView.hitTest(location, options: nil)
 if let result = hitResults.first {
      handleTouchFor(node: result.node)
     }
  }

func handleTouchFor(node: SCNNode) {
  if node.name == "ThreeDShape" {
         print("SCNNode Touched")
    }
  }
}

这是我的 Spritekit 叠加场景

import Foundation
import SpriteKit

class spritekitHUD: SKScene{

var game:GameViewController!
var shapeNode: SKSpriteNode!

init(size: CGSize, game: GameViewController){
    super.init(size: size)
    self.backgroundColor = UIColor.white

    let spriteSize = size.width/12
    self.shapeNode= SKSpriteNode(imageNamed: "shapeNode")
    self.shapeNode.size = CGSize(width: spriteSize, height: spriteSize)
    self.shapeNode.position = CGPoint(x: spriteSize + 8, y: spriteSize + 8)
    self.shapeNode.name="test"
    self.game=game


    self.addChild(self.pauseNode)

}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch=touches.first else{
        return
    }
    let location=touch.location(in: self)
    if self.atPoint(location).name=="test" {
     print("Spritekit node pressed")
    }
 }
}

因此,我可以成功地获得我的 spritenode 已在我的 overlaySKScene 上被触摸的通知,但我无法弄清楚如何获得我的 SCNode 已被触摸的通知。如果你不能有 2 个 touchesbegan 函数,有人知道我如何同时处理 3d 事件和 2d 事件吗?

感谢您的帮助!!

【问题讨论】:

    标签: swift scenekit


    【解决方案1】:

    如果您想为用户控件使用SCNViewSKScene 叠加层(例如,您想在 SKScene 叠加层中实现一个“消耗”触摸的按钮),但也有触摸不点击控件以通过并在底层SCNView 中注册,您必须这样做:在 SKScene 叠加层本身上将isUserInteractionEnabled 设置为false,然后在该叠加层内的任何单个元素上设置true '想充当按钮。

    let overlay = SKScene(fileNamed: "overlay")
    overlay?.isUserInteractionEnabled = false
    let pauseButton = overlay?.childNode(withName: "pauseButton") as? Button 
    // Button is a subclass of SKSpriteNode that overrides touchesEnded
    pauseButton?.isUserInteractionEnabled = true
    sceneView.overlaySKScene = overlay
    

    如果用户触摸一个按钮,按钮的触摸事件(touchesBegantouchesEnded 等)将触发并消耗触摸(虽然底层手势识别器仍然触发)。但是,如果他们触摸按钮外部,则触摸将传递到底层 SCNView。

    【讨论】:

    • 有没有办法防止底层手势识别器在触摸覆盖按钮时触发?
    • 不,我不这么认为。由于手势识别器不能附加到 SKNode,您必须将它们附加到 SCNView,然后查询它们是否接触到覆盖中的任何 SKNode。如果没有,则查询 SCNNodes。
    【解决方案2】:

    这是直接从 Xcode 的游戏模板中“提升”出来的......

    在 viewDidLoad 中添加手势识别器:

           // add a tap gesture recognizer
           let tapGesture = UITapGestureRecognizer(target: self, action:  
               #selector(handleTap(_:)))
            scnView.addGestureRecognizer(tapGesture)
    
        func handleTap(_ gestureRecognize: UIGestureRecognizer) {
        // retrieve the SCNView
        let scnView = self.view as! SCNView
    
        // check what nodes are tapped
        let p = gestureRecognize.location(in: scnView)
        let hitResults = scnView.hitTest(p, options: [:])
        // check that we clicked on at least one object
        if hitResults.count > 0 {
            // retrieved the first clicked object
            let result: AnyObject = hitResults[0]
    
            // result.node is the node that the user tapped on
            // perform any actions you want on it
    
    
        }
    }
    

    【讨论】:

      【解决方案3】:

      你可以在 spritekitHUD 中实现这个方法:

      override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) 
      {
         game.touchesBegan(touches, with: event)
      }
      

      【讨论】:

        猜你喜欢
        • 2016-02-19
        • 1970-01-01
        • 2020-08-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多