![最终产品图片](https://i-blog.csdnimg.cn/blog_migrate/be3be763bba4d2431fa331765891e64d.png)
介绍
SpriteKit和SceneKit是iOS框架,旨在使开发人员可以轻松地在休闲游戏中创建2D和3D资产。 在本教程中,我将向您展示如何将在两个框架中创建的内容组合到一个视图中,以利用Apple提供的API。
您可以通过使用基于2D SpriteKit的界面向3D SceneKit场景添加简单的播放/暂停按钮和得分保持功能来实现此目的。
本教程要求您至少运行Xcode 6+,并且具有使用SpriteKit和SceneKit基本内容的先前经验。 如果没有,那么我建议您首先阅读有关SpriteKit和SceneKit的其他Tuts +教程。
还建议您使用一台物理iOS设备进行测试,这需要一个有效的付费iOS开发人员帐户。 您还需要从GitHub下载入门项目。
1.项目设置
当您打开入门项目时,除了默认的AppDelegate
和ViewController
类外,您还将看到另外两个类MainScene
和OverlayScene
。
该MainScene
类的子类SCNScene
,并提供您的应用程序的3D内容。 同样, OverlayScene
类的子类SKScene
并包含在你的应用程序中的2D内容SpriteKit。
随意查看这些类的实现。 如果您对SpriteKit和SceneKit有一定的经验,应该看起来很熟悉。 在ViewController
类的viewDidLoad
方法中,您还将找到用于设置基本SCNView
实例的代码。
在iOS模拟器或物理设备上构建并运行您的应用。 在此阶段,您的应用程序包含一个蓝色旋转立方体。
![初始3D场景](https://i-blog.csdnimg.cn/blog_migrate/fe48e26730418186bffe8238af09dc16.png)
现在是时候在3D内容之上添加SpriteKit场景了。 这是通过在符合SCNSceneRenderer
协议的任何对象上设置overlaySKScene
属性来完成的,在我们的示例中为SCNView
实例。 在ViewController.swift中,将以下行添加到viewDidLoad
方法:
override func viewDidLoad() {
...
self.spriteScene = OverlayScene(size: self.view.bounds.size)
self.sceneView.overlaySKScene = self.spriteScene
}
当您再次构建并运行应用程序时,您会看到您现在在应用程序视图的左下角有一个暂停按钮,并且在视图的底部中央有一个分数标签。
![叠加SpriteKit场景](https://i-blog.csdnimg.cn/blog_migrate/ce5d0f4c44d9bd62e20e4d2ecd3486e3.png)
您可能想知道为什么使用此属性而不是简单地将SKView
添加为SCNView
对象的子视图SCNView
。 使用overlaySKScene
属性时,应用程序的2D和3D组件都使用相同的OpenGL上下文将内容呈现到屏幕上。 这比创建两个单独的视图要好得多,每个视图都有各自的OpenGL上下文和渲染管道。 即使这种简单设置的差异可以忽略不计,但在更大,更复杂的场景中获得的性能仍然是无价的。
2. SceneKit和SpriteKit的交互
您可以通过多种不同的方式在MainScene
和OverlayScene
实例之间传输信息。 在本教程中,您将使用键值观察,简称KVO。
在实现暂停立方体动画的功能之前,首先需要将此功能添加到SpriteKit场景中。 在OverlayScene.swift中 ,将以下方法添加到OverlayScene
类中:
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as? UITouch
let location = touch?.locationInNode(self)
if self.pauseNode.containsPoint(location!) {
if !self.paused {
self.pauseNode.texture = SKTexture(imageNamed: "Play Button")
}
else {
self.pauseNode.texture = SKTexture(imageNamed: "Pause Button")
}
self.paused = !self.paused
}
}
当用户从设备的屏幕上抬起手指时,将调用touchesEnded(_:withEvent:)
方法。 使用这种方法,您可以检查用户是否触摸了暂停按钮并相应地更新了场景。 再次构建并运行您的应用,以检查这一难题是否正常运行。
![工作暂停按钮](https://i-blog.csdnimg.cn/blog_migrate/e824cf239b9aabd206ed885fe29d214b.png)
现在,当用户点击暂停按钮时,我们需要停止3D立方体旋转。 返回ViewController.swift并将以下行添加到viewDidLoad
方法:
override func viewDidLoad() {
...
self.spriteScene.addObserver(self.sceneView.scene!, forKeyPath: "paused", options: .New, context: nil)
}
最后,将以下方法添加到MainScene.swift以启用键值观察:
override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
if keyPath == "paused" {
self.paused = change[NSKeyValueChangeNewKey] as! Bool
}
}
如果您再次构建并运行您的应用程序,则在点击暂停按钮时,多维数据集应停止旋转。
正如可以将信息从SpriteKit场景传输到SceneKit场景一样,您也可以将数据从SceneKit实例发送到SpriteKit实例。 在这个简单的应用程序中,每次用户点击多维数据集时,您都将为得分添加一个点。 在ViewController.swift中 ,添加以下方法:
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as? UITouch
let location = touch?.locationInView(self.sceneView)
let hitResults = self.sceneView.hitTest(location!, options: nil)
for result in (hitResults as! [SCNHitTestResult]) {
if result.node == (self.sceneView.scene as! MainScene).cubeNode {
self.spriteScene.score += 1
}
}
}
请注意,我们使用touchesEnded(_:withEvent:)
方法而不是UITapGestureRecognizer
,因为UIGestureRecognizer
对象导致touchesEnded(_:withEvent:)
方法执行得非常不一致。 由于您将这种方法用于暂停按钮,因此需要确保每次用户点击屏幕时都会调用该方法。
在touchesEnded(_:withEvent:)
方法中,我们对您的sceneView
触摸的最终位置执行命中测试。 如果触摸的位置与立方体的位置相对应,则将一个点添加到spriteScene
的分数中。 由于OverlayScene
类中score
属性的属性观察器,场景中的文本将自动更新。
再次运行您的应用程序,然后点击多维数据集以验证分数标签是否在每次点击多维数据集时更新。
![轻按多维数据集时得分更新](https://i-blog.csdnimg.cn/blog_migrate/994a75c6ac82d202805897a6abf23dba.png)
暂停按钮和得分标签都说明了如何在SpriteKit和SceneKit场景之间传输信息。 但是,此信息不限于数字和布尔值,它可以是项目需要的任何数据类型。
3.使用SpriteKit场景作为SceneKit材质
除了能够将SpriteKit场景叠加在SceneKit场景之上之外,还可以将SKScene
实例用作SceneKit几何体的材质。 这是通过分配进行SKScene
对象为contents
的财产SCNMaterialProperty
对象。 这使您可以轻松地将动画材质添加到任何3D对象上。
让我们来看一个例子。 在您的应用中,您将向多维数据集添加一个简单的颜色过渡动画,而不是其当前具有的静态蓝色。 在MainScene
类的init
方法中,替换以下代码块:
override init() {
super.init()
let cube = SCNBox(width: 3, height: 3, length: 3, chamferRadius: 0)
let cubeMaterial = SCNMaterial()
cubeMaterial.diffuse.contents = UIColor.blueColor()
cube.materials = [cubeMaterial]
self.cubeNode = SCNNode(geometry: cube)
self.cubeNode.runAction(SCNAction.repeatActionForever(SCNAction.rotateByX(0, y: 0.01, z: 0, duration: 1.0/60.0)))
...
}
使用以下代码块:
override init() {
super.init()
let cube = SCNBox(width: 3, height: 3, length: 3, chamferRadius: 0)
let materialScene = SKScene(size: CGSize(width: 100, height: 100))
let backgroundNode = SKSpriteNode(color: UIColor.blueColor(), size: materialScene.size)
backgroundNode.position = CGPoint(x: materialScene.size.width/2.0, y: materialScene.size.height/2.0)
materialScene.addChild(backgroundNode)
let blueAction = SKAction.colorizeWithColor(UIColor.blueColor(), colorBlendFactor: 1, duration: 1)
let redAction = SKAction.colorizeWithColor(UIColor.redColor(), colorBlendFactor: 1, duration: 1)
let greenAction = SKAction.colorizeWithColor(UIColor.greenColor(), colorBlendFactor: 1, duration: 1)
backgroundNode.runAction(SKAction.repeatActionForever(SKAction.sequence([blueAction, redAction, greenAction])))
let cubeMaterial = SCNMaterial()
cubeMaterial.diffuse.contents = materialScene
cube.materials = [cubeMaterial]
self.cubeNode = SCNNode(geometry: cube)
self.cubeNode.runAction(SCNAction.repeatActionForever(SCNAction.rotateByX(0, y: 0.01, z: 0, duration: 1.0/60.0)))
...
}
此代码段创建一个带有一个背景节点的简单SKScene
实例,该背景节点最初是蓝色的。 然后,我们创建三个动作,以实现从蓝色到红色和绿色的过渡。 我们在后台节点上重复执行这些动作。
虽然我们在示例中使用了基本颜色,但在SpriteKit场景中可以完成的所有操作都可以转换为SceneKit材质。
最后一次构建并运行您的应用。 您将看到立方体的颜色从蓝色过渡到红色和绿色。
![立方体颜色变化](https://i-blog.csdnimg.cn/blog_migrate/50ff4a788f1348e5f13fb562ca89d822.png)
请注意,暂停SceneKit场景不会暂停用作素材的SpriteKit场景。 要暂停材质的动画,您将需要保留对SpriteKit场景的引用并明确地将其暂停。
结论
将SpriteKit和SceneKit内容组合在一起可以通过多种方式带来很大的好处。 在3D场景之上叠加2D场景可以创建动态界面,这将提高性能,因为两个场景都使用相同的OpenGL上下文和渲染管道。 您还学习了如何利用SpriteKit为3D对象创建动画材料。 如果您有任何意见或问题,请将其留在下面的评论中。
翻译自: https://code.tutsplus.com/tutorials/combining-the-power-of-spritekit-and-scenekit--cms-24049