Building An Ethereum Simulation Game - Part 1

Building An Ethereum Simulation Game – Part 1 – Inception

Building An Ethereum Simulation Game - Part 1 - Inception

I recently wrote an article on ERC721 tokens. To demonstrate their use, I used the example of a Pokemon-like game. It got me thinking of some of the games I couldn’t get enough of as a kid.

The hours I spent on my Gameboy Colour trying to catch ’em all must number in the hundreds if not thousands. As I grew older, my taste moved towards simulation games like The Sims, SimCity, and sports-oriented sims. One game, in particular, stands out more than others: Football Manager.

Sports Simulations

“Take over a football team and make it completely your own. From tactics and training, to transfers and trophies.” — footbalmanager.com

It’s an enticing prospect. You can finally compare yourself to the pros by running your team the way you think it should be run.


Backing up a little… Before I found out about Football Manager, there was a similar online game that took up a lot of my after-school time.

Sundayleague.com is of the same premise, except instead of simulating against a computer, you manage your team against other people. You play with fake generated players with funny names like Ben Dover. The pyramid system of leagues spans tens of levels with promotion and relegation. There are online forums for tactics, training, buying players, etc. All of these aspects contribute to the success of your team.

It’s time-based, so only one game is played per day at a scheduled time. Training your team is also limited and time-based.

In-game money can be won, but it can also be bought with real money if you want to progress your team faster.

You can bid for and buy players, increasing the quality of your team.

Whilst I was reminiscing about all of this, it struck me that these in-game football players could be considered ERC721 compliant if the game was running on the Blockchain. How easy could it be to recreate a game like this on the Ethereum Blockchain?

ERC721 is Non-Fungible Token Standard

Breaking It Down

Let’s assume, in our Ethereum tennis game, each player is an ERC721 token. In each squad, there are 20 players.

Each player has several attributes dictating their ability: fitness, speed, strength, creativity, work rate, aggression, passing, shooting, tackling.

Each player has an age, which increases depending on some metric (actual time, in-game time or matches played perhaps).

Training the players increases their stats depending on age, current stats, etc.

Managers can pick the formation, tactics and starting lineup for future matches. Matches take into account each player in each team, the starting eleven and the bench.

Each one of these decisions has some bearing on the result of each match, with some element of chance thrown in also.


At this point, the scale of our Ethereum tennis game is getting a little out of hand. We’re starting to rack up a lot of computing time for a lot of calculations, meaning lots and lots of gas.

Maybe team sports aren’t a great starting point. Let’s try something simpler, like a solo sport. At least then we only have one ERC721 token to deal with when performing calculations for training, and two for competing. How about Tennis?


Tennis Manager

I’m not a Tennis expert, but I’ve watched a few Wimbledon tournaments so I can make an educated guess to the kinds of attributes tennis players would consider important.

Each tennis player is an ERC721 token and has basic attributes:

  • Personal: name, age, height
  • Physical: technique, power, agility, stamina, condition

Let’s assume that we can train our players to increase their stats, and we can set up matches to compete against other players.

Training

Increase specific physical attributes by training, whether that be agility, power, stamina or technique. It also has the side effect of decreasing the condition of the player, which can be increased by resting the player.

All of these operations should cost something. Let’s call it XP. 

XP is gained by playing matches against other players.

Note: In its current state, XP is another attribute in the Tennis Player ERC721 token. However, there could be scope to convert this into an ERC20. Explore this later on.

Matches

Matches can only be played against players which have registered to be available to play matches. They can only play if their condition is higher than a certain value, otherwise, they’re considered not match fit.

Tactics can be set before each match which influences the payer’s stats temporarily for that game.

For example, The Attack tactic increases the power attribute but reduces stamina. The Patient tactic increases technique but reduces power.

The mechanism for calculating match-winners is yet to be decided. (Initial thoughts: weightings on attributes and tactics, or numeric rules based on those same things.)

Both players gain XP from playing matches, but the winner gains more. Both player’s conditions decrease as a result of playing matches, which can be recuperated by rest.

The First Smart Contracts

ERC721 Player Contract

Given that the game is built on Ethereum and based around ERC721, I’m starting with the TennisPlayerBase ERC721 token.

The below smart contract shows the token at this stage.

// Author: Alex Roan
pragma solidity ^0.5.5;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/ownership/Ownable.sol";
// TennisPlayer ERC721 Token
contract TennisPlayerBase is ERC721, Ownable {
// Player information
struct Player {
// game details
bool isBot;
uint xp;
// personal details
string name;
uint8 age;
uint8 height;
uint8 condition;
// attributes
uint8 agility;
uint8 power;
uint8 stamina;
uint8 technique;
}
// List of all players
Player[] public players;
// Create new player on behalf of manager
function newPlayer(
bool _isBot,
uint _xp,
string memory _name,
uint8 _age,
uint8 _height,
uint8 _condition,
uint8 _agility,
uint8 _power,
uint8 _stamina,
uint8 _technique,
address _to
) public onlyOwner
{
uint id = players.length;
players.push(
Player( _isBot, _xp, _name, _age, _height, _condition,
_agility, _power, _stamina, _technique)
);
_safeMint(_to, id);
}
}
view raw TennisPlayerBase.sol hosted with ❤ by GitHub

I’ve added in a boolean value in the Player struct called isBot to distinguish between players managed by real people and bot players.

Training Smart Contract

Training the players requires a bit of logic, but not too much. The below smart contract shows us TrainableTennisPlayer.sol, a child of TennisPlayerBase.sol.

// Author: Alex Roan
pragma solidity ^0.5.5;
import "./TennisPlayerBase.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/SafeCast.sol";
contract TrainableTennisPlayer is TennisPlayerBase {
using SafeMath for uint;
using SafeCast for uint;
// TODO – xp costs to change depending on current attribute level?
// Training costs
uint8 conditionCostToTrain = 5;
uint8 xpCostToTrain = 8;
uint8 attributeGainOnTrain = 1;
// Rest costs and gains
uint8 xpCostToRest = 6;
uint8 conditionGainOnRest = 15;
enum Attribute { agility, power, stamina, technique }
// Train a player increasing an attribute
function train(uint _id, Attribute _attr) public {
// Only the owner of the player can train
require(ownerOf(_id) == msg.sender, "Must be owner of player to train");
// The player must be fit enough to train
players[_id].condition = castSubtract8(players[_id].condition, conditionCostToTrain);
// Must have enough XP
players[_id].xp = castSubtract256(players[_id].xp, xpCostToTrain);
// Increase the chosen attribute
if (_attr == Attribute.agility) {
players[_id].agility = castAdd8(players[_id].agility, attributeGainOnTrain);
}
else if (_attr == Attribute.power) {
players[_id].power = castAdd8(players[_id].power, attributeGainOnTrain);
}
else if (_attr == Attribute.stamina) {
players[_id].stamina = castAdd8(players[_id].stamina, attributeGainOnTrain);
}
else if (_attr == Attribute.technique) {
players[_id].technique = castAdd8(players[_id].technique, attributeGainOnTrain);
}
}
// Rest player, increasing condition
function rest(uint _id) public {
// Only the owner of the player can rest
require(ownerOf(_id) == msg.sender, "Must be owner of player to rest");
// Must have enough XP
players[_id].xp = castSubtract256(players[_id].xp, xpCostToRest);
players[_id].condition = castAdd8(players[_id].condition, conditionGainOnRest);
}
// Cast and add a uint8 to a uint8
function castAdd8(uint8 _a, uint8 _b) private pure returns (uint8) {
return uint(_a).add(uint(_b)).toUint8();
}
// Cast and subtract a uint8 from uint8
function castSubtract8(uint8 _a, uint8 _b) private pure returns (uint8) {
return uint(_a).sub(uint(_b)).toUint8();
}
// Cast and subtract a uint8 from a uint
function castSubtract256(uint _a, uint8 _b) private pure returns (uint) {
return _a.sub(uint(_b));
}
}

The train() function on line 28 ensures that the player has enough XP and condition, subtracts the costs and adds the attribute gain.

The rest() function on line 53 ensures that the player has enough XP, then increases the condition attribute.

There are some private functions below these which help cast uint8 variables to uint256 so the contract can utilize OpenZeppelin’s SafeMath library.

I’ve left a todo statement near the state variables as a reminder that it might be a good idea to increase the difficulty of leveling up as players level up


Next Steps

This project is in active development. At the time of writing, the current state of the code is as described in this article.

I’ll write some tests for the current contracts next, which probably isn’t worthy of another article. Once tested adequately, I’ll likely move on to adding the ability to play matches against other players., which will be the subject of part 2.

I’ve added the code repo to Github so it’s public and open to pull requests. If you’re interested in helping out with this Ethereum Game, You can contribute! Here is the repo.

Also Read:

If you want to learn more about the Crypto ecosystem, sign up for the weekly newsletter.

Default image
Alex Roan
Blockchain Developer, writer. https://alexroan.co.uk

Wanna learn about Crypto?

Subscribe to our weekly newsletter

Leave a Reply