- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在使用 SceneKit 的 physicsBody 系统来检测对象之间的碰撞,并得到一些非常奇怪的结果。为了说明这一点,我有一个最小的示例,它生成两个具有运动学 physicsBodies 的球体并沿直线移动它们,以便它们短暂重叠。
我希望看到 physicsWorld(:didBeginContact:) 在球体第一次重叠时被调用一次,而 physicsWorld(:didEndContact:) 在它们停止重叠时被调用一次。相反,我看到每个函数被调用了 25 次!
下面是要重现的代码:在 Xcode 8.0 中,使用“游戏”模板创建一个全新的项目。将 GameViewController.swift 的内容替换为:
import UIKit
import SceneKit
class GameViewController: UIViewController, SCNSceneRendererDelegate, SCNPhysicsContactDelegate {
var scnScene: SCNScene!
var scnView: SCNView!
var cameraNode: SCNNode!
var nodeA: SCNNode!
var nodeB: SCNNode!
var countBeginnings: Int = 0
var countEndings: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
setupScene()
setupNodes()
}
func setupScene() {
// create a new SCNScene and feed it to the view
scnView = self.view as! SCNView
scnScene = SCNScene()
scnView.scene = scnScene
// assign self as SCNView delegate to get access to render loop
scnView.delegate = self
// assign self as contactDelegate to handle collisions
scnScene.physicsWorld.contactDelegate = self
// create the camera and position it at origin
cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3Zero
scnScene.rootNode.addChildNode(cameraNode)
// tell scnView to update every frame
scnView.isPlaying = true
}
func setupNodes() {
// create two spheres with physicsBodies, one inside the other
nodeA = SCNNode()
nodeA.name = "Node A"
nodeA.geometry = SCNSphere(radius: 1.0)
nodeA.geometry!.firstMaterial?.diffuse.contents = UIColor.yellow.withAlphaComponent(0.6)
// expected behavior
// nodeA.position = SCNVector3(x: 0.0, y: -0.8, z: -10.0)
// weird behavior
nodeA.position = SCNVector3(x: 0.0, y: -0.9, z: -10.0)
nodeA.physicsBody = SCNPhysicsBody(type: .kinematic, shape: SCNPhysicsShape(geometry: nodeA.geometry!, options: nil))
scnScene.rootNode.addChildNode(nodeA)
nodeB = SCNNode()
nodeB.name = "Node B"
nodeB.geometry = SCNSphere(radius: 0.5)
nodeB.geometry!.firstMaterial?.diffuse.contents = UIColor.red
nodeB.position = SCNVector3(x: -2.0, y: 0.0, z: -10.0)
nodeB.physicsBody = SCNPhysicsBody(type: .kinematic, shape: SCNPhysicsShape(geometry: nodeB.geometry!, options: nil))
scnScene.rootNode.addChildNode(nodeB)
// node A can collide with node B but not the other way around
nodeA.physicsBody!.categoryBitMask = 2
nodeB.physicsBody!.categoryBitMask = 1
nodeA.physicsBody!.contactTestBitMask = 1
}
func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
countBeginnings += 1
print("(" + String(countBeginnings) + ") " + contact.nodeA.name! + " began contact with " + contact.nodeB.name!)
}
func physicsWorld(_ world: SCNPhysicsWorld, didEnd contact: SCNPhysicsContact) {
countEndings += 1
print("(" + String(countEndings) + ") " + contact.nodeA.name! + " ended contact with " + contact.nodeB.name!)
}
var frameNumber = 0
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
nodeB.position.x += 0.01
nodeB.position.y -= 0.01
}
}
还有其他奇怪的事情发生。如果我稍微改变其中一个球体的初始位置,将 y 位置从 -0.9 移动到 -0.8:
nodeA.position = SCNVector3(x: 0.0, y: -0.8, z: -10.0)
现在我得到了预期的行为,一次调用开始,一次调用结束!稍微不同的碰撞角度会导致完全不同的行为。
这可能是 SceneKit 错误还是这实际上是预期的行为?
最佳答案
SCNRenderer 在每一帧运行物理模拟,调用 renderer(_:didSimulatePhysicsAtTime:)其方法SCNSceneRendererDelegate .
在两个球体相交的过程中,会渲染几帧,每次运行物理模拟时,都会检测到碰撞。
这是预料之中的。由您来处理碰撞并将两个球体置于不再碰撞的状态。例如,在游戏中,一旦弹丸击中玩家,它就会消失。碰撞已处理,因此不再触发。
我在 XCode Version 8.0 beta 5 (8S193k) 作为 OS X 应用程序运行时以下列方式使用了您的代码。我在控制台中看到以下跟踪。 begin 和 end 方法只调用一次!
(1) Node A began contact with Node B
(1) Node A ended contact with Node B
import SceneKit
import QuartzCore
class GameViewController: NSViewController, SCNSceneRendererDelegate, SCNPhysicsContactDelegate {
@IBOutlet weak var gameView: GameView!
// MARK: Properties
var cameraNode: SCNNode!
var nodeA: SCNNode!
var nodeB: SCNNode!
var countBeginnings: Int = 0
var countEndings: Int = 0
// MARK: Initialization
override func awakeFromNib(){
super.awakeFromNib()
// create a new scene
let scene = SCNScene(named: "art.scnassets/scene.scn")!
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
// place the camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
// create and add a light to the scene
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = SCNLightTypeOmni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)
// create and add an ambient light to the scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = NSColor.darkGray
scene.rootNode.addChildNode(ambientLightNode)
// set the scene to the view
self.gameView!.scene = scene
// allows the user to manipulate the camera
self.gameView!.allowsCameraControl = true
// show statistics such as fps and timing information
self.gameView!.showsStatistics = true
// configure the view
self.gameView!.backgroundColor = NSColor.black
self.gameView!.delegate = self
setupScene()
setupNodes()
}
func setupScene() {
// assign self as contactDelegate to handle collisions
self.gameView!.scene?.physicsWorld.contactDelegate = self
// create the camera and position it at origin
cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3Zero
self.gameView!.scene?.rootNode.addChildNode(cameraNode)
// tell scnView to update every frame
self.gameView.isPlaying = true
}
func setupNodes() {
// create two spheres with physicsBodies, one inside the other
nodeA = SCNNode()
nodeA.name = "Node A"
nodeA.geometry = SCNSphere(radius: 1.0)
nodeA.geometry!.firstMaterial?.diffuse.contents = NSColor.yellow.withAlphaComponent(0.6)
nodeA.position = SCNVector3(x: 0.0, y: -0.8, z: -10.0)
nodeA.physicsBody = SCNPhysicsBody(type: .kinematic, shape: SCNPhysicsShape(geometry: nodeA.geometry!, options: nil))
self.gameView!.scene?.rootNode.addChildNode(nodeA)
nodeB = SCNNode()
nodeB.name = "Node B"
nodeB.geometry = SCNSphere(radius: 0.5)
nodeB.geometry!.firstMaterial?.diffuse.contents = NSColor.red
nodeB.position = SCNVector3(x: -2.0, y: 0.0, z: -10.0)
nodeB.physicsBody = SCNPhysicsBody(type: .kinematic, shape: SCNPhysicsShape(geometry: nodeB.geometry!, options: nil))
self.gameView!.scene?.rootNode.addChildNode(nodeB)
// node A can collide with node B but not the other way around
nodeA.physicsBody!.categoryBitMask = 2
nodeB.physicsBody!.categoryBitMask = 1
nodeA.physicsBody!.contactTestBitMask = 1
}
// MARK: SCNPhysicsContactDelegate
func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
countBeginnings += 1
print("(" + String(countBeginnings) + ") " + contact.nodeA.name! + " began contact with " + contact.nodeB.name!)
}
func physicsWorld(_ world: SCNPhysicsWorld, didEnd contact: SCNPhysicsContact) {
countEndings += 1
print("(" + String(countEndings) + ") " + contact.nodeA.name! + " ended contact with " + contact.nodeB.name!)
}
// MARK: SCNSceneRendererDelegate
var frameNumber = 0
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
nodeB.position.x += 0.01
nodeB.position.y -= 0.01
}
}
关于swift - 为什么 SceneKit 的 physicsWorld didBeginContact 会为一次碰撞触发多次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39424122/
目标是创建无限的棋盘图案。 使用SCNFloor和附加的图像,我们可以生成接近但不太像棋盘的东西。一些黑色正方形在不应该合并的位置合并。 我们尝试了Scale,WrapS,WrapT,Min filt
这看起来很简单,但我就是无法缩小!使用这些搜索词的所有在线内容都是关于在应用程序中编写效果的。我的问题不在应用程序中;我只想在用户界面中评估和编辑 SceneKit 场景中的所有对象,并在我可以看到整
我在这里遗漏了什么吗?在各种向量/矩阵函数中here ,我看不到任何简单地将 SCNMatrix4 变换应用于 SCNVector4 的函数。我当然可以通过直接写出矩阵/向量乘法来做到这一点,但这肯定
我试图了解 ArKit 中引入的不同元素与 SceneKit 中可能的等价物之间的区别: SCNNode.simdTransform对比 SCNNode.transform .在 ARKit 中,似乎
我已经实现了向 ARKit 和 SceneKit 场景添加阴影平面的多种方法之一。它工作得很好,阴影看起来很好。 问题是大部分时间这架飞机也有灰白色。换句话说,它不是完全透明的。另一方面,有时灰色的类
我在游戏执行过程中随机弹出以下错误: 我正在随机时刻创建 carNode 的多个实例,并且所有实例都具有从场景中删除节点的操作。大多数情况下,这不是问题,但在某些情况下,应用程序会崩溃并显示照片中的错
我正在使用 Metal 计算内核生成网格数据(目前是三角汤)。 是否可以高效(无需任何复制)将网格数据导入 SceneKit 以利用 SceneKit 的渲染器?网格数据会经常更新,因此避免数据复制非
我想使用 Metal 计算着色器来计算一些位置,然后将这些位置输入到 Metal 着色器中。听起来很简单,但我无法将 MTLBuffer 数据导入基于 Metal 的 SCNProgram。 计算内核
在 Xcode 8 中,SceneKit 编辑器 允许您在使用 SCNLightingModelPhysicallyBased 时为 metalness 属性设置浮点值。选项包括金属、电介质、浮点值或
我注意到,如果您有一个空场景,然后在其中加载具有基于物理照明的 3D 模型,则在对象出现时会出现一些卡顿。如果之后我再添加一个不同的对象,就不会发生口吃。 查看分析器,似乎默认 PBR 着色器正在第一
我有一个 SceneKit 游戏,我正在尝试将其与 GameplayKit 集成。 为了让 GameplayKit 正常工作,我需要通过调用 updateWithDeltaTime(seconds:)
我正在 iOS SceneKit 中使用 SCNMorpher 在从 Blender 导出为 DAE 文件的 3D 面部模型上的不同面部表情之间进行变形。变形本身效果很好。 在我第一次在变形器上调用
文档 states GameplayKit also works well for 3D games built with the SceneKit framework 但是,似乎没有提及使用Scen
我通过使用 Interface Builder 将 3D 文本拖到场景中创建了这个 SceneKit 文本。 它是这样创建的: 轴在左下方。有没有一种方法可以使用界面生成器使轴在该文本上居中? 最佳答
我正在尝试将 SwiftUI 路径添加到 Scenekit 场景(作为 SCNShape)。 我创建了:Scenekit View (图片 1)SwiftUI 路径(图 2) 然后我尝试根据以下方法调
我想之前一定有人问过这个问题,但我现在找不到,所以暂时先问一下。 当 SceneKit 动画停止时,SpriteKit 的动画覆盖在 SceneKit 上。这是出乎意料的。这就像整个 SCNView
如何绘制边框以突出显示 SCNNode 并向用户指示该节点已被选中? 在我的项目中,用户可以放置多个虚拟对象,用户可以随时选择任何对象。选择后,我应该向用户显示突出显示的 3D 对象。有没有办法直接实
我正在 Scenekit 中加载一个 .obj 模型。当我尝试加载像(水瓶)这样的小模型时,它工作得很好。但是当我尝试加载更大的模型(如沙发、 table )时,它加载完美,但超出了场景的边界。 在S
我正在编写一个 iOS 应用程序,它使用自定义几何体在 SceneKit 中渲染点云。 This post对我实现这一目标非常有帮助(尽管我将其翻译为 Objective-C),David Rönnq
必须使用什么 orthographicProjection 才能在 SceneKit 中以 1:1 SceneKit 点与屏幕点/像素比率制作 2D 应用程序? 例子:我想在屏幕上的 (200, 20
我是一名优秀的程序员,十分优秀!