Practical development of Pokemon game based on Ethereum

In this tutorial, we will learn how to develop a small game based on ERC721, which is similar to the decentralized version of Pok é mon game. The development tool used in the tutorial is Truffle, the development language is solid, and the third-party library is OpenZeppelin.

Learn Ethereum in your familiar development language DApp Development: Java | Php | Python | .Net / C# | Golang | Node.JS | Flutter / Dart

1. Create the POC é mon game project of ERC721 version

We use the Truffle development framework to create this pocemon game project based on ERC721.

First create a new folder, then initialize the Truffle project:

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

2. Using the mature ERC721 contract implementation code of OpenZeppelin

In order to use OpenZepplin, we need to import this library with npm. Let's initialize npm first, and then get the correct version of OpenZeppelin. We use version 2.5.0 of OpenZeppelin, so you need to use version 0.5.5 of the solid compiler:

~/ethermon$ npm init
~/ethermom$ npm install @openzeppelin/contracts@2.5.0 --save

3. Extending ERC721 contract of OpenZeppelin

In our contracts / folder, first create a new file, ethermon.sol. To use the features in the OpenZeppelin code, we need to introduce and extend ERC721.sol.

The following code shows the contents of Ethermon.sol so far:

pragma solidity ^0.5.5;

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

contract Ethermon is ERC721 {
    
}

First, use the truss compile to check and make sure our contract compiles correctly. Next, we write a migration script to deploy the contract to the local blockchain. In the migrations / directory Create a new migration file, 2 "deploy" contracts.js, as follows:

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

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

Make sure that your configuration of truffle-config.js can correctly connect to the local blockchain. You can use truffle test to test first.

4. Writing the implementation logic of pocemon in ERC721

We need the Ethermon contract to achieve the following functions:

  • Create a new monster
  • Assign monsters to their owners
  • Master can arrange monster fight

Let's implement the first function first. We need an array to hold all the monsters in the Ethermon contract. The monster related data to be saved include name, level, etc. So we use a structure.

The code of the Ethermon contract so far is as follows:

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);
    }
}

The Monster structure is defined on line 7, and the array is defined on line 12. We also added a gameOwner variable to hold the deployment account of the Ethermon contract. Line 19 begins with the implementation of the createNewMonster() function, which is responsible for creating new monsters.

First, it checks whether the function is called by the contract's deployment account. Then an ID is generated for the new monster, and the new monster is stored in the array. Finally, the newly created monster is assigned to its owner using the ﹣ safeMint() function.

_safeMint() is a function implemented in our inherited ERC721 contract. It can safely assign an ID to the specified account and check whether the ID already exists before assigning.

OK, now we can create a new monster and assign it to the specified account. It's time for the third step: Battle logic.

5. The battle logic implementation of pocemon game of ERC721

As mentioned before, our battle logic determines how many levels a monster can be promoted. Higher level monsters can win and be promoted to two levels, while losers can be upgraded to one level. If two monsters are at the same level, the attacker wins. The following code shows the implementation of combat logic in the contract:

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);
    }
}

Line 19 begins with the monster's battle logic. At present, any account can call the battle() method. However, we need to limit this, only allowing the owner of the attacking monster to call this method. To do this, we can add a modifier that uses the ownerOf() function in the ERC721.sol contract to check the calling account. The following code shows the modification of this part:

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);
    }
}

Okay! We have finished an ERC721 version of Pokemon like monster fighting game, although it is still very rough!

Original link: ERC721 imitation Pok é mon game development - huizhi.com

Tags: Blockchain npm Java PHP

Posted on Fri, 03 Apr 2020 01:29:41 -0700 by Dream$of$uccess