SceneKit框架详细解析(四) —— 基于SceneKit的简单游戏示例的实现(三)

版本记录

版本号 时间
V1.0 2018.10.20 星期六

前言

SceneKit使用高级场景描述创建3D游戏并将3D内容添加到应用程序。 轻松添加动画,物理模拟,粒子效果和逼真的基于物理性的渲染。接下来这几篇我们就详细的解析一下这个框架。感兴趣的看下面几篇文章。
1. SceneKit框架详细解析(一) —— 基本概览(一)
2. SceneKit框架详细解析(二) —— 基于SceneKit的简单游戏示例的实现(一)
3. SceneKit框架详细解析(三) —— 基于SceneKit的简单游戏示例的实现(二)

开始

在这部分中,您将学习如何通过Scene Kit物理的强大功能使几何体移动。

我们开始吧!

在本教程中,您将使用SceneKit的物理引擎为您的游戏添加物理。

SceneKit的物理引擎功能强大,易于使用。 您只需告诉SceneKit您想要应用物理的对象,引擎将从该点接管,模拟重力和碰撞等事物。

在深入将物理学集成到游戏中之前,您首先需要为项目添加一些game utilities


Introducing the Game Utilities - 介绍游戏工具

game utilities是专门为您创建的。 它们包括辅助方法,可以处理游戏中的复杂位。 这让你专注于游戏玩法,而不是那些讨厌的比特。

在这里加了一些游戏相关的工具,就不细说了,后面用到会详细说明。

1. Adding the Game Utilities - 添加游戏工具

要添加游戏实用程序,只需将GameUtils文件夹拖放到GeometryFighter组文件夹下的项目中:

SceneKit框架详细解析(四) —— 基于SceneKit的简单游戏示例的实现(三)_第1张图片

将所有设置保留为默认值,然后单击Finish

SceneKit框架详细解析(四) —— 基于SceneKit的简单游戏示例的实现(三)_第2张图片

这会将整个GameUtils文件夹作为一个组导入到您的项目中。 展开此组文件夹,快速查看一些帮助程序方法。 如果某些代码对您没有意义,请不要太担心。


Physics - 物理

是时候快速状态检查游戏的当前状态了。构建并运行游戏;一个很酷的随机几何物体像某种黑暗魔法一样在空气中产生。这可能现在看起来不太多,但很快就会有所改善!

刚刚产生的物体只是挂在空旷的空间里并没有做太多。当然,你可以围绕它旋转相机并放大和缩小,但也就是只能这样。这不是一个有趣的游戏。为了提高兴奋程度,如果物体至少移动一点,那就太好了。

现在,你可以走很长的路,并随着时间的推移操纵对象的位置和旋转,以便旋转和移动。您很快就会意识到虽然可以以这种方式为对象设置动画,但它需要大量的编码工作 - 尤其是当您添加其他功能(如真实碰撞和对象之间的交互)时。

值得庆幸的是,Apple的开发人员已经考虑过这一点;为此,他们将一个非常强大的3D物理引擎集成到SceneKit中。要使用这个内置的物理引擎,您只需要让引擎知道您的对象。

以将几何信息附加到节点的方式相同,可以将physics body附加到节点。物理主体描述了节点的所有物理属性,包括形状,质量,摩擦,阻尼和恢复等内容。物理引擎在模拟对象的真实物理交互时会考虑所有这些信息。这包括重力,摩擦和物理世界中其他物体碰撞等事物。

下一节将详细介绍物理机构的一些重要特征。

1. Physics Body Types - 物理体类型

创建物理主体时必须指定的关键属性之一是其类型(type)。物理体类型定义了物体如何与模拟中的力和其他物体相互作用。

SceneKit中使用了三种类型:

  • 静态(Static)物体不会移动:当其他物体可能与这些物体碰撞时,静态物体本身不受模拟中任何力和碰撞的影响。您可以将此类型用于墙壁和巨大的固定巨石等物体。
  • 动态(Dynamic)物体由物理引擎自动移动以响应力和碰撞。您可以将此类型用于可移动椅子,桌子和杯子等物品。
  • 物理引擎不会自动移动运动(Kinematic)物体以响应力和碰撞。换句话说,如果运动物体与动态(dynamic)物体碰撞,动态物体将会移动,但运动物体不会移动。但是,您可以在代码中手动移动运动体。您可以将此类型用于手动控制的内容,例如移动电梯或可以打开和关闭的门。

2. Physics Shapes - 物理形状

除了物体的类型之外,在创建物理主体时必须指定的另一个导入属性是其形状(shape)。 物理形状定义物理引擎在碰撞检测期间使用的3D形状。 虽然几何定义了节点的视觉效果,但物理主体定义了节点如何与物理模拟中的其他对象进行交互。

您可以使形状(shape)与视觉几何形状完全相同,但这通常比您需要的计算成本更高(因此导致您的游戏运行速度变慢)。 相反,您通常应该使用几何体的简化版本,例如简单的边界框,球体或其中一个提供的原始形状,大致匹配节点的可见外观,如下所示:

SceneKit框架详细解析(四) —— 基于SceneKit的简单游戏示例的实现(三)_第3张图片

3. Adding Physics - 添加物理

现在你已经学会了物理背后的理论,现在是时候开始使用这些概念来改变游戏中的事物了。

在SceneKit中,所有物理实体都是SCNPhysicsBody对象。 创建物理主体后,可以将其分配给SCNNode实例的physicsBody属性。 一旦将物理主体分配给适当的节点,物理引擎就可以为您模拟物理。 就这么简单!

打开GameViewController.swift并在spawnShape()中创建geometryNode的代码行之后添加以下内容:

geometryNode.physicsBody =
  SCNPhysicsBody(type: .dynamic, shape: nil)

这行代码创建了SCNPhysicsBody的新实例,并将其分配给geometryNodephysicsBody属性。 创建物理实体时,可以指定实体的类型和形状。 如果为物理形状传递nilSceneKit将根据节点的可视几何体自动生成形状。

如果要向物理形状添加更多细节,可以创建SCNPhysicsShape并将其用于形状而不是传入nil

构建并运行您的游戏; 一个随机的形状产生进入场景,然后以死鸟的所有优雅的方式从空中掉落,掉出视线:

SceneKit框架详细解析(四) —— 基于SceneKit的简单游戏示例的实现(三)_第4张图片

您甚至可以平移相机以观察物体。 你在这里看到的是重力作用于物体的影响。 SceneKit中的场景默认情况下重力打开。 现在生成的对象具有物理主体,物理模拟将模拟力(例如重力)应用于对象。


Forces - 力

想一想现实生活中的物体:做一些移动的东西 - 比如桌子上的勺子 - 你必须对它施加某种类型的物理力。

SceneKit物理引擎在模拟真实物理方面做得相当不错,所以就像你在现实生活中使用力来移动物体一样,你需要在你的物理体上施加一个力来移动物体。

当你将力施加到一个物理体,你用applyForce(direction: at: asImpulse:)并传递一个SCNVector3实例。可以获得你要施加力时候的力和位置,您施加的力会影响物理体的线性加速度和角加速度。

冲击(impulse)仅将力施加到物理体上,例如当你踢球时。物理模拟中的每一步都应用非冲击力。 SceneKit将在对象上添加所有施加的力,并根据这些力的最终结果加速物理体。这可以模拟类似于助推火箭的东西,其中力是连续的。

之前,您了解到力是具有x,y和z分量的向量。但是,这是什么意思?看看下图:

SceneKit框架详细解析(四) —— 基于SceneKit的简单游戏示例的实现(三)_第5张图片

力具有大小和方向,因此矢量确定每个轴的力的大小。 在上面的示例中,应用具有(x:0,y:10,z:0)向量的力可以使用垂直力向上移动主体。

要应用水平力,您只能使用(x:10,y:0,z:0)的向量指定x轴上的力的大小。 要向左移动而不是向右移动,您将在x轴上施加负的力大小。 当您将各种矢量组合在一起时(x:10,y:10,z:0),您可以准确控制身体的移动方式 - 在这种情况下,对角线。

力也可以应用于物理体的特定位置以产生不同的运动:

SceneKit框架详细解析(四) —— 基于SceneKit的简单游戏示例的实现(三)_第6张图片

同样,它有助于思考现实生活中的例子。 如果你前面有一个挡块并推动它,挡块会根据你施加推动的位置而有所不同。 将相同的力施加到身体质心的左侧或右侧,例如,在(x:1,y:0,z:0)处将使其旋转。在(x:0,y:0,z:0)处直接施加与质心一致的力将不会产生旋转。

1. Applying Force - 施力

卷起你的袖子 - 是时候施加一些力量了!

spawnShape()中为geometryNode创建物理体的行之后添加以下代码:

// 1
let randomX = Float.random(min: -2, max: 2)
let randomY = Float.random(min: 10, max: 18)
// 2
let force = SCNVector3(x: randomX, y: randomY , z: 0)
// 3
let position = SCNVector3(x: 0.05, y: 0.05, z: 0.05)
// 4
geometryNode.physicsBody?.applyForce(force,
  at: position, asImpulse: true)

下面进行详细说明:

  • 1) 这将创建两个随机浮点值,表示力的x和y分量。 它使用您在本教程前面添加的实用程序的Float扩展。
  • 2) 接下来,使用这些随机组件创建一个向量来表示此力。
  • 3) 这将创建另一个向量,表示力将应用到的位置。 该位置稍微偏离中心,以便在物体上产生旋转。
  • 4) 最后,使用所有这些组件,使用applyForce(direction:at:asImpulse :)将力应用于geometryNode的物理体。

构建并运行;当物体凭空产生时,一些神奇的力量将它踢向空中,而不是像死鸟一样掉落:

SceneKit框架详细解析(四) —— 基于SceneKit的简单游戏示例的实现(三)_第7张图片

当重力作用时,物体最终会落下。


Torque - 扭力

扭矩是另一种可以使用applyTorque(torque: asImpulse:)应用于物体的旋转力。 扭矩仅影响物理体的角动量(自旋),而不影响线性动量(x,y,z)。 施加扭矩导致物体围绕其质心旋转。

要了解扭矩如何影响物理机构,请查看下图:

SceneKit框架详细解析(四) —— 基于SceneKit的简单游戏示例的实现(三)_第8张图片

应用扭矩力时,使用SCNVector4指定四分量矢量,而不是像使用力一样使用三分量矢量。 x,y和z分量确定旋转轴,而w分量确定旋转角度,即扭矩的大小。
就像使用applyForce(direction:at:asImpulse :)一样,您可以选择是否将扭矩应用为冲击,这会影响物理引擎处理矢量的方式。

如果扭矩是冲击,则方向矢量被视为角动量的瞬时变化。想想用手指旋转篮球;为了保持球的旋转,你必须用你的手快速挥动球的一侧,每次轻弹都会产生一个冲击,瞬间增加球的角动量。

当扭矩不作为冲击施加时,它在每个物理模拟步骤之后应用。 SceneKit将对所有施加的力和扭矩求和,并根据这些力的净效应加速物理体的角力。可以把它想象成一个围绕自己的轴以恒定速度旋转的行星。

注意:SceneKit物理模拟使用国际单位系统(SI)进行测量:质量单位的公斤数,力单位的牛顿,脉冲(impulse)单位的牛顿秒和扭矩单位的牛顿米。


Adding Flair - 添加Flair

既然你已经移动了几何物体,你可能已经注意到它在屏幕中间的空气中产生,这看起来有点尴尬。 为了解决这个问题,你可以将相机在y轴上移动一点,这样物体就会在屏幕外产生。

1. Positioning the Camera - 定位相机

要向上移动摄像机位置,请使用以下内容替换在setupCamera()中设置摄像机位置的行:

cameraNode.position = SCNVector3(x: 0, y: 5, z: 10)

构建并运行,您将看到该对象似乎在屏幕外生成!

SceneKit框架详细解析(四) —— 基于SceneKit的简单游戏示例的实现(三)_第9张图片

2. Adding some Color - 添加一些颜色

最后,您可以为随机生成的形状添加一些变化。

spawnShape()中添加以下几行,在您随机创建geometry的位置之后,但在创建geometryNode之前:

geometry.materials.first?.diffuse.contents = UIColor.random()

要为随机对象着色,可以修改geometry上的materials;此行获取几何体的第一个可用材质,并将diffuse属性的内容设置为随机UIColor。 UIColor上的random()方法是另一个被定义为game utilities内部扩展的助手。

注意:这里需要注意的是,您可以为漫反射(diffuse )属性的内容指定UIColor,以便更改对象的颜色。

最后,构建并运行游戏以查看颜色漂亮的对象:

SceneKit框架详细解析(四) —— 基于SceneKit的简单游戏示例的实现(三)_第10张图片

后记

本篇主要讲述了基于SceneKit的简单游戏示例的实现,感兴趣的给个赞或者关注~~~

SceneKit框架详细解析(四) —— 基于SceneKit的简单游戏示例的实现(三)_第11张图片

你可能感兴趣的:(SceneKit框架详细解析(四) —— 基于SceneKit的简单游戏示例的实现(三))