• 日常搜索
  • 百度一下
  • Google
  • 在线工具
  • 搜转载

结合SpriteKit和SceneKit的强大功能

结合SpriteKit和SceneKit的强大功能  第1张你将要创建 的东西

介绍

SpriteKit 和 SceneKit 是 ios框架,旨在使开发人员可以轻松地在休闲游戏中创建 2D 和 3D 资源。在本教程中,我将向您展示如何将在两个框架中创建的内容组合到一个视图中,以利用应用程序提供的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 模拟器或物理设备上构建并运行您的应用程序。在这个阶段,您的应用程序包含一个蓝色旋转立方体。

结合SpriteKit和SceneKit的强大功能  第2张

是时候在 3D 内容之上添加 SpriteKit 场景了。这是通过 overlaySKScene在任何符合 SCNSceneRenderer协议的对象上设置属性来完成的,在我们的示例中就是SCNView 实例。在ViewController.swift 中将以下几行添加到 viewDidLoad方法中:

override func viewDidLoad() {
    ...
    self.spriteScene = OverlayScene(size: self.view.bounds.size)
    self.sceneView.overlaySKScene = self.spriteScene
}

当您再次构建并运行您的应用程序时,您将看到您现在在左下角有一个暂停按钮位置,在应用程序视图的底部中心有一个分数标签。

结合SpriteKit和SceneKit的强大功能  第3张

你可能想知道为什么使用这个属性比简单地添加一个 对象SKView的子视图 更好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:)当用户从设备的屏幕上抬起手指时调用该 方法。在此方法中,您检查用户是否触摸了暂停按钮并相应地更新场景。再次构建并运行您的应用程序,以检查这部分拼图是否正常工作。

结合SpriteKit和SceneKit的强大功能  第4张

我们现在需要在用户点击暂停按钮时停止 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:)方法而不是 a  UITapGestureRecognizer,因为 UIGestureRecognizer对象会导致 touchesEnded(_:withEvent:)方法的执行非常不一致。由于您将此方法用于暂停按钮,因此您需要确保每次用户点击屏幕时都会调用它。

在该touchesEnded(_:withEvent:)方法中,我们对您的 sceneView. 如果触摸的位置与立方体的位置相对应,则在您的得分上加一分 spriteScene。score由于类中属性 的属性观察者,场景中的文本将自动更新 OverlayScene。

再次运行您的应用程序并点击多维数据集,以验证无论何时点击多维数据集都会更新分数标签。

结合SpriteKit和SceneKit的强大功能  第5张

暂停按钮和乐谱标签都举例说明了如何在 SpriteKit 和 SceneKit 场景之间传输信息。但是,此信息不限于数值和布尔值,它可以是您的项目需要的任何数据类型。

3.使用 SpriteKit 场景作为 SceneKit 材质

除了能够在 SceneKit 场景之上覆盖 SpriteKit 场景,您还可以使用SKScene 实例作为 SceneKit 几何体的材质。这是通过将对象分配给SKScene对象的 contents属性来完成的 SCNMaterialProperty。这使您可以轻松地将动画材质添加到任何 3D 对象上。

让我们看一个例子。在您的应用程序中,您将向立方体添加一个简单的颜色过渡动画,而不是它当前具有的静态蓝色。在类的init方法中 MainScene, 替换以下代码块:

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 材质。

最后一次构建并运行您的应用程序。您将看到立方体的颜色从蓝色变为红色和绿色。

结合SpriteKit和SceneKit的强大功能  第6张

请注意,暂停 SceneKit 场景不会暂停我们用作材质的 SpriteKit 场景。要暂停材质的动画,您需要保留对 SpriteKit 场景的引用并显式暂停它。

结论

结合 SpriteKit 和 SceneKit 内容在很多方面都非常有益。将 2D 场景叠加在 3D 场景之上允许您创建动态界面,并且由于两个场景使用相同的 OpenGL 上下文和渲染管道,这将带来性能提升。您还学习了如何利用 SpriteKit 为 3D 对象创建动画材质。如果您有任何意见或问题,请将其留在下面的评论中。


文章目录
  • 介绍
  • 1. 项目设置
  • 2. SceneKit 和 SpriteKit 交互
  • 3.使用 SpriteKit 场景作为 SceneKit 材质
  • 结论