perf: 支持奖励特效

This commit is contained in:
richarjiang
2025-09-26 10:49:23 +08:00
parent b83817e246
commit f27a27d2ce
15 changed files with 1340 additions and 305 deletions

View File

@@ -0,0 +1,9 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "82ec7e8b-6ed5-4b5e-8c43-801849f5e508",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,98 @@
[
{
"__type__": "cc.AnimationClip",
"_name": "bonus",
"_objFlags": 0,
"__editorExtras__": {
"embeddedPlayerGroups": []
},
"_native": "",
"sample": 60,
"speed": 1,
"wrapMode": 2,
"enableTrsBlending": false,
"_duration": 0.35,
"_hash": 500763545,
"_tracks": [
{
"__id__": 1
}
],
"_exoticAnimation": null,
"_events": [],
"_embeddedPlayers": [],
"_additiveSettings": {
"__id__": 6
},
"_auxiliaryCurveEntries": []
},
{
"__type__": "cc.animation.ObjectTrack",
"_binding": {
"__type__": "cc.animation.TrackBinding",
"path": {
"__id__": 2
},
"proxy": null
},
"_channel": {
"__id__": 4
}
},
{
"__type__": "cc.animation.TrackPath",
"_paths": [
{
"__id__": 3
},
"spriteFrame"
]
},
{
"__type__": "cc.animation.ComponentPath",
"component": "cc.Sprite"
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 5
}
},
{
"__type__": "cc.ObjectCurve",
"_times": [
0,
0.08333333333333333,
0.16666666666666666,
0.25,
0.3333333333333333
],
"_values": [
{
"__uuid__": "ef0a4723-ab8e-481f-9567-e9b2a1400181@f9941",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "3cbd569e-fed7-4498-87b4-11444552dfb5@f9941",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "4d9cec20-8b34-46e7-9251-59272d42b227@f9941",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "67702aaf-c444-4d4c-8605-026cdbe6fee5@f9941",
"__expectedType__": "cc.SpriteFrame"
},
{
"__uuid__": "05946790-3cbd-42a1-a3b9-523d0e99ea3a@f9941",
"__expectedType__": "cc.SpriteFrame"
}
]
},
{
"__type__": "cc.AnimationClipAdditiveSettings",
"enabled": false,
"refClip": null
}
]

View File

@@ -0,0 +1,13 @@
{
"ver": "2.0.4",
"importer": "animation-clip",
"imported": true,
"uuid": "e22ce611-db61-41a0-a1ac-f568696a8b26",
"files": [
".bin"
],
"subMetas": {},
"userData": {
"name": "bonus"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

View File

@@ -0,0 +1,134 @@
{
"ver": "1.0.27",
"importer": "image",
"imported": true,
"uuid": "ef0a4723-ab8e-481f-9567-e9b2a1400181",
"files": [
".json",
".png"
],
"subMetas": {
"6c48a": {
"importer": "texture",
"uuid": "ef0a4723-ab8e-481f-9567-e9b2a1400181@6c48a",
"displayName": "奖励特效_00000",
"id": "6c48a",
"name": "texture",
"userData": {
"wrapModeS": "clamp-to-edge",
"wrapModeT": "clamp-to-edge",
"imageUuidOrDatabaseUri": "ef0a4723-ab8e-481f-9567-e9b2a1400181",
"isUuid": true,
"visible": false,
"minfilter": "linear",
"magfilter": "linear",
"mipfilter": "none",
"anisotropy": 0
},
"ver": "1.0.22",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"f9941": {
"importer": "sprite-frame",
"uuid": "ef0a4723-ab8e-481f-9567-e9b2a1400181@f9941",
"displayName": "奖励特效_00000",
"id": "f9941",
"name": "spriteFrame",
"userData": {
"trimThreshold": 1,
"rotated": false,
"offsetX": 20.5,
"offsetY": 27.5,
"trimX": 41,
"trimY": 155,
"width": 679,
"height": 915,
"rawWidth": 720,
"rawHeight": 1280,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"packable": true,
"pixelsToUnit": 100,
"pivotX": 0.5,
"pivotY": 0.5,
"meshType": 0,
"vertices": {
"rawPosition": [
-339.5,
-457.5,
0,
339.5,
-457.5,
0,
-339.5,
457.5,
0,
339.5,
457.5,
0
],
"indexes": [
0,
1,
2,
2,
1,
3
],
"uv": [
41,
1125,
720,
1125,
41,
210,
720,
210
],
"nuv": [
0.05694444444444444,
0.1640625,
1,
0.1640625,
0.05694444444444444,
0.87890625,
1,
0.87890625
],
"minPos": [
-339.5,
-457.5,
0
],
"maxPos": [
339.5,
457.5,
0
]
},
"isUuid": true,
"imageUuidOrDatabaseUri": "ef0a4723-ab8e-481f-9567-e9b2a1400181@6c48a",
"atlasUuid": "",
"trimType": "auto"
},
"ver": "1.0.12",
"imported": true,
"files": [
".json"
],
"subMetas": {}
}
},
"userData": {
"type": "sprite-frame",
"hasAlpha": true,
"fixAlphaTransparencyArtifacts": false,
"redirect": "ef0a4723-ab8e-481f-9567-e9b2a1400181@6c48a"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

View File

@@ -0,0 +1,134 @@
{
"ver": "1.0.27",
"importer": "image",
"imported": true,
"uuid": "3cbd569e-fed7-4498-87b4-11444552dfb5",
"files": [
".json",
".png"
],
"subMetas": {
"6c48a": {
"importer": "texture",
"uuid": "3cbd569e-fed7-4498-87b4-11444552dfb5@6c48a",
"displayName": "奖励特效_00002",
"id": "6c48a",
"name": "texture",
"userData": {
"wrapModeS": "clamp-to-edge",
"wrapModeT": "clamp-to-edge",
"imageUuidOrDatabaseUri": "3cbd569e-fed7-4498-87b4-11444552dfb5",
"isUuid": true,
"visible": false,
"minfilter": "linear",
"magfilter": "linear",
"mipfilter": "none",
"anisotropy": 0
},
"ver": "1.0.22",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"f9941": {
"importer": "sprite-frame",
"uuid": "3cbd569e-fed7-4498-87b4-11444552dfb5@f9941",
"displayName": "奖励特效_00002",
"id": "f9941",
"name": "spriteFrame",
"userData": {
"trimThreshold": 1,
"rotated": false,
"offsetX": 20.5,
"offsetY": 27.5,
"trimX": 41,
"trimY": 155,
"width": 679,
"height": 915,
"rawWidth": 720,
"rawHeight": 1280,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"packable": true,
"pixelsToUnit": 100,
"pivotX": 0.5,
"pivotY": 0.5,
"meshType": 0,
"vertices": {
"rawPosition": [
-339.5,
-457.5,
0,
339.5,
-457.5,
0,
-339.5,
457.5,
0,
339.5,
457.5,
0
],
"indexes": [
0,
1,
2,
2,
1,
3
],
"uv": [
41,
1125,
720,
1125,
41,
210,
720,
210
],
"nuv": [
0.05694444444444444,
0.1640625,
1,
0.1640625,
0.05694444444444444,
0.87890625,
1,
0.87890625
],
"minPos": [
-339.5,
-457.5,
0
],
"maxPos": [
339.5,
457.5,
0
]
},
"isUuid": true,
"imageUuidOrDatabaseUri": "3cbd569e-fed7-4498-87b4-11444552dfb5@6c48a",
"atlasUuid": "",
"trimType": "auto"
},
"ver": "1.0.12",
"imported": true,
"files": [
".json"
],
"subMetas": {}
}
},
"userData": {
"type": "sprite-frame",
"hasAlpha": true,
"fixAlphaTransparencyArtifacts": false,
"redirect": "3cbd569e-fed7-4498-87b4-11444552dfb5@6c48a"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

View File

@@ -0,0 +1,134 @@
{
"ver": "1.0.27",
"importer": "image",
"imported": true,
"uuid": "4d9cec20-8b34-46e7-9251-59272d42b227",
"files": [
".json",
".png"
],
"subMetas": {
"6c48a": {
"importer": "texture",
"uuid": "4d9cec20-8b34-46e7-9251-59272d42b227@6c48a",
"displayName": "奖励特效_00004",
"id": "6c48a",
"name": "texture",
"userData": {
"wrapModeS": "clamp-to-edge",
"wrapModeT": "clamp-to-edge",
"imageUuidOrDatabaseUri": "4d9cec20-8b34-46e7-9251-59272d42b227",
"isUuid": true,
"visible": false,
"minfilter": "linear",
"magfilter": "linear",
"mipfilter": "none",
"anisotropy": 0
},
"ver": "1.0.22",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"f9941": {
"importer": "sprite-frame",
"uuid": "4d9cec20-8b34-46e7-9251-59272d42b227@f9941",
"displayName": "奖励特效_00004",
"id": "f9941",
"name": "spriteFrame",
"userData": {
"trimThreshold": 1,
"rotated": false,
"offsetX": 20.5,
"offsetY": 27.5,
"trimX": 41,
"trimY": 155,
"width": 679,
"height": 915,
"rawWidth": 720,
"rawHeight": 1280,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"packable": true,
"pixelsToUnit": 100,
"pivotX": 0.5,
"pivotY": 0.5,
"meshType": 0,
"vertices": {
"rawPosition": [
-339.5,
-457.5,
0,
339.5,
-457.5,
0,
-339.5,
457.5,
0,
339.5,
457.5,
0
],
"indexes": [
0,
1,
2,
2,
1,
3
],
"uv": [
41,
1125,
720,
1125,
41,
210,
720,
210
],
"nuv": [
0.05694444444444444,
0.1640625,
1,
0.1640625,
0.05694444444444444,
0.87890625,
1,
0.87890625
],
"minPos": [
-339.5,
-457.5,
0
],
"maxPos": [
339.5,
457.5,
0
]
},
"isUuid": true,
"imageUuidOrDatabaseUri": "4d9cec20-8b34-46e7-9251-59272d42b227@6c48a",
"atlasUuid": "",
"trimType": "auto"
},
"ver": "1.0.12",
"imported": true,
"files": [
".json"
],
"subMetas": {}
}
},
"userData": {
"type": "sprite-frame",
"hasAlpha": true,
"fixAlphaTransparencyArtifacts": false,
"redirect": "4d9cec20-8b34-46e7-9251-59272d42b227@6c48a"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

View File

@@ -0,0 +1,134 @@
{
"ver": "1.0.27",
"importer": "image",
"imported": true,
"uuid": "67702aaf-c444-4d4c-8605-026cdbe6fee5",
"files": [
".json",
".png"
],
"subMetas": {
"6c48a": {
"importer": "texture",
"uuid": "67702aaf-c444-4d4c-8605-026cdbe6fee5@6c48a",
"displayName": "奖励特效_00006",
"id": "6c48a",
"name": "texture",
"userData": {
"wrapModeS": "clamp-to-edge",
"wrapModeT": "clamp-to-edge",
"imageUuidOrDatabaseUri": "67702aaf-c444-4d4c-8605-026cdbe6fee5",
"isUuid": true,
"visible": false,
"minfilter": "linear",
"magfilter": "linear",
"mipfilter": "none",
"anisotropy": 0
},
"ver": "1.0.22",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"f9941": {
"importer": "sprite-frame",
"uuid": "67702aaf-c444-4d4c-8605-026cdbe6fee5@f9941",
"displayName": "奖励特效_00006",
"id": "f9941",
"name": "spriteFrame",
"userData": {
"trimThreshold": 1,
"rotated": false,
"offsetX": 20.5,
"offsetY": 27.5,
"trimX": 41,
"trimY": 155,
"width": 679,
"height": 915,
"rawWidth": 720,
"rawHeight": 1280,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"packable": true,
"pixelsToUnit": 100,
"pivotX": 0.5,
"pivotY": 0.5,
"meshType": 0,
"vertices": {
"rawPosition": [
-339.5,
-457.5,
0,
339.5,
-457.5,
0,
-339.5,
457.5,
0,
339.5,
457.5,
0
],
"indexes": [
0,
1,
2,
2,
1,
3
],
"uv": [
41,
1125,
720,
1125,
41,
210,
720,
210
],
"nuv": [
0.05694444444444444,
0.1640625,
1,
0.1640625,
0.05694444444444444,
0.87890625,
1,
0.87890625
],
"minPos": [
-339.5,
-457.5,
0
],
"maxPos": [
339.5,
457.5,
0
]
},
"isUuid": true,
"imageUuidOrDatabaseUri": "67702aaf-c444-4d4c-8605-026cdbe6fee5@6c48a",
"atlasUuid": "",
"trimType": "auto"
},
"ver": "1.0.12",
"imported": true,
"files": [
".json"
],
"subMetas": {}
}
},
"userData": {
"type": "sprite-frame",
"hasAlpha": true,
"fixAlphaTransparencyArtifacts": false,
"redirect": "67702aaf-c444-4d4c-8605-026cdbe6fee5@6c48a"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

View File

@@ -0,0 +1,134 @@
{
"ver": "1.0.27",
"importer": "image",
"imported": true,
"uuid": "05946790-3cbd-42a1-a3b9-523d0e99ea3a",
"files": [
".json",
".png"
],
"subMetas": {
"6c48a": {
"importer": "texture",
"uuid": "05946790-3cbd-42a1-a3b9-523d0e99ea3a@6c48a",
"displayName": "奖励特效_00008",
"id": "6c48a",
"name": "texture",
"userData": {
"wrapModeS": "clamp-to-edge",
"wrapModeT": "clamp-to-edge",
"imageUuidOrDatabaseUri": "05946790-3cbd-42a1-a3b9-523d0e99ea3a",
"isUuid": true,
"visible": false,
"minfilter": "linear",
"magfilter": "linear",
"mipfilter": "none",
"anisotropy": 0
},
"ver": "1.0.22",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"f9941": {
"importer": "sprite-frame",
"uuid": "05946790-3cbd-42a1-a3b9-523d0e99ea3a@f9941",
"displayName": "奖励特效_00008",
"id": "f9941",
"name": "spriteFrame",
"userData": {
"trimThreshold": 1,
"rotated": false,
"offsetX": 20.5,
"offsetY": 27.5,
"trimX": 41,
"trimY": 155,
"width": 679,
"height": 915,
"rawWidth": 720,
"rawHeight": 1280,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"packable": true,
"pixelsToUnit": 100,
"pivotX": 0.5,
"pivotY": 0.5,
"meshType": 0,
"vertices": {
"rawPosition": [
-339.5,
-457.5,
0,
339.5,
-457.5,
0,
-339.5,
457.5,
0,
339.5,
457.5,
0
],
"indexes": [
0,
1,
2,
2,
1,
3
],
"uv": [
41,
1125,
720,
1125,
41,
210,
720,
210
],
"nuv": [
0.05694444444444444,
0.1640625,
1,
0.1640625,
0.05694444444444444,
0.87890625,
1,
0.87890625
],
"minPos": [
-339.5,
-457.5,
0
],
"maxPos": [
339.5,
457.5,
0
]
},
"isUuid": true,
"imageUuidOrDatabaseUri": "05946790-3cbd-42a1-a3b9-523d0e99ea3a@6c48a",
"atlasUuid": "",
"trimType": "auto"
},
"ver": "1.0.12",
"imported": true,
"files": [
".json"
],
"subMetas": {}
}
},
"userData": {
"type": "sprite-frame",
"hasAlpha": true,
"fixAlphaTransparencyArtifacts": false,
"redirect": "05946790-3cbd-42a1-a3b9-523d0e99ea3a@6c48a"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
import { _decorator, Component, Node, Vec3, input, Input, EventTouch, Camera, view, tween, Animation, Collider2D, Contact2DType, Label, Color, Canvas } from 'cc'; import { _decorator, Component, Node, Vec3, input, Input, EventTouch, Camera, view, tween, Animation, Collider2D, Contact2DType, Label, Color, Canvas, UITransform } from 'cc';
import { TiledMapPathfinder } from './TiledMapPathfinder'; import { TiledMapPathfinder } from './TiledMapPathfinder';
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
@@ -10,6 +10,9 @@ export class PlayerController extends Component {
@property(Node) @property(Node)
player: Node | null = null; // 玩家节点 player: Node | null = null; // 玩家节点
@property(Node)
bonus: Node | null = null;
@property(Camera) @property(Camera)
camera: Camera | null = null; // 主摄像机 camera: Camera | null = null; // 主摄像机
@@ -33,6 +36,10 @@ export class PlayerController extends Component {
private currentAnimation: string = 'stand'; // 当前播放的动画 private currentAnimation: string = 'stand'; // 当前播放的动画
private lastTargetPosition: Vec3 = new Vec3(); // 上一个目标位置,用于方向判断 private lastTargetPosition: Vec3 = new Vec3(); // 上一个目标位置,用于方向判断
private isUpgraded: boolean = false; // 玩家是否已升级 private isUpgraded: boolean = false; // 玩家是否已升级
private isGameOver: boolean = false; // 游戏是否结束(玩家死亡)
private isWin: boolean = false; // 游戏是否胜利(到达终点)
private hasWinTimes = 0
// 道具列表 // 道具列表
private props: Node[] = []; private props: Node[] = [];
@@ -117,7 +124,7 @@ export class PlayerController extends Component {
} }
private onTouchStart(event: EventTouch) { private onTouchStart(event: EventTouch) {
if (!this.player || !this.camera || !this.pathfinder || this.isAttacking) return; if (!this.player || !this.camera || !this.pathfinder || this.isAttacking || this.isGameOver || this.isWin) return;
// 获取触摸点的UI坐标 // 获取触摸点的UI坐标
const touchLocation = event.getUILocation(); const touchLocation = event.getUILocation();
@@ -294,7 +301,7 @@ export class PlayerController extends Component {
* 移动到路径中的下一个路径点 * 移动到路径中的下一个路径点
*/ */
private moveToNextWaypoint() { private moveToNextWaypoint() {
if (this.currentAnimation === 'attack') { if (this.currentAnimation === 'attack' || this.isAttacking) {
return return
} }
@@ -405,6 +412,7 @@ export class PlayerController extends Component {
// 比较生命值,判断输赢 // 比较生命值,判断输赢
console.log('判定攻击结果玩家HP:', playerHp, '怪物HP:', monsterHp); console.log('判定攻击结果玩家HP:', playerHp, '怪物HP:', monsterHp);
if (playerHp >= monsterHp) { if (playerHp >= monsterHp) {
this.hasWinTimes++
// 玩家获胜 // 玩家获胜
console.log('玩家获胜!更新玩家生命值为:', playerHp + monsterHp); console.log('玩家获胜!更新玩家生命值为:', playerHp + monsterHp);
@@ -432,6 +440,11 @@ export class PlayerController extends Component {
}, 1); }, 1);
this.switchAnimation('stand'); // 玩家站立 this.switchAnimation('stand'); // 玩家站立
if (this.hasWinTimes === 10) {
this.isWin = true
this.showBonusPopup()
}
} else { } else {
// 怪物获胜 // 怪物获胜
console.log('怪物获胜玩家生命值变为0'); console.log('怪物获胜玩家生命值变为0');
@@ -449,6 +462,10 @@ export class PlayerController extends Component {
if (monsterAnimation) { if (monsterAnimation) {
monsterAnimation.play(`${otherCollider.node.name}_stand`); monsterAnimation.play(`${otherCollider.node.name}_stand`);
} }
// 设置游戏结束标志,禁止后续寻路
this.isGameOver = true;
console.log('游戏结束,禁止寻路');
} }
this.isAttacking = false; this.isAttacking = false;
@@ -599,4 +616,91 @@ export class PlayerController extends Component {
// 播放升级动画 // 播放升级动画
levelUpAnimation.play('levelUp'); levelUpAnimation.play('levelUp');
} }
/**
* 显示奖励弹窗
* 根据当前镜头位置和正交高度,将奖励节点正确缩放并移动到画面正中间
*/
public showBonusPopup() {
if (!this.bonus || !this.camera || !this.canvas) {
console.warn('奖励节点、相机或画布未设置,无法显示奖励弹窗');
return;
}
// 确保奖励节点是激活状态
this.bonus.active = true;
// 获取相机位置,相机所在的世界坐标就是当前屏幕的中心
const cameraPos = this.camera.node.position;
const orthoHeight = this.camera.orthoHeight;
// 直接将弹窗设置到相机位置(屏幕中心)
this.bonus.setPosition(cameraPos.x, cameraPos.y, 0);
// 计算合适的缩放比例,确保弹窗在不同正交高度下都能正确显示
// 基础缩放比例
const baseScale = 1.0;
// 根据正交高度调整缩放,确保弹窗大小合适
// 假设标准正交高度为500以此为基准进行缩放
const standardOrthoHeight = 500;
const scaleRatio = standardOrthoHeight / orthoHeight;
const finalScale = baseScale * scaleRatio;
// 设置奖励节点的缩放
this.bonus.setScale(finalScale, finalScale, 1);
// 添加弹窗出现动画
this.playBonusPopupAnimation();
}
/**
* 播放奖励弹窗出现动画
*/
private playBonusPopupAnimation() {
if (!this.bonus) return;
// 保存原始缩放
const originalScale = this.bonus.scale.clone();
// 初始状态设置为很小
this.bonus.setScale(0.1, 0.1, 1);
// 创建弹窗弹出动画
tween(this.bonus)
.to(0.3, {
scale: new Vec3(originalScale.x * 1.2, originalScale.y * 1.2, originalScale.z)
}, {
easing: 'backOut'
})
.to(0.1, {
scale: originalScale
}, {
easing: 'sineInOut'
})
.call(() => {
console.log('奖励弹窗显示完成');
})
.start();
}
/**
* 隐藏奖励弹窗
*/
public hideBonusPopup() {
if (!this.bonus) return;
// 创建弹窗消失动画
tween(this.bonus)
.to(0.2, {
scale: new Vec3(0.1, 0.1, 1)
}, {
easing: 'backIn'
})
.call(() => {
this.bonus.active = false;
console.log('奖励弹窗已隐藏');
})
.start();
}
} }