CoreGraphic框架解析 (九)—— 一个简单小游戏 (一)

版本记录

版本号 时间
V1.0 2019.02.01 星期五

前言

quartz是一个通用的术语,用于描述在iOSMAC OS X 中整个媒体层用到的多种技术 包括图形、动画、音频、适配。Quart 2D 是一组二维绘图和渲染APICore Graphic会使用到这组APIQuartz Core专指Core Animation用到的动画相关的库、API和类。CoreGraphicsUIKit下的主要绘图系统,频繁的用于绘制自定义视图。Core Graphics是高度集成于UIView和其他UIKit部分的。Core Graphics数据结构和函数可以通过前缀CG来识别。在app中很多时候绘图等操作我们要利用CoreGraphic框架,它能绘制字符串、图形、渐变色等等,是一个很强大的工具。感兴趣的可以看我另外几篇。
1. CoreGraphic框架解析(一)—— 基本概览
2. CoreGraphic框架解析(二)—— 基本使用
3. CoreGraphic框架解析(三)—— 类波浪线的实现
4. CoreGraphic框架解析(四)—— 基本架构补充
5. CoreGraphic框架解析 (五)—— 基于CoreGraphic的一个简单绘制示例 (一)
6. CoreGraphic框架解析 (六)—— 基于CoreGraphic的一个简单绘制示例 (二)
7. CoreGraphic框架解析 (七)—— 基于CoreGraphic的一个简单绘制示例 (三)
8. CoreGraphic框架解析 (八)—— 基于CoreGraphic的一个简单绘制示例 (四)

开始

首先看下写作环境

Swift 4.2, iOS 12, Xcode 10

在这个Core Graphics教程中,您将创建样式(patterns),在Playgrounds中对它们进行原型化,并强化一些概念,如基于路径的绘制。

在本教程中,您将使用Core Graphics来完成名为Recall的模式识别游戏。

打开已经下载好的工程并运行,如下所示:

RecallLeft vs Right brain应用程序中的游戏中获取灵感。 游戏的目标是为视图中的对象选择流行的方向。 一旦做出选择,就会显示一组新对象。 在比赛结束前你有五次尝试。

Recall对四个象限中的图案对象进行分组。 入门应用中的每个象限都有一个label。 文本表示方向,背景颜色表示填充颜色。

这个游戏现在相当平庸。

您的任务是使用新发现的Core Graphics将其转换为下面的完成的应用程序:

看看Xcode中的项目。这些是主要文件:

  • GameViewController.swift:控制游戏玩法并显示游戏视图。
  • ResultViewController.swift:显示最终得分和重启游戏的按钮。
  • PatternView.swift:显示游戏视图中其中一个象限的样式视图。

您将增强PatternView以显示所需的模式。

对于初学者,您将在Playgrounds中对新的和改进的PatternView进行原型设计。这使您可以更快地迭代,同时了解Core Graphics模式的细节。完成后,您将相关代码传输到Recall启动项目。

在Xcode中,转到File ▸ New ▸ Playground…,选择Single View模板。单击Next,将playground命名为PatternView.playground,然后单击Create。您的playground包含一个带有单个视图的视图控制器。

选择Editor ▸ Run Playground以执行playground。单击Show the Assistant Editor以显示启动器视图。它显示了标志性的“Hello World!”,结果:

在浏览下一节时,您将使用模式视图(pattern view)替换起始视图。准备开始了吗?


Anatomy of a Pattern

在之前的Core Graphics教程中,您已经了解了如何定义和绘制这样的路径:

上面的示例显示您使用颜色填充左侧的路径。 请记住,您还可以使用颜色描边路径。

使用Core Graphics,您还可以使用模式(pattern)描边或填充路径。 下面的示例显示填充路径的彩色图案:

您可以通过执行以下操作来设置模式:

  • 1) 编写一个绘制单个模式单元格的方法。
  • 2) 使用包含如何绘制和放置单个单元格的参数创建模式。
  • 3) 定义模式将使用的颜色信息。
  • 4) 使用您创建的模式绘制所需的路径。

现在,check out 一个略有不同的模式单元格和额外的填充。 细黑边框显示单元格的边界:

要在单元格的边界内绘制,请为模式单元格编写draw方法。 Core Graphics剪辑除界限之外的任何内容。 Core Graphics还希望您每次都以完全相同的方式绘制图案单元格(pattern cell)

设置图案单元格时,draw方法可以应用颜色。 这是一个彩色图案。 无色或掩蔽图案是在draw方法之外应用填充颜色的图案。 这使您可以灵活地在有意义的地方设置图案颜色。

Core Graphics重复调用draw方法来设置模式。 模式创建参数定义模式的外观。 下面的示例显示了一个基本的重复模式,其中单元格彼此相邻排列:

配置模式时,可以指定模式单元格之间的间距:

您还可以应用变换来更改图案的外观。 下图显示了由模糊边框表示的空间内绘制的图案:

第一个显示未更改的模式。 在第二个中,您会看到translated的模式。 第三个显示旋转的图案。 同样,图案单元周围的黑色边框突出了它的边界。

配置模式时,您有很多选项可用。 你将在下一节开始把所有这些放在一起。


Creating your First Pattern

PatternView.playground中的视图控制器类之前添加以下代码:

class PatternView: UIView {
  override func draw(_ rect: CGRect) {
    // 1
    let context = UIGraphicsGetCurrentContext()!
    // 2
    UIColor.orange.setFill()
    // 3
    context.fill(rect)
  }
}

这表示模式的自定义视图。 在这里,您重写draw(_ :)以执行以下操作:

  • 1) 获取视图的图形上下文。
  • 2) 设置上下文的当前填充颜色。
  • 3) 使用当前填充颜色填充整个上下文。

将图形上下文视为可以绘制的画布。 上下文包含将填充或描边路径的颜色等信息。 在使用上下文的颜色信息绘制路径之前,您可以在画布中绘制路径。

MyViewController内部,使用以下内容替换与label相关的loadView()中的代码:

let patternView = PatternView()
patternView.frame = CGRect(x: 10, y: 10, width: 200, height: 200)
view.addSubview(patternView)

这将创建模式视图的实例,设置其frame并将其添加到视图中。

Shift + Command + Return以运行playground。 之前的label已经消失,取而代之的是橙色子视图:

着色只是旅程的开始。 你知道还有更多来自哪里!

PatternView的顶部添加以下属性:

let drawPattern: CGPatternDrawPatternCallback = { _, context in
  context.addArc(
    center: CGPoint(x: 20, y: 20), radius: 10.0,
    startAngle: 0, endAngle: CGFloat(2.0 * .pi),
    clockwise: false)
  context.setFillColor(UIColor.black.cgColor)
  context.fillPath()
}

上面的代码在图形上下文中绘制一个圆形路径,并用黑色填充它。

这表示模式单元格的绘制方法,其类型为CGPatternDrawPatternCallback。 该方法接受指向与模式关联的私有数据的指针。 您没有使用私有数据,因此使用了未命名的参数。 该方法还接受绘制模式单元格时使用的图形上下文。

将以下代码添加到draw(_:)

var callbacks = CGPatternCallbacks(
  version: 0, drawPattern: drawPattern, releaseInfo: nil)

您为drawPattern提供回调,releaseInfo接受系统释放模式时调用的回调。 如果您在模式中使用私有数据,通常会设置一个release回调函数。 由于您不在draw方法中使用私有数据,因此将nil传递给此回调。

在回调分配后立即添加以下内容:

let pattern = CGPattern(
  info: nil,
  bounds: CGRect(x: 0, y: 0, width: 20, height: 20),
  matrix: .identity,
  xStep: 50,
  yStep: 50,
  tiling: .constantSpacing,
  isColored: true,
  callbacks: &callbacks)

这会创建一个模式对象。 在上面的代码中,您传递以下参数:

  • info:指向要在模式回调中使用的任何私有数据的指针。 你传递的是nil,因为你没有使用任何。
  • boundsPattern cell的边界框。
  • matrix:表示要应用的变换的矩阵。 您传递了单位矩阵,因为您没有应用任何变换。
  • xStep:模式单元格之间的水平间距。
  • yStep:图案单元格之间的垂直间距。
  • tiling:更改为用户空间单位和设备像素之间的差异。
  • isColored:图案单元格绘制方法是否应用颜色。 您将此设置为true,因为您的绘制方法设置了颜色。
  • callbacks:指向保存模式回调的结构的指针。

pattern分配后立即添加以下代码:

var alpha : CGFloat = 1.0
context.setFillPattern(pattern!, colorComponents: &alpha)
context.fill(rect)

上面的代码设置了图形上下文的填充模式。 对于彩色图案,还必须传入alpha值以指定图案不透明度。 图案绘制方法提供颜色。 最后,代码使用模式绘制视图的frame区域。

Shift + Command + Return运行playground。 您的模式没有显示出来。 奇怪。 这是怎么回事?

您需要为Core Graphics提供有关图案颜色空间的信息,以便它知道如何处理图案颜色。

alpha声明上面添加以下内容:

// 1
let patternSpace = CGColorSpace(patternBaseSpace: nil)!
// 2
context.setFillColorSpace(patternSpace)

这是代码的作用:

  • 1) 创建图案颜色空间。 对于彩色图案,基本空间参数应为nil。 这会将着色委托给您的图案单元格绘制方法。
  • 2) 将填充颜色空间设置为定义的图案颜色空间。

运行playground。 好的! 你现在应该看到一个圆形的黑色图案:

如何更好地配置模式?


Configuring a Pattern

在您的playground中,更改设置pattern的间距参数,如下所示:

xStep: 30,
yStep: 30,

运行playground,请注意,圆点似乎彼此更接近:

这是有意义的,因为你缩小了模式单元格之间的步长。

现在,更改间距参数,如下所示:

xStep: 20,
yStep: 20,

运行playground,你的圆圈变成了四分之一:

要了解原因,请注意您的绘制方法返回一个半径为10的圆,其中心位于(20,20)。 模式的水平和垂直位移为20,单元格的边界框在原点(0,0)处为20✕20。 这导致重复的四分之一圆从右下边缘开始。

更改绘制圆的drawPattern代码,如下所示:

context.addArc(
      center: CGPoint(x: 10, y: 10), radius: 10.0,
      startAngle: 0, endAngle: CGFloat(2.0 * .pi),
      clockwise: false)

您已将中心点更改为(10,10)而不是(20,20)

运行playground,由于圆圈中心的移动,你回到了整个圈子:

图案单元格边界也与圆圈完美匹配,导致每个单元格与另一个单元格相邻。

您可以通过许多有趣的方式转换模式。 在draw(_:)内部,用以下内容替换pattern

// 1
let transform = CGAffineTransform(translationX: 5, y: 5)
// 2
let pattern = CGPattern(
      info: nil,
      bounds: CGRect(x: 0, y: 0, width: 20, height: 20),
      matrix: transform,
      xStep: 20,
      yStep: 20,
      tiling: .constantSpacing,
      isColored: true,
      callbacks: &callbacks)

您已通过传递转换矩阵来修改CGPattern。 下面是详细分解:

  • 1) 创建表示translation的仿射变换矩阵。
  • 2) 通过将其传递给matrix参数来配置模式以使用此转换。

运行playground,注意图案如何向右和向下移动以匹配您定义的平移:

除了translating图案外,您还可以缩放和旋转图案单元格。 您将在以后为应用程序构建模式时看到如何旋转模式。

这是你如何填充和描绘彩色图案。 在drawPattern中替换:

context.setFillColor(UIColor.black.cgColor)
context.fillPath()  

用下面的代码

context.setFillColor(UIColor.yellow.cgColor)
context.setStrokeColor(UIColor.darkGray.cgColor)
context.drawPath(using: .fillStroke)

在这里,您将填充颜色更改为黄色并设置描边颜色。 然后使用填充和描边路径的选项调用drawPath(using :)

运行你的playground,检查模式现在显示你的新填充颜色和边缘:

到目前为止,您已经使用了彩色图案并在图案绘制方法中定义了颜色。 在完成的应用程序中,您必须创建具有不同颜色的图案。 您可能意识到为每种颜色编写draw方法不是可行的方法。 这就是masking patterns发挥作用的地方。

后记

本篇主要讲述了一个简单小游戏,感兴趣的给个赞或者关注~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容