[英]HitTest for both Spritekit and Scenekit
我有什么似乎是一個非常基本的ViewController
具有SCNView
它有一個overlaySKScene
。
我遇到的問題是,如果首先在覆蓋場景中的SpriteKit節點中檢測到它,我不希望在底層的self.scene
(下gameScene
中的gameScene
)中檢測到tap。
使用以下內容,即使在SKOverlay場景節點actionButtonNode
上發生了敲擊,兩個場景也都會報告發生了命中。
視圖控制器
import UIKit
import SceneKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
sceneView = self.view as? SCNView
gameScene = GameScene()
let view = sceneView
view!.scene = gameScene
view!.delegate = gameScene as? SCNSceneRendererDelegate
view!.overlaySKScene = OverlayScene(size: self.view.frame.size)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.handleTap(_:)))
tapGesture.cancelsTouchesInView = false
view!.addGestureRecognizer(tapGesture)
}
@objc func handleTap(_ sender:UITapGestureRecognizer) {
let projectedOrigin = self.sceneView!.projectPoint(SCNVector3Zero)
let taplocation = sender.location(in: self.view!)
let opts = [ SCNHitTestOption.searchMode:1, SCNHitTestOption.ignoreHiddenNodes:0 ]
let hitList = self.sceneView!.hitTest(taplocation, options: opts)
if hitList.count > 0 {
for hit in hitList {
print("hit:", hit)
}
}
}
}
OverlayScene
import UIKit
import SpriteKit
class OverlayScene: SKScene {
var actionButtonNode: SKSpriteNode!
override init(size: CGSize) {
super.init(size: size)
self.backgroundColor = UIColor.clear
self.actionButtonNode = SKSpriteNode()
self.actionButtonNode.size = CGSize(width: size.width / 2, height: 60)
self.actionButtonNode.position = CGPoint(x: size.width / 2, y: 80)
self.actionButtonNode.color = UIColor.blue
self.addChild(self.actionButtonNode)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let location = touch?.location(in: self)
if self.actionButtonNode.contains(location!) {
print("actionButtonNode touch")
}
}
}
我沒有為您提供代碼的奇特解決方案,但有兩種可能的解決方法:
一個。 通過處理主viewcontroller中的所有觸摸來避免這種情況。 我也使用SceneKit和SpriteKit疊加來實現這一點,將邏輯保留在疊加場景之外,並僅將其用於預期目標(圖形疊加,而不是常規的交互式SpriteKit場景)。 您可以測試是否在Scenekit視圖控制器中命中了動作按鈕或任何其他按鈕。 如果沒有按下按鈕,則3D場景被擊中。
灣 將bool添加到主要的Scenekit視圖控制器isHandledInOverlay,並在觸摸按鈕時將其設置在SpriteKit場景中。 在主要的Scenekit視圖控制器中檢查handletap中的bool並返回,如果為true則不執行任何操作。
根據評論進行編輯:我只是建議移動這段代碼:
if self.actionButtonNode.contains(location!) {
print("actionButtonNode touch")
}
到ViewController中的handleTap函數。 你必須創建一個包含SKOverlayScene的var,而后者又將actionButtonNode(以及任何其他按鈕)作為屬性,因此在handleTap中你最終得到如下內容:
if self.theOverlay.actionButtonNode.contains(taplocation) {
print("actionButtonNode touch")
} else if self.theOverlay.action2ButtonNode.contains(taplocation) {
print("action2ButtonNode touch")
} else if self.theOverlay.action3ButtonNode.contains(taplocation) {
print("action3ButtonNode touch")
} else {
//no buttons hit in 2D overlay, let's do 3D hittest:
let opts = [ SCNHitTestOption.searchMode:1, SCNHitTestOption.ignoreHiddenNodes:0 ]
let hitList = self.sceneView!.hitTest(taplocation, options: opts)
if hitList.count > 0 {
for hit in hitList {
print("hit:", hit)
}
}
}
因此,首先將2D點擊位置與按鈕的2D坐標進行比較以查看它們是否被點擊,如果沒有,則使用2D點擊位置來查看是否使用點擊測試點擊了3D場景中的對象。
編輯:只是查看我自己的(obj c)代碼並注意到我在主視圖控制器中翻轉Y坐標以獲取SKOverlay中的坐標:
CGPoint tappedSKLoc = CGPointMake(location.x, self.menuOverlayView.view.frame.size.height-location.y);
您可能必須使用您提供給按鈕節點的contains函數的位置來執行此操作。
猶豫要發帖,因為我不是專家,如果我正確理解Xartec,我“想”我以類似的方式解決了它。 我還需要在scenekit中使用屏幕邊緣平移 - 花了一些時間來計算出那個。
我創建了handleTap和handlePan(識別器狀態為begin,changed和end)。
我打電話給CheckMenuTap循環瀏覽所有活動的SpriteKit按鈕,如果其中一個按鈕被點擊則返回true。
如果不是,那么我處理hitTest並查看是否有節點命中。 這是我發現如果我不想要它們就避免在SpriteKit和SceneKit上受到打擊的唯一方法 - 希望有所幫助。
@IBAction func handleTap(識別器:UITapGestureRecognizer){let location:CGPoint = recognizer.location(in:scnView)
if(windowController.checkMenuTap(vLocation: location) == true)
{
return
}
let hitResults: [SCNHitTestResult] = scnView.hitTest(location, options: hitTestOptions)
if(data.gameStateManager.gameState == .run)
{
for vHit in hitResults
{
//print("Hit: \(vHit.node.name)")
if(vHit.node.name?.prefix(5) == "Panel")
{
if(data.gamePaused == true) { return }
windowController.gameControl.selectPanel(vPanel: vHit.node.name!)
return
}
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.