In this tutorial we are going to create an art gallery where users can move around freely and see various artworks. These artworks will be stored as NFTs on the blockchain. Our application is comprised of two parts, an NFT Marketplace Smart contract that will be present on the blockchain (we are using Mumbai Testnet in this tutorial) and a 3D game built using Unity3D game engine that will be used to fetch the NFTs listed in the Marketplace smart contract and display them inside an interactive 3D art gallery.
This tutorial assumes you have completed the Create an NFT smart contract with HardHat and Building an NFT Marketplace using HardHat tutorial. It is also recommend to have basic idea of Unity3D game engine. It is highly recommended that you complete the Create a Personal 3D Gallery Project with Unity with Unity version
2019.4. Besides this, knowledge and understanding of C# and how to use C# Script with Unity3D will be very helpful.
The requirements for this tutorial are:
- Install Unity Hub and Unity3D version
2019.4. Using UnityHub you can install multiple versions of Unity3D simultaneously.
- Already have an NFT Marketplace smart contract deployed to the Mumbai Testnet.
Open Unity Hub and create a new Unity3D project with the
3Dtemplate. Make sure you are using version
2019.4(the subversion may differ). It is recommended to use a relatable name. We will name our project Figment 3D Art Gallery, however any other name will work as well.
This will create an Empty Unity3D project to begin with
The interface of Unity3D is divided into various Window, each with it's own unique purpose. These windows can be arranged freely by the developers and hence they are referred to by their name rather than location. You can get a detailed tour of Unity's User Interface here.
It is important to visualise how our end project should look and what features we want in our project. The kew feature that we want in our project are:
- A 3D virtual world representing an Art Gallery where the player can freely mode around.
- Various art works must be displayed throughout this Art Gallery.
- This Art works will be representing NFT present in the blockchain.
- Only the NFTs listed in the Marketplace Smart contract will be displayed.
- The users should be able to view the information about the NFTs when they move close to them.
Create a Personal 3D Gallery Project with Unity is an official Unity tutorial that teaches us how to create an Art Gallery. While building our project we will be taking inspiration from this tutorial and using some of the assets available here.
Note: Before using any Asset in your game please make sure the form of licensing used by the creator of those assets and you are legally entitled to use these assets.
For the simplicity of this tutorial we are not going to design the 3D Art Gallery ourselves. Rather we are going to use the one already available here. Unzip the downloaded
.zipfile and import them into our Unity Project. To do so, drag and drop the extracted folder into
The Project Window.
After successful import you will see the folder appear. The name however may vary depending on what is the name of the extracted folder. Inside this folder there will be another folder called
Models, open this folder. Here you will notice we have a Prefab named
Drag this to
The Hierarchy Window. From The Inspector Window make sure that coordinates of the asset is
X:0, Y:0, Z:0and is scaled to
X:10, Y: 10, Z:10. So finally it should look like:
Collider is a special type of component used by Unity to detect collision. You can think of the Collider as like a layer of Skin. You can read more about Colliders here. We will be adding a Mesh Collider to our Museum model so that we can detect collisions once we add our player game object.
museumgameobject and select all the child component. Then from the
Inspector Windowclick on the Add Component button and select
Now that we have our game world ready, let's create a character to represent the player in the game world. In this tutorial, we will be creating the game as a FPS (First Person Shooter), which means the player will interact with the game world in first person view.
Using the keyboard and mouse, we should be able to make our character run, walk, jump and look around. The module we need for this is commonly termed as "First person controller". The controller we will be using is available at
Unity Asset Store.
Open the Asset Store window. If it is not visible select
Asset Storefrom the
Windowoption in the top menu. Search for "First Person All In One". Click on Add to My Assets and then click on Accept to accept the terms and conditions. Now click on the Import button. This shall open the
Import Unity Packagewindow. By default everything will be selected, if not click on All button, and then click on Import.
This will import the entire package into our project and you can see it in
The Project Window. Ignore if you seen any yellow warning messages.
FirstPerson-AIOPrefab by clicking on
FirstPersionAIO → FirstPersonAIO. Drag and drop the Prefab (Blue Box) into the
Hierarchy Window. Make sure that the Controller is not a child of another game object. You can place your character anywhere inside the Museum where you want your character to spawn when the game starts. I placed mine inside the
RoundRoomwith the welcome sign.
FirstPerson-AIOalready have a camera attached to it which will act as our main camera. Delete or Deactivate the
MainCameracomponent which was present in our Hierarchy since we created a blank unity project.
Click on the Play button. You will be able to move around freely inside the game.
Before we start displaying NFTs from the blockchain, let's create a demo artwork to be displayed.
We will be using the Classic Picture Frame asset pack from Asset Store for the frames of our pictures. Import the package like we imported the
First Persion AIOpackage. If the package is imported properly you can see a
Classic Picture Framefolder in the
pictureprefab in the
Classic Picture Framedirectory and drag it into the
Hierarchy Windowand over the
museumobject to make it a child of
museumgame object. You can place the frame at any place of your choice. In this tutorial it is placed in the front wall while entering the
Rectangle Roomand is scaled to
X: 0.2, Y: 0.2, Z: 0.1.
We will convert this game object into a Prefab and later use it to spawn new Artworks when NFTs are fetched from the Smart contract. You can read about what is Prefab in Unity's official documentation here.
Before creating the prefab, create a Folder called
Prefabsin the root asset directory and open it. Drag the
Hierarchy Windowinto the
Project Window. A pop up will appear, select
Original Prefab. This will create a new Prefab for the art work.
Now that we have our artwork in place, we want to display various informations associated with the image on screen when the player moves close to the artwork. This information will be displayed as UI element for which we will need a
Canvasgame component. You can read more about
Canvasin the official documentation here.
Right click in the
Hierarchy Windowand select
Canvas. This will create a new
Canvascomponent. To view the
Canvasproperly, switch your editor to 2D.
Now we are ready to design how the various details will be displayed. For the simplicity of the tutorial we will display the details as simple text on the screen.
Right click on the
Text - TextMeshProfrom
This will pop up a menu asking to Import TMP Essentials. Click on the Import TMP Essentials button. Then click on Import TMP Examples & Extras. Now you can close the pop-up dialog box.
A new Text Area will appear on the screen. Change the name of the game object to
Hierarchy Window. From the Inspector Window change the content of the Text Field to "Title" and change
Vertex Colorto Green. Also position the Text area towards the top of the screen and make sure the text area takes up most of the horizontal area available.
The Title of the NFT will be displayed in this area. The text area denotes the amount of space the text to be displayed can take up. The text area is place on the Canvas based on how we want the title to look. You can also make various changes to the text like changing font size, font style, etc. from the
We duplicate this text area and create some additional fields for various informations to be displayed. The final outcome should look something like this:
All this details will be either fetched from the Metadata of the NFT (Title and Desc) while other details (Owner, On Sale and Price) will be fetched from the Marketplace smart contract.
Now you can switch back to the 3D view. Quickly click on the
Game Windowto have a preview of how these text fields will appear on the screen.
If now we try to play our game, you will notice that the texts constantly appear on the screen. We want the text to appear only when we move close to some artwork. In order to do this, we will have to take the help of scripts (Uinty3D uses C# for writing scripts). Before we start writing our scripts we do two small tweaks:
PlayerTag: Tags are used so that any script used in a game can identify a GameObject that belongs to a particular type. You can read about it in details here. Select the
FirstPerson - AIOfrom the
Hierarchy Windowand check in the top of
Inspector Windowwhether it is tagged as
Player. If not, click on the drop down menu and select the
- Add Tags to the UI elements: We also have to add Tags to the Text areas we added so that our script can easily detect it. To do so, select the text area (Title for example) from the
Hierarchy Window, in the
Inspector Window,click on the drop down beside
Tagfield and click on
Add Tag.... Click on the plus(+) icon and create a new Tag named
Titleand click on Save. Repeat this process and create tags named
Price. Now select the Text Field from the
Hierarchy Windowand assign them their respective tags.
Now we are ready to start writing our scripts. Create a new folder inside the root directory in
Scripts. Inside it create a new directory called
GameScripts. Since even a small game can have multiple scripts, it is very important to ensure that these scripts are organised properly. Inside the
GameScriptsdirectory create a new C# Script called
Open this script in any code editor of your choice. I will be using Visual Studio for writing and editing C# scripts. Open the
ProximityScriptand paste the following code:
Let's understand the code:
By default the
Startfunction is called only once when the Game Object is loaded while the
Updatefunction is called once every frame as long as the Game Object is present inside the game. You can read about the basics of scripting for Unity3D here.
We import certain libraries with the help of
usingkeyword. The first 3 imported libraries are needed by most scripts present in a unity project and they help the script to interact with the Game Engine. The
TMProlibrary is used to interact with the UI elements and Text Boxed present.
We then define the class with name
MonoBehaviourclass. The class name should always be the same.
MonoBehaviouris the base class from which every Unity Script is derived. Read more about it in the docs.
We define some public variables that will store the various data that will be displayed on the screen. Later this variable will be set by another script that will load the Artworks from our Marketplace smart contract.
The variable of type
Transformis used to store co-ordinates of a game object and the variable
otherwill store the current co-ordinates of the player.
The text boxes we created were of type
Text Mesh Prohence we create variables of type
TMP_Textto refer to those text boxes.
distvariable will be used to calculate the distance between player and artwork.
Everything present in the Game World (3D objects or 2D UI elements) belong to the
GameObjectclass. We create variables of type
GameObjectto store reference to various game objects.
Start()function we use the
GameObject.FindWithTag()function to find the game object holding a specific tag. Since we have assigned various game objects (player and UI elements) with specific tag, this line helps us to create instance to those game objects.
GetComponent<>()function is used to get a particular component present in a game object. We pass the type of Component we want an instance to. For the player we want a reference to
Transformcomponent so that we can get the location of the player. Similarly for the Text areas it will be of type
The value for the text fields are initiated as blank. This will ensure no text is displayed on screen when the game loads.
Update()function is called every frame. In this function we will first calculate the distance between the player and the artwork. If the distance is less than a threshold, we modify the text field to show the data associated with the artwork.We calculate the distance using the
Vector3.Distance()function that takes two positions as parameters.
tranform.positionreturns the location of the game object to which the script is attached to (we will attach this script to the artwork) and
other.positionreturns the position of the player as we have used the
othervariable to store the
Transformcomponent of the game object with
If the distance between the artwork and the player is less than
4units, we modify the text to be displayed to store the data associated with the artwork.
Now that our script is ready, we attach it to our
picturegame object. This is done by either:
- Drag the script from
picturegame object in
- Select the
picturegame object from
Hierarchy Windowand click on the Add Component button in the
Inspector Windowand search and add
Once the script is attached, in the
Inspector Windowenter some test values for
New Is For Saleand
New Price. Later this values will be set from a separate script, but now we set random values for testing.
Now click on the Play Button. If everything is done properly, you shall see the details appear on screen when you move closer to the artwork and disappear as you move further away.
If not so, some of the possible errors can be:
- There is some error in the C# Script.
- The tags were not properly associated with various game objects.
Nethereumthat is a C# library used for interacting with the Ethereum Blockchain. The same can also be used to interact with Polygon chain and in this example with Mumbai Testnet. We will also need separate libraries so that we can make Asynchronous calls from our game.
nugetas a package manager, but it is difficult to import packages using
nugetin an Unity3D project. This is mostly because of the way Unity manages its various dependencies. Any plugin that is to be used but be stored in a folder named
Pluginswhile any other dependency must be imported as Asset along with the compiled
For the simplicity of this tutorial, the content of both the folders are uploaded here. Download both the
Pluginsfolder and import them directly into your Unity project by dragging and dropping them in the
Project Window. Make sure that both the folders are imported into the root
NEthercontains all the required files and scripts needed to use the
Nethereumlibrary while the
AsyncAwaitUtilplugin that will be used for making Asynchronous calls. Although there are many other available Libraries for Asynchronous calls, this particular one seems to work smoothly with
Nethereumwhile others ran into various errors.
Now it's the time we all were waiting for. Now we are ready to write our Scripts to interact with the blockchain. To start with we create a new folder inside
HelperScripts. This folder will store all those scripts that are not directly used by our game but act as "Helpers". Inside this folder create a new C# script called
Constantsand open it in your favourite IDE. This script is going to store all the various constants that we are going to use. Paste the following code:
The Contract Address of the Marketplace smart contract will be stored in
MARKETPLACE_ADDRESSvariable. This is going to be different for you. Paste in the contract address of the contract you deployed. The
ABIshould be same if the contract is same. if the smart contract is verified, you can copy its ABI from the block explorer under the Code section. Remember to replace the
"in the ABI with
Since this script is not going to be used to control any game object, we are not importing any Libraries nor are we inheriting the
HelperScriptsfolder, create another C# script and let's name it
QueryMarketplace. Let's start by importing some libraries:
System.Collections.Genericenables us to use the
List<>datatype which is helpful in storing multiple values of same type.
System.Numbericsenables us to use a new datatype called
BigIntegerthat replicates the type
uint256used in smart contracts.
System.Threading.Tasksis used to define
Tasksthat is used for making
asyncfunction calls since asynchronous functions are handles by Unity using the concept of Threading.
Nethereumis used to interact with the blockchain.
Now we define the class. The class name should be same as the file name
First we start by creating an object of class
newkeyword. This object will help us make RPC calls to the blockchain. We initiate the object by passing the RPC Url stored in the variable named
In order to call any public function in our smart contract, we first have to define a FunctionMessage that tells the compiler what type of function we are going to call, the parameters accepted by the function and the datatype of the returned value. There are two functions in the Marketplace smart contract that we are interested in, they are
itemCounter, we define the FunctionMessage as follows:
Functionkeyword, we pass two values as arguments. The first is the name of the function we want to call, i.e.
itemCounterand the second is the datatype of the value returned by that function, that is
uint256. Then we define a class that inherits the
FunctionMessageclass. If the function takes in any parameters, those would be defined inside this function. Since
itemCounterfunction doesn't take any parameter, this class is empty.
getMarketItemfunction, we define the function message as:
getMarketItemfunction returns a struct, which is a composite datatype, we don't pass the return type after
Functionkeyword. The function takes in one parameter called
itemIdwhich is of type
uint256. This is defined by passing this values after the
1signifies that this is the first parameter. In case of this function, the first parameter is also the only parameter the function takes. We define a global variable
itemIdalong with a Getter (
get) and Setter. (
set) that will contain the value that is to be passed to the function. When the function will be called with this FunctionMessage, the value stored in this global variable will be passed as parameter to the function. To represent the type
uint256, we use the
getMarketItemreturns a composite datatype, we have to define an Output DTO which will define the type of value that will be received after the function call. We are going to Deserialise the returned value based on this Output DTO. The Output DTO is defined as:
In structure, it is quite similar to how we defined the Function Message. The only key difference being, we are using the
FunctionOutputkeyword, inheriting the
IFunctionOutputDTOclass and while defining the
Parameter, we first pass the datatype and then the variable name followed by the index number. The returned value is deserialised and stored in the public variables which can be accessed using the setters defined.
Now that we have defined the
FunctionOutput, we can write the functions that will be used to make call to the smart contract.
We use the
asyncfunction calls are made using the concept of multi-threading. The first function we are defining is used to call the
itemCounterfunction and it returns a
uint256value that is defined by
BigIntergerdatatype in C#.
We start by creating an instance of
ItemCounterFunctionMessageclass using the
newkeyword and store it in
itemCounterMessagevariable. We then create a query handler using the
GetContractQueryHandlerfunction and pass the
ItemCounterFunctionMessagetype within the anchor brackets(<>) to define the type of function to be called.
The call is made using the
QueryAsyncfunction and we pass type
BigIntegerwithin anchor brackets to signify the type of data to be returned. We pass the contract address of the Marketplace smart contract stored in the variable
BlockchainConstantsclass and the
The value returned from the function call is stored in
itemCountervariable which we then return.
In a similar fashion we define the function that calls the
The main differences noticed here are:
- While creating an instance of the FunctionMessage we set the value of the
itemIdvariable with the value passed to the function. This stored value is going to be passed to the function as parameter.
- In the query handler, we pass the type to be
- While making the query, instead of using the
QueryAsyncwe use the
QueryDeserializingToObjectAsyncfunction because the returned value will be deserialised to the type passed within the anchor brackets, that is
- While making the query, we first pass the instance of FunctionMessage(
marketItemsMessage) and then the contract address of the Marketplace smart contract.
Finally we create a function combining the above two that will return all the NFTs that are listed in the marketplace smart contract:
First we create a
MarketItemDTOtype to store the details of the all the NFTs returned. First we call the
GetItemCounterfunction to get a count of the total number of NFTs listed on the smart contract. Then we loop through the possible itemIds and call the
GetMarketItemfunction to get the details of the NFT and store it in the
Addkeyword. Finally we return the list.
Therefore, putting it all together, the content of the
QueryMarketplacescript will be:
Still there is one error left. If you are using Visual Studio as the Editor will be the Red Squiggly line under the keyword
BigInteger. If you hover over it, you will see an error message similar to:
To solve this, open
Player Settingsfrom the
Build Settingswindow, and select API Compatibility Level as
QueryMarketplacescript, we create a new script inside the
QueryNFT. This will be used to Query the NFT smart contract to get the
tokenURIof the NFT listed in the Marketplace smart contract.
Like incase of QueryMarketplace, we first create a Function Message that will be used to call the function and define the parameters that will be passed to the function. We want to get the
tokenURIby passing the
tokenIdwhich is of type
GetTokenURIfunction that takes two parameters,
tokenIdwhich represents the tokenId of the NFT we want to query and
contractAddresswhich contains the address of the NFT.
Besides this two Helper Scripts, we need two other Helper Scripts,
MetadataFormat, that would help us create an object that represents all the details to be displayed and create an object of the Metadata that is stored in the tokenURI respectively.
HelperScriptsdirectory create a new script called
ArtworkDetails. This is going to be a simple class with public variables representing the values that will be displayed on the screen and is fetched from the Marketplace smart contract. This variables will be
price. The remaining variables that is Title and Description of the artwork will be fetched from the Marketplace Contract. The code for
Now we are going to create a script called
MetadataFormatthat is used to create an object containing the variables that represent the Metadata. We will be following the OpenSea Metadata Standards for our NFTs. You can find a sample of this standard here. It has the following important fields:
attributes: A list of various attributes in form of traits, their value and display type associated with the NFT.
description: A small description of the NFT.
external_url: An URL pointing to a different website associated with the NFT.
image: Contains a link to the image that will be associated with the NFT.
name: This contains the name of the NFT.
We represent this in our
MetadataFormatscript as follows:
With this we are ready with all our helper scripts. Before moving to the next section make sure you have the following scripts in the
We have our script to query the Marketplace smart contract and NFT smart contract ready along with some other helper scripts. The steps to be followed to fetch and display an artwork are:
- Get all the NFTs listed in the marketplace smart contract.
- Spawn the ART works in game world.
- Get the tokenURI and contract address of the NFT.
- From the image url present in the metadata in
imagefield, fetch the image and display it.
The script for step 2 will be written later. Now let's try to write a script that can fetch an image from a URL passed as parameter and display it as an artwork. This script will be attached to every artwork spawned.
We start by creating a new script in the
GameScriptsfolder and let's name it
GetArtwork. We start the script with our usual import statements and defining our class. Since this script will be directly attached to a game object and will control how the game works, we will inherit
Now let's add some global variables:
imageRendereris an object of type
Renderer. We are going to use this
Rendererobject to display our image.
urlis a variable that is going to hold the url from which the image is going to be fetched.
proximityis an object of script
ProximityScriptthat helps us to display details on the screen.
Unity manages asynchronous calls using Coroutines. We will first define a coroutine that will fetch the image from a url. We will be using
UnityWebRequestfor calling an API and getting the image returned in form of a
Textuethat can be attached to a game object.
We use the
UnityWebRequestTextureclass to make a call to the passed
imageURLand retried the returned image file in form of a texture. The request is sent using the
SendWebRequest()function and we use
www.isDoneto check if the reply has been received.
Once we receive the image, we use
downloadHandlermethod to get the texture and store it in a variable. Next we use the
SetTexturefunction to set the desired image as a texture. If observed closely, the
picturepresent in our game has two materials associated with it, the first is for the frame and the second is the image that is displayed.
materialsto chose the 2nd Texture and set the "Main Texture" to our desired texture. Refer to the official documentation here to understand
SetTexturefunction in more details.
Our next coroutine will be the one we use to fetch the Metadata from tokenURI. For this we are going to use
UnityWebRequestclass to make an API call. We also use
JsonConvertclass to convert the returned value into an object of class
OpenSeaMetadata, that we have defined earlier. Finally we set the extract the Title and Description and set the values using the
proximityvariable. Finally we get the imageURL and call the
GetAndSetTexturecoroutine. We use the
StartCoroutineto call a coroutine.
Next we define a
SetArtworkDetailsfunction that takes an argument of type
ArtworkDetailsand sets the value to be displayed.
Finally we define a Coroutine named
GetArtworkDetailsthat will take the tokenURI and a object of
ArtworkDetailsand call the
The diagram below summarise the flow of Coroutine once the
GetArtworkDetailsCoroutine is called.
Putting it all together, the entire code for
Before moving on to the next section, attach the
GetArtworkscript to the
picturegame object. This can be done either by dragging and dropping the script on top of the game object or select the game object, click on Add Component Button and then search and add
pictureobject selected in the
Hierarchy Window, click on the
Overridesbutton on the
Inspector Windowand click on Apply All button. This will add all the changes made to the game object to its prefab as well.
Now we are almost ready to display the artworks listed in the Marketplace smart contract. However before doing so we should be able to spawn the artworks into our museum depending on the number of NFTs listed. Since our museum is of fixed dimension, there will be a maximum number of artworks that can be listed.
Since the artworks must be spawned in an organised manner, first we have to decide the places where we want our artworks to be displayed. We will be referring this points as "Spawn Points". Using your Designer Skills create some spawn points throughout the gallery. The steps to create a spawn point is:
- Decide the coordinate of the spawn point (You can drag the
picturegame object to decide the positions you like and copy the value of
- Create a new Empty Game Object and set the correct values for
- Repeat this process until you have created all the spawn points you want.
For simplicity, I have defined 5 spawn points:
In order to keep our project organised, in the
Hierarchy Windowcreate a new Empty Game Object, and name it
ArtworkSpawnerand drag the spawn points over it, to make them a child object of
Finally, you can safely delete the
GameScriptsdirectory, we will create another script that is going to help us spawn the Artworks. Create a new C# script called
Like always, we start by importing dependencies and defining our class:
Next we are going to create two global variables. First is
GameObject. This is going to store a prefab that we are going to spawn at the designated spawn points. Next is a List of type
Transformcalled spawnPoints. This list stores all the spawn points we created in the previous step.
Next we are going to write the function that will spawn our artworks. First we will query the marketplace smart contract to get the total number of NFTs listed. Since we have limited number of Spawn Points, we will calculate the number of NFTs listed and number of spawn points available. If available spawn points is less than listed NFTs, we can display only the number of spawn points we have. Finally we run a loop for every spawn point available and:
- Create a new game object similar to the one stored in
artworkvariable using the
Instantiatefunction. We pass in the position and rotation of the spawn point as arguments.
- We get a reference to the
GetArtworkscript attached to the game object using the
- Next we get the contract address of the NFT to be displayed and get its token URI using the
GetTokenURIfunction we created.
- Next we call the
GetArtworkDetailscoroutine we designed in the
GetArtworkscript to display our artwork and set the details to be displayed.
The script will be:
Now that we have our script ready, we attach this script to the
ArtworkSpawnergame object we created. Now with
ArtworkSpawnerselected in the
Hierarchy Windowwe set the public variables of the script from
Inspector Window. We drag the
pictureprefab, present in
Prefabsfolder, into the
Artworkfield. In the Spawn Points field, we enter the number of spawn points created (in this example
5), and then drag each Spawn Point one-by-one in respective fields. It should look something like this:
Now we are finally ready to test our product.
Create a new NFT and list it in the marketplace smart contract. I am using this contract to create NFT and this is my Marketplace contract. Now click on the play button. The artwork will spawn at the first spawn point listed. When you move closer to the artwork, the details to appear on the screen.
Congratulations 🎉🎉🎉, your game is ready.
Before we wrap up, there is one last step remaining, i.e. to build our game so that it can run on a browser. Follow the following steps:
- Open Build Settings from the File Menu.
- Make sure that the
Target Platformis set to the Operating System of you choice.
- Click on the Build and Run button.
- Select the Location to save the built file and click on Save.
This will start the built process and once done, it will run the game. You can play the game and also share it with your friends.
Congratulations on making it all the way through this tutorial! We have learned how to interact with a smart contract from a Unity3D game. We have learned how to read data from the blockchain and display information to the user. We also learned the basics of Nethereum, which is a C# library used for interacting with Ethereum based blockchains.
For simplicity purposes, we have limited this tutorial to just reading from the blockchain. It is also possible to connect wallets and submit transactions to the blockchain. As next step, you can also try to build an VR version of the game which would create a more immersive experience.
Hi, my name is Bhaskar Dutta and I am a blockchain Developer, Researcher and Freelancer. I am always looking forward to learn new things and discuss about Sitcoms. To know me better, you can checkout my Github.