feat: 提交资源
This commit is contained in:
9
assets/games/scripts/currency.meta
Normal file
9
assets/games/scripts/currency.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "99123257-14dc-48cf-a23c-a1155cd6dd44",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
64
assets/games/scripts/currency/CurrencyManager.ts
Normal file
64
assets/games/scripts/currency/CurrencyManager.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { _decorator } from "cc";
|
||||
|
||||
import { EventManager } from "@max-studio/core/event/EventManager";
|
||||
import { Singleton } from "@max-studio/core/Singleton";
|
||||
import LogUtils from "@max-studio/core/utils/LogUtils";
|
||||
|
||||
import { CurrencyEventMessage, CurrencyType } from "./Types";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass("CurrencyManager")
|
||||
export class CurrencyManager extends Singleton {
|
||||
private currencyValues: Record<CurrencyType, number> = {} as Record<CurrencyType, number>;
|
||||
|
||||
/** 获取货币值 */
|
||||
public getCurrencyValue(type: CurrencyType): number {
|
||||
return this.currencyValues[type] || 0;
|
||||
}
|
||||
|
||||
/** 设置货币值 */
|
||||
public setCurrencyValue(type: CurrencyType, value: number, isNotify: boolean = true) {
|
||||
this.currencyValues[type] = value;
|
||||
if (isNotify) {
|
||||
EventManager.getInstance().emit(CurrencyEventMessage.CURRENCY_VALUE_CHANGED, type, value);
|
||||
}
|
||||
}
|
||||
|
||||
/** 格式化货币显示 */
|
||||
public formatCurrencyDisplay(type: CurrencyType, value?: number): string {
|
||||
const amount = value ?? this.getCurrencyValue(type);
|
||||
|
||||
// 根据货币类型返回不同的格式
|
||||
if (amount >= 1000000) {
|
||||
return `${(amount / 1000000).toFixed(1)}M`;
|
||||
} else if (amount >= 1000) {
|
||||
return `${(amount / 1000).toFixed(1)}K`;
|
||||
}
|
||||
|
||||
return amount.toString();
|
||||
}
|
||||
|
||||
/** 检查货币是否足够 */
|
||||
public isCurrencyEnough(type: CurrencyType, amount: number): boolean {
|
||||
return this.getCurrencyValue(type) >= amount;
|
||||
}
|
||||
|
||||
/** 消耗货币 */
|
||||
public consumeCurrency(type: CurrencyType, amount: number, isNotify: boolean = true): boolean {
|
||||
if (amount <= 0) {
|
||||
LogUtils.warn(`[CurrencyManager] 消耗货币数量必须大于0: ${amount}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.isCurrencyEnough(type, amount)) {
|
||||
LogUtils.warn(`[CurrencyManager] 货币不足: ${type}, 需要: ${amount}, 当前: ${this.getCurrencyValue(type)}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const currentValue = this.getCurrencyValue(type);
|
||||
const newValue = currentValue - amount;
|
||||
this.setCurrencyValue(type, newValue, isNotify);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
9
assets/games/scripts/currency/CurrencyManager.ts.meta
Normal file
9
assets/games/scripts/currency/CurrencyManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "0474457b-c003-444f-b68b-9279920ba444",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
9
assets/games/scripts/currency/Types.ts
Normal file
9
assets/games/scripts/currency/Types.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export enum CurrencyType {
|
||||
ENERGY = "energy",
|
||||
GEM = "gem",
|
||||
GOLD = "gold",
|
||||
}
|
||||
|
||||
export enum CurrencyEventMessage {
|
||||
CURRENCY_VALUE_CHANGED = 'currency_value_changed',
|
||||
}
|
||||
9
assets/games/scripts/currency/Types.ts.meta
Normal file
9
assets/games/scripts/currency/Types.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "4eb1626b-f4b8-4566-b197-30c135c7e3a8",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
9
assets/games/scripts/currency/components.meta
Normal file
9
assets/games/scripts/currency/components.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "ea4b3885-21a2-4076-8162-00bd5ee2c090",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
46
assets/games/scripts/currency/components/CurrencyItem.ts
Normal file
46
assets/games/scripts/currency/components/CurrencyItem.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { _decorator, Component, Enum, Label } from "cc";
|
||||
|
||||
import { EventManager } from "@max-studio/core/event/EventManager";
|
||||
import UIManager from "@max-studio/core/ui/UIManager";
|
||||
import LogUtils from "@max-studio/core/utils/LogUtils";
|
||||
|
||||
import { ShopUI } from "../../uis/ShopUI";
|
||||
import { CurrencyManager } from "../CurrencyManager";
|
||||
import { CurrencyEventMessage, CurrencyType } from "../Types";
|
||||
import { onEvent } from "@max-studio/core/decorators";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass("CurrencyItem")
|
||||
export class CurrencyItem extends Component {
|
||||
@property({ type: Enum(CurrencyType) })
|
||||
public type: CurrencyType = CurrencyType.ENERGY;
|
||||
|
||||
@property(Label)
|
||||
public label: Label = null!;
|
||||
|
||||
protected onLoad(): void {
|
||||
this.node.onClick(this.onGotoCurrencyShop, this);
|
||||
}
|
||||
|
||||
private onGotoCurrencyShop() {
|
||||
LogUtils.log("点击了货币商店:", this.type);
|
||||
void UIManager.getInstance().openUI(ShopUI, this.type);
|
||||
}
|
||||
|
||||
@onEvent(CurrencyEventMessage.CURRENCY_VALUE_CHANGED)
|
||||
private onCurrencyValueChanged(type: CurrencyType, value: number) {
|
||||
if (type !== this.type) {
|
||||
return;
|
||||
}
|
||||
this.label.string = CurrencyManager.getInstance().formatCurrencyDisplay(this.type, value);
|
||||
}
|
||||
|
||||
protected onDestroy(): void {
|
||||
EventManager.getInstance().off(CurrencyEventMessage.CURRENCY_VALUE_CHANGED, this.onCurrencyValueChanged, this);
|
||||
}
|
||||
|
||||
protected start(): void {
|
||||
this.label.string = CurrencyManager.getInstance().formatCurrencyDisplay(this.type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "8840c2d8-d822-482c-b68f-2a88cd9c8e72",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
9
assets/games/scripts/uis.meta
Normal file
9
assets/games/scripts/uis.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "64114bf3-6b22-4ea3-b229-87984f6eb045",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
153
assets/games/scripts/uis/CommonDialogBox.ts
Normal file
153
assets/games/scripts/uis/CommonDialogBox.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import BasePopup from "@max-studio/core/ui/BasePopup";
|
||||
import { uiConfig, UIType } from "@max-studio/core/ui/UIDecorator";
|
||||
import UIManager from "@max-studio/core/ui/UIManager";
|
||||
import { IDialogBoxOptions } from "assets/scripts/DialogBox";
|
||||
import { Vec3 } from "cc";
|
||||
import { Button } from "cc";
|
||||
import { tween } from "cc";
|
||||
import { Label } from "cc";
|
||||
import { _decorator, Node } from "cc";
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
* 基础对话框组件
|
||||
*/
|
||||
@uiConfig({
|
||||
bundle: "games",
|
||||
prefab: "prefabs/uis/CommonDialogBox",
|
||||
isMulti: true,
|
||||
isCache: true,
|
||||
type: UIType.POPUP,
|
||||
})
|
||||
@ccclass("CommonDialogBox")
|
||||
export class CommonDialogBox extends BasePopup {
|
||||
@property(Label)
|
||||
titleLabel: Label = null!;
|
||||
|
||||
@property(Node)
|
||||
contentRoot: Node = null!;
|
||||
|
||||
@property(Label)
|
||||
contentLabel: Label = null!;
|
||||
|
||||
@property(Button)
|
||||
confirmBtn: Button = null!;
|
||||
|
||||
@property(Label)
|
||||
confirmBtnLabel: Label = null!;
|
||||
|
||||
@property(Button)
|
||||
cancelBtn: Button = null!;
|
||||
|
||||
@property(Label)
|
||||
cancelBtnLabel: Label = null!;
|
||||
|
||||
@property(Button)
|
||||
closeBtn: Button = null!;
|
||||
|
||||
// 回调函数
|
||||
private onConfirmCallback: (() => void) | null = null;
|
||||
private onCancelCallback: (() => void) | null = null;
|
||||
|
||||
protected onLoad(): void {
|
||||
// 绑定按钮事件
|
||||
if (this.confirmBtn) {
|
||||
this.confirmBtn.node.on(Button.EventType.CLICK, this.onConfirmClick, this);
|
||||
}
|
||||
|
||||
if (this.cancelBtn) {
|
||||
this.cancelBtn.node.on(Button.EventType.CLICK, this.onCancelClick, this);
|
||||
}
|
||||
|
||||
if (this.closeBtn) {
|
||||
this.closeBtn.node.on(Button.EventType.CLICK, this.onCloseClick, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确定按钮点击事件
|
||||
*/
|
||||
private onConfirmClick(): void {
|
||||
// 执行回调
|
||||
if (this.onConfirmCallback) {
|
||||
this.onConfirmCallback();
|
||||
}
|
||||
|
||||
// 隐藏对话框
|
||||
void UIManager.getInstance().closeUI(this);
|
||||
}
|
||||
|
||||
async onShow(options: IDialogBoxOptions = {}) {
|
||||
this.contentRoot.scale = Vec3.ZERO;
|
||||
tween(this.contentRoot).to(0.3, { scale: Vec3.ONE }, { easing: "backOut" }).start();
|
||||
|
||||
const {
|
||||
title = "提示",
|
||||
content = "",
|
||||
onConfirm,
|
||||
onCancel,
|
||||
confirmText = "确定",
|
||||
cancelText = "取消",
|
||||
showCancel = true,
|
||||
hideClose = false,
|
||||
} = options;
|
||||
|
||||
// 设置标题和内容
|
||||
if (this.titleLabel) {
|
||||
this.titleLabel.string = title;
|
||||
}
|
||||
if (this.contentLabel) {
|
||||
this.contentLabel.string = content;
|
||||
}
|
||||
|
||||
// 设置按钮文本
|
||||
if (this.confirmBtnLabel) {
|
||||
this.confirmBtnLabel.string = confirmText;
|
||||
}
|
||||
if (this.cancelBtnLabel) {
|
||||
this.cancelBtnLabel.string = cancelText;
|
||||
}
|
||||
|
||||
// 控制取消按钮显示状态
|
||||
if (this.cancelBtn) {
|
||||
this.cancelBtn.node.active = showCancel;
|
||||
}
|
||||
|
||||
if (this.closeBtn) {
|
||||
this.closeBtn.node.active = !hideClose;
|
||||
}
|
||||
|
||||
// 保存回调函数
|
||||
this.onConfirmCallback = onConfirm || null;
|
||||
this.onCancelCallback = onCancel || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消按钮点击事件
|
||||
*/
|
||||
private onCancelClick(): void {
|
||||
// 执行回调
|
||||
if (this.onCancelCallback) {
|
||||
this.onCancelCallback();
|
||||
}
|
||||
|
||||
// 隐藏对话框
|
||||
void UIManager.getInstance().closeUI(this);
|
||||
}
|
||||
|
||||
private onCloseClick(): void {
|
||||
// 隐藏对话框
|
||||
void UIManager.getInstance().closeUI(this);
|
||||
}
|
||||
|
||||
async onHide(): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
tween(this.contentRoot)
|
||||
.to(0.2, { scale: new Vec3(0.8, 0.8, 0.8) }, { easing: "quadIn" })
|
||||
.call(() => {
|
||||
resolve();
|
||||
})
|
||||
.start();
|
||||
});
|
||||
}
|
||||
}
|
||||
9
assets/games/scripts/uis/CommonDialogBox.ts.meta
Normal file
9
assets/games/scripts/uis/CommonDialogBox.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "ee46f250-e044-478d-91ea-70023cf1ce2e",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
77
assets/games/scripts/uis/CommonToast.ts
Normal file
77
assets/games/scripts/uis/CommonToast.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import BaseToast from "@max-studio/core/ui/BaseToast";
|
||||
import { uiConfig, UIType } from "@max-studio/core/ui/UIDecorator";
|
||||
import UIManager from "@max-studio/core/ui/UIManager";
|
||||
import { SpriteAtlas, tween, Vec3, UITransform } from "cc";
|
||||
import { RichText } from "cc";
|
||||
import { _decorator, Component, Node } from "cc";
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@uiConfig({
|
||||
prefab: "prefabs/uis/CommonToast",
|
||||
bundle: "games",
|
||||
type: UIType.TOAST,
|
||||
isMulti: true,
|
||||
isCache: true,
|
||||
})
|
||||
@ccclass("CommonToast")
|
||||
export class CommonToast extends BaseToast {
|
||||
@property(RichText)
|
||||
private contentLabel: RichText;
|
||||
|
||||
@property(Node)
|
||||
private containerNode: Node;
|
||||
|
||||
async onShow(tip: string, atlas: SpriteAtlas): Promise<void> {
|
||||
if (atlas) {
|
||||
this.contentLabel.imageAtlas = atlas;
|
||||
}
|
||||
this.contentLabel.string = tip;
|
||||
|
||||
// 播放滑入动画
|
||||
this.playSlideInAnimation();
|
||||
|
||||
// 显示3秒后自动滑出
|
||||
this.scheduleOnce(() => {
|
||||
this.playSlideOutAnimation();
|
||||
}, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放滑入动画
|
||||
*/
|
||||
private playSlideInAnimation() {
|
||||
this.containerNode.setPosition(0, 930, 0);
|
||||
|
||||
// 播放滑入动画
|
||||
tween(this.containerNode)
|
||||
.to(
|
||||
0.5,
|
||||
{ position: new Vec3(0, 720, 0) },
|
||||
{
|
||||
easing: "backOut",
|
||||
},
|
||||
)
|
||||
.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放滑出动画
|
||||
*/
|
||||
private playSlideOutAnimation() {
|
||||
// 滑出到屏幕顶部外面
|
||||
const endY = 930;
|
||||
|
||||
tween(this.containerNode)
|
||||
.to(
|
||||
0.3,
|
||||
{ position: new Vec3(0, endY, 0) },
|
||||
{
|
||||
easing: "backIn",
|
||||
},
|
||||
)
|
||||
.call(() => {
|
||||
UIManager.getInstance().closeUI(this);
|
||||
})
|
||||
.start();
|
||||
}
|
||||
}
|
||||
9
assets/games/scripts/uis/CommonToast.ts.meta
Normal file
9
assets/games/scripts/uis/CommonToast.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "3c5321d0-7e80-418b-bf2a-fac4d8069ceb",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
22
assets/games/scripts/uis/MainUI.ts
Normal file
22
assets/games/scripts/uis/MainUI.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { _decorator } from "cc";
|
||||
|
||||
import BaseLayer from "@max-studio/core/ui/BaseLayer";
|
||||
import { uiConfig, UIType } from "@max-studio/core/ui/UIDecorator";
|
||||
import UIManager from "@max-studio/core/ui/UIManager";
|
||||
import { CommonDialogBox } from "./CommonDialogBox";
|
||||
import { CommonToast } from "./CommonToast";
|
||||
import { ResManager } from "@max-studio/core/res/ResManager";
|
||||
import { SpriteAtlas } from "cc";
|
||||
|
||||
const { ccclass, property, menu } = _decorator;
|
||||
|
||||
@ccclass("MainUI")
|
||||
@uiConfig({
|
||||
prefab: "prefabs/uis/MainUI",
|
||||
bundle: "games",
|
||||
isCache: false,
|
||||
})
|
||||
@menu("max/ui/MainUI")
|
||||
export class MainUI extends BaseLayer {
|
||||
async onShow(...args: any[]) {}
|
||||
}
|
||||
9
assets/games/scripts/uis/MainUI.ts.meta
Normal file
9
assets/games/scripts/uis/MainUI.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "66960106-0303-42e3-9866-7750a922851b",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
23
assets/games/scripts/uis/ShopUI.ts
Normal file
23
assets/games/scripts/uis/ShopUI.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { _decorator } from "cc";
|
||||
|
||||
import BaseLayer from "@max-studio/core/ui/BaseLayer";
|
||||
import { uiConfig, UIType } from "@max-studio/core/ui/UIDecorator";
|
||||
|
||||
const { ccclass, property, menu } = _decorator;
|
||||
|
||||
@ccclass("ShopUI")
|
||||
@uiConfig({
|
||||
prefab: "prefabs/uis/ShopUI",
|
||||
bundle: "games",
|
||||
type: UIType.NORMAL,
|
||||
isMulti: false,
|
||||
isCache: false,
|
||||
})
|
||||
@menu("max/ui/ShopUI")
|
||||
export class ShopUI extends BaseLayer {
|
||||
protected onLoad(): void {
|
||||
// ProtoDefinitions.pkg1.User
|
||||
let user = new ProtoDefinitions.pkg1.User();
|
||||
console.log(user, ProtoDefinitions.pkg1.User.encode(user));
|
||||
}
|
||||
}
|
||||
9
assets/games/scripts/uis/ShopUI.ts.meta
Normal file
9
assets/games/scripts/uis/ShopUI.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "2c244a4a-c1be-4ed6-a768-4e60bfc0a520",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
Reference in New Issue
Block a user