first commit

This commit is contained in:
2026-03-30 09:39:59 +08:00
parent 6c52425fca
commit 5ac73d3c6d
4484 changed files with 1144395 additions and 0 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,595 @@
import { _decorator, Node, tween, Vec3, Sprite, Asset, ImageAsset, SpriteFrame, Texture2D, Label, UIOpacity, Animation, math, VideoPlayer, UITransform, VideoClip } from 'cc';
import BaseView from '../../../../../../extensions/app/assets/base/BaseView';
import { PageTips } from '../../tips/native/PageTips';
import { app } from 'db://assets/app/app';
import { Tools } from 'db://assets/res-native/tools/Tools';
import { PageRewardhistory } from '../../rewardhistory/native/PageRewardhistory';
import { USERDATA } from 'db://assets/res-native/data/UserData';
import { LANG_ENUM, LANG_SET, LangType } from 'db://assets/res-native/setting/LangSet';
const { ccclass, property } = _decorator;
/** 移动方向 */
const enum M_DIR {
CLOCKWISE = 0, /** 顺时针 */
COUNTER_CLOCKWISE = 1, /** 逆时针 */
}
@ccclass('PageMain')
export class PageMain extends BaseView {
/** 声音按钮 */
@property(Node) btn_music: Node = null!;
/** 当前余额 */
@property(Label) lab_gold: Label = null!;
/** 姓名 */
@property(Label) lab_name: Label = null!;
/** 当前剩余抽奖次数 */
@property(Label) remain: Label = null!;
/** 方向选择 */
@property(Node) n_dir: Node[] = [];
/** 标签 */
@property(Node) sign: Node = null!;
/** 方块 */
@property(Node) blocks: Node = null!;
/** 骰子 */
@property(Node) dices: Node[] = [];
/** 中奖 */
@property(Node) rw: Node = null!;
/** 未中奖 */
@property(Node) norw: Node = null!;
/** 购买次数按钮 */
@property(Node) btns_buy: Node = null!;
/** 开始游戏按钮 */
@property(Node) btn_play: Node = null!;
/** 开始游戏按钮 */
@property(Node) btn_auto: Node = null!;
/** 胜利数字 */
@property(Node) lab_add: Node = null!;
/** 失败数字 */
@property(Node) lab_sub: Node = null!;
/** 分数标签 */
@property(Node) lab_point: Node = null!;
/** 金币雨 */
@property(Node) gold_rain: Node = null!;
/** 背景视频 */
@property(VideoPlayer) video_bg: VideoPlayer = null!;
/** 视频背景图片 */
@property(Sprite) video_sprite: Sprite = null!;
/** 骰子动画 */
@property(Node) ani_dice: Node = null!;
/** 骰子总点数 */
@property(Node) dice_all: Node = null!;
/** 失败视频资源 */
@property(VideoClip) video_win: VideoClip = null!;
@property(VideoClip) video_lose: VideoClip = null!;
@property(VideoClip) video_normal: VideoClip = null!;
/** 方块移动方向 */
private _move_dir: M_DIR = M_DIR.CLOCKWISE;
/** 是否正在游戏 */
private _is_playing = false;
/** 骰子数据 */
private _game_data: any = null;
/** 是否正在连续 */
private _is_continuous : boolean = true
/** 方块顺时针顺序,从顶端开始 */
private _b_sequence : string[] = [
"20","27","24","10","5","15","8","22","30","23","16","12","13","7","17","9","21","26","6","29","19","11","25","14","28","18"
];
/** 标签位置 */
private _sign_position: Vec3[] =[
new Vec3(11, 491.7, 0),
new Vec3(178.2, 407, 0),
new Vec3(323.4, 310.2, 0),
new Vec3(456.5, 227.7, 0),
new Vec3(341, 143, 0),
new Vec3(233.2, 63.8, 0),
new Vec3(121, 0, 0),
new Vec3(231, -77, 0),
new Vec3(341, -143, 0),
new Vec3(467.5, -214.5, 0),
new Vec3(341, -321.2, 0),
new Vec3(231, -401.5, 0),
new Vec3(116.6, -473, 0),
new Vec3(0, -550, 0),
new Vec3(-117.7, -484, 0),
new Vec3(-234.3, -407, 0),
new Vec3(-344.3, -344.3, 0),
new Vec3(-465.3, -242, 0),
new Vec3(-336.6, -159.5, 0),
new Vec3(-226.6, -92.4, 0),
new Vec3(-115.5, -18.7, 0),
new Vec3(-227.7, 48.4, 0),
new Vec3(-341, 121, 0),
new Vec3(-451, 201.3, 0),
new Vec3(-301.4, 298.1, 0),
new Vec3(-159.5, 402.6, 0),
]
private _video:HTMLVideoElement = null
private _canvas:HTMLCanvasElement = null
private _ctx:CanvasRenderingContext2D = null
// 在类中新增变量用于缓存旧资源
private _currentSpriteFrame: SpriteFrame | null = null;
private _isUpdating = false;
// 初始化的相关逻辑写在这
onLoad() {}
// 界面打开时的相关逻辑写在这(onShow可被多次调用-它与onHide不成对)
onShow(params: any) {
this.initUserData()
this.swichBuyAndPlay()
this.initDir()
this.getRwData()
this.onClickTips()
this.bindVideoEvents()
this._canvas = document.createElement('canvas');
this._canvas.width = this.video_sprite.getComponent(UITransform).width;
this._canvas.height = this.video_sprite.getComponent(UITransform).height;
this._canvas.style.display = 'none';
this._ctx = this._canvas.getContext('2d');
tween(this.ani_dice)
.repeatForever(
tween()
// 0.8秒内放大到1.2倍 + 顺时针旋转180度
.to(0.8, {
scale: new Vec3(1.2, 1.2, 1.2),
angle: 180 // 如果是2D节点用angle3D节点建议用 eulerAngles
}, { easing: 'sineOut' })
// 0.8秒内缩小回1倍 + 再旋转180度总共360度
.to(0.8, {
scale: new Vec3(1, 1, 1),
angle: 360
}, { easing: 'sineIn' })
// 完成一圈后,手动重置 angle 为 0防止数值无限叠加导致精度问题
.call(() => { this.ani_dice.angle = 0; })
)
.start()
}
// 界面关闭时的相关逻辑写在这(已经关闭的界面不会触发onHide)
onHide(result: undefined) {
// app.manager.ui.show<PageMain>({name: 'PageMain', onHide:(result) => { 接收到return的数据并且有类型提示 }})
return result;
}
initUserData(){
this.lab_gold.string = USERDATA.coin.toString()
this.lab_name.string = USERDATA.name
this.remain.string = USERDATA.total_ticket_count.toString()
//this.remain.node.active = USERDATA.total_ticket_count > 0
Tools.ActChild(this.btn_auto, "auto", this._is_continuous)
Tools.ActChild(this.btn_auto, "no_auto", !this._is_continuous)
}
swichBuyAndPlay(){
this.btns_buy.active = USERDATA.total_ticket_count <= 0
this.btn_play.active = USERDATA.total_ticket_count > 0
}
bindVideoEvents() {
if (this.video_bg) {
this.video_bg.node.on('ready-to-play', () => {
this._video = this.video_bg.nativeVideo
}, this);
}
}
/** 初始化方向选择 */
initDir(){
for (let i = 0; i < 2; i++) {
const element = this.n_dir[i];
Tools.ActChild(element, "light", i == this._move_dir)
Tools.ActChild(element, "dark", i != this._move_dir)
}
}
getRwData(){
Tools.httpReq("game/lotteryPool", {}, (res:any) => {
for (let index = 0; index < res.length; index++) {
const d = res[index];
Tools.SetChildText(this.blocks, String(d.grid_number) + "/num", d.ui_text)
}
})
}
/** 购买游戏次数 */
buyTimes(a : any, d : any){
Tools.httpReq("game/buyLotteryTickets", { "count" : d }, (res:any) => {
USERDATA.coin = res.coin
USERDATA.total_ticket_count = res.total_ticket_count
this.swichBuyAndPlay()
this.initUserData()
})
}
chooseDir(d:any, dir: number){
this._move_dir = dir
this.initDir()
}
/** 点击提示 */
onClickTips(){
app.manager.ui.show<PageTips>({name: 'PageTips'})
}
/** 点击音乐 */
oncClickMusic(){
let music = app.manager.sound.isMusicPlaying
music ? app.manager.sound.stopMusic() : app.manager.sound.playDefaultMusic()
this.loadRes(music ? "main_btn_sounds_off" : "main_btn_sounds_on", Asset, (res: ImageAsset)=>{
let sp = new SpriteFrame()
let tex = new Texture2D();
tex.image = res;
sp.texture = tex
this.btn_music.getComponent(Sprite).spriteFrame = sp
});
}
/** 点击历史 */
onClickRwHis(){
app.manager.ui.show<PageRewardhistory>({name: 'PageRewardhistory'})
}
btnGameAuto(){
this._is_continuous = !this._is_continuous
this.initUserData()
}
btnPlayGary(){
this.btn_play.getComponent(Sprite).grayscale = true
Tools.GetChildComp(this.btn_play, "lab", Sprite).grayscale = true
}
btnPlayWhite(){
this.btn_play.getComponent(Sprite).grayscale = false
Tools.GetChildComp(this.btn_play, "lab", Sprite).grayscale = false
}
/** 开始游戏 */
btnGameStart(){
if (this._b_sequence.length != this._sign_position.length) {
return app.manager.ui.showToast(Tools.GetLocalized("数据错误"))
}
if (this._is_playing) return
this._is_playing = true
this.btnPlayGary()
Tools.httpReq("game/playStart", {
"direction" : this._move_dir
}, (res:any) => {
this._game_data = res
this._move_dir = res.direction
USERDATA.total_ticket_count--
this.initUserData()
let steps = 0
for (let i = 0; i < res.roll_array.length; i++) {
const element = res.roll_array[i];
steps += element
}
let index:any = this._b_sequence.findIndex(v => v == steps.toString())
let b = this.blocks.getChildByName(steps.toString())
// 计算移动路径
let path = this.calculatePath(index, steps);
// 播放骰子动画
this.playDiceAni(res.roll_array)
// 判断是否是豹子
let baozi = this._game_data.is_win == 1
Tools.ActChild(this.rw, "bg/bg_title_super", baozi)
Tools.ActChild(this.rw, "bg/bg_title", !baozi)
this.gold_rain.active = baozi
// 如果是豹子,展示豹子特效后停止继续
if (baozi){
this.scheduleOnce(() => {
app.manager.sound.playEffect({name : "effect/eff_unsheathe"})
for (let i = 0; i < this.dices.length; i++) {
let eff = this.dices[i].getChildByPath("dice/eff")
eff.active = true
eff.setPosition(new Vec3(-25, -40, 0))
tween(eff)
.to(0.5, { position: new Vec3(25, 45, 0) })
.call(() => {
this.scheduleOnce(() => {
eff.active = false
}, 0.2)
})
.start()
}
this.scheduleOnce(() => {
Tools.ActChild(this.rw, "bg/win_lab/en", LANG_SET.langIndex == LangType.EN)
Tools.ActChild(this.rw, "bg/win_lab/zh", LANG_SET.langIndex == LangType.ZH)
Tools.SetChildText(this.rw, "bg/win_lab/" + LANG_ENUM[LANG_SET.langIndex] + "/num", this._game_data.win_coin)
this.rw.active = true
app.manager.sound.playEffect({name : "effect/eff_gold_rain"})
app.manager.sound.playEffect({name : "effect/eff_bigwin"})
USERDATA.coin = this._game_data.coin
USERDATA.total_ticket_count = this._game_data.total_ticket_count
this._is_playing = false
this.initUserData()
this.swichBuyAndPlay()
this.btnPlayWhite()
}, 1)
}, 1.2)
}else {
// 骰子总数展示
this.scheduleOnce(() => {
this.dice_all.active = true
Tools.SetChildText(this.dice_all, "dice/lab", steps.toString())
}, 1.2)
this.scheduleOnce(() => {
this.dice_all.active = false
}, 2.4)
//亮灯
this.scheduleOnce(() => {
Tools.ActChild(b, "light", true)
// 设置初始位置
this.sign.setPosition(this._sign_position[index]);
this.sign.active = true;
}, 2.4);
let lastIndex = index
if (this._move_dir == M_DIR.CLOCKWISE) {
lastIndex = (lastIndex + steps) % this._sign_position.length;
} else {
lastIndex = (lastIndex - steps + this._sign_position.length) % this._sign_position.length;
}
// 移动标签
this.scheduleOnce(() => {
// 执行动画
this.animateSign(path, steps * 0.12, lastIndex);
Tools.ActChild(b, "light", false)
}, 3);
}
},()=>{
this._is_playing = false
})
}
/**
* 计算移动路径
* @param index 当前位置索引
* @param steps 移动步数
*/
private calculatePath(index:number, steps: number): Vec3[] {
let path: Vec3[] = [];
let currentIndex = index;
for (let i = 0; i < steps; i++) {
if (this._move_dir == M_DIR.CLOCKWISE) {
currentIndex = (currentIndex + 1) % this._sign_position.length;
} else {
currentIndex = (currentIndex - 1 + this._sign_position.length) % this._sign_position.length;
}
path.push(this._sign_position[currentIndex]);
}
return path;
}
/**
* 执行动画
* @param path 移动路径
* @param duration 总时间(秒)
* @param lastIndex 最后一个位置索引
*/
private animateSign(path: Vec3[], duration: number, lastIndex: number = 0) {
let totalTime = duration;
let segmentTime = totalTime / path.length;
let moveNext = (index: number) => {
let targetPos = path[index];
app.manager.sound.playEffect({name : "effect/eff_jump", volume: 0.5})
/** 跟随闪烁 */
this.scheduleOnce(() => {
let n = this._sign_position.findIndex(v => v == targetPos)
let nowPoint = this._b_sequence[n]
let light = this.blocks.getChildByName(nowPoint).getChildByName("light")
light.active = true
let opc = light.getComponent(UIOpacity)
opc.opacity = 0
tween(opc)
.to(0.12, { opacity: 255 }) // 渐隐
.to(0.12 / 2, { opacity: 0 }) // 渐显 tween(opc)
.call(() => {
light.active = false
opc.opacity = 255
})
.start();
}, 0.06 / 2);
tween(this.sign)
.to(segmentTime, { position: targetPos }, { easing: "linear" })
.call(() => {
if (index + 1 >= path.length) {
this.scheduleOnce(() => {
this.sign.active = false;
let b = this._b_sequence[lastIndex]
if (this._game_data.win_coin >= 0){
app.manager.sound.playEffect({name : "effect/eff_start"})
}else{
app.manager.sound.playEffect({name : "effect/eff_finish", volume: 0.5})
}
this.blinkLightWithTween(this.blocks.getChildByName(b).getChildByName("light"), 1, 2)
}, 0.5);
return;
}
this.scheduleOnce(() => {
moveNext(index + 1);
}, 0.06);
})
.start();
};
moveNext(0);
}
/** 闪烁动画
* @param node 节点
* @param duration 持续时间(秒)
* @param times 闪烁次数
*/
private blinkLightWithTween(node: Node, duration: number, times: number) {
let opc = node.getComponent(UIOpacity);
if (!opc) return;
node.active = true
/** 胜利失败动画 */
this.video_bg.clip = this._game_data.win_coin >= 0 ? this.video_win : this.video_lose
app.manager.sound.playEffect({name : this._game_data.win_coin >= 0 ? "effect/eff_happy" : "effect/eff_thunder", volume: 0.5})
this.scheduleOnce(() => {
this.video_bg.clip = this.video_normal
}, 3.2);
let blinkCount = 0;
const blink = () => {
tween(opc)
.to(duration / 2, { opacity: 0 }) // 渐隐
.to(duration / 2, { opacity: 255 }) // 渐显
.call(() => {
blinkCount++;
if (blinkCount < times) {
blink(); // 重复执行
// 游戏结束
}else{
opc.opacity = 255
node.active = false
this._is_playing = false
if (this._is_continuous){
let lab = Tools.AddChild(this.lab_point, this._game_data.win_coin > 0 ? this.lab_add : this.lab_sub)
let cb = () => {
lab.destroy()
USERDATA.coin = this._game_data.coin
USERDATA.total_ticket_count = this._game_data.total_ticket_count
this.initUserData()
this.swichBuyAndPlay()
if (USERDATA.total_ticket_count > 0){
this.btnGameStart()
}else{
this.btnPlayWhite()
}
}
// T5是再来一次不需要飘字
if (this._game_data.tier != "T5"){
let pos = new Vec3(node.parent.position.x, node.parent.position.y + 80, 0 )
lab.setPosition(pos)
lab.active = true
Tools.SetText(lab, this._game_data.win_coin > 0 ? "+" + this._game_data.win_coin : this._game_data.win_coin)
app.manager.sound.playEffect({name : this._game_data.win_coin > 0 ? "effect/eff_win" : "effect/eff_lose"})
tween(lab)
.by(1, { position: new Vec3(0, 200, 0) })
.call(()=>{
cb()
})
.start()
}else {
cb()
}
}else {
if (this._game_data.tier != "T5"){
if (this._game_data.win_coin > 0){
Tools.ActChild(this.rw, "bg/win_lab/en", LANG_SET.langIndex == LangType.EN)
Tools.ActChild(this.rw, "bg/win_lab/zh", LANG_SET.langIndex == LangType.ZH)
Tools.SetChildText(this.rw, "bg/win_lab/" + LANG_ENUM[LANG_SET.langIndex] + "/num", this._game_data.win_coin)
app.manager.sound.playEffect({name : this._game_data.win_coin > 0 ? "effect/eff_win" : "effect/eff_lose"})
this.rw.active = true
}else{
this.norw.active = true
}
}
USERDATA.coin = this._game_data.coin
USERDATA.total_ticket_count = this._game_data.total_ticket_count
this.swichBuyAndPlay()
this.initUserData()
this.btnPlayWhite()
}
}
})
.start();
};
blink();
}
/** 播放骰子动画 */
playDiceAni(array:any[]){
app.manager.sound.playEffect({name : "effect/shaizi"})
for (let i = 0; i < this.dices.length; i++) {
let dice = this.dices[i]
let animation = dice.getComponent(Animation);
if (animation) {
this.scheduleOnce(() => {
animation.play();
}, math.random() * 0.1);
animation.once(Animation.EventType.FINISHED, () => {
this.loadSprite("dice_" + array[i], dice.getChildByName("dice"))
});
}
}
}
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
});
}
closeRw(){
this.rw.active = false
this.norw.active = false
}
update(){
if (this._video) {
this.updateTexture();
}
}
private async updateTexture() {
if (this._isUpdating) return;
this._isUpdating = true;
try {
this._ctx.save(); // 保存当前状态
this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);
// 绘制视频帧
this._ctx.drawImage(this._video, 0, 0, this._canvas.width, this._canvas.height);
this._ctx.restore(); // 恢复原始状态
const canvasData = this._canvas;
// 销毁旧纹理
if (this._currentSpriteFrame) {
const oldTexture = this._currentSpriteFrame.texture;
oldTexture?.destroy();
this._currentSpriteFrame.destroy();
}
const texture = new Texture2D();
texture.image = new ImageAsset(canvasData);
const spriteFrame = new SpriteFrame();
spriteFrame.texture = texture;
this.video_sprite.spriteFrame = spriteFrame;
this._currentSpriteFrame = spriteFrame;
} finally {
this._isUpdating = false;
}
}
}

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、如不再需要可以直接删除此文件夹