天天看點

去中心化Pokemon遊戲開發教程【以太坊】

在這個教程裡,我們将學習如何開發一個基于ERC721的妖怪戰鬥小遊戲,它類似于去中心化版本的Pokémon遊戲。教程中使用的開發工具為Truffle,開發語言為Solidity,第三方庫為OpenZeppelin。

用你熟悉的開發語言學習以太坊DApp開發: Java | Php Python .Net / C# Golang Node.JS Flutter / Dart

1、建立ERC721版本的Pokémon遊戲項目

我們使用Truffle開發架構建立這個基于ERC721的Pokemon遊戲項目。

首先建立一個新的檔案夾,然後初始化Truffle項目:

~$ mkdir ethermon
~$ cd ethermon/
~/ethermon$ truffle init           

2、使用OpenZeppelin成熟的ERC721合約實作代碼

為了使用OpenZepplin,我們需要利用npm導入這個庫。讓我們先初始化npm,然後擷取正确版本的OpenZeppelin。我們使用的是2.5.0版本的OpenZeppelin,是以你需要使用0.5.5版本的Solidity編譯器:

~/ethermon$ npm init
~/ethermom$ npm install @openzeppelin/[email protected] --save           

3、擴充OpenZeppelin的ERC721合約

在我們的contracts/檔案夾,先建立一個新的檔案ethermon.sol。要使用OpenZeppelin代碼中的功能,我們需要引入并擴充ERC721.sol。

下面的代碼展示了目前為止Ethermon.sol的内容:

pragma solidity ^0.5.5;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract Ethermon is ERC721 {
    
}           

首先使用

truffle compile

檢查并確定我們的合約可以正确編譯。接下來,我們編寫遷移腳本以便将合約部署到本地區塊鍊。在migrations/目錄

建立一個新的遷移檔案2_deploy_contracts.js,内容如下:

const Ethermon = artifacts.require("Ethermon");

module.exports = function(deployer) {
    deployer.deploy(Ethermon);
};           

確定你的truffle-config.js的配置可以正确連接配接本地區塊鍊,你可以使用

truffle test

先測試一下。

4、編寫ERC721版Pokemon的實作邏輯

我們需要Ethermon合約實作如下功能:

  • 建立新的妖怪
  • 将妖怪配置設定給主人
  • 主人可以安排妖怪戰鬥

讓我們先實作第一個功能。我們需要在Ethermon合約中用一個數組儲存所有的妖怪。需要儲存的妖怪相關的資料包括名字、級别等。是以我們使用一個結構。

到目前為止Ethermon合約的代碼如下所示:

pragma solidity ^0.5.5;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract Ethermon is ERC721 {

    struct Monster {
        string name;
        uint level;
    }

    Monster[] public monsters;
    address public gameOwner;

    constructor() public {
        gameOwner = msg.sender;
    }

    function createNewMonster(string memory _name, address _to) public {
        require(msg.sender == gameOwner, "Only game owner can create new monsters");
        uint id = monsters.length;
        monsters.push(Monster(_name, 1));
        _safeMint(_to, id);
    }
}           

Monster結構在第7行定義,數組在第12行定義。我們也添加了一個gameOwner變量來儲存Ethermon合約的部署賬戶。第19行開始是createNewMonster()函數的實作,該函數負責建立新的妖怪。

首先,它會檢查這個函數是否是由合約的部署賬号調用的。然後為新妖怪生成一個ID,并将新妖怪存入數組,最後使用_safeMint()函數将這個新建立的妖怪配置設定給其主人。

_safeMint() 是我們繼承的ERC721合約中實作的函數。它可以安全地将一個ID配置設定給指定的賬号,在配置設定之前會檢查ID是否已經存在。

好了,現在我們已經可以建立新的妖怪并将其配置設定給指定的賬号。該進行第三步了:戰鬥邏輯。

5、ERC721版Pokemon遊戲的戰鬥邏輯實作

正如之前所述,我們的戰鬥邏輯決定了一個妖怪可以晉升多少等級。較高等級的妖怪可以獲勝并升兩級,失敗的妖怪升一級。如果兩個妖怪處于同一等級,那麼進攻者獲勝。下面的代碼展示了合約中戰鬥邏輯的實作:

pragma solidity ^0.5.5;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract Ethermon is ERC721 {

    struct Monster {
        string name;
        uint level;
    }

    Monster[] public monsters;
    address public gameOwner;

    constructor() public {
        gameOwner = msg.sender;
    }

    function battle(uint _attackingMonster, uint _defendingMonster) public {
        Monster storage attacker = monsters[_attackingMonster];
        Monster storage defender = monsters[_defendingMonster];

        if (attacker.level >= defender.level) {
            attacker.level += 2;
            defender.level += 1;
        }
        else{
            attacker.level += 1;
            attacker.level += 2;
        }
    }

    function createNewMonster(string memory _name, address _to) public {
        require(msg.sender == gameOwner, "Only game owner can create new monsters");
        uint id = monsters.length;
        monsters.push(Monster(_name, 1));
        _safeMint(_to, id);
    }
}           

第19行開始展示了妖怪的戰鬥邏輯。目前任何賬号都可以調用battle()方法。然而我們需要對此加以限制,隻允許發起進攻的妖怪的主人調用該方法。為此,我們可以添加一個修飾符,該修飾符利用ERC721.sol合約中的ownerOf()函數來檢查調用賬号。下面的代碼展示了這部分的修改:

pragma solidity ^0.5.5;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract Ethermon is ERC721 {

    struct Monster {
        string name;
        uint level;
    }

    Monster[] public monsters;
    address public gameOwner;

    constructor() public {
        gameOwner = msg.sender;
    }

    modifier onlyOwnerOf(uint _monsterId) {
        require(ownerOf(_monsterId) == msg.sender, "Must be owner of monster to battle");
        _;
    }

    function battle(uint _attackingMonster, uint _defendingMonster) public onlyOwnerOf(_attackingMonster) {
        Monster storage attacker = monsters[_attackingMonster];
        Monster storage defender = monsters[_defendingMonster];

        if (attacker.level >= defender.level) {
            attacker.level += 2;
            defender.level += 1;
        }
        else{
            attacker.level += 1;
            attacker.level += 2;
        }
    }

    function createNewMonster(string memory _name, address _to) public {
        require(msg.sender == gameOwner, "Only game owner can create new monsters");
        uint id = monsters.length;
        monsters.push(Monster(_name, 1));
        _safeMint(_to, id);
    }
}           

好了!我們完成了一個ERC721版本的類似Pokemon的妖怪戰鬥遊戲,雖然還很粗糙!

原文連結:

ERC721仿Pokémon遊戲開發 — 彙智網