特定关卡加首次过关率弹窗

冰冻按钮加未操作5秒 提示
This commit is contained in:
huanghaipeng 2025-11-24 12:00:45 +08:00
parent 162a91377a
commit ed2bfe78c8
16 changed files with 5769 additions and 3368 deletions

File diff suppressed because it is too large Load Diff

View File

@ -100,6 +100,7 @@ export default class MapConroler extends cc.Component {
//复活
@property(cc.Node)
revive: cc.Node = null;
timeLabel: cc.Node = null;
levelLabel: cc.Node = null;
coin: cc.Node = null;
@ -129,6 +130,8 @@ export default class MapConroler extends cc.Component {
timeNumber: number = 0; //游戏时间 用于倒计时
count_Time: number = 0; //用于统计总游戏时长
add_Time: number = 0; //复活时间
lastBlockClickTime: number = 0; // 上次点击方块的时间
noBlockClickDuration: number = 0; // 未点击方块的持续时间
mapBlockArray: any; //地图的所有格子状态存储
pause: boolean = false;//暂停状态
hammer: boolean = false;//锤子状态
@ -165,6 +168,7 @@ export default class MapConroler extends cc.Component {
// mapInfo: number[][] = [];
getProgressLevel: number = 0;
getProgress: number = 0;
isRippleShrink: boolean = false;
private magicEffectIndex: number = 0;
private magicEffect1: cc.Node = null; // 第一套特效节点
@ -370,6 +374,8 @@ export default class MapConroler extends cc.Component {
}
startUpdate() {
// 停止冰冻外圈特效
this.onBlockClick();
if (this.iceTrue() == true) {
return;
}
@ -477,6 +483,7 @@ export default class MapConroler extends cc.Component {
this.lockArray2 = [];
this.count_Time = 0;
this.add_Time = 0;
this.isRippleShrink = true;
let startX = this.mapWidth % 2 == 0 ? -(this.mapWidth - 1) * 60 : -(this.mapWidth - 1) * 60;
@ -555,6 +562,39 @@ export default class MapConroler extends cc.Component {
this.guideItem.active = true;
}
const currentLevel = cc.fx.GameConfig.GM_INFO.level + 1;
const lastVisitedLevel = cc.fx.StorageMessage.getStorage("visitedLevels");
const isFirstTime = (lastVisitedLevel !== currentLevel);
if (isFirstTime) {
cc.fx.StorageMessage.setStorage("visitedLevels", currentLevel);
const passCheckJson = cc.fx.GameConfig.PASS_RATE;
// 直接查找匹配的记录
const levelData = passCheckJson.find(item => item.level === currentLevel);
if (levelData) {
// 找到了对应的记录
let passRateNode = this.node.parent.parent.getChildByName("popUpPassRate")
passRateNode.active = true;
let passRate = passRateNode.getChildByName("pass_rate_bg").getChildByName("passRate");
// NumberToImage.numberToImageNodes4(levelData.pass_rate, 50, 0, "Black", passRate, true)
passRate.getComponent(cc.Label).string = levelData.pass_rate.toString();
if (passRateNode) {
let targetY = cc.winSize.height / 2 - 500;
cc.tween(passRateNode)
.to(1.5, { y: targetY }, { easing: 'sineOut' })
.delay(2) // 停留2秒
.to(1, { opacity: 0 })
.start();
passRateNode.y = 0;
}
} else {
console.log("未找到关卡数据");
}
} else {
}
}
@ -2735,8 +2775,27 @@ export default class MapConroler extends cc.Component {
//开始倒计时
startTimeCutDown() {
this.startBoom();
this.lastBlockClickTime = Date.now(); // 初始化上次点击时间
this.noBlockClickDuration = 0; // 重置未点击持续时间
this.scheduleCallback = function () {
if (this.pause || this.gameWin || this.gameOver) return;
// 检查玩家是否长时间未点击方块
const currentTime = Date.now();
this.noBlockClickDuration = (currentTime - this.lastBlockClickTime) / 1000; // 转换为秒
// 如果超过一定时间未点击方块
if (cc.fx.GameConfig.GM_INFO.level + 1 >= 11) {
if (this.noBlockClickDuration >= 5) {
let rippleShrink = this.node.parent.getChildByName("Bottom").getChildByName("rippleShrink").getComponent('RippleShrink');
if (this.isRippleShrink && rippleShrink && rippleShrink.startRipple) {
rippleShrink.startRipple();
this.isRippleShrink = false;
}
}
}
if (this.timeNumber <= 0) {
this.stopTimeCutDown();
var timeTemp = cc.fx.GameTool.getTimeMargin(this.timeNumber);
@ -2763,8 +2822,18 @@ export default class MapConroler extends cc.Component {
this.unschedule(this.scheduleCallback);
this.scheduleCallback = null;
}
this.onBlockClick();
}
onBlockClick() {
this.lastBlockClickTime = Date.now();
this.noBlockClickDuration = 0;
let rippleShrink = this.node.parent.getChildByName("Bottom").getChildByName("rippleShrink").getComponent('RippleShrink');
if (rippleShrink && rippleShrink.stopRipple) {
rippleShrink.stopRipple();
}
}
//使用时间道具
useTimeProp() {
if (this.gameOver == true || this.gameWin == true) {
@ -3853,6 +3922,8 @@ export default class MapConroler extends cc.Component {
this.blocks[i].getChildByName("boom").getComponent("Boom").stopBoom();
}
}
// 停止特效
this.onBlockClick();
}
getSmoothPath(pts: cc.Vec3[], radius = 10): cc.Vec3[] {

View File

@ -0,0 +1,82 @@
const { ccclass, property } = cc._decorator;
@ccclass
export default class RippleShrink extends cc.Component {
@property(cc.Sprite)
targetSprite: cc.Sprite = null!; // 拖自己的 Sprite
private mat: cc.Material = null!;
private running = false;
private totalTime = 0;
private timer = 0;
private interval = 0.2; // 间隔时间0.2秒
private shouldShow = false; // 标记是否应该显示和运行动画
onLoad() {
const shared = this.targetSprite.getMaterial(0);
this.mat = shared;
this.mat.setProperty('time', 0);
// 设置中心点为纹理中心
this.mat.setProperty('center', [0.5, 0.5]);
// 初始化时隐藏节点
this.node.active = false;
}
// 开始涟漪效果
startRipple() {
this.shouldShow = true;
this.node.active = true;
}
// 停止涟漪效果
stopRipple() {
this.shouldShow = false;
}
// 触发波纹效果的方法
triggerRipple() {
// 使用纹理中心作为波纹起始点
this.mat.setProperty('center', [0.5, 0.5]);
this.totalTime = 0;
this.running = true;
}
update(dt: number) {
if (!this.shouldShow && !this.running) {
// 如果不需要显示且当前没有运行中的动画,则隐藏节点
if (this.node.active) {
this.node.active = false;
}
return;
}
if (!this.running) {
// 不在运行状态下,计算间隔时间
this.timer += dt;
if (this.timer >= this.interval) {
if (this.shouldShow) {
this.triggerRipple();
}
this.timer = 0; // 重置计时器
}
return;
}
this.totalTime += dt;
this.mat.setProperty('time', this.totalTime);
// 当波纹效果完成时
if (this.totalTime > 2.0) {
this.running = false;
// 重置计时器,准备下次执行
this.timer = 0;
// 如果已经要求停止,则隐藏节点
if (!this.shouldShow) {
this.node.active = false;
}
}
}
}

View File

@ -0,0 +1,10 @@
{
"ver": "1.1.0",
"uuid": "31fe626d-0b74-45b7-b5c6-c4a1444ea8ec",
"importer": "typescript",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -57,6 +57,7 @@ export class GameConfig {
static NEW_LEVEL: any;
static NEW_GUIDE: any;
static PASS_CHECK: any;
static PASS_RATE: any;
static TA: any;
static GE: any;
@ -347,6 +348,14 @@ export class GameConfig {
// 可以根据需求对 newLevelData 进行处理
// //console.log("PASS_CHECK.JSON 加载成功:", newLevelData);
})
cc.resources.load("Json/PASS_RATE", (err: any, res: cc.JsonAsset) => {
if (err) {
console.error("加载 PASS_RATE.JSON 失败:", err);
return;
}
const newLevelData = res.json;
this.PASS_RATE = newLevelData;
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,38 @@
{
"ver": "2.3.7",
"uuid": "5ae64d0c-d19d-4727-9de9-5301e4e5e955",
"importer": "texture",
"type": "sprite",
"wrapMode": "clamp",
"filterMode": "bilinear",
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"width": 1080,
"height": 358,
"platformSettings": {},
"subMetas": {
"pass_rate_bg": {
"ver": "1.0.6",
"uuid": "457c9278-3c51-4b04-8e4c-a07302912a0a",
"importer": "sprite-frame",
"rawTextureUuid": "5ae64d0c-d19d-4727-9de9-5301e4e5e955",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 1,
"width": 1080,
"height": 356,
"rawWidth": 1080,
"rawHeight": 358,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"subMetas": {}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -0,0 +1,38 @@
{
"ver": "2.3.7",
"uuid": "c65cd0d9-f3f6-413c-993a-45149f6a9714",
"importer": "texture",
"type": "sprite",
"wrapMode": "clamp",
"filterMode": "bilinear",
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"width": 668,
"height": 160,
"platformSettings": {},
"subMetas": {
"pass_rate_label": {
"ver": "1.0.6",
"uuid": "c3199bb6-6ad7-470b-8bc4-fb9f251b22a2",
"importer": "sprite-frame",
"rawTextureUuid": "c65cd0d9-f3f6-413c-993a-45149f6a9714",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 0,
"width": 403,
"height": 94,
"rawWidth": 403,
"rawHeight": 94,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"subMetas": {}
}
}
}

View File

@ -0,0 +1,13 @@
{
"ver": "1.1.3",
"uuid": "634c714d-7bef-42c0-a151-4559cd02a0fa",
"importer": "folder",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -0,0 +1,111 @@
CCEffect %{
techniques:
- name: normal
passes:
- vert: vs
frag: fs
blendState:
targets:
- blend: true
rasterizerState:
cullMode: back
properties:
texture: { value: white }
center: { value: [0.5, 0.5] }
time: { value: 0.0 }
ringCount: { value: 5.0 }
ringWidth: { value: 0.04 }
waveSpeed: { value: 0.3 } // 扩散速度
shrink: { value: 2.0 } // 内缩强度
fadePow: { value= 2.0 } // 淡出速度
color: { value: [0.95, 0.95, 0.95, 0.45] } // 淡白
}%
CCProgram vs %{
precision highp float;
#include <cc-global>
#include <cc-local>
in vec3 a_position;
in vec2 a_uv0;
out vec2 v_uv0;
void main () {
vec4 pos = vec4(a_position, 1);
#if CC_USE_MODEL
pos = cc_matViewProj * cc_matWorld * pos;
#else
pos = cc_matViewProj * pos;
#endif
gl_Position = pos;
v_uv0 = a_uv0;
}
}%
CCProgram fs %{
precision highp float;
#include <cc-global>
#include <alpha-test>
in vec2 v_uv0;
uniform sampler2D texture;
uniform fs_uniforms {
vec4 color;
vec2 center;
float time;
float ringCount;
float ringWidth;
float waveSpeed;
float shrink;
float fadePow;
};
void main () {
vec4 tex = texture2D(texture, v_uv0);
float dist = distance(v_uv0, center);
float alpha = 0.0;
// 计算从中心到边界的最大距离
vec2 lowerDist = center;
vec2 upperDist = vec2(1.0 - center.x, 1.0 - center.y);
float maxDist = max(max(lowerDist.x, lowerDist.y), max(upperDist.x, upperDist.y));
// 设置渐隐开始和结束位置
float fadeStartDist = maxDist * 0.25; // 从中心向外1/4位置开始渐隐
float fadeEndDist = maxDist * 0.95; // 外圈往里一些位置完全隐藏
// 生成5个独立的波纹环每个间隔一定时间出现
for (int i = 0; i < 3; ++i) {
// 每个波纹环间隔0.3秒出现
float ringStartTime = float(i) * 0.3;
if (time < ringStartTime) continue;
// 当前波纹环的时间
float ringTime = time - ringStartTime;
// 波纹半径随时间增长
float radius = ringTime * waveSpeed;
// 当波纹超出边界时不再显示
if (radius > maxDist) continue;
if (radius > 1.5) continue;
float inner = radius - ringWidth;
float a = smoothstep(inner, radius, dist)
* (1.0 - smoothstep(radius, radius + 0.01, dist));
// 涟漪效果
a *= sin(dist * shrink - ringTime * 6.0) * 0.5 + 0.5;
a *= pow(1.0 - radius / 1.5, fadePow);
// 添加边界渐隐效果从1/4位置开始渐隐直到边界附近完全隐藏
if (radius > fadeStartDist) {
float boundaryFade = 1.0 - smoothstep(fadeStartDist, fadeEndDist, radius);
a *= boundaryFade;
}
alpha += a;
}
alpha = clamp(alpha, 0.0, 1.0);
gl_FragColor = vec4(color.rgb, alpha * color.a);
ALPHA_TEST(gl_FragColor);
}
}%

View File

@ -0,0 +1,18 @@
{
"ver": "1.0.27",
"uuid": "a8d32911-ed30-4276-b226-042abd867f53",
"importer": "effect",
"compiledShaders": [
{
"glsl1": {
"vert": "\nprecision highp float;\nuniform mat4 cc_matViewProj;\nuniform mat4 cc_matWorld;\nattribute vec3 a_position;\nattribute vec2 a_uv0;\nvarying vec2 v_uv0;\nvoid main () {\n vec4 pos = vec4(a_position, 1);\n #if CC_USE_MODEL\n pos = cc_matViewProj * cc_matWorld * pos;\n #else\n pos = cc_matViewProj * pos;\n #endif\n gl_Position = pos;\n v_uv0 = a_uv0;\n}",
"frag": "\nprecision highp float;\n#if USE_ALPHA_TEST\n uniform float alphaThreshold;\n#endif\nvoid ALPHA_TEST (in vec4 color) {\n #if USE_ALPHA_TEST\n if (color.a < alphaThreshold) discard;\n #endif\n}\nvoid ALPHA_TEST (in float alpha) {\n #if USE_ALPHA_TEST\n if (alpha < alphaThreshold) discard;\n #endif\n}\nvarying vec2 v_uv0;\nuniform sampler2D texture;\nuniform vec4 color;\nuniform vec2 center;\nuniform float time;\nuniform float ringWidth;\nuniform float waveSpeed;\nuniform float shrink;\nuniform float fadePow;\nvoid main () {\n vec4 tex = texture2D(texture, v_uv0);\n float dist = distance(v_uv0, center);\n float alpha = 0.0;\n vec2 lowerDist = center;\n vec2 upperDist = vec2(1.0 - center.x, 1.0 - center.y);\n float maxDist = max(max(lowerDist.x, lowerDist.y), max(upperDist.x, upperDist.y));\n float fadeStartDist = maxDist * 0.25;\n float fadeEndDist = maxDist * 0.95;\n for (int i = 0; i < 3; ++i) {\n float ringStartTime = float(i) * 0.3;\n if (time < ringStartTime) continue;\n float ringTime = time - ringStartTime;\n float radius = ringTime * waveSpeed;\n if (radius > maxDist) continue;\n if (radius > 1.5) continue;\n float inner = radius - ringWidth;\n float a = smoothstep(inner, radius, dist)\n * (1.0 - smoothstep(radius, radius + 0.01, dist));\n a *= sin(dist * shrink - ringTime * 6.0) * 0.5 + 0.5;\n a *= pow(1.0 - radius / 1.5, fadePow);\n if (radius > fadeStartDist) {\n float boundaryFade = 1.0 - smoothstep(fadeStartDist, fadeEndDist, radius);\n a *= boundaryFade;\n }\n alpha += a;\n }\n alpha = clamp(alpha, 0.0, 1.0);\n gl_FragColor = vec4(color.rgb, alpha * color.a);\n ALPHA_TEST(gl_FragColor);\n}"
},
"glsl3": {
"vert": "\nprecision highp float;\nuniform CCGlobal {\n mat4 cc_matView;\n mat4 cc_matViewInv;\n mat4 cc_matProj;\n mat4 cc_matProjInv;\n mat4 cc_matViewProj;\n mat4 cc_matViewProjInv;\n vec4 cc_cameraPos;\n vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n};\nuniform CCLocal {\n mat4 cc_matWorld;\n mat4 cc_matWorldIT;\n};\nin vec3 a_position;\nin vec2 a_uv0;\nout vec2 v_uv0;\nvoid main () {\n vec4 pos = vec4(a_position, 1);\n #if CC_USE_MODEL\n pos = cc_matViewProj * cc_matWorld * pos;\n #else\n pos = cc_matViewProj * pos;\n #endif\n gl_Position = pos;\n v_uv0 = a_uv0;\n}",
"frag": "\nprecision highp float;\nuniform CCGlobal {\n mat4 cc_matView;\n mat4 cc_matViewInv;\n mat4 cc_matProj;\n mat4 cc_matProjInv;\n mat4 cc_matViewProj;\n mat4 cc_matViewProjInv;\n vec4 cc_cameraPos;\n vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n};\n#if USE_ALPHA_TEST\n uniform ALPHA_TEST {\n float alphaThreshold;\n };\n#endif\nvoid ALPHA_TEST (in vec4 color) {\n #if USE_ALPHA_TEST\n if (color.a < alphaThreshold) discard;\n #endif\n}\nvoid ALPHA_TEST (in float alpha) {\n #if USE_ALPHA_TEST\n if (alpha < alphaThreshold) discard;\n #endif\n}\nin vec2 v_uv0;\nuniform sampler2D texture;\nuniform fs_uniforms {\n vec4 color;\n vec2 center;\n float time;\n float ringCount;\n float ringWidth;\n float waveSpeed;\n float shrink;\n float fadePow;\n};\nvoid main () {\n vec4 tex = texture2D(texture, v_uv0);\n float dist = distance(v_uv0, center);\n float alpha = 0.0;\n vec2 lowerDist = center;\n vec2 upperDist = vec2(1.0 - center.x, 1.0 - center.y);\n float maxDist = max(max(lowerDist.x, lowerDist.y), max(upperDist.x, upperDist.y));\n float fadeStartDist = maxDist * 0.25;\n float fadeEndDist = maxDist * 0.95;\n for (int i = 0; i < 3; ++i) {\n float ringStartTime = float(i) * 0.3;\n if (time < ringStartTime) continue;\n float ringTime = time - ringStartTime;\n float radius = ringTime * waveSpeed;\n if (radius > maxDist) continue;\n if (radius > 1.5) continue;\n float inner = radius - ringWidth;\n float a = smoothstep(inner, radius, dist)\n * (1.0 - smoothstep(radius, radius + 0.01, dist));\n a *= sin(dist * shrink - ringTime * 6.0) * 0.5 + 0.5;\n a *= pow(1.0 - radius / 1.5, fadePow);\n if (radius > fadeStartDist) {\n float boundaryFade = 1.0 - smoothstep(fadeStartDist, fadeEndDist, radius);\n a *= boundaryFade;\n }\n alpha += a;\n }\n alpha = clamp(alpha, 0.0, 1.0);\n gl_FragColor = vec4(color.rgb, alpha * color.a);\n ALPHA_TEST(gl_FragColor);\n}"
}
}
],
"subMetas": {}
}

View File

@ -0,0 +1,24 @@
{
"__type__": "cc.Material",
"_name": "ripple_shrink",
"_objFlags": 0,
"_native": "",
"_effectAsset": {
"__uuid__": "a8d32911-ed30-4276-b226-042abd867f53"
},
"_techniqueIndex": 0,
"_techniqueData": {
"0": {
"defines": {},
"props": {
"color": {
"__type__": "cc.Vec4",
"x": 0.95,
"y": 0.95,
"z": 0.95,
"w": 0.8
}
}
}
}
}

View File

@ -0,0 +1,7 @@
{
"ver": "1.0.5",
"uuid": "c0ebe7f6-1b12-4cac-ba19-12a57ddaae8b",
"importer": "material",
"dataAsSubAsset": null,
"subMetas": {}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
{
"ver": "1.0.2",
"uuid": "211e0879-ce10-47f7-b971-5ae8aaf597c3",
"importer": "json",
"subMetas": {}
}