首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

如何在以太坊上编写你自己的CryptoKitties风格游戏

CryptoKitties很好地证明了区块链不仅仅只能用来做虚拟货币交易。

我希望在不久的将来很快能看到很多区块链的创新用途,因此我写了一个快速上手,介绍一下CryptoKitties的代码,展示一下它是如何实现的。

这篇文章是面向开发者的,虽然不是一个Solidity的入门教程,但我将尽量把所有的文档链接都附上,好让各个水平的开发者们都能上手。

我们开始吧。

CryptoKitties的源代码

几乎所有CryptoKitties的代码都是开源的。所以了解其工作机制的最好方法是阅读源代码。

源代码总共有大约2000行,在这篇文章里面我将着重介绍我认为最重要的那些部分。不过,如果你想要自己阅读所有的代码,在EthFiddle有一份:

https://ethfiddle.com/09YbyJRfiI

表层预览

如果你还对CryptoKitties不太了解,基本上它是一个可以买卖、繁殖虚拟猫咪的游戏。每个猫咪都有自身基因定义的独特外观。当你让两只猫繁殖的时候,它们的基因就会以独特的方式组合起来,并产生后代,然后你就可以繁殖或者出售它们。

CryptoKitties的代码被分解成很多小的独立合约,以便将相关的代码绑定在一起,而不是把所有东西都放在一个单独的大文件里。

子合约对自猫咪主合约的继承看起来是这样的:

因此KittyCore是最终该应用所指向的合约地址,它继承了之前合约中所有的数据和方法。

我们来一个个看一下这些合约代码:

1.KittyAccessControl:谁来控制这个合约?

“这个合约管理不同操作的地址和约束条件,这些操作只能由特定的角色执行,例如CEO, CFO以及COO。”

这个合约是对合约的管理,与游戏机制无关。基本上,它

给“CEO”、“COO”、“CFO”们定义了一些“setter”方法,这些角色是以太坊中,通过特定函数对合约有特殊的所有权和控制权的地址。

KittyAccessControl定义了一些函数修改器,例如onlyCEO(这个方法限定一个函数只能由CEO来执行),也添加了一些能暂停、重启合约或者提现的方法:

pause()函数或许只是为了让开发者可以在发现任何bug的时候,可以升级到一个新版本才添加的进去的。不过我同事Luke指出,这个方法实际是允许开发者彻底冻结合约,以保证任何人都不能交易、出售或者繁殖他们的猫咪。这并不是说他们想这么做——指出这点很有趣,因为大多数人都认为,因为运行在以太坊上,所以DApp是完全去中心化的。

继续……

2.KittyBase:猫咪(Kitty)到底是个啥?

“在这里,我们定义了在核心功能中共享的最基本的代码。包括了我们的主要数据存储、常量和数据类型,以及用来管理这些东西的内部函数。”

KittyBase定义了应用的许多核心数据。首先它将Kitty定义为一个结构体(struct):

所以我猜,一个猫咪其实就是一组无符号整形数。

我们将每个部分都分解:

genes—一个256比特位长的整形,用来定义猫咪的基因代码。这是决定猫咪外观的核心代码。

birthTime— 猫咪出生的时间戳

cooldownEndBlock— 这只猫咪可以进行繁殖的最短时间

matronId&sireId—猫咪的母亲和父亲的ID

siringWithId— 如果猫咪怀孕了,这个值就是孩子父亲的ID,否则为0

cooldownIndex— 当前猫咪冷却的怀孕时间(距离它下次可以繁殖还需要多长时间)

generation — 猫咪的“代数”。合约产生的首代猫咪其代数编号为0,其下一代的代数则在其父母代数上加一。

需要注意的是,在CryptoKitties中,任意两只猫都可以繁殖后代,因此猫咪是没有性别的。

KittyBase合约则用来定义一个Kitty结构体数组:

这个数组存储所有猫咪实例的数据,有点像猫咪数据库。一个猫咪一旦创建,它就会被添加进这个数组,其数组下标就是这个猫咪的ID。比如这个Genesis拥有编号1的猫咪:

我的数组下标是“1”

这个合约同时也包含了从猫咪的ID到其主人地址的映射,可以用来追踪猫咪的主人是谁:

还定义了一些其他的映射,不过为了让本文不至于太长,我就不再赘述每一个的细节了。

当一个猫咪被从一个主人那里交易到另外一个主人那里的的时候,这个kittyIndexToOwner就会被更新以反映其新的主人。

转移所有权会将猫咪ID的kittyIndexToOwner设置成接收者的“_to_”地址(代码源见1)

我们来看一下新建一个猫咪的时候会发生什么:

(代码源见2)

这个函数被传入了其父亲和母亲的ID、猫咪的代数、256比特的基因代码以及所有者的地址。然后它就创建了新的猫咪,把它放进主Kitty数组,然后调用_transfer()来把它分配给它的新主人。

很厉害吧?我们见识了CryptoKitties如何将猫咪定义成一个数据类型,如何将所有的猫咪保存在区块链上,以及如何追踪每个猫咪的主人。

3.KittyOwnership:猫咪如代币

“遵循ERC-721规范,它为基本的不可替代的令牌事务提供了所需的方法。”

CryptoKitties符合ERC-721令牌规范,这是一种不可替代的代币类型,它可以很好地跟踪数字财产的所有权,比如数字扑克牌或者MMORPG中的稀有物品。

可替代性的一点解释:以太是可替代的,因此任何5个代币都和其他5个代币一样。但是有了像CryptoKitties这样的不可替代代币,并不是所有的猫咪都是完全一样地被创建出来,因此它们之间是不可替代的。

从这个合约定义中你可以看出,KittyOwnership继承自ERC721合约

另外所有的ERC721令牌都遵循相同的标准,所以KittyOwnership合约充满了以下函数的实现:

由于图片规格限制,第20行被截部分为:returns(string infoUrl);

由于这些方法都是公开的,这就为用户提供了一个标准的方式,让他们可以用与其他ERC721令牌交互的方式来和CryptoKitties令牌交互。你可以通过直接和以太坊区块链上的CryptoKitties合约交互,来将你的令牌交易给其他人,而不用去它们的网页。从这个意义来说,你真正地拥有你自己的猫咪(除非你的CEO暂停了合约)。

我不会详述所有这些方法的实现,如果你感兴趣的化,可以在EthFiddle上查看(搜索KittyOwnership)。

插个广告:你想开发你自己的以太坊游戏么?

这篇文章在发布伊始,收到了成千上万了好评,所以我们创建了CryptoZombies:一个教你开发以太坊游戏的在线互动教程。它将手把手教你学习如何编写Solidity代码,开发你自己的以太坊游戏。如果你喜欢这篇文章,快来试试。(https://cryptozombies.io/)

4.KittyBreeding:猫咪变得有点色情

“这个文件包含了培育猫咪的必要方法,以及对繁衍的追踪溯源,其依赖一个外部基组合合约。”

“外部基因组合合约” (geneScience)存储在一个单独的合约中,且没有开源。

KittyBreeding合约包含了让CEO设置这个外部合约地址的方法:

由于图片规格限制,第6行被截部分为:https://github.com/Lunyr/crowdsale-contracts/

blob/cfadd15986c30521d8ba7d5b6f7b4fefcc7ac38/contracts/LunyrToken.sol#L117

(代码源见3)

CryptoKitties之所以这么做,是为了让游戏不至于太简单。如果你能从代码里面读到如猫咪的DNA是如何编译的,那么很容易就能知道哪些猫咪可以繁衍出“名贵”的猫咪了。

稍后giveBirth()方法(我将在后面介绍)将调用geneScience合约来决定新猫咪的DNA。

我们来看看两只猫咪在一起繁殖的时候会发生什么:

(代码源见4)

这个方法拿到母亲和父亲的ID,然后在主kitties数组里面找到它们,将母亲的siringWithId设置为父亲的ID。(siringWithId不为就代表母亲怀孕了)。

它还在父母身上都执行一次triggerCooldown(),来确保它们在设置的时间里无法再次繁殖。

下一步,我们将用giveBirth()方法来创建一个新的猫咪。

(代码源见5)

代码里的注释可以很好地解释代码了。基本上这段代码首先检查母亲是否准备好生产。然后调用geneScience.mixGenes()来确定孩子的基因,将新猫咪的所有权分配给其母亲的所有者。然后调用我们在KittyBase里面已经介绍过的_createKitty()方法。

需要注意的是,geneScience.mixGenes()是一个黑盒方法,因为其代码是闭源的,因此我们无法知道孩子的基因是如何确定的。不过我们知道是一些调用了父母基因以及母亲的cooldownEndBlock的方法。

5.KittyAuctions:出售、购买以及给猫咪拉皮条

“这里面有一些公开方法,用来拍卖、竞拍猫咪或者提供配种服务。实际的拍卖功能由两个兄弟合约处理(一个用来出售,一个用来交配),同时拍卖的创建和出价则大部分由核心合约的相关方面来完成。”

根据开发者的说法,它们将这种拍卖的功能分解成了“兄弟”合约,因为“它们的逻辑有点复杂,而且总是存在微妙的bug。通过将它们保留在自己的合约中,我们可以在升级它们的时候,不会破坏到追踪喵咪所有权的主合约。

所以KittyAuction合约包含了setSaleAuctionAddress()和setSiringAuctionAddress()方法。像setSaleAuctionAddress()只能被CEO调用,并设置一个来处理这些函数的外部合约的地址。

注意:“配种”在这里指给猫咪拉皮条,把猫咪放出去拍卖,让其他用户付费给你,好让它们的猫咪可以和你的交配。

这意味着,即使CryptoKitties合约本身是不可变的,CEO依然可以在后面很灵活地修改拍卖的合约地址。再次,虽然因为开发者需要修复bug,所以这点并不是很么坏事,但是我们需要留意这一点。

为了不至于让大家太长不看,我不会更深入地探讨拍卖和出价逻辑是如何处理的。你可以自行在EthFiddle上查看代码(搜索KittyAuctions)即可。

6.KittyMinting:首代(Gen0)猫咪工厂

“最后一个方面包含了用来创建首代猫咪的方法。我们可以制作多达5000只“宣传”猫咪,用来送给社区成员(这点对全新的社区来说非常重要)。之后所有其他的猫咪都只能被创建出来,接着立刻上线以算法决定的初始价格来拍卖。不管这些猫咪是如何被创建的,50000是首代猫咪的上限。在这之后,就全靠社区去繁殖、繁殖、繁殖。”

可创建的宣传猫咪和首代猫咪的数量是写死在这里的:

这里是COO可以创建宣传猫咪和首代猫咪的代码:

(代码源见6)

从createPromoKitty()方法看,COO可以创建任一一代的猫咪,然后送给任何人(5000只是上限)。我猜他们这么做是出于送给早期的测试者、朋友和家人,或者用免费的猫咪来宣传的目的。

但是这也意味着,你的猫咪也许没有你以为的那么特别,因为COO可能会创建5000只一模一样的猫咪。

在createGen0Auction()里,也提供了COO用来创建新猫咪的方法。但是这个方法将会发起一个拍卖让用户出价来购买猫咪,而不是直接将猫咪分配给一个特定的用户地址。

7.KittyCore:主合约

这是CryptoKitties的主合约,它将编译和运行在以太坊区块链上。这个合约把所有的东西都联系在一起。

因为其继承结构,它继承了所有我们之前看到的合约,并添加了一些终极方法,比如下面这个函数,用ID来获取一个猫咪的所有数据。

(代码源见7)

这是一个公开的方法,它将从区块链返回一个指定猫咪的所有数据。我猜他们就是用这个方法,在他们网络服务器上查询并在网站上展示猫咪的。

等等……我没看到任何图像数据。什么决定了一个猫长什么样的?

我们从上面的代码可以看出,一个“猫咪”的长相基本上由一个256比特位的无符号整形来表示的,也就是其基因编码。

在Solidity合约代码里,没有相关存储猫咪图像或者描述的代码,也没有256比特整形到底是什么描述。遗传编码的解析在CryptoKitties的网络服务器上完成。

因此,这是一个非常聪明的基于区块链游戏的演示,实际上它并非100%基于区块。如果他们的网站有天下线了,除非有人备份了所有的图片,否则你只能拥有一组毫无意义的256比特位整形数。

在合约代码中,我发现一个名为ERC721Metadata的合约。但是它从没有被调用来做任何事。因此我猜一开始他们计划把所有的数据都存在区块链,但是稍后就否决了(在以太坊中存储大量数据成本太高?),所以最后就把一些数据存储在网络服务器上。

放在一起试试看

所有这些简要概括如下:

如何将kitties表示为数据

现存的kitties是如何保存在一个智能合约里的,以及如何追踪谁拥有什么

首代(Gen0)猫咪是如何生产的

猫咪是如何在一起繁殖新猫咪的

这只是一个表层概述。如果你在找一个更深层的教程来教你如何编写自己的游戏,你肯定会对我们的在线互动编程教程感兴趣:https://cryptozombies.io/!

Notes

代码源1:https://gist.github.com/jamesmartinduffy/eb5ea03cf070ad56186402697e5e3d24#file-cryptokitties00-js

代码源2:

https://gist.github.com/jamesmartinduffy/39826094e0d4e1337d901662000fbd30#file-cryptokitties01-js

代码源3:

https://gist.github.com/jamesmartinduffy/64d4ca8768bb2f3c5012c2af3cca8f58#file-cryptokitties03-js

代码源4:https://gist.github.com/jamesmartinduffy/0cb95c849ba0065819058be5550c3af4#file-cryptokitties04-js

代码源5:https://gist.github.com/jamesmartinduffy/450ec9b3a7d2e6d34645591e07c27d9b#file-cryptokitties05-js

代码源6:

https://gist.github.com/jamesmartinduffy/9c1d0bd6a1e7e34dfcfb6e8577e589c4#file-cryptokitties06-js

代码源7:

https://gist.github.com/jamesmartinduffy/200dd362fb880fc27d36cb70f5dee773#file-cryptokitties07-js

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180128G030TV00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券