feat: 替换人物形象以及动画逻辑
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { _decorator, Component, Node, Vec3, input, Input, EventTouch, Camera, view, tween, Animation, Collider2D, BoxCollider2D, Contact2DType, Label, Color, Canvas, UITransform, AudioSource, Sprite, director, PhysicsSystem2D, EPhysics2DDrawFlags } from 'cc';
|
||||
import { _decorator, Component, Node, Vec3, input, Input, EventTouch, Camera, view, tween, Animation, Collider2D, BoxCollider2D, Contact2DType, Label, Color, Canvas, UITransform, AudioSource, director } from 'cc';
|
||||
import { TiledMapPathfinder } from './TiledMapPathfinder';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@@ -17,9 +17,6 @@ export class PlayerController extends Component {
|
||||
@property(Node)
|
||||
bonus: Node | null = null;
|
||||
|
||||
@property(Node)
|
||||
bonusWuqi: Node | null = null;
|
||||
|
||||
@property(Node)
|
||||
failedDialog: Node | null = null;
|
||||
|
||||
@@ -35,11 +32,6 @@ export class PlayerController extends Component {
|
||||
@property({ range: [1, 300] })
|
||||
moveSpeed: number = 300; // 移动速度(像素/秒)
|
||||
|
||||
@property
|
||||
mapWidth: number = 1080; // 地图宽度
|
||||
|
||||
@property
|
||||
mapHeight: number = 2560; // 地图高度
|
||||
|
||||
private isMoving: boolean = false;
|
||||
private isAttacking: boolean = false;
|
||||
@@ -97,6 +89,9 @@ export class PlayerController extends Component {
|
||||
start() {
|
||||
if (this.player) {
|
||||
this.originalPosition.set(this.player.position);
|
||||
// 初始化时设置站立动画和正确的方向
|
||||
this.switchAnimation('stand');
|
||||
this.updatePlayerScale();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,20 +263,15 @@ export class PlayerController extends Component {
|
||||
}
|
||||
|
||||
private clampPositionWithinMap(position: Vec3): Vec3 {
|
||||
// 计算地图边界(地图锚点为0.5,0.5,所以范围是-mapWidth/2到+mapWidth/2)
|
||||
const mapHalfWidth = this.mapWidth * 0.5;
|
||||
const mapHalfHeight = this.mapHeight * 0.5;
|
||||
|
||||
// 限制位置
|
||||
const clampedPosition = position.clone();
|
||||
// clampedPosition.x = Math.max(-mapHalfWidth, Math.min(mapHalfWidth, position.x));
|
||||
// clampedPosition.y = Math.max(-mapHalfHeight, Math.min(mapHalfHeight, position.y));
|
||||
|
||||
return clampedPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据移动方向获取对应的动画名称
|
||||
* 现在只返回基础动画名称,不包含方向信息
|
||||
*/
|
||||
private getAnimationNameByDirection(currentPos: Vec3, targetPos: Vec3): string {
|
||||
const deltaX = targetPos.x - currentPos.x;
|
||||
@@ -290,29 +280,28 @@ export class PlayerController extends Component {
|
||||
// 如果移动距离很小,保持当前动画
|
||||
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
if (distance < 1) {
|
||||
return this.currentAnimation;
|
||||
return this.currentAnimation.includes('walk') ? 'walk' : this.currentAnimation;
|
||||
}
|
||||
|
||||
// 计算主要移动方向
|
||||
const absX = Math.abs(deltaX);
|
||||
const absY = Math.abs(deltaY);
|
||||
|
||||
// 添加角度判断,更精确地确定方向
|
||||
const angle = Math.atan2(deltaY, deltaX) * 180 / Math.PI; // 转换为角度
|
||||
|
||||
if (absX > absY) {
|
||||
// 水平移动为主
|
||||
this.currentDirection = deltaX < 0 ? 3 : 5;
|
||||
return deltaX < 0 ? 'walk3' : 'walk5';
|
||||
} else {
|
||||
// 垂直移动为主
|
||||
this.currentDirection = deltaY < 0 ? 3 : 5;
|
||||
return deltaY < 0 ? 'walk3' : 'walk5'; // 上移用walk3,下移用walk5
|
||||
}
|
||||
|
||||
// 只返回基础动画名称,不包含方向信息
|
||||
return 'walk';
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换动画,避免不必要的切换
|
||||
* 根据 this.currentDirection 来决定 player 的 scale 是否要取反,不再需要通过动画名称进行区分
|
||||
*/
|
||||
private switchAnimation(animationName: string) {
|
||||
if (!this.player) {
|
||||
@@ -320,42 +309,85 @@ export class PlayerController extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果切换到站立动画,根据当前方向选择对应的站立动画
|
||||
let targetAnimationName = animationName;
|
||||
// 根据动画类型获取基础动画名称,不再包含方向信息
|
||||
let baseAnimationName = animationName;
|
||||
if (animationName === 'stand') {
|
||||
targetAnimationName = this.currentDirection === 3 ? 'stand3' : 'stand5';
|
||||
baseAnimationName = 'stand';
|
||||
} else if (animationName.startsWith('walk')) {
|
||||
baseAnimationName = 'walk';
|
||||
} else if (animationName.startsWith('attack')) {
|
||||
baseAnimationName = 'attack';
|
||||
} else if (animationName.startsWith('die')) {
|
||||
baseAnimationName = 'die';
|
||||
}
|
||||
|
||||
// 如果玩家已升级,在动画名称后添加 "_2" 后缀
|
||||
let finalAnimationName = targetAnimationName;
|
||||
if (this.isUpgraded && !targetAnimationName.endsWith('_2')) {
|
||||
finalAnimationName = targetAnimationName + '_2';
|
||||
let finalAnimationName = baseAnimationName;
|
||||
if (this.isUpgraded && !baseAnimationName.endsWith('_2')) {
|
||||
finalAnimationName = baseAnimationName + '_2';
|
||||
}
|
||||
|
||||
// 检查是否需要切换动画
|
||||
if (this.currentAnimation === finalAnimationName) {
|
||||
return; // 已经是目标动画,不需要切换
|
||||
// 即使动画名称相同,也需要检查方向是否改变,可能需要调整scale
|
||||
this.updatePlayerScale();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const animation = this.player.getChildByName('Anim').getComponent(Animation);
|
||||
if (animation) {
|
||||
// 检查动画是否存在
|
||||
const state = animation.getState(finalAnimationName);
|
||||
if (!state) {
|
||||
console.warn(`动画 ${finalAnimationName} 不存在,使用默认动画`);
|
||||
this.currentAnimation = 'stand5';
|
||||
animation.play('stand5');
|
||||
this.currentAnimation = 'stand_2';
|
||||
animation.play('stand_2');
|
||||
this.updatePlayerScale();
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentAnimation = finalAnimationName;
|
||||
animation.play(finalAnimationName);
|
||||
console.log(`切换动画: ${finalAnimationName}`);
|
||||
|
||||
// 根据当前方向更新玩家scale
|
||||
this.updatePlayerScale();
|
||||
} else {
|
||||
console.warn('未找到Animation组件,无法播放动画');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据当前方向更新玩家Anim子节点的scale
|
||||
* 当 currentDirection 为 3 时,需要翻转Anim节点(scale.x 取反)
|
||||
*/
|
||||
private updatePlayerScale() {
|
||||
if (!this.player) return;
|
||||
|
||||
// 获取Anim子节点
|
||||
const animNode = this.player.getChildByName('Anim');
|
||||
if (!animNode) {
|
||||
console.warn('未找到Anim子节点,无法更新方向');
|
||||
return;
|
||||
}
|
||||
|
||||
const currentScale = animNode.scale.clone();
|
||||
|
||||
// 根据方向决定是否需要翻转
|
||||
// currentDirection: 3表示左/上,5表示右/下
|
||||
if (this.currentDirection === 3) {
|
||||
// 需要翻转,确保scale.x为负值
|
||||
if (currentScale.x > 0) {
|
||||
animNode.setScale(-currentScale.x, currentScale.y, currentScale.z);
|
||||
}
|
||||
} else {
|
||||
// 不需要翻转,确保scale.x为正值
|
||||
if (currentScale.x < 0) {
|
||||
animNode.setScale(-currentScale.x, currentScale.y, currentScale.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动到路径中的下一个路径点
|
||||
*/
|
||||
@@ -527,20 +559,17 @@ export class PlayerController extends Component {
|
||||
const absX = Math.abs(deltaX);
|
||||
const absY = Math.abs(deltaY);
|
||||
|
||||
// 根据移动方向选择动画
|
||||
let animationName = 'walk';
|
||||
// 更新当前方向
|
||||
if (absX > absY) {
|
||||
// 水平移动为主
|
||||
this.currentDirection = deltaX < 0 ? 3 : 5;
|
||||
animationName = deltaX < 0 ? 'walk3' : 'walk5';
|
||||
} else {
|
||||
// 垂直移动为主
|
||||
this.currentDirection = deltaY < 0 ? 3 : 5;
|
||||
animationName = deltaY < 0 ? 'walk3' : 'walk5';
|
||||
}
|
||||
|
||||
// 切换到对应的动画
|
||||
this.switchAnimation(animationName);
|
||||
// 切换到对应的动画(只传递基础动画名称)
|
||||
this.switchAnimation('walk');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -637,9 +666,8 @@ export class PlayerController extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
const movingRight = targetLocalPos.x >= currentLocalPos.x;
|
||||
const moveAnimation = movingRight ? 'walk5' : 'walk3';
|
||||
this.switchAnimation(moveAnimation);
|
||||
// 只传递基础动画名称,方向由 currentDirection 控制
|
||||
this.switchAnimation('walk');
|
||||
|
||||
const baseDuration = this.moveSpeed > 0 ? distance / this.moveSpeed : 0.2;
|
||||
const duration = Math.min(Math.max(baseDuration, 0.12), 0.45);
|
||||
@@ -740,9 +768,8 @@ export class PlayerController extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
// 播放玩家攻击动画
|
||||
const attackAnimationName = this.currentDirection === 3 ? 'attack3' : 'attack5';
|
||||
this.switchAnimation(attackAnimationName);
|
||||
// 播放玩家攻击动画(只传递基础动画名称)
|
||||
this.switchAnimation('attack');
|
||||
|
||||
// 监听玩家攻击动画结束事件
|
||||
playerAnimation.once(Animation.EventType.FINISHED, async () => {
|
||||
@@ -871,7 +898,7 @@ export class PlayerController extends Component {
|
||||
// 播放生命值标签的失败动画
|
||||
this.playLabelFailAnimation(playerLabel);
|
||||
|
||||
// 玩家死亡动画
|
||||
// 玩家死亡动画(只传递基础动画名称)
|
||||
this.switchAnimation('die');
|
||||
|
||||
// 怪物站立动画
|
||||
|
||||
Reference in New Issue
Block a user