DEV Community

Cover image for I Built A Web3 Clone Of The Hill Climb Game Using Unity, ThirdWeb GamingKit, and ContractKit.
Mahmoud Harmouch
Mahmoud Harmouch

Posted on

I Built A Web3 Clone Of The Hill Climb Game Using Unity, ThirdWeb GamingKit, and ContractKit.

Over the past month, I participated in the ThirdWeb hackathon in which I set myself the challenge of building a web3 clone of The Hill Climb game using both ThirdWeb GamingKit and ContractKit. I was so excited about the opportunity to explore the different ways in which the Ethereum blockchain can be utilized to create games with unique features.

In this post, I will analyze the different parts of the game I built over the past month. I'll explain how I used ThirdWeb GamingKit and ContractKit to customize different game parts. Finally, I'll show you how you can customize this game to build your own decentralized version of The Hill Climb.

Model Analysis

Model Analysis is a method that allows us to comprehend the prerequisites of specific software, in this case, a game, and how they interact with one another. This technique gives us a high-level overview of what must be done to build the game and a plan for developing it.

Use Case Diagram


Use-case diagram of the game (Image by author).

The Use Case Diagram outlines the interactions between a user and the software. It illustrates the user's activities and how they are interconnected. A player progresses through the game by completing a series of activities represented by modules/panels. Each panel signifies a different game stage, and the player must complete all tasks within each panel to move on to the next one.

This use case diagram begins when a user playing the game triggers the server to run and the game has loaded. A user connects their wallet, selects a car and level, and then begins playing the game. As they play, they may upgrade their vehicle.

  • Steps:
  1. Go to the dashboard.
  2. Claim an NFT to grant access to the game.
  3. Go to the main menu of the game.
  4. Connect the wallet.
  5. Select a level.
  6. Select a car.
  7. Upgrade your car.
  8. The game is loaded.

Activity Diagram


Activity diagram of the game (Image by author).

An activity Diagram is a great tool to understand better the order of activities that need to be performed to complete a task and the relationships between them. It is mainly used to identify potential areas for improvement.

You can comprehensively understand the project by reading the above activity diagram from the top right corner.

Architecture


Game architecture (Image by author).

ThirdWeb Integration

This section describes how ThirdWeb was integrated into this game.

Smart Contract

Using the ThirdWeb ContractKit CLI, we can quickly write and deploy secure contracts by only focusing on the smart contract itself. The code snippet below represents a custom ERC721 Drop contract.

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "@thirdweb-dev/contracts/base/ERC721Drop.sol";
import "@thirdweb-dev/contracts/extension/Permissions.sol";

contract Contract is ERC721Drop, Permissions {
    // An array of notes.
    mapping(uint256 => string) public notes;

    constructor(
        string memory _name,
        string memory _symbol,
        address _royaltyRecipient,
        uint128 _royaltyBps,
        address _primarySaleRecipient
    )
        ERC721Drop(
            _name,
            _symbol,
            _royaltyRecipient,
            _royaltyBps,
            _primarySaleRecipient
        )
    {
        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
    }

    /**
     *  A function that allows writing notes to the owner of the NFT.
     */
    function writeNote(uint256 _tokenId, string memory _msg) public {
        require(
            msg.sender == ownerOf(_tokenId),
            "You are not the token owner."
        );
        notes[_tokenId] = _msg;
    }

    /**
     *  A function that allows notes update only to holders of the NFT that has the `DEFAULT_ADMIN_ROLE` permission.
     */
    function updateNote(
        uint256 _tokenId,
        string memory _msg
    ) public onlyRole(DEFAULT_ADMIN_ROLE) {
        notes[_tokenId] = _msg;
    }
}
Enter fullscreen mode Exit fullscreen mode

The code shows that only the owner of a given NFT has permission to write, update, and read notes for a given token.

The reason why I chose the ERC721 Drop contract is because of the following features:

  • Batch uploading because it saves time and gas fees on the upload process.
  • Set up robust claiming options for claiming these tokens from users, like setting up an allow list, etc.
  • Great for PFP projects like our game in this case.

For more info on how to build and deploy this contract, you can refer to the following repo:

GitHub logo hill-climb / smart-contract

A custom ERC721 Drop smart contract.

Getting Started

Create a project using this example:

npx thirdweb create --contract --template hardhat-javascript-starter
Enter fullscreen mode Exit fullscreen mode

You can start editing the page by modifying contracts/Contract.sol.

To add functionality to your contracts, you can use the @thirdweb-dev/contracts package which provides base contracts and extensions to inherit. The package is already installed with this project. Head to our Contracts Extensions Docs to learn more.

Building the project

After any changes to the contract, run:

npm run build
# or
yarn build
Enter fullscreen mode Exit fullscreen mode

to compile your contracts. This will also detect the Contracts Extensions Docs detected on your contract.

Deploying Contracts

When you're ready to deploy your contracts, just run one of the following command to deploy you're contracts:

npm run deploy
# or
yarn deploy
Enter fullscreen mode Exit fullscreen mode

Releasing Contracts

If you want to release a version of your contracts publicly, you can use one of the followings command:

npm run release
# or
yarn release
Enter fullscreen mode Exit fullscreen mode

Join

The Game

The game utilizes Unity and the ThirdWeb GamingKit to create a powerful unique web3 gaming experience. This game was developed in Unity version 2021.15.1f because it is the only existing version on my PC. So, make sure to have this version to build and deploy the game. For more info on how to build and deploy the game, please refer to the following repo:

GitHub logo hill-climb / game

A web3 clone of Hill Climb powered by Unity, ThirdWeb GamingKit and ContractKit

Hill Climb ThirdWeb

A web3 clone of Hill Climb powered by Unity, ThirdWeb GamingKit and ContractKit.

Features

  • Four levels.
  • Four cars.

Requirements

  • Unity version 2021.3.15f1.

Build

  • Create a new unity project.
  • Import Assets, packages and ProjectSettings folders into your project.
  • Deploy your smart contract using this repo.
  • Change the smart contract address under ContractAddress of the MainMenu Scene component.

smart contract address

  • Set the player build settings to the following:

build resolution

disable compression format

Demos

Resources

Feedback

Have questions? Hit me up on twitter: @wiseaidev.

Fixes or feature additions? Send a pull request, happy to integrate them!

License

This project and the accompanying materials are made available under the terms and conditions of the MIT LICENSE.




Unity

Scenes

At the moment of writing this guide, there are four playable levels and menu scenes. Double-click on a scene to start your edit.

Levels

When developing a game, you must consider the different levels a player will progress through. Each level can have similar game objects and components to maintain continuity throughout the game. However, you will also need to customize the terrain heights for each level; this is where the 2D Terrain Editor comes in handy.

To create a new level, you only need to customize terrain heights for each level. You can use the 2D Terrain Editor for this purpose. This tool can spawn coins, fuels, and other items randomly.

The Input component is attached to the Canvas and automatically switches between the keyboard and touch buttons on each platform.

Menus

The main menu system is a crucial part of the game, providing access to all necessary features and allowing us to navigate easily through the game. This system is based on activating and deactivating menu panels, which are stored under empty game objects.

As you can notice, the main menu consists of five different panels. If you want to switch to a particular menu panel, it can be activated or deactivated accordingly by right-clicking on the intended panel and clicking Toggle Active State.


Toggle active state for a given component (Image by author).

Similarly, you can click on a particular panel and check the box that is left aligned with the panel's name in the inspector.

The components of each panel are fully customizable; you can customize different properties of objects (e.g., color, width, height, script, etc.) under the currently activated panel.

1. Main Menu

The Main Menu is the first thing you see when you open the MainMenu game scene. It's activated by default, so you can connect your wallet and start playing. The Main Menu is where you'll find all the options and settings for the game.


Main menu panels (Image by author).

This panel has two primary components: Connected and Disconnected. These components are programmatically activated and deactivated based on the wallet connection status. On a successful attempt, the Connected component will be activated, and the Disconnected component will be deactivated. This provides us with an easy way to check the wallet connection status.


The Connected component is activated, and the Disconnected component is deactivated (Image by author).

Creating a new input component is pretty straightforward. To create a new input component, you can copy, paste, and customize it to your liking.

2. Settings Menu


Settings Menu (Image by author).

The settings menu is where you gain complete control over the gaming experience. It provides access to various features and settings so that you can tailor their game as much as possible.

For example, if you want to use a particular feature in the game, you can find it in the settings menu and activate it with just a few clicks. Similarly, you can customize your experience by enabling or disabling certain graphics options from here too. Using this menu system, you can control your gaming experience and customize it according to your needs and preferences.

Another example is changing the background music's volume by sliding the indicator left or right like a sliding window. You can turn off the music and sound effects to enjoy a more peaceful atmosphere while playing. You also have the opportunity to adjust the quality of each pixel displayed on the screen.

Creating a new component is pretty straightforward. To create a new component, you can copy, paste, and customize it.

3. Level Select Menu


Levels select Menu (Image by author).

The level select menu is easy to use and navigate. You click the LevelSelect GameObject icon on your screen and scroll down to the item icons in the inspector, where you can choose from four available levels. These levels are ordered from left to right according to their length, price, and terrain difficulty.

If you want to add a new level, you can click the plus icon in the inspector and drag and drop a level sprite onto your screen. After that, you can change its animation, sound, and icons as needed.

4. Car Select Menu


Cars select Menu (Image by author).

This panel is a powerful tool that allows you to add new cars, control animation, and more. This Menu is similar to the previous one.

5. Upgrade Menu


Cars select Menu (Image by author).

The upgrade menu is where you can customize the recently selected car. You can adjust the engine, fuel, wheels, and speed levels.

Creating A New Menu Panel

You can also create a new panel using the built-in Empty GameObject in Unity. To do so, select GameObject > Create Empty under the canvas.

This will create a new empty GameObject that you can rename to whatever you like, YourCustomPanelName.


Custom Component (Image by author).

As the object is invisible, you will need to add a Canvas Renderer to it so that we can see something in the scene view that lives inside the canvas. This is not, however, related to the animation states. It simply gives us an on-screen representation of the panel.


Create a canvas renderer (Image by author).

After adding the Canvas Renderer component, you can add an Image component. The Image component provides many options for customizing the look and feel of your image. You can choose from a variety of presets or customize the settings yourself.


Image Component (Image by author).

The image component is now visible in the scene. To attach a sprite to that component, drag the image from the Project window into the inspector.


Attach an image to the image component (Image by author).

If you want to take your panel user experience to the next level, you can even attach a script to the component that controls its behavior based on custom logic. This means you have complete control over how your panel looks and behaves.


A script component is attached (Image by author).

Now, you can start adding your custom panel components children. You can take inspiration from existing panels.

Switch between panels

You can attach a button to the current panel to switch between panels. To make that button switch to the next one, you can add a runtime event under the OnClick header by clicking on the plus icon. Now, you must drag and drop the canvas into the GameObject placeholder.


Add a button to a component (Image by author).


Add a canvas to a function (Image by author).

Now you can attach a custom function available in the game, which is true in this case, that accepts a GameObject.


Choose a button function (Image by author).


Add hide/show panels functions to a button (Image by author).

The game object represents the next panel. This function will display the next panel. Similarly, to hide the current panel, drag and drop the current panel as an argument to setFalse.

Initial State


Canvas Initial State (Image by author).

When you first open the canvas, all of the values for the game's initial states are present there. You can control the game variables' initial values under the inspector's canvas script. The initial states are important because they set the starting point for the player's actions. If you want to change how the game plays, you can do so by altering the initial states.

Create A New Car


Create a new car (Image by author).

Creating a new car is relatively easy. To create a new one, copy and paste a car prefab, and change its objects under the Hierarchy tab. To enhance your car's performance, open the Body object in the Hierarchy tab. Then select any of these components from the list to customize them to your car body.

To change the car body image, Click the VehicleSprite object in the Hierarchy tab. Now you need to specify a car image.


Change car sprite (Image by author).

Now, you need to change the bounding volume of the car body collider. To do so, click the Collider object in the Hierarchy tab. Now you need to click edit collider in the inspector to match the car sprite recently added.


Change car bounding volume (Image by author).

The Dead trigger component controls when the lost state is set. If the top of the car touches the ground,
you will lose the game.

Similarly, you can customize the remaining components of the car. After changing all these properties to your liking, your new vehicle is ready to be used in your game!

Resources

hill-climb · GitHub

A web3 2D racing game powered by Thirdweb and Unity. - hill-climb

favicon github.com

Top comments (5)

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
jd2r profile image
DR

Really interesting and in-depth post. Nice work! :)

Collapse
 
wiseai profile image
Mahmoud Harmouch

Thanks for your feedback; it is much appreciated.

Collapse
 
vulcanwm profile image
Medea

nice work!

Collapse
 
wiseai profile image
Mahmoud Harmouch

Thanks!