
在前面的部分中,我们为使用SceneKit和SpriteKit构建游戏奠定了坚实的基础。 当然,它仍然很粗糙并且图形也可以改进,但这是次要的。 最重要的是要成为可玩的东西。 进行改进是较容易的部分。
运动控制
我们现在将进行一项改进,以使游戏更加有趣和可玩。 到目前为止,这是我们遗漏的内容: 用户输入 。
- 团队领导失败-武士小鸡的方式
- Herrero Games Mercury Race独家开发商专访
- 仅iPad,gamedev –#12 –与pixelart的合作变得更好。
- 是否可以在50分钟内完成游戏?
- 多人沙发相机
驾驶飞机的可能性更加真实。 当然,我们可以通过滑动向左或向右操纵它,但这对于飞机来说并不现实。 这是CoreMotion进入游戏的地方:
Core Motion报告来自iPhone的与运动和环境有关的数据。 它包括来自加速度计,陀螺仪,计步器和磁力计的数据,您可以使用此框架访问硬件生成的数据来控制游戏。
将CoreMotion添加到游戏
在我们的游戏中包含CoreMotion的步骤并不是很复杂,下面逐行进行说明。 必须在GameViewController.swift中进行第一个更改。 也许你问自己为什么我不直接在GameLevel类中那样做。 从技术上讲,我们可以做到这一点,但我建议始终将与设备相关的内容放入GameViewController中,以使游戏本身不受依赖于任何平台的代码的约束 。 当我们稍后将游戏移植到macOS甚至tvOS时,这使操作变得更加容易。 但是,让我们现在开始:
首先,我们导入CoreMotion,因此可以在我们的项目中使用它。 然后,我添加了三个成员变量。 一个用于CMMotionManager本身,另外两个用于存储开始数据(稍后将详细介绍)和加速度计的当前数据。
private var _motionManager = CMMotionManager()
private var _startAttitude: CMAttitude?
private var _currentAttitude: CMAttitude?
然后,我们可以使用以下代码行启动CMMotionManager:
private func setupMotionHandler() {
if (_motionManager.isAccelerometerAvailable) {
_motionManager.accelerometerUpdateInterval = 1/60.0
_motionManager.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: {(data, error) in
self.motionDidChange(data: data!)
})
}
}
这段代码应该大部分是自我解释的,但是用简单的话来说:我们检查加速度计设备是否可用,如果有,我们调用startDeviceMotionUpdates()并分配一个处理程序(Swift块)。 现在以1 / 60.0秒的频率调用此块获取。 并给我们准确的数据。 因为我们对绝对值不感兴趣,但对给定起始值(用户滚动或俯仰iPhone的程度)的差异不感兴趣,因此我们将这两个值都保存下来。 因此, _startAttitude是一个参考值,在玩家开始与此相关的动作之前,我们会立即保存该参考值。 所有这些都是在motionDidChange()中完成的 :
private func motionDidChange(data: CMDeviceMotion) {
_currentAttitude = data.attitude
guard _level != nil, _level?.state == .play else { return }
// Up/Down
let diff1 = _startAttitude!.roll - _currentAttitude!.roll
if (diff1 >= Game.Motion.threshold) {
_level!.motionMoveUp()
}
else if (diff1 <= -Game.Motion.threshold) {
_level!.motionMoveDown()
}
else {
_level!.motionStopMovingUpDown()
}
// Left/Riight
let diff2 = _startAttitude!.pitch - _currentAttitude!.pitch
if (diff2 >= Game.Motion.threshold) {
_level!.motionMoveLeft()
}
else if (diff2 <= -Game.Motion.threshold) {
_level!.motionMoveRight()
}
else {
_level!.motionStopMovingLeftRight()
}
}
通过前面的解释,现在很容易阅读此内容。 我们感兴趣的是滚动参数可以上下飞行(是的!现在也可以),而音高参数则可以左右飞行。 因此,我们现在有了所需的数据,只需在GameLevel中调用一些新方法,就可以告诉飞机要向哪个方向飞行。 现在您还可以看到我们所做的抽象。 GameLevel本身永远不会知道数据来自何处。 因此,像这样,我们可以使用我们想要的任何东西来操纵飞机,而无需更改游戏。
适应播放器类
当然,这只是故事的一半。 飞机现在还必须能够对此命令做出反应。 顺便说一句。 GameLevel本身只是将命令传递给Player类,因此我们专注于此。 因为所有四个动作的工作方式相同,所以我根据moveUp对其进行了解释。 如在motionDidChange()中所见,我们调用了两个方法:
- 当差异> = 0.2(阈值)时, motionMoveUp()或motionMoveDown( )
- 差异小于0.2时的motionStopMovingUpDown()
这对于理解移动的概念很重要。 第一步,我们实际上从内部开始进行此移动的SCNAction() ,第二步(当用户将Phone 滑回到起始位置时),我们将删除该动作。 这就是整个秘密,在代码中看起来像这样:
func moveUp() {
let oldDirection = _upDownDirection
if _upDownDirection == .none {
let moveAction = SCNAction.moveBy(x: 0, y: Game.Player.upDownMoveDistance, z: 0, duration: 0.5)
self.runAction(SCNAction.repeatForever(moveAction), forKey: "upDownDirection")
_upDownDirection = .up
}
else if (_upDownDirection == .down) {
self.removeAction(forKey: "upDownDirection")
_upDownDirection = .none
}
if oldDirection != _upDownDirection {
adjustCamera()
}
}
和
func stopMovingUpDown() {
let oldDirection = _upDownDirection
self.removeAction(forKey: "upDownDirection")
_upDownDirection = .none
if oldDirection != _upDownDirection {
adjustCamera()
}
}
很简单,不是吗? 现在,我们在所有四个方向上都执行了此操作,并且飞机的飞行行为几乎完美。 实际上,这足以玩游戏,但与往常一样,我们将继续加倍努力,以使其看起来更好。 使它看起来更专业的一种方法是使用平滑的相机移动。 这是好莱坞大片中大量使用的一种技术,因此我们也要这样做……每当我们改变方向时,我们都将摄像机的位置移动到播放器后面,但会延迟一点。 为此,我们使用SCNTransaction.begin()和SCNTransaction.end() ,使用SCNTransaction.animationDuration = 1.0设置动画时间,现在我们在中间所做的每个更改都将被动画化。 看起来很酷吧?
我们要做的第二件事是在向任何方向移动时稍微旋转平面,因此它看起来更自然。 这发生在Player类的update()方法中,并且看起来与相机几乎相同:
SCNTransaction.begin()
SCNTransaction.animationDuration = 1.0
_playerNode?.eulerAngles = SCNVector3(eulerX, 0, eulerZ)
SCNTransaction.commit()
就这样。 现在,我们有了一个完美的飞机,在此之上,我唯一要做的就是控制(同样在update()方法中)允许飞机向上,向下,向左或向右飞行的最大值。
一些小东西
我希望您也喜欢本章。 这是从一开始就拥有的第一个Hello World教程中真正制作真实游戏所需的最后一步(概念性)。 但是不用担心,接下来还会有5章,其中包括SceneKit的更多有趣方面。 我们还将看到如何在其他(苹果)平台上使用它。
除了使用CoreMotion控制平面的主要更改之外,我还在项目的各个位置添加了一些较小的改进。
戒指位置
我们现在也可以上下飞行,因此合乎逻辑的步骤是将吊环放置在不同的高度。 这样,游戏变得更加困难和有趣。 您还会注意到,戒指现在有数字。 只是一种视觉效果,但是看起来很不错,您可以花一些时间使外观更加优美。
地形
我也通过使其更波浪来改变了地形的外观。 然后添加一些额外的灯光并更改电流并将雾添加到场景中。 有了这三个参数,游戏看起来比以前要好得多,您应该试一试这种效果,看看有什么可能!
游戏设置
如上一章所述,我更喜欢将所有游戏参数都放在一个设置类( GameSettings.swift )中。 更改游戏玩法更加容易,甚至可以轻松地将它们从文件保存并加载到文件中以更改此参数,而无需再次编译游戏。
教程章节:
–第1部分–建立地形
–第2部分–创建一个真实的玩家游戏对象
–第3部分–为您的地形增添生命
–第4部分–实施游戏循环
–第5部分–使用CoreMotion平稳地飞行
–第六部分–完成游戏(缺少的部分)
–第7部分– ARKit:在您的环境中玩
–第8部分–多平台:我们在macOS上的游戏
–第9部分– tvOS:出色的游戏平台
–第10部分-高级SceneKit(有待改进)
别忘了……再次链接到源代码