产品 API 使用示例
18 分
以下是使用产品API管理世界货币和世界产品的示例。
此示例使您能够基本了解产品API,并实现服务器与客户端之间的消息发送和接收,以便您可以轻松测试授予和扣除世界货币和产品。
此示例包括世界货币和世界产品客户端脚本的描述,随后是处理所有服务器端处理的集成服务器脚本,并包括以下功能:
- 授予世界货币
- 扣除世界货币
- 在不扣除货币的情况下授予世界产品
- 扣除世界产品

授予与扣除世界货币
以下是管理世界货币授予和扣除的完整客户端代码,以及如何实现它。
货币客户端脚本
import { Button, Text } from 'UnityEngine.UI';
import { ZepetoScriptBehaviour } from 'ZEPETO.Script'
import { LocalPlayer, ZepetoPlayers } from 'ZEPETO.Character.Controller';
import { Room, RoomData } from 'ZEPETO.Multiplay';
import { ZepetoWorldMultiplay } from 'ZEPETO.World';
export default class CurrencyManagerSample extends ZepetoScriptBehaviour {
public currencyId: string;
public increaseQuantity: number;
public decreaseQuantity: number;
public increaseCurrencyBtn: Button;
public decreaseCurrencyBtn: Button;
public balanceText: Text;
public multiplay: ZepetoWorldMultiplay;
private _localPlayer: LocalPlayer;
Start() {
ZepetoPlayers.instance.OnAddedLocalPlayer.AddListener(() => {
this._localPlayer = ZepetoPlayers.instance.LocalPlayer;
this.loadCurrencyBalance(this.currencyId);
});
// 处理房间加入事件以更新货币 UI
this.multiplay.RoomJoined += (room: Room) => {
room.AddMessageHandler("SyncCurrencyInfo", (message: CurrencyMessage) => {
const currentCurrencyId = message.currencyId;
const currentQuantity = message.quantity;
this.balanceUIUpdate(currentCurrencyId, currentQuantity);
});
};
// 增加货币的按钮事件监听器:请求信用
this.increaseCurrencyBtn.onClick.AddListener(() => {
const data = new RoomData();
data.Add("currencyId", this.currencyId);
data.Add("quantity", this.increaseQuantity);
this.multiplay.Room?.Send("CreditCurrency", data.GetObject());
})
// 减少货币的按钮事件监听器:请求借记
this.decreaseCurrencyBtn.onClick.AddListener(() => {
const data = new RoomData();
data.Add("currencyId", this.currencyId);
data.Add("quantity", this.decreaseQuantity);
this.multiplay.Room?.Send("DebitCurrency", data.GetObject());
})
}
// 请求指定货币的当前数量
private loadCurrencyBalance(currentCurrencyId: string) {
this.multiplay.Room?.Send("LoadBalance", currentCurrencyId);
}
// 更新 UI 以反映当前货币的数量
private balanceUIUpdate(currentCurrencyId: string, currentQuantity: number) {
this.balanceText.text = currentQuantity.toString();
}
}
// 货币同步消息的接口
interface CurrencyMessage {
currencyId: string,
quantity: number,
}
货币客户端脚本描述
- 当角色加载时,会向服务器发送房间消息以加载现有的货币余额。然后根据从服务器接收到的余额信息更新 UI。
this.multiplay.Room?.Send("LoadBalance", currentCurrencyId);- 为了促进消息交换,CurrencyMessage 接口被定义。
interface CurrencyMessage {
currencyId: string,
quantity: number,
}- 当用户增加或减少他们的货币时,他们会作为房间消息向服务器发送请求。 它包括有关要增加或减少哪种货币以及增加或减少多少的数据。
this.multiplay.Room?.Send("CreditCurrency", data.GetObject());
this.multiplay.Room?.Send("DebitCurrency", data.GetObject());- 服务器然后处理货币的增加或减少,并将最终余额信息发送给客户端。客户端接收此信息并更新用户界面。
this.multiplay.RoomJoined += (room: Room) => {
room.AddMessageHandler("SyncCurrencyInfo", (message: CurrencyMessage) => {
const currentCurrencyId = message.currencyId;
const currentQuantity = message.quantity;
this.updateBalanceUI(currentCurrencyId, currentQuantity);
});
};
授予与扣除世界产品
以下是管理世界产品授予和扣除的完整客户端代码,以及如何实现它。
产品客户端脚本
import { Button, Text } from 'UnityEngine.UI';
import { ZepetoScriptBehaviour } from 'ZEPETO.Script'
import { LocalPlayer, ZepetoPlayers } from 'ZEPETO.Character.Controller';
import { Room, RoomData } from 'ZEPETO.Multiplay';
import { ZepetoWorldMultiplay } from 'ZEPETO.World';
import { InventoryRecord, InventoryService } from 'ZEPETO.Inventory';
import { WaitUntil } from 'UnityEngine';
export default class ProductManagerSample extends ZepetoScriptBehaviour {
public productId: string;
public productAddQuantity: number;
public acquireItemBtn: Button;
public useItemBtn: Button;
public itemCountText: Text;
public multiplay: ZepetoWorldMultiplay;
private _localPlayer: LocalPlayer;
Start() {
ZepetoPlayers.instance.OnAddedLocalPlayer.AddListener(() => {
this._localPlayer = ZepetoPlayers.instance.LocalPlayer;
this.StartCoroutine(this.refreshProductUI());
});
// 处理房间加入事件以更新产品 UI
this.multiplay.RoomJoined += (room: Room) => {
room.AddMessageHandler("SyncProductInfo", (message: ProductMessage) => {
this.StartCoroutine(this.refreshProductUI());
});
};
// 获取物品的按钮事件监听器:添加产品
this.acquireItemBtn.onClick.AddListener(() => {
const data = new RoomData();
data.Add("productId", this.productId);
data.Add("quantity", this.productAddQuantity);
this.multiplay.Room?.Send("AddProduct", data.GetObject());
})
// 使用物品的按钮事件监听器:使用产品
this.useItemBtn.onClick.AddListener(() => {
const data = new RoomData();
data.Add("productId", this.productId);
data.Add("quantity", 1);
this.multiplay.Room?.Send("UseProduct", data.GetObject());
})
}
private * refreshProductUI() {
const request = InventoryService.GetAsync(this.productId);
yield new WaitUntil(() => request.keepWaiting == false);
// 如果请求成功,更新产品 UI
if (request.responseData.isSuccess) {
this.updateItemCountText(request.responseData.product);
}
else {
console.log("加载产品物品失败。");
}
}
private updateItemCountText(item: InventoryRecord) {
if (item != null) {
this.itemCountText.text = item.quantity.toString();
}
else {
this.itemCountText.text = "0";
}
}
}
// 产品消息的接口。
interface ProductMessage {
productId: string,
productAction: ProductAction,
}
// 定义产品操作类型的枚举。
export enum ProductAction {
Use,
Add,
}
产品客户端脚本描述
private * refreshProductUI() {
const request = InventoryService.GetAsync(this.productId);
yield new WaitUntil(() => request.keepWaiting == false);
if (request.responseData.isSuccess) {
this.updateItemCountText(request.responseData.product);
}
else {
console.log("加载产品项失败。");
}
}- 要发送和接收消息,定义 ProductMessage 接口。定义一个 ProductAction 枚举以供示例实现。
interface ProductMessage {
productId: string,
productAction: ProductAction,
}
export enum ProductAction {
使用,
添加,
}- 当您增加或减少产品时,您将该数据作为房间消息发送到服务器。 它包括有关要增加或减少哪个产品以及增加或减少多少的数据。
this.multiplay.Room?.Send("AddProduct", data.GetObject());
this.multiplay.Room?.Send("UseProduct", data.GetObject());- 处理产品变更后,服务器将最终库存信息发送给客户端,客户端相应地更新UI。
this.multiplay.RoomJoined += (room: Room) => {
room.AddMessageHandler("SyncProductInfo", (message: ProductMessage) => {
this.StartCoroutine(this.refreshProductUI());
});
};- 通常,世界产品需要花费货币进行购买。
服务器脚本
以下是管理世界货币和产品的完整服务器代码,以及如何实现它。
完整服务器脚本
import { Sandbox, SandboxOptions, SandboxPlayer } from "ZEPETO.Multiplay";
import { loadCurrency } from "ZEPETO.Multiplay.Currency";
import { loadInventory } from "ZEPETO.Multiplay.Inventory";
export default class extends Sandbox {
async onCreate(options: SandboxOptions) {
// 货币
//请求加载货币
this.onMessage("LoadBalance", (client, message: string) => {
this.loadBalance(client, message);
});
//请求添加信用
this.onMessage("CreditCurrency", (client, message: CurrencyMessage ) => {
const currencyId = message.currencyId;
const quantity = message.quantity;
this.addCredit(client, currencyId, quantity);
});
//请求扣除信用
this.onMessage("DebitCurrency", (client, message: CurrencyMessage ) => {
const currencyId = message.currencyId;
const quantity = message.quantity;
this.onDebit(client, currencyId, quantity);
});
// 产品
//请求添加物品
this.onMessage("AddProduct", (client, message: any) => {
const productId = message.productId;
const quantity = message.quantity;
this.addProduct(client, productId, quantity);
});
//请求使用物品
this.onMessage("UseProduct", (client, message: any) => {
const productId = message.productId;
const quantity = message.quantity;
this.useProduct(client, productId, quantity);
});
}
async addCredit(client: SandboxPlayer, currencyId: string, quantity: number) {
try {
const currency = await loadCurrency(client.userId);
await currency.credit(currencyId, quantity);
this.loadBalance(client, currencyId);
} catch (e) {
console.error(`AddCredit 错误: ${e}`);
}
}
async onDebit(client: SandboxPlayer, currencyId: string, quantity: number) {
try {
const currency = await loadCurrency(client.userId);
if (await currency.debit(currencyId, quantity) === true) {
this.loadBalance(client, currencyId);
} else {
console.error("DebitCredit 错误: 货币不足");
}
} catch (e) {
console.error(`DebitCredit 错误: ${e}`);
}
}
async loadBalance(client: SandboxPlayer, currencyId: string) {
try {
const currency = await loadCurrency(client.userId);
let balancesObject = await currency.getBalances();
let balancesMap: Map<string, number> = new Map(Object.entries(balancesObject));
const specificCurrencyID = currencyId;
const specificBalance = balancesMap.get(specificCurrencyID) ?? 0;
const currencySync: CurrencyMessage = {
currencyId: specificCurrencyID,
quantity: specificBalance
}
client.send("SyncCurrencyInfo", currencySync);
} catch (e) {
console.error(`loadBalance 错误: ${e}`);
}
}
async addProduct(client: SandboxPlayer, productId: string, quantity: number) {
try {
const inventory = await loadInventory(client.userId);
await inventory.add(productId, quantity);
const productMessage: ProductMessage = {
productId: productId,
productAction: ProductAction.Add
}
client.send("SyncProductInfo", productMessage);
} catch (e) {
console.error(`addProduct 错误: ${e}`);
}
}
async useProduct(client: SandboxPlayer, productId: string, quantity: number) {
try {
const inventory = await loadInventory(client.userId);
await inventory.use(productId, quantity);
const productMessage: ProductMessage = {
productId: productId,
productAction: ProductAction.Use
}
client.send("SyncProductInfo", productMessage);
} catch (e) {
console.error(`useProduct 错误: ${e}`);
}
}
onJoin(client: SandboxPlayer) {
// 加入逻辑在这里
}
onTick(deltaTime: number): void {
// Tick 逻辑在这里
}
onLeave(client: SandboxPlayer, consented?: boolean) {
// 处理离开逻辑在这里
}
}
// 货币消息接口
interface CurrencyMessage {
currencyId: string,
quantity: number,
}
// 产品消息接口。
interface ProductMessage {
productId: string,
productAction: ProductAction,
}
// 定义产品操作类型的枚举。
export enum ProductAction {
Use,
Add,
}
服务器脚本描述
- 使用 currency.credit() 和 currency.debit() 来增加或减少所需货币的余额。之后,调用 currency.getBalances() 来获取每种货币的当前余额。
currency.credit(currencyId, quantity);
currency.debit(currencyId, quantity);
currency.getBalances();- 使用 inventory.add() 和 inventory.use() 来增加或减少所需货币的余额。
inventory.add(productId, quantity);
inventory.use(productId, quantity);- 处理来自客户的增加或减少货币和产品的请求。
- 使用loadBalance()来获取在ZEPETO Studio中注册的货币信息。
- 如果有多种货币,您可以根据特定的货币ID值进行条件筛选,以仅获取该货币的余额。
- 将最终余额值作为房间消息传递给客户端。