- Get link
- X
- Other Apps
- Get link
- X
- Other Apps
Unity3d WebGL with Solana connect Phantom wallet
Since i'm back to working in game development and this is my first time in my life about cryptocurrency they're many way to implement but for who never coding, heard more about Unity but never get in touch, interested in crypto wallet, you can get started with zero budget.
Required
Windows 11
Unity3d 2021.3.45f2 [install from Unity Hub]
Unity Web Build Support [install from Unity Hub]
Phantom Wallet [Install Desktop version] **Beware fake Phantom App
Optional (Required for example only)
Microsoft Edge [You can use any browser that support Phantom Wallet browser extension]
Visual Studio Code [Prefer for lightweight and compatible Unity Editor]
Better WebGL template 2020 [Prefer for consistency without often change code.]
Setup Phantom App [for testing only]
Download Phantom Wallet app and install from previous section. After that open and login in with your password. **if no account you can follow this instruction to create new wallet.
After login, you need to click on Avatar, then choose account and then click on Settings > Developer Settings, turn on Testnet mode and select Solana Devnet mode.
If your settings were corrected, you should see notice on your Phantom App liked this. "You are currently in Testnet Mode",
Get free SOL for testing
If your account not having SOL, you cannot pay for anything because any transaction required gas fee. Open this url to request an Airdrop , then copy your public address and paste here, select SOL amount you need then click Confirm Airdrop.
If it's successful, you'll see a message on the bottom-right of screen.
Then take a look SOL in your Phantom Wallet, here your SOL ready for testing. **I recommended to create 2 wallet accounts for testing transfer one to another account.
Setup and installation Unity [skip this section if you already have unity installed.]
Download Unity Hub install from their instruction, then install Unity3d from Unity Hub, I've use Unity3d 2021.3.45f2, you can download any same version or above, you need an Account to sign-up and sign-in through Unity Hub, after success sign-in, then launch Unity Hub on the left menu click "Installs" and look at the top-right choose "Install Editor"
Once Install Unity Editor popup. Select "Official releases" if you appreciate latest version look at [LTS][Recommended] then click Install.
**if you want others previous Unity version. Click on section "Archive" then click on "download", your browser will open archive page. Find any version and focus on [LTS] and no security issues.
Then click "Install", browser will popup asking to open in Unity Hub, just click "Open". Unity Editor will add into Unity Hub and pop over install options.
From Install Unity version LTS, i recommended checkbox install "Web Build Support" then click "Install" and wait until it's finish installed. **If your Unity Editor installed, just click "Manage" then install "Web Build Support".
You can check progress on the top-right download icon, if you have any install problem by internet you can try install Web Build Support later and focus on Install Editor first.
Once your installation is successful, it should be like this below image.
From Unity Hub, on the left menu click "Projects" then on the top-right click "+ New project"
Pickup "Editor version", then under "All" section just click "Core 2D (built-in render pipeline)" is enough. Under "Project name", I've use local (Not require project on cloud) named the project as you wish then choose "Location" where you need to store a new project. Then click "+ Create project", wait a while till project loading all and complete setup new project.
Once your project done initialized, it's open Unity Editor with your new project similar this below image without any error from console logs.
It's easy, safe customize and keep it out of Unity main WebGL template. download betterunitytemplate2020.0.1.0.unitypackage from GitHub.
Double click file betterunitytemplate2020.0.1.0.unitypackage and choose Unity version that created project. Click "Just once".
Mark all checkboxes then click "Import".
[Option 1] modified default template (recommended for debug)
This option will be changed default template before it deployed then we don't need to update html every time when build WebGL, however if you're working with other project WebGL this modified will adapt on any project too.
Open index.html from your install path "C:\Program Files\Unity\Hub\Editor\2021.3.45f2\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\WebGLTemplates\Default", right click on index.html > Open with > Visual Studio Code.
you may need to run as Admin to save changed to file.
[Option 2] modified custom template
Open index.html with Visual Studio Code by browse to your project folder under Assets/WebGLTemplate/Better2020, right click on index.html > Open with > Visual Studio Code.
Open index.html with Visual Studio Code by browse to your project folder under Assets/WebGLTemplate/Better2020, right click on index.html > Open with > Visual Studio Code.
Saved index.html by choose menu File > Save, you've done for this file.
Update target platform WebGL
From Unity Editor, choose File > Build Settings..., after popup appear check under "Scenes In Build" already have "Scene/SampleScene", click on "WebGL" under Platform. Then click "Switch Platform". Wait until project complete re-import. This button will be change to "Build".
Choose "Player Settings..." on the bottom left, popup Player setting opened, then click [Option 1] from your modified or [Option 2] "Better 2020" under "WebGL Template", click [x] close this window.
Click button "Build and Run", browse to folder you need to export WebGL and Run.
For me, i'm just create new folder named "WebGL" same level as Assets folder. Then click "Select Folder", wait until project complete build and run on your default browser.
Your result should be like this. Close this tab for now. Get back to Unity Editor.
[Option 2]
After this i will use based [Option 1] to show debug compatible view than full screen of [Option 2].
Click on "SampleScene" to be highlight then press Ctrl + C and then press Ctrl + V, "SampleScene" will be duplicated as "SampleScene 1".
Just click "SampleScene 1" to highlight and click again and rename to "LoginScene", double-click "LoginScene" to open as current working scene, do same thing with "SampleScene", to highlight and click again rename to "GameScene". Your result should be like this. Click "File > Save" or "press Ctrl + S" to save project.
Just click "SampleScene 1" to highlight and click again and rename to "LoginScene", double-click "LoginScene" to open as current working scene, do same thing with "SampleScene", to highlight and click again rename to "GameScene". Your result should be like this. Click "File > Save" or "press Ctrl + S" to save project.
Click "File > Build Settings...", choose "Add Open Scenes" since previous step your current scene is "LoginScene" and "GameScene" already in "Scene In Build".
"LoginScene" is 0 as first scene and "GameScene" is 1 as second scene in build. Click [x] close window.
Right-click under "Hierarchy" choose "GameObject > UI > Legacy > Button", It's enough for testing not need to import TextMesh Pro.
Look at Inspector panel adjust Button Connect to center of screen by Pos X = 0, Pos Y = 0, Width = 400, Height = 80.
On Hierarchy, click Text (Legacy) under Button Connect, then on Inspector change text from "Button" to "Connect Wallet", change font style Normal to "Bold", change font size to "36". Click "File > Save" or "press Ctrl + S" to save project.
Double click "GameScene" under Assets/Scenes your GameScene will open replaced LoginScene, similar LoginScene, right-click under "Hierarchy" choose "GameObject > UI > Legacy > Button", renamed Button (Legacy) to "Button Buy Item".
Look at Inspector panel adjust Button Connect to center of screen by Pos X = 0, Pos Y = 0, Width = 400, Height = 80. Also click Text (Legacy) under Button Buy Item, then on Inspector change text from "Button" to "Buy Item", change font style Normal to "Bold", change font size to "36".
On Hierarchy, same level as Button Buy Item, create Text (Legacy), renamed to "Total Item"
Right-click on "Total Item" then "UI > Panel", the panel will add under "Total Item", you can adjust any color as a background of text field.
I've leave panel color as default. update value on Inspector "Total Item" Pos X = 0, Pos Y = -120, Width = 400, Height = 80.
Change text "New Text" to "Potion x 0", change font style to "Bold", change font size to "36", change alignment to middle and center, change color to green. Click "File > Save" or "press Ctrl + S" to save project.
Like below image create 3 empty folders via right-click "Create > Folder".
Right-click at Scripts folder, choose "Create > C# Script", rename "NewBehaviourScript" to "Login" and do it again "NewBehaviourScript" to "BuyItem"
Using Visual Studio Code (or your code editor), choose "File > New Text File", then choose "File > Save As..." or press Ctrl + S then browse to Project/Assets/Plugins/WebGL then named it "Login" on file type choose "JSLib Programming Language (*.jslib)", click "Save".
Do it again with "BuyItem.jslib" after saved. Look at Unity Editor, your structure should be look like below image. Now we have 2 pairs of files Login.cs work with Login.jslib and BuyItem,cs work with BuyItem.jslib. (You can use single file jslib contain everything, however i want each file too short so i separated to pairs of files.)
Type below or copy paste to your file. This code provided Platform specific that code can be working properly only on WebGL and not Editor. Also provided when success or error callback from jslib respond to this file. Only "ShowAlert" is not necessary for your mainly purpose but it's useful UI debugging respond to user that way without open developer tools.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Runtime.InteropServices;
public class Login : MonoBehaviour
{
// since jslib working on WebGL platform
// we need to target WebGL and not in Editor
#if UNITY_WEBGL && !UNITY_EDITOR
[DllImport("__Internal")]
private static extern void SolanaConnect(
string objectName,
string methodSuccss,
string methodError
);
[DllImport("__Internal")]
private static extern void ShowAlert(string message);
#endif
public void ConnectWallet()
{
#if UNITY_WEBGL && !UNITY_EDITOR
// call function SolanaConnect in Login.jslib
// 1st param is game object that Login.sc atteched,
// 2nd param is success function callback,
// 3nd param is error function callback
SolanaConnect(
gameObject.name,
nameof(OnWalletConnected),
nameof(OnWalletError)
);
#endif
}
public void OnWalletConnected(string publicKey)
{
//save public key
PlayerPrefs.SetString("public_key", publicKey);
//change scene to GameScene
SceneManager.LoadScene("GameScene");
}
public void OnWalletError(string error)
{
// see error log from browser developer tools, console
Debug.Log("OnWalletError >> " + error);
#if UNITY_WEBGL && !UNITY_EDITOR
// show any error as alert popup on browser.
ShowAlert(error);
#endif
}
}
Type this below code or just copy and paste to your file, this JavaScript provided function "SolanaConnect" to call Phantom Wallet app extension (Don't click on your Phantom Wallet browser extension, Unity will invoke Phantom popup by self), when you need to publish your game, just comment out or remove any line of console.log, console.warn and console.error, all need to investigate actual data by developer tools on console log.
mergeInto(LibraryManager.library, {
SolanaConnect: function (uniObjName, uniMethodSuccess, uniMethodError) {
//all params need to convert to UTF8 before using.
const strObjName = UTF8ToString(uniObjName);
const strMethodSuccess = UTF8ToString(uniMethodSuccess);
const strMethodError = UTF8ToString(uniMethodError);
try {
if (window.solana && window.solana.isPhantom) {
window.solana.connect()
.then(resp => {
console.warn("pub key: " + resp.publicKey.toString());
SendMessage(strObjName, strMethodSuccess, resp.publicKey.toString());
})
.catch(err => {
console.error("err >> " + err.message);
SendMessage(strObjName, strMethodError, err.message);
});
} else {
console.error("err wallet not found >> ");
SendMessage(strObjName, strMethodError, 'Phantom wallet not found');
}
} catch (error) {
console.error("catch err wallet >> ");
SendMessage(strObjName, strMethodError, error.toString());
}
},
ShowAlert: function (message) {
window.alert(UTF8ToString(message));
}
});
Let's Finish Connect Wallet
Attach Login.cs to button "Connect Wallet" by click on "Button Connect" under Canvas then look at Inspector panel Choose "Add Component" type Login or Drag "Login.cs" to "Add Component", your Inspector should be like this.
Then look at On Click List is Empty, click on "+" then Drag "Button Connect" from Hierarchy to field "none (object)" your Inspector should be like this.
Then click on "No Function" dropdown, choose "Login > ConnectWallet ()". Choose "File > Save or Ctrl + S" to save your progress.
From Unity Editor choose File > Build and Run, then waiting until your app/game run on Web Browser if your "Connect Wallet" on blue screen.
Click "Connect Wallet" the Phantom Wallet should be pop open on the top-right (this Phantom Wallet is one of an App on your task bar)
Click "Connect Wallet" the Phantom Wallet should be pop open on the top-right (this Phantom Wallet is one of an App on your task bar)
Then Enter your wallet password and choose "Unlock". Once success unlock wallet you should see Cancel and Connect button, let's try "Cancel" first.
When choose Cancel, Phantom Wallet should be quit, and you will see "ShowAlert" function on screen. Here an error event already captures and respond correct as expected, you can modify, remove or use Unity UI built-in on your own way. Click ok to close alert.
Let's click "Connect Wallet" again, now choose "Connect" (sometimes you need to Enter password to unlock Phantom Wallet again before proceeds), Once success connected, your screen should be change from LoginScene to GameScene. Now your app/game already connected Phantom Wallet. Now close this tab.
Type below or copy paste to your file. Similar Login.cs this script provided simple BuyPotion call SolanaSignAndSend in jslib to ask user grant Phantom Wallet pay for Potion in game, the process will run a while to proceed Transaction and Confirmation at once. Also provided callback when OnTransactionCompleted and OnTransactionError when any error occurs. Don't forget to save file, File > save or Ctrl + S.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Runtime.InteropServices;
using UnityEngine.UI;
public class BuyItem : MonoBehaviour
{
// your public address as a Shopkeeper Wallet to receive SOL from customer.
private string receiptKey = "xxxxxxxx"; //<-- update to your public address.
[SerializeField] Text textField;
private int potion = 0;
#if UNITY_WEBGL && !UNITY_EDITOR
[DllImport("__Internal")]
private static extern void SolanaSignAndSend(
string objectName,
string methodSuccss,
string methodError,
string publicAddress,
string receiptAddress,
float priceSOL);
[DllImport("__Internal")]
private static extern void ShowAlert(string message);
#endif
public void BuyPotion()
{
#if UNITY_WEBGL && !UNITY_EDITOR
// customer public address fromm LoginScene
string publicKey = PlayerPrefs.GetString("public_key");
SolanaSignAndSend(
gameObject.name,
nameof(OnTransactionCompleted),
nameof(OnTransactionError),
publicKey, //<-- customer public address as a Customer Wallet
receiptKey, //<-- your public address as a Shopkeeper Wallet
0.002f //<-- 0.002 SOL, price of your Item, not included gas fee.
);
#endif
}
public void OnTransactionCompleted(string signature)
{
Debug.Log("OnTransactionCompleted >> " + signature);
// Once succes Transaction, increase Potion +1.
potion++;
// Update Potion amount on Screen
textField.text = "Potion x " + potion;
}
public void OnTransactionError(string error)
{
Debug.Log("OnTransactionError >> " + error);
#if UNITY_WEBGL && !UNITY_EDITOR
ShowAlert(error);
#endif
}
}
Start implement BuyItem.jslib
In BuyItem.jslib it's provided SolanaSignAndSend contain 3 mainly step, first build Transaction, second SignAndSendTransaction and last one ConfirmTransaction, you can divide each step to be shorten function one by one for more verify and tune up more error message detail. However, this is just simple as last step will be grant transaction confirm and callback to BuyItem.cs, you'll need extra work if you need to use detail form confirm json data. As Login.jslib, remove console.log, console.warn and console.error when release. We already have ShowAlert in Login.jslib it's share across all any jslib so we don't need to implement here, and you can merge this function SolanaSignAndSend into Login.jslib. if you needed. Don't forget to save file, File > save or Ctrl + S.
mergeInto(LibraryManager.library, {
SolanaSignAndSend: async function (
uniObjName, uniMethodSuccess, uniMethodError,
publicKey, receiptKey, solPrice) {
const strObjName = UTF8ToString(uniObjName);
const strMethodSuccess = UTF8ToString(uniMethodSuccess);
const strMethodError = UTF8ToString(uniMethodError);
const publicAddress = UTF8ToString(publicKey);
const recipientAddress = UTF8ToString(receiptKey);
var solValue = solPrice.toFixed(3); //<-- 0.002, toFixed(4) can be 0.0002
console.warn("solValue: "+solValue);
// when release change to "mainnet-beta", "devnet" use for testing only
const connection = new solanaWeb3.Connection(solanaWeb3.clusterApiUrl("devnet"));
const fromPublicKey = new solanaWeb3.PublicKey(publicAddress);
console.warn("fromPublicKey: "+fromPublicKey);
const toPublicKey = new solanaWeb3.PublicKey(recipientAddress);
console.warn("toPublicKey: "+toPublicKey);
const transaction = new solanaWeb3.Transaction().add(
solanaWeb3.SystemProgram.transfer({
fromPubkey: fromPublicKey,
toPubkey: toPublicKey,
lamports: BigInt(Math.floor(solanaWeb3.LAMPORTS_PER_SOL * solValue)),
})
);
transaction.feePayer = fromPublicKey;
transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
console.warn("transaction:", transaction);
try {
const res = await window.solana.signAndSendTransaction(transaction);
console.warn("res signature: "+res.signature);
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
const confirm = await connection.confirmTransaction({
signature: res.signature,
blockhash: blockhash,
lastValidBlockHeight: lastValidBlockHeight
});
var strJson = JSON.stringify(confirm);
console.warn("strJson:", strJson);
SendMessage(strObjName, strMethodSuccess, strJson);
} catch (error) {
console.error("err >> ", error);
SendMessage(strObjName, strMethodError, error.message || error.toString());
}
}
});
Let's Finish Transaction
Attach BuyItem.cs to button "Button Buy Item" by click on "Button Buy Item" under Canvas then look at Inspector panel Choose "Add Component" type BuyItem or Drag "BuyItem.cs" to "Add Component", your Inspector should be like this.
Then look at On Click List is Empty, click on "+" then Drag "Button Buy Item" from Hierarchy to field "none (object)" your Inspector should be like this.
Then click on "No Function" dropdown, choose "BuyItem > BuyPotion ()". Choose "File > Save or Ctrl + S" to save your progress.
One last thing, as we need to update amount of Potion when buy success, drag object "Total Item" from Hierarchy to Text Field "None (text)" your Inspector should be like this. Choose "File > Save or Ctrl + S" to save your progress.
Test Connect Wallet through Buy Item
From Unity Editor choose File > Build and Run, then waiting until your app/game run on Web Browser then click "Connect Wallet" and choose "Connect", your app/game should change scene to "GameScene". Click on "Buy Item", Phantom Wallet should be prompt like below.
Here your transaction completed, Phantom Wallet will be close, and you should see Potion increase from 0 to 1. All done.
Check your wallet SOL balance, Example, my wallet Account 2 previous first Airdrop 5 SOL now it's 4.689 SOL and Account 1 received from Account 2 correctly.
Extra section
If you don't know how and where to selling your app/game, look at this.
dApp Store and checkout Seeker Phone specification to provided best experience deliver to user. They're provided everything for you from zero to hero.
Another direct support WebGL, many player and developer meeting here Itch.io.
Buy Me a Coffee.
Free Download Content Updated!!
Provide unitypackage
>> Download <<
Provide full source
>> Download <<