跳至主要内容
本页面使用机器翻译自英语,可能包含错误或不清楚的语言。如需最准确的信息,请参阅英文原文。由于更新频繁,部分内容可能与英文原文有出入。请加入我们在 Crowdin 上的努力,帮助我们改进本页面的翻译。 (Crowdin translation page, Contributing guide)

将 Web3 整合到 Cocos Creator 项目中

在本节中,我们将通过创建代币合约、编写与之交互的脚本以及利用 DApp Portal SDK 进行钱包连接、代币铸造和余额检索,把 Web3 功能集成到我们的 Cocos Creator 项目中。 最后,您的 dApp 将与区块链无缝互动,在游戏中实现流畅的 Web3 互动。

创建和部署 KIP7 智能合约

首先,我们使用 Kaia Contract Wizard 生成智能合约。

步骤 1:使用 Kaia 合同向导

  • 导航至 Kaia 合同向导。
  • 选择 KIP7(Kaia 的令牌标准,类似于 ERC20)。
  • 配置您的令牌:
    • 名称:名称: ExampleTestToken(或其他名称)
    • 符号:ET(您的代币代码)
    • Premint:100(初始代币供应)
    • 特点检查 ✅ 可造币

在本指南中,我们将调整 mint 函数,使其不包含 onlyOwner 修饰符。 为此,我们必须删除 ownable.sol 导入和 Ownable 继承。 调整后的代码现在应该是这样的:


// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@kaiachain/contracts/KIP/token/KIP7/KIP7.sol";
contract ExampleTokens is KIP7 {
constructor() KIP7("ExampleTokens", "ET") {
_mint(msg.sender, 100 * 10 ** decimals());
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override
returns (bool)
{
return
super.supportsInterface(interfaceId);
}
function mint(uint256 amount) public {
_mint(msg.sender, amount);
}
}

信息

我们删除了 onlyOwner 修改器,以允许除原始部署者或合同所有者之外的任何人调用铸币厂函数。

步骤 2:通过 Remix IDE 进行部署

  1. 将上述代码复制并粘贴到 Remix IDE 上新建的文件 ET.sol。
  2. 在 Remix IDE 中:
  • 点击编译合同按钮。
  • 在插件管理器中激活 Kaia 插件
  • 在 Kaia 插件选项卡的环境下,选择 ** 注入提供程序 - Kaia 钱包**。
  • 合同下拉菜单中找到您的合同(ExampleTokens)。
  • 点击 部署,启动令牌!
  1. 当你的 Kaia 钱包弹出时:
  • 查看部署详情。
  • 单击 "确认 "将其部署到 Kaia Kairos Testnet。
备注

复制并保存已部署的合同地址。 稍后的教程中会用到它。

创建脚本文件

要集成 Web3 功能,我们需要创建脚本文件,用于处理区块链交互和用户界面管理。

1. 创建脚本文件夹

  • 导航至项目的 assets 文件夹。
  • 右键单击并选择 ** 创建 → 文件夹**

  • 将其命名为脚本

2. 创建 Web3 脚本文件

在脚本文件夹中,创建两个 TypeScript 文件:

  • Web3Manager.ts - 处理区块链交互。
  • UIManager.ts - 管理用户界面元素和用户交互。

现在您的项目结构应该是这样的


assets/
scripts/
Web3Manager.ts
UIManager.ts

Web3Manager.ts - 处理区块链交互

Web3Manager 脚本负责所有与区块链相关的功能。

主要特点

  • SDK 初始化 - 设置 DApp Portal SDK。
  • 钱包连接 - 允许用户连接自己的钱包。
  • 代币铸造 - 启用代币铸造功能。
  • 余额检索 - 获取用户的令牌余额。

代码执行:


import { _decorator, Component, Node, director, EventTarget, sys } from 'cc';
const { ccclass, property } = _decorator;
// Global event bus for Web3 events
export const web3Events = new EventTarget();
@ccclass('Web3Manager')
export class Web3Manager extends Component {
private static instance: Web3Manager = null;
private sdk: any = null;
private connectedAddress: string = '';
// Configuration
private readonly CONTRACT_ADDRESS = '0xbe9b8eB864F7E363ee834054e4391fb9b4e69B90'; // REPLACE CONTRACT ADDRESS
private readonly CHAIN_ID = '1001';
private readonly CLIENT_ID = 'PASTE CLIENT ID';
onLoad() {
if (Web3Manager.instance === null) {
Web3Manager.instance = this;
director.addPersistRootNode(this.node);
this.initializeSDK();
this.tryRestoreSession();
} else {
this.node.destroy();
}
}
private async initializeSDK(): Promise<boolean> {
try {
// @ts-ignore
this.sdk = await window.DappPortalSDK.init({
clientId: this.CLIENT_ID,
chainId: this.CHAIN_ID
});
console.log("SDK initialized successfully");
web3Events.emit('sdkInitialized');
return true;
} catch (error) {
console.error("SDK initialization error:", error);
web3Events.emit('sdkInitError', error.message);
return false;
}
}
private async tryRestoreSession() {
const savedAddress = sys.localStorage.getItem('connectedAddress');
if (savedAddress) {
this.connectedAddress = savedAddress;
web3Events.emit('walletConnected', this.connectedAddress);
this.getBalance();
}
}
public async connectWallet(): Promise<void> {
try {
if (!this.sdk) {
const initialized = await this.initializeSDK();
if (!initialized) return;
}
const provider = this.sdk.getWalletProvider();
const accounts = await provider.request({
method: 'kaia_requestAccounts'
});
if (accounts && accounts.length > 0) {
this.connectedAddress = accounts[0];
sys.localStorage.setItem('connectedAddress', this.connectedAddress);
web3Events.emit('walletConnected', this.connectedAddress);
this.getBalance();
}
} catch (error) {
console.error("Wallet connection error:", error);
web3Events.emit('walletError', error.message);
}
}
public async mintToken(amount: number): Promise<void> {
try {
if (!this.connectedAddress) {
throw new Error('Wallet not connected');
}
const provider = this.sdk.getWalletProvider();
const mintSignature = '0xa0712d68';
// @ts-ignore
const amountHex = amount.toString(16).padStart(64, '0');
const data = mintSignature + amountHex;
const tx = {
from: this.connectedAddress,
to: this.CONTRACT_ADDRESS,
value: '0x0',
data: data,
gas: '0x4C4B40'
};
const txHash = await provider.request({
method: 'kaia_sendTransaction',
params: [tx]
});
// After getting txHash, immediately update balance
web3Events.emit('mintSuccess', txHash);
await this.getBalance(); // Get updated balance right after minting
} catch (error) {
console.error("Minting error:", error);
web3Events.emit('mintError', error.message);
}
}
public async getBalance(): Promise<void> {
try {
if (!this.connectedAddress) {
throw new Error('Wallet not connected');
}
const provider = this.sdk.getWalletProvider();
const balanceSignature = '0x70a08231';
// @ts-ignore
const addressParam = this.connectedAddress.substring(2).padStart(64, '0');
const data = balanceSignature + addressParam;
const result = await provider.request({
method: 'kaia_call',
params: [{
from: this.connectedAddress,
to: this.CONTRACT_ADDRESS,
data: data
}, 'latest']
});
const balance = parseInt(result, 16);
web3Events.emit('balanceReceived', balance.toString());
} catch (error) {
console.error("Balance fetch error:", error);
web3Events.emit('balanceError', error.message);
}
}
public getConnectedAddress(): string {
return this.connectedAddress || '';
}
}

主要功能

  • initializeSDK() - 初始化 DApp Portal SDK。
  • connectWallet() - 处理钱包连接。
  • mintToken(amount) - 铸造代币。
  • getBalance() - 读取令牌余额。

运行脚本前,请确保

  • 替换 Web3Manager.ts 中的 YOUR_CLIENT_ID
  • 如有需要,请更新CONTRACT_ADDRESS
  • 更新 CHAIN_ID 以获得正确的网络。

UIManager.ts - 处理用户界面交互

UIManager 脚本管理所有用户界面组件和用户交互。

代码执行:


import { _decorator, Component, Node, Label, Button } from 'cc';
import { Web3Manager, web3Events } from './Web3Manager';
const { ccclass, property } = _decorator;
@ccclass('UIManager')
export class UIManager extends Component {
@property(Label)
addressLabel: Label = null;
@property(Label)
balanceLabel: Label = null;
@property(Button)
connectButton: Button = null;
@property(Button)
mintButton: Button = null;
private web3Manager: Web3Manager = null;
start() {
this.web3Manager = this.getComponent(Web3Manager);
this.updateUIState(false);
this.setupEventListeners();
this.setupButtonHandlers();
}
private setupEventListeners() {
web3Events.on('sdkInitialized', this.onSDKInitialized, this);
web3Events.on('walletConnected', this.onWalletConnected, this);
web3Events.on('balanceReceived', this.onBalanceReceived, this);
web3Events.on('mintSuccess', this.onMintSuccess, this);
web3Events.on('walletError', this.onError, this);
web3Events.on('mintError', this.onError, this);
web3Events.on('balanceError', this.onError, this);
}
private setupButtonHandlers() {
this.connectButton.node.on('click', this.onConnectClick, this);
this.mintButton.node.on('click', this.onMintClick, this);
}
onDestroy() {
web3Events.off('sdkInitialized', this.onSDKInitialized, this);
web3Events.off('walletConnected', this.onWalletConnected, this);
web3Events.off('balanceReceived', this.onBalanceReceived, this);
web3Events.off('mintSuccess', this.onMintSuccess, this);
web3Events.off('walletError', this.onError, this);
web3Events.off('mintError', this.onError, this);
web3Events.off('balanceError', this.onError, this);
}
private updateUIState(isConnected: boolean) {
if (this.connectButton) {
this.connectButton.node.active = !isConnected;
}
if (this.mintButton) {
this.mintButton.interactable = isConnected;
}
if (this.addressLabel) {
this.addressLabel.node.active = isConnected;
}
if (this.balanceLabel) {
this.balanceLabel.node.active = isConnected;
}
}
async onConnectClick() {
await this.web3Manager.connectWallet();
}
async onMintClick() {
await this.web3Manager.mintToken(1); // Mint 1 token as example
}
onSDKInitialized() {
console.log('SDK initialized');
}
onWalletConnected(address: string) {
this.updateUIState(true);
if (this.addressLabel) {
this.addressLabel.string = `Connected: ${address.substring(0, 6)}...${address.substring(address.length - 4)}`;
}
}
onBalanceReceived(balance: string) {
if (this.balanceLabel) {
this.balanceLabel.string = `Balance: ${balance}`;
console.log('Balance updated:', balance); // Add this to debug
}
}
onMintSuccess(txHash: string) {
console.log(`Mint successful! TX: ${txHash}`);
// The balance update will happen automatically because we called getBalance() in mintToken
}
onError(error: string) {
console.error('Error:', error);
}
}

将脚本附加到节点并连接用户界面元素

1. 将脚本附加到 Web3UI 节点

  • 选择 Web3UI 节点。
  • 检查器中,单击添加组件
  • 搜索并选择 Web3Manager

  • 重复上述步骤添加 UIManager。

2. 连接用户界面元素

  • 选择 Web3UI 后,转到检查器。
  • 将相应的用户界面元素从层次结构拖放到各自的字段中:
    • 地址标签
    • 余额标签
    • 连接钱包按钮
    • 薄荷纽扣

让这个页面变得更好