新增错误提示

This commit is contained in:
2026-03-11 15:40:31 +08:00
parent c9354c02b7
commit 220725206f
11 changed files with 19077 additions and 3 deletions

View File

@@ -0,0 +1,4 @@
存放UI以及脚本的文件夹
1、除了UI本身外不允许存放其它任何预置体或场景资源🔥
2、UI脚本在根目录下其它脚本放到expansion目录下
3、不可单独删除此文件夹

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
{
"ver": "1.1.50",
"importer": "prefab",
"imported": true,
"uuid": "4892f711-598c-44a7-888d-fb1ceb7ae920",
"files": [
".json"
],
"subMetas": {},
"userData": {
"syncNodeName": "PageMain"
}
}

View File

@@ -0,0 +1,641 @@
import { _decorator, Asset, BoxCollider2D, Contact2DType, EventTouch, Game, game, ImageAsset, Input, input, KeyCode, Node, NodeEventType, Skeleton, sp, Sprite, SpriteFrame, Texture2D, tween, UIOpacity, UITransform, Vec3 } from 'cc';
import BaseView from '../../../../../../extensions/app/assets/base/BaseView';
import { Tools } from 'db://assets/res-native/tools/Tools';
import { app } from 'db://assets/app/app';
const { ccclass, property } = _decorator;
/** 游戏时间 */
const GAME_TIME = 30;
/** 游戏边界 */
const MOVE_BOUNDARY = 500;
@ccclass('PageMain')
export class PageMain extends BaseView {
/** 掉落红包预制件 */
@property(Node) redPacket: Node = null!;
/** 时间 */
@property(Node) lab_time: Node = null!;
/** 分数 */
@property(Node) lab_score: Node = null!;
/** 开始按钮 */
@property(Node) btn_start: Node = null!;
/** 红包天空 */
@property(Node) red_sky: Node = null!;
/** 财神 */
@property(Node) caiShen: Node = null!;
/** 财神上位节点,用来防止文字旋转 */
@property(Node) caiShen_up: Node = null!;
/** 背景 */
@property(Node) background: Node = null!;
/** 需要浮动 */
@property(Node) needFlow: Node[] = [];
/** 需要闪烁 */
@property(Node) needFlash: Node[] = [];
/** 获奖文字 */
@property(Node) lab_add: Node = null!;
/** 准备页面 */
@property(Node) readyPage: Node[] = [];
/** 游戏页面 */
@property(Node) gamePage: Node[] = [];
/** 去充值按钮 */
@property(Node) btn_to_charge: Node = null!;
/** 去游戏按钮 */
@property(Node) btn_to_game: Node = null!;
/** 奖励界面 */
@property(Node) rw: Node = null!;
/** 倒计时 */
@property(Node) count: Node = null!;
/** 音乐按钮 */
@property(Node) btn_music: Node = null!;
/** 关闭音乐按钮 */
@property(Node) btn_no_music: Node = null!;
/** logo展示 */
@property(Sprite) logo: Sprite = null!;
/** 金币雨 */
@property(Node) gold_rain: Node = null!;
/** 是否正在游戏 */
private _gaming = false;
/** 剩余游戏时间 */
private _time = 0;
/** 红包管理器 */
private _redMgr : Node[] = [];
/** 红包掉落间隔时间 秒 */
private _redTime: number = 1/2;
/** 当前游戏id */
private _game_id = "";
/** 当前分数 */
private _score = 0;
/** 最大分数 */
private _maxScore = 0;
/** 剩余红包个数 */
private _redRemain = 0;
/** 财神移动速度 */
private readonly caiShenMoveSpeed: number = 600;
/** 移动边界 */
private readonly leftBoundary: number = -MOVE_BOUNDARY;
private readonly rightBoundary: number = MOVE_BOUNDARY;
/** 当前移动方向 */
private _currentDirection: number = 0; // -1:左, 0:无, 1:右
/** 倒计时 */
private countdownInterval: any;
/** 游戏开始需要的时间和充值 */
private _money_need : boolean = false;
private _time_need : boolean = false;
private _chance_balance : number = 0;
/** 记录切换到后台时间 */
private _hideTime: number = 0;
// 初始化的相关逻辑写在这
onLoad() {}
// 界面打开时的相关逻辑写在这(onShow可被多次调用-它与onHide不成对)
onShow(params: any) {
input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
input.on(Input.EventType.KEY_UP, this.onKeyUp, this);
// 注册触摸事件
this.background.on(NodeEventType.TOUCH_MOVE, this.onTouchMove, this);
this.background.on(NodeEventType.TOUCH_START, this.onTouchStart, this);
this.background.on(NodeEventType.TOUCH_END, this.onTouchEnd, this);
// 监听隐藏事件(切换到后台)
game.on(Game.EVENT_HIDE, this.onAppHide, this);
// 监听显示事件(从前台返回)
game.on(Game.EVENT_SHOW, this.onAppShow, this);
// 开始更新循环以处理持续移动
this.schedule(this.updateMovement, 1/60); // 每帧更新
this.startFlow()
this.goToReadyPage()
// Tools.httpGetReq("mini-games/angpau/assets", (res: any) => {
// Tools.remoteLoadSprite(res.logo, this.logo)
// })
}
// 界面关闭时的相关逻辑写在这(已经关闭的界面不会触发onHide)
onHide(result: undefined) {
// 注销键盘事件
input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this);
input.off(Input.EventType.KEY_UP, this.onKeyUp, this);
// 注销触摸事件
this.background.off(NodeEventType.TOUCH_MOVE, this.onTouchMove, this);
this.background.off(NodeEventType.TOUCH_START, this.onTouchStart, this);
this.background.off(NodeEventType.TOUCH_END, this.onTouchEnd, this);
// 移除事件监听
game.off(Game.EVENT_HIDE, this.onAppHide, this);
game.off(Game.EVENT_SHOW, this.onAppShow, this);
// 取消更新循环
this.unschedule(this.updateMovement);
return result;
}
initReadyPage(d:any){
// d.progress.current = 500
// d.event.start_at = "2026-01-22T23:59:59+08:00"
Tools.SetChildText(this.readyPage[0], "lab_title", d.title)
Tools.SetChildText(this.readyPage[0], "lab_act_time", d.footer1.title)
Tools.SetChildText(this.readyPage[0], "lab_act_time/time", d.footer1.desc)
Tools.SetChildText(this.readyPage[0], "lab_act_qua", d.footer2.title)
Tools.SetChildText(this.readyPage[0], "lab_act_qua/time", d.footer2.desc)
Tools.SetChildText(this.readyPage[0], "lab_charge_pro/now", d.progress.current)
Tools.SetChildText(this.readyPage[0], "lab_charge_pro/all", d.progress.max)
Tools.SetChildText(this.readyPage[0], "lab_charge_goal/num", (d.progress.max - d.progress.current).toString())
Tools.ActChild(this.readyPage[0], "btn_save", d.progress.max > d.progress.current)
Tools.ActChild(this.readyPage[0], "btn_start", d.progress.max <= d.progress.current)
Tools.ActChild(this.readyPage[0], "lab_charge", d.progress.max > d.progress.current)
Tools.ActChild(this.readyPage[0], "lab_charge_goal", d.progress.max > d.progress.current)
Tools.ActChild(this.readyPage[0], "lab_get_res", d.progress.max <= d.progress.current)
const fill = Tools.MathClampZeroToOne(d.progress.current / d.progress.max);
const bar = this.readyPage[0].getChildByName("pro_bar")
Tools.GetChildComp(bar, "bar", Sprite).fillRange = fill;
bar.getChildByName("point").setPosition(fill * bar.getComponent(UITransform).width, 0, 0)
this.startCountdown(d.event.start_at)
this._money_need = d.progress.max <= d.progress.current
this._time_need = false
this._chance_balance = d.angpau_chance_balance
}
/**
* 计算倒计时剩余时间
* @param targetDate 目标日期
* @returns 包含天、小时、分钟、秒的对象
*/
calculateCountdown(targetDate: string | Date): { days: number; hours: number; minutes: number; seconds: number } {
const targetTime = new Date(targetDate).getTime();
const currentTime = new Date().getTime();
// 如果目标时间已过,则返回全零
if (targetTime <= currentTime) {
return { days: 0, hours: 0, minutes: 0, seconds: 0 };
}
const diffTime = targetTime - currentTime;
const days = Math.floor(diffTime / (1000 * 60 * 60 * 24));
const hours = Math.floor((diffTime % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((diffTime % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((diffTime % (1000 * 60)) / 1000);
return { days, hours, minutes, seconds };
}
/**
* 开始倒计时显示
*/
startCountdown(targetDate:string) {
// 立即更新一次
this.updateCountdownDisplay(targetDate);
// 每秒更新一次倒计时
this.countdownInterval = setInterval(() => {
this.updateCountdownDisplay(targetDate);
}, 1000);
}
/**
* 停止倒计时
*/
stopCountdown() {
if (this.countdownInterval) {
clearInterval(this.countdownInterval);
this.countdownInterval = null;
}
}
/**
* 更新倒计时显示
*/
updateCountdownDisplay(targetDate: string) {
const countdown = this.calculateCountdown(targetDate);
// 更新UI显示
if (this.readyPage && this.readyPage[0]) {
Tools.SetChildText(this.readyPage[0], "lab_time/day", countdown.days.toString());
Tools.SetChildText(this.readyPage[0], "lab_time/hour", countdown.hours.toString());
Tools.SetChildText(this.readyPage[0], "lab_time/minute", countdown.minutes.toString());
Tools.SetChildText(this.readyPage[0], "lab_time/second", countdown.seconds.toString());
}
if (countdown.days == 0 && countdown.hours == 0 && countdown.minutes == 0 && countdown.seconds == 0){
this.stopCountdown()
this._time_need = true
}
}
/** 去游戏界面 */
btnToGamePage(){
if (!this._money_need){
app.manager.ui.showToast("存款金额不够")
return
}
if (!this._time_need){
app.manager.ui.showToast("游戏时间未到")
return
}
if (this._chance_balance <= 0){
app.manager.ui.showToast("抽奖次数已用完")
return
}
for (let i = 0; i < this.readyPage.length; i++) {
this.readyPage[i].active = false;
}
for (let i = 0; i < this.gamePage.length; i++) {
this.gamePage[i].active = true;
}
this.caiShen.getComponent(sp.Skeleton).paused = true
}
/** 去准备页面 */
goToReadyPage(){
for (let i = 0; i < this.gamePage.length; i++) {
this.gamePage[i].active = false;
}
Tools.httpGetReq("mini-games/angpau/event", (res: any) => {
for (let i = 0; i < this.readyPage.length; i++) {
this.readyPage[i].active = true;
}
this.initReadyPage(res)
})
}
btnGameStart(){
this.btn_start.active = false;
this._game_id = "";
Tools.httpReq("mini-games/angpau/reward", {}, (res: any) => {
this.count.active = true;
this._maxScore = res.max_reward;
this._game_id = res.game_id;
this._redRemain = Math.floor(GAME_TIME / this._redTime) - 1;
//开始动画
this.loadSprite("main_count_3", this.count);
app.manager.sound.playEffect({name : "effect/start"});
let countNum = 3;
let fun = () => {
countNum--;
if (countNum <= -1) {
this.unschedule(fun);
this.count.active = false;
this._gaming = true;
this._time = GAME_TIME;
this._score = 0;
this.updateScore();
this.resetRedMgr();
Tools.SetText(this.lab_time, this._time + "s");
this.schedule(this.countTime, 1);
this.schedule(this.dropRedPacket, this._redTime);
return
}
this.loadSprite(`main_count_${countNum}`, this.count);
}
this.schedule(fun, 1);
app.manager.sound.playEffect({name : "effect/start"});
},()=>{
this.btn_start.active = true;
})
}
startFlow(){
for (let i = 0; i < this.needFlow.length; i++) {
this.aniFlow(this.needFlow[i])
}
for (let i = 0; i < this.needFlash.length; i++) {
this.aniFlash(this.needFlash[i])
}
}
aniFlash(node: Node){
let light = Math.random() * 255;
let time = (255 - light) / 100;
let opacity = node.getComponent(UIOpacity);
if (opacity) {
tween(opacity)
.to(time, {opacity: light})
.to(time, {opacity: 255})
.call(() => {
this.aniFlash(node)
})
.start();
}
}
aniFlow(node: Node){
let dis = Math.random() * 20 + 50;
tween(node)
.by(dis / 12, {position: new Vec3(0, -dis, 0)})
.by(dis / 12, {position: new Vec3(0, dis, 0)})
.call(() => {
this.aniFlow(node)
})
.start();
}
resetRedMgr(){
this.desAllRed();
this._redMgr = [];
}
desAllRed(){
// 创建副本以避免在遍历时修改数组
const redPacketsToDestroy = [...this._redMgr];
for (let i = 0; i < redPacketsToDestroy.length; i++) {
if (redPacketsToDestroy[i] && redPacketsToDestroy[i].isValid) {
const collider = redPacketsToDestroy[i].getComponent(BoxCollider2D);
if (collider) {
try {
collider.off(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
} catch (error) {
console.warn('移除碰撞监听器时出错:', error);
}
}
// 延迟销毁
this.scheduleOnce(() => {
if (redPacketsToDestroy[i] && redPacketsToDestroy[i].isValid) {
redPacketsToDestroy[i].destroy();
}
}, 0.01);
}
}
// 清空管理器
this._redMgr = [];
}
countTime(){
if (!this._gaming) return;
this._time--;
Tools.SetText(this.lab_time, this._time + "s");
if (this._time <= 0) {
this.gameOver();
}
}
gameOver(){
Tools.SetText(this.lab_time, "0s");
this._gaming = false;
this.caiShen.getComponent(sp.Skeleton).paused = true;
this.btn_start.active = true;
this.unschedule(this.countTime);
this.unschedule(this.dropRedPacket);
this.desAllRed();
Tools.httpReq("mini-games/angpau/finalize", {game_id:this._game_id, final_amount:this._score}, (res: any) => {
Tools.SetChildText(this.rw, "bg/lab_layout/num", res.credited_amount);
this.rw.active = true;
let rain = Tools.AddChild(this.rw, this.gold_rain, "gold_rain");
rain.setPosition(0, 420, 0);
rain.active = true;
this.scheduleOnce(()=>{ rain?.destroy(); }, 5)
app.manager.sound.playEffect({name : "effect/gold_rain"});
})
}
btnCloseRw(){
this.rw.active = false;
}
dropRedPacket(){
let n = this._redMgr.length
this._redMgr[n] = Tools.AddChild(this.red_sky, this.redPacket, "redPacket");
this._redMgr[n].active = true;
this._redMgr[n].setPosition(Math.random() * MOVE_BOUNDARY * 2 - MOVE_BOUNDARY, 0);
const collider = this._redMgr[n].getComponent(BoxCollider2D);
if (collider) {
collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
}
const amounts = (this._maxScore / this._redRemain ).toFixed(1);
this._maxScore -= parseFloat(amounts);
this._redRemain--
//@ts-ignore
this._redMgr[n].amount = amounts; // 存储金额
}
/**
* 碰撞开始时的回调
* @param contact 碰撞信息
* @param selfCollider 自身碰撞器
* @param otherCollider 另一个碰撞器
*/
onBeginContact(selfCollider: any, otherCollider: any) {
if (otherCollider.node.name === 'red_floor') {
this.removeRedPacket(selfCollider.node);
} else if (otherCollider.node.name === 'CaiShen') {
app.manager.sound.playEffect({name : "effect/catch"});
const redPacketNode = selfCollider.node;
const amount = redPacketNode.amount || 0; // 默认为0
this.removeRedPacket(selfCollider.node);
this._score = this._score + parseFloat(amount)
let lab = Tools.AddChild(this.caiShen_up, this.lab_add)
Tools.SetText(lab, "+" + amount)
this.aniScoreUp(lab)
this.updateScore();
if (navigator.vibrate) {
navigator.vibrate(200);
}
}
}
aniScoreUp(node: Node){
node.active = true
node.setPosition(0, 400, 0)
let opacity = node.getComponent(UIOpacity)
tween(opacity)
.to(0.5, {opacity: 0})
.call(() => {
node.destroy()
})
.start();
tween(node)
.by(0.5, {position: new Vec3(0, 50, 0)})
.start();
}
/**
* 更新分数
*/
updateScore() {
let score = this._score == 0 ? "0" : this._score.toFixed(1);
Tools.SetText(this.lab_score, score);
}
/**
* 移除红包
*/
removeRedPacket(redPacketNode: Node) {
// 检查节点是否有效
if (!redPacketNode || redPacketNode.isValid === false) {
return;
}
// 获取碰撞体组件并移除监听器
const collider = redPacketNode.getComponent(BoxCollider2D);
if (collider) {
try {
collider.off(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
} catch (error) {
console.warn('移除碰撞监听器时出错:', error);
}
}
//从管理器中移除
const index = this._redMgr.findIndex(item => item === redPacketNode);
if (index > -1) {
this._redMgr.splice(index, 1);
}
this.scheduleOnce(()=>{
tween(redPacketNode.getComponent(UIOpacity))
.to(0.1, { opacity: 0 })
.call(() => {
try {
redPacketNode.destroy();
} catch (error) {
console.warn('销毁节点时出错:', error);
}
})
.start();
}, 0)
}
/**
* 键盘按下处理
*/
private onKeyDown(event: any) {
if (!this._gaming) return
this.caiShen.getComponent(sp.Skeleton).paused = false
switch (event.keyCode) {
case KeyCode.ARROW_LEFT:
case KeyCode.KEY_A:
this._currentDirection = -1;
this.caiShen.setScale(new Vec3(-1, 1, 1))
break;
case KeyCode.ARROW_RIGHT:
case KeyCode.KEY_D:
this._currentDirection = 1;
this.caiShen.setScale(new Vec3(1, 1, 1))
break;
}
}
/**
* 更新财神移动
*/
private updateMovement(dt: number) {
if (this._currentDirection === 0 || !this._gaming) {
return;
}
const currentPosition = this.caiShen_up.position;
let newX = currentPosition.x + this._currentDirection * this.caiShenMoveSpeed * dt;
// 边界限制
newX = Math.max(this.leftBoundary, Math.min(this.rightBoundary, newX));
this.caiShen_up.setPosition(newX, currentPosition.y, currentPosition.z);
}
/**
* 键盘释放处理
*/
private onKeyUp(event: any) {
switch (event.keyCode) {
case KeyCode.ARROW_LEFT:
case KeyCode.KEY_A:
if (this._currentDirection === -1) {
this._currentDirection = 0;
this.caiShen.getComponent(sp.Skeleton).paused = true
}
break;
case KeyCode.ARROW_RIGHT:
case KeyCode.KEY_D:
if (this._currentDirection === 1) {
this._currentDirection = 0;
this.caiShen.getComponent(sp.Skeleton).paused = true
}
break;
}
}
/**
* 触摸移动处理
*/
private onTouchMove(touch: EventTouch) {
if (!this._gaming) return
const delta = touch.getDelta();
const currentPosition = this.caiShen_up.position;
let newX = currentPosition.x + delta.x;
this.caiShen.setScale(new Vec3(delta.x > 0 ? 1 : -1, 1, 1))
// 边界限制
newX = Math.max(this.leftBoundary, Math.min(this.rightBoundary, newX));
this.caiShen_up.setPosition(newX, currentPosition.y, currentPosition.z);
}
private onTouchStart(touch: EventTouch) {
if (!this._gaming) return
this.caiShen.getComponent(sp.Skeleton).paused = false;
}
private onTouchEnd(touch: EventTouch) {
if (!this._gaming) return
this.caiShen.getComponent(sp.Skeleton).paused = true;
}
loadSprite(pic: string, node: Node){
this.loadRes(pic, Asset, (res: ImageAsset)=>{
let sp = new SpriteFrame()
let tex = new Texture2D();
tex.image = res;
sp.texture = tex
node.getComponent(Sprite).spriteFrame = sp
});
}
// 应用隐藏时的处理(切换到其他应用)
private onAppHide() {
// 暂停游戏逻辑
this._hideTime = Date.now();
}
// 应用显示时的处理(返回应用)
private onAppShow() {
// 计算在后台停留的时间(单位:毫秒)
const currentTime = Date.now();
const timeInBackground = currentTime - this._hideTime;
const timeInBackgroundSeconds = timeInBackground / 1000; // 转换为秒
// 如果在后台停留时间超过10秒结束游戏
if (this._gaming && timeInBackgroundSeconds > 10) {
app.manager.ui.showToast("离开时间过长,游戏已结束");
this.gameOver();
}
}
closeMusic(){
this.btn_music.active = false
this.btn_no_music.active = true
app.manager.sound.stopMusic()
}
openMusic(){
this.btn_music.active = true
this.btn_no_music.active = false
app.manager.sound.playDefaultMusic()
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "5c1d61a6-ff81-481b-9217-430a2187ff50",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "bdb63f02-2584-4780-ab06-23ee67be4568",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,2 @@
1、只能存放脚本⚠
2、如不再需要可以直接删除此文件夹