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

@@ -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';
const { ccclass, property } = _decorator;
@@ -10,6 +10,9 @@ export class PlayerController extends Component {
@property(Node)
player: Node | null = null; // 玩家节点
@property(Node)
bonus: Node | null = null;
@property(Camera)
camera: Camera | null = null; // 主摄像机
@@ -33,6 +36,10 @@ export class PlayerController extends Component {
private currentAnimation: string = 'stand'; // 当前播放的动画
private lastTargetPosition: Vec3 = new Vec3(); // 上一个目标位置,用于方向判断
private isUpgraded: boolean = false; // 玩家是否已升级
private isGameOver: boolean = false; // 游戏是否结束(玩家死亡)
private isWin: boolean = false; // 游戏是否胜利(到达终点)
private hasWinTimes = 0
// 道具列表
private props: Node[] = [];
@@ -117,7 +124,7 @@ export class PlayerController extends Component {
}
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坐标
const touchLocation = event.getUILocation();
@@ -294,7 +301,7 @@ export class PlayerController extends Component {
* 移动到路径中的下一个路径点
*/
private moveToNextWaypoint() {
if (this.currentAnimation === 'attack') {
if (this.currentAnimation === 'attack' || this.isAttacking) {
return
}
@@ -405,6 +412,7 @@ export class PlayerController extends Component {
// 比较生命值,判断输赢
console.log('判定攻击结果玩家HP:', playerHp, '怪物HP:', monsterHp);
if (playerHp >= monsterHp) {
this.hasWinTimes++
// 玩家获胜
console.log('玩家获胜!更新玩家生命值为:', playerHp + monsterHp);
@@ -432,6 +440,11 @@ export class PlayerController extends Component {
}, 1);
this.switchAnimation('stand'); // 玩家站立
if (this.hasWinTimes === 10) {
this.isWin = true
this.showBonusPopup()
}
} else {
// 怪物获胜
console.log('怪物获胜玩家生命值变为0');
@@ -449,6 +462,10 @@ export class PlayerController extends Component {
if (monsterAnimation) {
monsterAnimation.play(`${otherCollider.node.name}_stand`);
}
// 设置游戏结束标志,禁止后续寻路
this.isGameOver = true;
console.log('游戏结束,禁止寻路');
}
this.isAttacking = false;
@@ -599,4 +616,91 @@ export class PlayerController extends Component {
// 播放升级动画
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();
}
}