Swift 游戏开发之「方块弹珠」(一)

2,159 阅读6分钟

前言

在上一篇文章中,我们已经明白了「蜗牛睡不着」的游戏背景,知道我们要去完成的游戏是什么。在正式进入真正的游戏开发之前,为了有一个较好的过渡,我们先来利用 UIKit 框架本身的一些物理模拟能力,完成一些有趣的 demo,来协助我们理解一些游戏开发的中经常遇到的概念。

UIKit 物理模拟

self.animator = UIDynamicAnimator(referenceView: view)
let redView = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
redView.backgroundColor = .red
view.addSubview(redView)
let gravity = UIGravityBehavior(items: [redView])
self.animator?.addBehavior(gravity)

为视图添加重力

let collision = UICollisionBehavior(items: [redView])
collision.translatesReferenceBoundsIntoBoundary = true
self.animator?.addBehavior(collision)

为视图添加碰撞

默认情况下,碰撞的边界和容器视图的边界是相同的,如果我们想将碰撞边界设置为容器边界往内缩进一些,可以这么做:

collision.setTranslatesReferenceBoundsIntoBoundary(with: UIEdgeInsets(top: 50, left: 50, bottom: 50, right: 50))

2019-11-21 22.36.56.gif

let anchor = CGPoint(x: self.view.bounds.width / 2, y: 100)
let attachment = UIAttachmentBehavior(item: redView, attachedToAnchor: anchor)
self.animator?.addBehavior(attachment)

添加附着物

物理引擎的相关术语

这部分内容我纠结了一下,觉得还是有必要跟大家说明,回想我当初接触物理引擎时,因为一下子进入陌生的领域,很多基础概念需要补,为了一次到位,跟大家分享几个后续游戏开发过程中会经常接触到的术语。

向量

这部分应该是高中数学。在游戏中,向量通常用来描述位置速度。因为向量的内容实在太多,一一说完感觉都能开个辅导班了,因此我只列出一部分后续游戏中可能会用到的重点内容提示,细节大家有时间再自行展开。

向量的长度

移动向量

向量相加

旋转向量

向量的缩放

数量积

得益于在 Swift 中,所有的类型都可以使用「拓展」来增加额外的方法实现一套向量的计算一点都不难。Swift 自定义运算符的功能非常强大,因为它可以节约大量重复代码,但也存在一些问题。除非我们自定义的运算符能被其他阅读代码的人看懂(我自己也不能保证呀~),否则将一些晦涩难懂的符号定义为运算符将降低代码的可读性。

世界

「物理引擎」在一个游戏中是没办法直接去使用的,必须借助于一个附着体使其发挥对应的能力。而「世界」就是物理引擎发生作用的场景,其为所有游戏中的物体得以容身的「宇宙」,如果一个物体位于这个世界之外,那么它是无法被物理引擎管理的,也没有任何物体能够影响到它。

质量

常规概念。一个物体的质量越大,其重量越大,下坠的速度也就越快。

速度

常规概念。在 SpriteKit 物理世界中,速度由两部分构成:水平速度和垂直速度,也即「x 速度」和「y 速度」。

物体

其为物理世界中的对象本身。一个物体能够受外力作用,并且能够和其它物体发生碰撞,具有质量和速度。物理分为「动态物体」和「静态物体」,「静态物体」表明其不受外力作用,也不会移动。

作用力

作用力会导致物体移动。当本游戏中,我们发射一个小球,会给小球施加一个作用力,当我们松开球时,球会获得一个加速度,从而离开初始位置。重力和作用力不是一个概念,重力是另外一种力,它对处在当前重力环境中的所有物体都有影响。要作用多大的力才能使物体移动,这于物体本身的质量有关,在相同的力下,分别将该力作用于较重的物体和较轻的物体,较轻的物体移动速度会相对较快。

摩擦力

常规概念。当一个物体于其它物体接触时,会因二者之间产生的摩擦力而导致运动速度的衰减。在真实世界中,物体和物体之间产生的摩擦力会因为产生热能而被转移掉,但在 SpriteKit 中,仅能做到将动能凭空消耗掉,如果我们想要完全模拟热能的转换,需要再写一套逻辑。我们可以对某个物体制定其摩擦系数,摩擦系数越低,表面越光滑,与其它物体接触时,二者的动能损失就越小。

碰撞体

碰撞体规定了物体的形状,物体本身贴图并不能决定其真正的刚体大小,比如计算一个人的腰围时,必须要求贴身测量,我们测的就是人这个「刚体」本身的腰围,并不是穿着衣服的腰围。SpriteKit 默认提供正方形、矩形、圆形和多边形,可以自定义 Path 设置不同的碰撞体。

边缘碰撞体

边缘碰撞体是碰撞体的子集。其由一条或多条细线构成,边缘碰撞体多数用于构建「墙」等障碍物。具有边缘碰撞体的物体永远不会运动,它是「静态物体」。

碰撞

当两个物体/刚体发生碰撞时,我们称之为「碰撞」。碰撞是行为,碰撞体是对象。发生碰撞时,我们可以从「碰撞」中获取到碰撞体双方的信息,比如发生碰撞的是哪些物体以及碰撞的位置等。

连接

连接是两个物体之间的一种关系。最常用的是 pin 连接,即一个物体能够旋转,但不能从另一个物体的某个相对点离开。另一种是 spring 连接,一个物体能够离开另外一个物体,但当它运动到距离另一个物体的某个范围时,会被弹回去,如上文中的最后一个 demo 所演示的效果。

总结

在这篇文章中,我们通过 UIKit 里自带的一些物理模拟方法做了一些物理小实验,并描述了一遍相关概念,供后续进行游戏开发时的基础支撑。

在下一篇文章中,我们将引入 SpriteKit 的各种概念并实践。

  • 游戏讲解;
  • 熟悉 2D 编程(ing);
  • 刚体碰撞与检测;
  • 小球的发射与方块的消除;
  • 游戏逻辑完善。

GitHub 地址: github.com/windstormey…