feat: 支持道具以及升级
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import { _decorator, Component, Node, Vec3, input, Input, EventTouch, Camera, view, tween, Animation, Collider2D, Contact2DType, Label, Color } from 'cc';
|
||||
import { _decorator, Component, Node, Vec3, input, Input, EventTouch, Camera, view, tween, Animation, Collider2D, Contact2DType, Label, Color, Canvas } from 'cc';
|
||||
import { TiledMapPathfinder } from './TiledMapPathfinder';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass('PlayerController')
|
||||
export class PlayerController extends Component {
|
||||
@property(Canvas)
|
||||
canvas: Canvas | null = null;
|
||||
|
||||
@property(Node)
|
||||
player: Node | null = null; // 玩家节点
|
||||
@@ -30,6 +32,10 @@ export class PlayerController extends Component {
|
||||
private originalPosition: Vec3 = new Vec3();
|
||||
private currentAnimation: string = 'stand'; // 当前播放的动画
|
||||
private lastTargetPosition: Vec3 = new Vec3(); // 上一个目标位置,用于方向判断
|
||||
private isUpgraded: boolean = false; // 玩家是否已升级
|
||||
|
||||
// 道具列表
|
||||
private props: Node[] = [];
|
||||
|
||||
onLoad() {
|
||||
// 注册触摸事件
|
||||
@@ -40,6 +46,8 @@ export class PlayerController extends Component {
|
||||
// 监听碰撞事件
|
||||
collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
||||
}
|
||||
|
||||
this.initProps();
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
@@ -53,6 +61,61 @@ export class PlayerController extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
initProps() {
|
||||
if (!this.canvas) {
|
||||
console.warn('Canvas未设置,无法初始化道具');
|
||||
return;
|
||||
}
|
||||
|
||||
// 查找Canvas下的Props节点
|
||||
const propsNode = this.canvas.node.getChildByName('Props');
|
||||
if (!propsNode) {
|
||||
console.warn('未找到Props节点,请确保Canvas下有名为"Props"的节点');
|
||||
return;
|
||||
}
|
||||
|
||||
// 清空现有的道具列表
|
||||
this.props.length = 0;
|
||||
|
||||
// 获取Props节点下的所有子节点
|
||||
for (let i = 0; i < propsNode.children.length; i++) {
|
||||
const child = propsNode.children[i];
|
||||
this.props.push(child);
|
||||
console.log(`添加道具: ${child.name}`);
|
||||
|
||||
// 为每个道具添加悬浮动画
|
||||
this.addFloatingAnimation(child);
|
||||
}
|
||||
|
||||
console.log(`初始化道具完成,共找到 ${this.props.length} 个道具`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为道具添加悬浮动画
|
||||
*/
|
||||
private addFloatingAnimation(propNode: Node) {
|
||||
if (!propNode) return;
|
||||
|
||||
// 保存原始位置
|
||||
const originalY = propNode.position.y;
|
||||
const floatHeight = 10; // 悬浮高度(像素)
|
||||
const floatDuration = 2; // 悬浮周期(秒)
|
||||
|
||||
// 创建上下浮动的动画
|
||||
tween(propNode)
|
||||
.to(floatDuration / 2, { position: new Vec3(propNode.position.x, originalY + floatHeight, propNode.position.z) }, {
|
||||
easing: 'sineInOut'
|
||||
})
|
||||
.to(floatDuration / 2, { position: new Vec3(propNode.position.x, originalY, propNode.position.z) }, {
|
||||
easing: 'sineInOut'
|
||||
})
|
||||
.union() // 将动画串联起来
|
||||
.repeatForever() // 无限重复
|
||||
.start();
|
||||
|
||||
console.log(`为道具 ${propNode.name} 添加悬浮动画`);
|
||||
}
|
||||
|
||||
private onTouchStart(event: EventTouch) {
|
||||
if (!this.player || !this.camera || !this.pathfinder || this.isAttacking) return;
|
||||
|
||||
@@ -197,24 +260,30 @@ export class PlayerController extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.currentAnimation === animationName) {
|
||||
// 如果玩家已升级,在动画名称后添加 "_2" 后缀
|
||||
let finalAnimationName = animationName;
|
||||
if (this.isUpgraded && !animationName.endsWith('_2')) {
|
||||
finalAnimationName = animationName + '_2';
|
||||
}
|
||||
|
||||
if (this.currentAnimation === finalAnimationName) {
|
||||
return; // 已经是目标动画,不需要切换
|
||||
}
|
||||
|
||||
const animation = this.player.getComponent(Animation);
|
||||
if (animation) {
|
||||
// 检查动画是否存在
|
||||
const state = animation.getState(animationName);
|
||||
const state = animation.getState(finalAnimationName);
|
||||
if (!state) {
|
||||
console.warn(`动画 ${animationName} 不存在,使用默认动画`);
|
||||
console.warn(`动画 ${finalAnimationName} 不存在,使用默认动画`);
|
||||
this.currentAnimation = 'stand';
|
||||
animation.play('stand');
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentAnimation = animationName;
|
||||
animation.play(animationName);
|
||||
console.log(`切换动画: ${animationName}`);
|
||||
this.currentAnimation = finalAnimationName;
|
||||
animation.play(finalAnimationName);
|
||||
console.log(`切换动画: ${finalAnimationName}`);
|
||||
} else {
|
||||
console.warn('未找到Animation组件,无法播放动画');
|
||||
}
|
||||
@@ -331,7 +400,7 @@ export class PlayerController extends Component {
|
||||
this.switchAnimation('attack');
|
||||
|
||||
// 2秒后判定攻击结果
|
||||
this.scheduleOnce(() => {
|
||||
this.scheduleOnce(async () => {
|
||||
// 比较生命值,判断输赢
|
||||
console.log('判定攻击结果,玩家HP:', playerHp, '怪物HP:', monsterHp);
|
||||
if (playerHp >= monsterHp) {
|
||||
@@ -350,6 +419,11 @@ export class PlayerController extends Component {
|
||||
monsterAnimation.play(`${otherCollider.node.name}_die`);
|
||||
}
|
||||
|
||||
// 如果是攻击 guai_2 并且成功,创建道具飞向 player 的动画
|
||||
if (otherCollider.node.name === 'guai_2') {
|
||||
await this.createPropsFlyToPlayerAnimation()
|
||||
}
|
||||
|
||||
// 1秒后怪物消失
|
||||
this.scheduleOnce(() => {
|
||||
otherCollider.node.destroy();
|
||||
@@ -430,4 +504,98 @@ export class PlayerController extends Component {
|
||||
.to(0.1, { color: originalColor })
|
||||
.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建道具飞向玩家的动画(同步方法)
|
||||
*/
|
||||
private async createPropsFlyToPlayerAnimation(): Promise<void> {
|
||||
if (!this.player || this.props.length === 0) {
|
||||
console.warn('玩家或道具不存在,无法创建飞行动画');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('创建道具飞向玩家的动画');
|
||||
|
||||
// 获取玩家位置
|
||||
const playerPos = this.player.position.clone();
|
||||
|
||||
// 创建所有道具的飞行动画承诺
|
||||
const flyPromises: Promise<void>[] = [];
|
||||
|
||||
// 为每个道具创建飞行动画
|
||||
this.props.forEach((prop, index) => {
|
||||
if (!prop || !prop.isValid) return;
|
||||
|
||||
// 保存道具原始位置
|
||||
const originalPos = prop.position.clone();
|
||||
|
||||
// 计算飞行时间(根据距离调整)
|
||||
const distance = Vec3.distance(originalPos, playerPos);
|
||||
const flyDuration = Math.max(0.5, distance / 500); // 最少0.5秒,速度500像素/秒
|
||||
|
||||
// 添加延迟,让道具依次飞向玩家
|
||||
const delay = index * 0.1;
|
||||
|
||||
// 停止道具的悬浮动画
|
||||
tween(prop).stop();
|
||||
|
||||
// 创建飞行动画的承诺
|
||||
const flyPromise = new Promise<void>((resolve) => {
|
||||
this.scheduleOnce(() => {
|
||||
tween(prop)
|
||||
.to(flyDuration, {
|
||||
position: new Vec3(playerPos.x, playerPos.y, playerPos.z)
|
||||
}, {
|
||||
easing: 'quadOut',
|
||||
onComplete: () => {
|
||||
// 道具到达玩家位置后消失
|
||||
prop.destroy();
|
||||
console.log(`道具 ${prop.name} 已到达玩家位置并消失`);
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
.start();
|
||||
}, delay);
|
||||
});
|
||||
|
||||
flyPromises.push(flyPromise);
|
||||
});
|
||||
|
||||
// 等待所有道具飞行动画完成
|
||||
await Promise.all(flyPromises);
|
||||
|
||||
// 所有动画完成后,播放升级动画并设置升级状态
|
||||
this.playLevelUpAnimation();
|
||||
this.isUpgraded = true;
|
||||
console.log('所有道具飞行动画完成,玩家已升级,后续动画将使用升级版本');
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放玩家升级动画
|
||||
*/
|
||||
private playLevelUpAnimation() {
|
||||
if (!this.player) {
|
||||
console.warn('玩家节点不存在,无法播放升级动画');
|
||||
return;
|
||||
}
|
||||
|
||||
// 查找levelUp子节点
|
||||
const levelUpNode = this.player.getChildByName('levelUp');
|
||||
if (!levelUpNode) {
|
||||
console.warn('未找到levelUp子节点');
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取动画组件
|
||||
const levelUpAnimation = levelUpNode.getComponent(Animation);
|
||||
if (!levelUpAnimation) {
|
||||
console.warn('levelUp节点未找到Animation组件');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('播放玩家升级动画');
|
||||
|
||||
// 播放升级动画
|
||||
levelUpAnimation.play('levelUp');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user