Développement de jeux Blockchain (2): Zombie War

Source de ce projet https://cryptozombies.io/

0. Préface

Dans la section précédente, nous n'avons réalisé que la génération de zombies, mais n'avons pas spécifié de propriétaire spécifique pour chaque zombie.Aujourd'hui, nous avons principalement ajouté la fonction d'authentification des utilisateurs au projet, afin de prendre en charge plusieurs utilisateurs. Dans le même temps, la fonction de fusion d'attaque est ajoutée, qui peut fusionner deux zombies pour former un nouveau zombie, et en même temps appeler le code de chaîne de CryptoKitties pour compléter la fusion de CryptoKitties et de zombies.

1. Connaissances clés

  • Cartographie et adresse . L'adresse est un type de données unique dans le langage Solidity, qui marque un utilisateur Ethereum (il peut s'agir d'un utilisateur ordinaire ou d'un utilisateur sous contrat). Une carte est essentiellement une paire clé-valeur pour stocker et rechercher des données, déclarée comme suit :
 //声明了一个地址到uint类型的映射。
mapping (address => uint) public accountBalance;
//声明了一个uint类型到字符串类型的映射。
mapping (uint => string) userIdToName;
  • msg.sender : Dans Solidity, certaines variables globales peuvent être appelées par toutes les fonctions. L'un d'eux est msg.sender, qui fait référence à l'adresse de l'appelant actuel (ou contrat intelligent). Voici un exemple d'utilisation de msg.sender pour mettre à jour un mappage :
//声明一个映射。
mapping (address => uint) favoriteNumber;
function setMyNumber(uint _myNumber) public {
  // 更新我们的 `favoriteNumber` 映射来将 `_myNumber`存储在 `msg.sender`名下
  favoriteNumber[msg.sender] = _myNumber;
  // 存储数据至映射的方法和将数据存储在数组相似
}

function whatIsMyNumber() public view returns (uint) {
  // 拿到存储在调用者地址名下的值
  // 若调用者还没调用 setMyNumber, 则值为 `0`
  return favoriteNumber[msg.sender];
}
  • require : faire en sorte que la fonction génère une erreur lorsque certaines conditions ne sont pas remplies pendant l'exécution , et arrête l'exécution , comme indiqué ci-dessous :
function sayHiToVitalik(string _name) public returns (string) {
  // 比较 _name 是否等于 "Vitalik". 如果不成立,抛出异常并终止程序
  // (敲黑板: Solidity 并不支持原生的字符串比较, 我们只能通过比较
  // 两字符串的 keccak256 哈希值来进行判断)
  require(keccak256(_name) == keccak256("Vitalik"));
  // 如果返回 true, 运行如下语句
  return "Hi!";
}
  • Prise en charge de l'héritage et de l'introduction . Après avoir hérité de la classe parent, vous pouvez utiliser les fonctions de la classe parent. De même, vous pouvez également utiliser les fonctions de contrat à l'intérieur après les guillemets. Une utilisation raisonnable de l'héritage et de l'introduction peut rendre le code plus concis.
  • Deux formes de variables de stockage : stockage ou mémoire . Les variables de stockage font référence aux variables stockées en permanence dans la blockchain. La variable Memory est temporaire. Lorsque la fonction externe appelle un contrat, la variable memory est supprimée.
  • modificateurs internes et externes : interne et privé sont similaires, cependant, si un contrat hérite de son contrat parent, le contrat peut accéder aux fonctions "internes" définies dans le contrat parent . .
    external est similaire à public, sauf que ces fonctions ne peuvent être appelées que depuis l'extérieur du contrat - elles ne peuvent pas être appelées par d'autres fonctions à l'intérieur du contrat. Nous verrons plus tard quand utiliser external et public.
  • Interagissez avec d'autres contrats : vous devez d'abord définir une interface. S'il y a ce contrat sur la blockchain :
contract LuckyNumber {
  mapping(address => uint) numbers;
  function setNum(uint _num) public {
    numbers[msg.sender] = _num;
  }
  function getNum(address _myAddress) public view returns (uint) {
    return numbers[_myAddress];
  }
}

On peut déclarer une interface :

contract NumberInterface {
  function getNum(address _myAddress) public view returns (uint);
}

Quand on l'utilise comme ça :

contract MyContract {
  address NumberInterfaceAddress = 0xab38...;
  // ^ 这是FavoriteNumber合约在以太坊上的地址
  NumberInterface numberContract = NumberInterface(NumberInterfaceAddress);
  // 现在变量 `numberContract` 指向另一个合约对象
  function someFunction() public {
    // 现在我们可以调用在那个合约中声明的 `getNum`函数:
    uint num = numberContract.getNum(msg.sender);
    // ...在这儿使用 `num`变量做些什么
  }
}

2.Code

Les connaissances en programmation impliquées dans le code sont ci-dessus.

//zombiefeeding.sol
pragma solidity ^0.4.19;

import "./zombiefactory.sol";

contract KittyInterface {
  function getKitty(uint256 _id) external view returns (
    bool isGestating,
    bool isReady,
    uint256 cooldownIndex,
    uint256 nextActionAt,
    uint256 siringWithId,
    uint256 birthTime,
    uint256 matronId,
    uint256 sireId,
    uint256 generation,
    uint256 genes
  );
}
//继承僵尸工厂
contract ZombieFeeding is ZombieFactory {

  address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d;
  KittyInterface kittyContract = KittyInterface(ckAddress);

  function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public {
    require(msg.sender == zombieToOwner[_zombieId]);
    Zombie storage myZombie = zombies[_zombieId];
    _targetDna = _targetDna % dnaModulus;
    uint newDna = (myZombie.dna + _targetDna) / 2;
    if (keccak256(_species) == keccak256("kitty")) {
      newDna = newDna - newDna % 100 + 99;
    }
    _createZombie("NoName", newDna);
  }

  function feedOnKitty(uint _zombieId, uint _kittyId) public {
    uint kittyDna;
    (,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);
    feedAndMultiply(_zombieId, kittyDna, "kitty");
  }

}

Je suppose que tu aimes

Origine blog.csdn.net/doreen211/article/details/129170456
conseillé
Classement