一步一步教你用Swift开发俄罗斯方块:No.3 二维数组

数组是一个很有用的数据结构,很多程序都建立在数组之上,我很少看到哪个应用程序不用到数组的。

而我们的俄罗斯方块显然也需要数组,而且是更为特殊的  二维数组

为什么是二维数组呢?其实我们的整个游戏区域,可以看做是一个二维数组区域,就像这样:

我们的每一个block都占据在这样一个20x10的区域之内,20行,10列的一个200个block的二维数组让我们可以根据(x,y)坐标来确定block的位置,而这些blocks其实就是组成我们的L形,或者Z形 等等不同但我们都熟知的俄罗斯方块;

swift提供了我们array[index]供我们使用,但是我们还需要一个自定义的array2D[x,y]来更方便我们的使用,所以,让我们来自定义属于自己的二维数组吧!

确保你选中Swiftris文件夹,然后你可以选择? + N 或者 File > New > File…或者左下角的“+”号
> File
来创建新的swift类,如下图所示:

选择Swift然后点击Next, 给你的新类起个名字吧,我们叫做Array2D,意为二维数组,然后我们点击create

在编辑区域会自动打开我们刚刚建好的Array2D 类,我们照着下图进行修改

准备好了,虽然这段代码不长,但是如果你是个swift的新手,这里面却有很多学问,基本上每行都有一个知识点需要学习!

友情提醒: 

-号的红色代码需要移除,+号的绿色代码需要手动加上,注释掉的#1,2,3,4
是便于给大家分段讲解,大家输入的时候可以不输入

subscript函数里面 array[(row * columns) + column] , 注意是row 而不是rows。如果你不小心写成了rows,那很显然,你的数组会越界。刚开始的时候我没有注意,就导致数组越界了。

#1

这里我们命名了一个叫做Array2D的class,在swift里面通常array是用struct 而不是用class,但是这里我们却需要一个class,因为在我们的程序里面,我们需要传引用(pass by reference),而不是传值(pass by value),class是传引用的,而struct是传值的

关于传值和传引用的区别如果学过C++的应该不难理解,我记得Effective c++这本书里面对这部分有很详尽的解释,google一下应该也能找到很多答案,这里我就不展开描述了。

想要查看更多关于swift的class相关知识,请点击这里

另外我们还看到,我们的class类型是<T>, 这里如果学过c++的应该也很容易理解,其实就是模板类了,T表示任意类型,可以是int,可以是string,可以是char等等等等;就是说,我们的这个array2D是一个通用的二维数组,你想在数组里面存任何都是可以的

#2

首先我们定义了一个传统的swift array,数组里面的类型和我们的二维数组类型一样 是<T>,但是我们注意到其实这里是<T?>,多了一个

上一章节我们已经介绍过了,它表示这是一个optional的变量,也就是说可以是nil,可以不包含任何数据,而在我们的面板上,如果数组里面是ni就表示这个地方不显示任何的block

接下来是定义我们自己的init函数,init一个二维数组需要两个参数,行数和列数,前两行代码很简单,把形参中的值传给实例化后的类的两个私有变量,而用来存储数据的数组,就得用到swift原生的array类来建立了。

#3

接下来是定义我们自己的init函数,init一个二维数组需要两个参数,行数和列数,前两行代码很简单,把形参中的值传给实例化后的类的两个私有变量,而用来存储数据的数组,就得用到swift原生的array类来建立了。这里重点讲解一下关于swift array的 init函数  
init(cout: repeatedValue: )

先来看一下官方文档里面的描述:

init(count:repeatedValue:)  

Constructs an array with a given number of elements, each initialized to the same value.  

Declaration  

init(count: Int, repeatedValue: T)
Discussion  

The resulting array will have count elements in it, each initialized to the same value provided as the value for repeatedValue.  

For example:  

let numericArray = Array(count: 3, repeatedValue: 42)
// numericArray is [42, 42, 42]  

let stringArray = Array(count: 2, repeatedValue: "Hello")
// stringArray is ["Hello", "Hello"]  

从举的两个例子来说,很容易理解了:count表示数组的大小,在我们的程序里面就是定义的rows * columns,在具体点就是20 * 10=200;

repeatedValue就表示初始化的值,这里表示所有的值都是一样的,当我第一次看到这个函数,因为教程里面写到的repeatedValue是nil,我以为是是否允许数组有重复的值呢。知道详细查阅了swift的官方文档后,才正确理解了这个函数的意思。

提醒大家:千万不能想当然,不能眼高手低,不清楚的事,一定要翻阅下资料弄清楚了。

关于更多关于swift的array知识,请点击这里

#4

这里我们其实是定义了二维数组的查找符号。swift的array里面 这样的定义其实就是array[index] 中的[], 同理,因为我们的二维数组也需要用到符号,来找到指定位置的内容,因为同时需要两个参数,row和column,所以,这个也需要我们自己来定义,那么我们来详细看一下这个subscript函数吧。

这里可能你有会感到疑虑,-> 又是个什么意思?  其实swift是个尽量把语言描述成我们看到它时想到的意思,比如前面的?和!,一个变量后面加上?就好像在问他,你是不是optional的啊?

!就好像在说,你不是一个optional!

这里的-> 其实就是这样的意思,->前面输入一些参数,然后->后面会返回一个什么类型的东西。那这个函数的意思就是,你给我输入两个参数,一个是column,一个是row,然后经过函数的计算以后,我返回给你一个T类型的值,当然,我也可能返回给你一个空,因为T是optional的

还不是很明白,没关系,慢慢来,我们来看看官方文档里面,对subscript函数的描述,请打开这个文档

Classes, structures, and enumerations can define subscripts, which are shortcuts for accessing the member elements of a collection, list, or sequence.
You use subscripts to set and retrieve values by index without needing separate methods for setting and retrieval.
For example, you access elements in an Array instance as someArray[index] and elements in a Dictionary instance as someDictionary[key].
Subscripts are not limited to a single dimension,
and you can define subscripts with multiple input parameters to suit your custom type’s needs

看,我们就是定义了两个输入参数

Unlike instance methods, subscripts can be read-write or read-only.

也就是说你可以定义subscript函数为读写或者只读模式,我们看到的同时有set和get的是读写模式,如果想要只读模式的,不写get关键字就是了:

As with read-only computed properties, you can drop the get keyword for read-only subscripts:

subscript(index: Int) -> Int {
    // return an appropriate subscript value here
}

我们继续来看几个用到subscript函数的例子,其实定义是这样定义, 使用的时候,和普通的数组usage一样,一对“[]”就可以了

结构体

[plain] view
plain
copy

  1. struct TimesTable {
  2. let multiplier: Int
  3. subscript(index: Int) -> Int {
  4. return multiplier * index
  5. }
  6. }
  7. let threeTimesTable = TimesTable(multiplier: 3)
  8. println("six times three is \(threeTimesTable[6])")
  9. // prints "six times three is 18"

结构体的subscript函数就是返回输入的参数乘以结构体里的私有变量,所以也很容易理解举得例子的值了。

字典

[plain] view
plain
copy

  1. var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
  2. numberOfLegs["bird"] = 2

最后再来看一下官方文档里面给出的二维数组的源代码,是不是和教程里面的很像呢?

[plain] view
plain
copy

  1. struct Matrix {
  2. let rows: Int, columns: Int
  3. var grid: [Double]
  4. init(rows: Int, columns: Int) {
  5. self.rows = rows
  6. self.columns = columns
  7. grid = Array(count: rows * columns, repeatedValue: 0.0)
  8. }
  9. func indexIsValidForRow(row: Int, column: Int) -> Bool {
  10. return row >= 0 && row < rows && column >= 0 && column < columns
  11. }
  12. subscript(row: Int, column: Int) -> Double {
  13. get {
  14. assert(indexIsValidForRow(row, column: column), "Index out of range")
  15. return grid[(row * columns) + column]
  16. }
  17. set {
  18. assert(indexIsValidForRow(row, column: column), "Index out of range")
  19. grid[(row * columns) + column] = newValue
  20. }
  21. }
  22. }

只不过这里的Matrix返回的是double类型的数,而我们的教程里面用到是模板T而已。看到这里应该不用再多解释,关于二维数组的所有内容都一目了然吧?

时间: 2024-10-09 17:41:27

一步一步教你用Swift开发俄罗斯方块:No.3 二维数组的相关文章

一步一步教你用Swift开发俄罗斯方块:No.7 下落机制

上一章节我们完成了shape的建立,现在游戏里面的元素(blocks,shapes)都已经完成了,背景也搭好了(array2D),让我们开始制定游戏规则吧.首先就是需要让我们的shape掉下来,还记得我们刚开始的时候每个600毫秒要刷新一下屏幕呢?那会还有一个closure我们都不太明白是干嘛用的,马上就知道了. 好了,今天章节过后,你的程序运行起来应该是这样的: 让我们来修改代码吧,这次要修改的代码比较多,而且没有上一章节那样重复的工作.不用太过担心,我们一步一步来: 在#1, 函数在执行时会

一步一步教你用Swift开发俄罗斯方块:No.1 建立你的第一个Swift游戏工程

原文地址:https://www.bloc.io/tutorials/swiftris-build-your-first-ios-game-with-swift#!/chapters/677 好了,我们正式开始我们的swift游戏开发! 首先,需要新建一个工程,熟悉iOS开发的童鞋应该对这个步骤不会陌生.我们还是一步一步来吧: 这里有两种途径建立全新的工程,你可以: 如果你的Mac没有运行Xcode,请打开它,然后在欢迎页面点击Create a new Xcode project 这里我还是要重

一步一步教你用Swift开发俄罗斯方块:No.6 变形记

The object of art is to give life shape - William Shakespeare 上一章节我们介绍了这个游戏最基本的组成元素,block,那么接下来我们就开始更为清晰和形象地了解如果做出来俄罗斯方块的shape吧.是的,就是这样的形状: 首先我们来新建一个类,名字叫做Shape:到这里新建一个类的步骤应该很熟练了吧. 我们来修改下面的代码 在代码的第一部分,我们先建立了一个枚举类型,这个enumeration用来辅助我们定义我们的shape的4个方向,无

一步一步教你用Swift开发俄罗斯方块:No.2 准备工作

如果你已经成功建好了工程,运行之后你会发现是个小飞机的程序,如果我没记错的: 这个程序是spin-the-bottle:Space Edition,但是可惜的是,我们并不需要这些东西,我们需要一个干净的模板,所以,我们需要首先清理下战场,然后把我们需要用到的一些资源放进来. 打开项目导航栏,如下图中圆圈内的图标,或者点击? + 1: 右键点击GameScene.sks,选择delete 当系统询问的时候,选择move to trash 接下来点击image.xcassets,然后删除spaces

一步一步教你用Swift开发俄罗斯方块:No.4 滴答作响的时钟机制

为什么标题要叫做"滴答作响的时钟机制"呢? 想必我们大家都玩过俄罗斯方块,那些不同形状的东西,就是哪些不同形状,你懂的,会随着游戏级别的提高而下降的越来越快.是的 ,我们也要模仿那样,做出我们自己的时钟机制. 我们可以看到SKScene里面有一个函数 update(currentTime: CFTimeInterval). 这个函数被没一帧所调用.帧,frame, 是什么? 你可以理解一帧就是一副静态的图片,如果很多图片在很短的时间内连续播放,就成了动画.当你的眼睛开始去预知每一帧图像

一步一步教你用Swift开发俄罗斯方块:No.0

花了一周时间,按照Swift的开发教程,各种查阅资料,各种google,总算把俄罗斯方块游戏写完了,也想写个系列教学blog:因为虽然看着教程不长,但是对于从零学Swift的我,中间还是遇到了很多困难,好多bug不知道是怎么出来的,都是经过很纠结的过程才一一克服掉的,所以,这篇中文版的系列教学,也算是个为想学swift而又无从下手的童鞋们图个方便吧. 先上一个最终版本,基本效果就是这样,添加了动画效果和音效等等,其实还有很多事情可以做,只要照着这系列的blog进行下去,相信大家最终都创造出有着自

一步一步教你用Swift开发俄罗斯方块:No.5 Block Party

我实在想不出怎么才能起一个好听点的中文名字,还是用原教程中的名字,block party 吧 如果前面的几篇教程你觉得很简单,那么是时候开始加深难度了. 在俄罗斯方块游戏中,我们的主体就是那些形状,而每一个形状都是由不同的块组成的.所以,我们需要建立一个基础类,block,用来为我们更上层的显示打基础. 首先,按照建立二维数组array2D的步骤建立一个新的class,起名叫做Block 按照下面修改你的block类 可能你已经猜到了,这不是我们block 类的全部内容. 这部分只是定义了一个e

Swift - 25 - 控制转移和二维数组

//: Playground - noun: a place where people can play import UIKit // fallthrough // fallthrough会在当前case执行完之后继续下一个case // 如果在下一个case中声明了变量, 则不能使用fallthrough var coordinate = (1, 0) switch coordinate { case (0, 0): print("It's at origin!") fallthr

Swift语言学习No.2: 二维数组

之前在教程中学习了二维数组,原本里面很多知识点都不甚了解,后来经过一番资料查找,基本上理解透彻了,做个总结吧. 老规矩,先上代码: class Array2D<T> { let columns: Int let rows: Int var array: Array<T?> init(columns: Int, rows: Int) { self.columns = columns self.rows = rows array = Array<T?>(count:rows