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的模式识别游戏。

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

3691932-b7ed9e4f2d613513.png

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

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

这个游戏现在相当平庸。

3691932-ab5d674927214934.png

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

3691932-9a5aa0c1fe20c938.png

看看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!”,结果:

3691932-1596f3237cda658f.gif

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

3691932-0d0e7f1877ac5b04.png

Anatomy of a Pattern

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

3691932-0a9f3313b347cd84.png

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

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

3691932-02574953b6d54b42.png

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

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

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

3691932-ca322223908a8bc5.png

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

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

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

3691932-104b608da8e53f85.png

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

3691932-20205540915e33cb.png

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

3691932-030a66c03ac78f06.png

第一个显示未更改的模式。 在第二个中,您会看到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已经消失,取而代之的是橙色子视图:

3691932-11769adf4979938e.png

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

3691932-e059781f51d199f4.png

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。 好的! 你现在应该看到一个圆形的黑色图案:

3691932-0a1cd12e98bfa245.png

如何更好地配置模式?

3691932-0301b1ccbb99649a.png

Configuring a Pattern

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

xStep: 30,
yStep: 30,

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

3691932-6aa7c88373436e3a.png

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

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

xStep: 20,
yStep: 20,

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

3691932-7e37af7b0159f540.png

要了解原因,请注意您的绘制方法返回一个半径为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,由于圆圈中心的移动,你回到了整个圈子:

3691932-f7c1f145f6aa2699.png

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

您可以通过许多有趣的方式转换模式。 在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,注意图案如何向右和向下移动以匹配您定义的平移:

3691932-76fd6651b754dc8b.png

除了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,检查模式现在显示你的新填充颜色和边缘:

3691932-a25e5654b5e2de27.png

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

后记

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

3691932-1e82c982d90cb20f.png

猜你喜欢

转载自blog.csdn.net/weixin_34262482/article/details/87034423