perf: 优化攻击位置
This commit is contained in:
@@ -3748,8 +3748,8 @@
|
|||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
"x": 310.51,
|
"x": 283.495,
|
||||||
"y": -233.009,
|
"y": -254.621,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"_lrot": {
|
"_lrot": {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { _decorator, Component, Node, Vec3, input, Input, EventTouch, Camera, view, tween, Animation, Collider2D, 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, Sprite, director, PhysicsSystem2D, EPhysics2DDrawFlags } from 'cc';
|
||||||
import { TiledMapPathfinder } from './TiledMapPathfinder';
|
import { TiledMapPathfinder } from './TiledMapPathfinder';
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
@@ -58,6 +58,7 @@ export class PlayerController extends Component {
|
|||||||
private lastPosition: Vec3 = new Vec3(); // 上一帧位置
|
private lastPosition: Vec3 = new Vec3(); // 上一帧位置
|
||||||
|
|
||||||
private hasWinTimes = 0
|
private hasWinTimes = 0
|
||||||
|
private readonly attackAlignGap = 10; // 玩家与怪物对阵时的额外左右间距,单位:像素
|
||||||
|
|
||||||
// 道具列表
|
// 道具列表
|
||||||
private props: Node[] = [];
|
private props: Node[] = [];
|
||||||
@@ -575,26 +576,127 @@ export class PlayerController extends Component {
|
|||||||
// 禁用碰撞器,防止重复触发
|
// 禁用碰撞器,防止重复触发
|
||||||
otherCollider.enabled = false;
|
otherCollider.enabled = false;
|
||||||
if (otherCollider.node.name.startsWith('guai_')) {
|
if (otherCollider.node.name.startsWith('guai_')) {
|
||||||
this.handleAttack(otherCollider);
|
void this.handleAttack(selfCollider, otherCollider);
|
||||||
} else if (otherCollider.node.name.startsWith('box_')) {
|
} else if (otherCollider.node.name.startsWith('box_')) {
|
||||||
this.handleBoxCollision(otherCollider);
|
this.handleBoxCollision(otherCollider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将玩家移动到怪物正对位置,确保攻击前双方站位合理
|
||||||
|
*/
|
||||||
|
private alignPlayerForAttack(selfCollider: Collider2D, monsterCollider: Collider2D): Promise<void> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (!this.player || !selfCollider || !monsterCollider || !monsterCollider.node || !monsterCollider.node.isValid) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const playerNode = this.player;
|
||||||
|
const monsterNode = monsterCollider.node;
|
||||||
|
|
||||||
|
const playerWorldPos = playerNode.worldPosition.clone();
|
||||||
|
const monsterWorldPos = monsterNode.worldPosition.clone();
|
||||||
|
|
||||||
|
const playerBox = selfCollider instanceof BoxCollider2D ? selfCollider : null;
|
||||||
|
const monsterBox = monsterCollider instanceof BoxCollider2D ? monsterCollider : null;
|
||||||
|
|
||||||
|
const playerScale = playerNode.worldScale;
|
||||||
|
const monsterScale = monsterNode.worldScale;
|
||||||
|
|
||||||
|
const playerHalfWidth = playerBox ? (playerBox.size.x * Math.abs(playerScale.x)) / 2 : 40;
|
||||||
|
const monsterHalfWidth = monsterBox ? (monsterBox.size.x * Math.abs(monsterScale.x)) / 2 : 60;
|
||||||
|
|
||||||
|
const playerOffsetX = playerBox ? playerBox.offset.x * playerScale.x : 0;
|
||||||
|
const playerOffsetY = playerBox ? playerBox.offset.y * playerScale.y : 0;
|
||||||
|
const monsterOffsetX = monsterBox ? monsterBox.offset.x * monsterScale.x : 0;
|
||||||
|
const monsterOffsetY = monsterBox ? monsterBox.offset.y * monsterScale.y : 0;
|
||||||
|
|
||||||
|
const playerCenterX = playerWorldPos.x + playerOffsetX;
|
||||||
|
const monsterCenterX = monsterWorldPos.x + monsterOffsetX;
|
||||||
|
const standOnLeft = playerCenterX <= monsterCenterX;
|
||||||
|
|
||||||
|
const totalHalfWidth = playerHalfWidth + monsterHalfWidth + this.attackAlignGap;
|
||||||
|
const directionMultiplier = standOnLeft ? -1 : 1;
|
||||||
|
|
||||||
|
const targetWorldPos = new Vec3(
|
||||||
|
monsterWorldPos.x + monsterOffsetX + directionMultiplier * totalHalfWidth - playerOffsetX,
|
||||||
|
monsterWorldPos.y + monsterOffsetY - playerOffsetY,
|
||||||
|
playerWorldPos.z
|
||||||
|
);
|
||||||
|
|
||||||
|
const targetLocalPos = this.convertWorldToParentSpace(playerNode, targetWorldPos);
|
||||||
|
const currentLocalPos = playerNode.position.clone();
|
||||||
|
|
||||||
|
const distance = Vec3.distance(currentLocalPos, targetLocalPos);
|
||||||
|
|
||||||
|
if (distance < 1) {
|
||||||
|
playerNode.setPosition(targetLocalPos);
|
||||||
|
this.currentDirection = standOnLeft ? 5 : 3;
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const movingRight = targetLocalPos.x >= currentLocalPos.x;
|
||||||
|
const moveAnimation = movingRight ? 'walk5' : 'walk3';
|
||||||
|
this.switchAnimation(moveAnimation);
|
||||||
|
|
||||||
|
const baseDuration = this.moveSpeed > 0 ? distance / this.moveSpeed : 0.2;
|
||||||
|
const duration = Math.min(Math.max(baseDuration, 0.12), 0.45);
|
||||||
|
|
||||||
|
tween(playerNode)
|
||||||
|
.to(duration, { position: targetLocalPos }, {
|
||||||
|
easing: 'smooth',
|
||||||
|
onComplete: () => {
|
||||||
|
playerNode.setPosition(targetLocalPos);
|
||||||
|
this.currentDirection = standOnLeft ? 5 : 3;
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.start();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private convertWorldToParentSpace(node: Node, worldPos: Vec3): Vec3 {
|
||||||
|
const parent = node.parent;
|
||||||
|
if (!parent) {
|
||||||
|
return worldPos.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentTransform = parent.getComponent(UITransform);
|
||||||
|
if (parentTransform) {
|
||||||
|
return parentTransform.convertToNodeSpaceAR(worldPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fallback = worldPos.clone();
|
||||||
|
fallback.subtract(parent.worldPosition);
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理攻击逻辑
|
* 处理攻击逻辑
|
||||||
*/
|
*/
|
||||||
private handleAttack(otherCollider: Collider2D) {
|
private async handleAttack(selfCollider: Collider2D, otherCollider: Collider2D) {
|
||||||
if (this.isAttacking) {
|
if (this.isAttacking) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
this.isAttacking = true;
|
|
||||||
|
|
||||||
|
if (!this.player || !otherCollider || !otherCollider.node || !otherCollider.node.isValid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isAttacking = true;
|
||||||
|
this.stopMovement();
|
||||||
|
|
||||||
|
await this.alignPlayerForAttack(selfCollider, otherCollider);
|
||||||
|
|
||||||
|
if (!this.player || !otherCollider.node || !otherCollider.node.isValid) {
|
||||||
|
this.isAttacking = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
console.log('开始攻击,怪物名称:', otherCollider.node.name);
|
console.log('开始攻击,怪物名称:', otherCollider.node.name);
|
||||||
|
|
||||||
this.stopMovement();
|
|
||||||
|
|
||||||
// 获取玩家和怪物的生命值
|
// 获取玩家和怪物的生命值
|
||||||
const playerHpLabel = this.player.getChildByName('hp');
|
const playerHpLabel = this.player.getChildByName('hp');
|
||||||
const monsterHpLabel = otherCollider.node.getChildByName('hp');
|
const monsterHpLabel = otherCollider.node.getChildByName('hp');
|
||||||
@@ -629,25 +731,35 @@ export class PlayerController extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 播放攻击动画
|
// 播放攻击动画
|
||||||
const monsterAnimation = otherCollider.node.getChildByName('Anim').getComponent(Animation);
|
const animNode = otherCollider.node.getChildByName('Anim');
|
||||||
|
const monsterAnimation = animNode ? animNode.getComponent(Animation) : null;
|
||||||
if (monsterAnimation) {
|
if (monsterAnimation) {
|
||||||
monsterAnimation.play(`${otherCollider.node.name}_attack`);
|
monsterAnimation.play(`${otherCollider.node.name}_attack`);
|
||||||
}
|
}
|
||||||
this.switchAnimation(this.currentDirection === 3 ? 'attack3' : 'attack5');
|
this.switchAnimation(this.currentDirection === 3 ? 'attack3' : 'attack5');
|
||||||
// this.switchAnimation('attack3');
|
|
||||||
|
|
||||||
// 1.2秒后判定攻击结果
|
// 1.2秒后判定攻击结果
|
||||||
this.scheduleOnce(async () => {
|
this.scheduleOnce(async () => {
|
||||||
|
if (!this.player || !playerLabel.isValid || !monsterLabel.isValid) {
|
||||||
|
this.isAttacking = false;
|
||||||
|
if (this.attackAudio) {
|
||||||
|
const audioSource = this.attackAudio.getComponent(AudioSource);
|
||||||
|
if (audioSource) {
|
||||||
|
audioSource.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
// 比较生命值,判断输赢
|
// 比较生命值,判断输赢
|
||||||
console.log('判定攻击结果,玩家HP:', playerHp, '怪物HP:', monsterHp);
|
console.log('判定攻击结果,玩家HP:', playerHp, '怪物HP:', monsterHp);
|
||||||
if (playerHp >= monsterHp) {
|
if (playerHp >= monsterHp) {
|
||||||
const hit = otherCollider.node.getChildByName('Hit')
|
const hit = otherCollider.node.getChildByName('Hit');
|
||||||
|
|
||||||
if (hit) {
|
if (hit) {
|
||||||
hit.active = true;
|
hit.active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.hasWinTimes++
|
this.hasWinTimes++;
|
||||||
// 玩家获胜
|
// 玩家获胜
|
||||||
console.log('玩家获胜!更新玩家生命值为:', playerHp + monsterHp);
|
console.log('玩家获胜!更新玩家生命值为:', playerHp + monsterHp);
|
||||||
|
|
||||||
@@ -665,19 +777,21 @@ export class PlayerController extends Component {
|
|||||||
|
|
||||||
// 如果是攻击 guai_2 并且成功,创建道具飞向 player 的动画
|
// 如果是攻击 guai_2 并且成功,创建道具飞向 player 的动画
|
||||||
if (otherCollider.node.name === 'guai_2') {
|
if (otherCollider.node.name === 'guai_2') {
|
||||||
await this.createPropsFlyToPlayerAnimation()
|
await this.createPropsFlyToPlayerAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1秒后怪物消失
|
// 1秒后怪物消失
|
||||||
this.scheduleOnce(() => {
|
this.scheduleOnce(() => {
|
||||||
console.log('怪物已消失');
|
if (!otherCollider.node || !otherCollider.node.isValid) {
|
||||||
console.log('otherCollider', otherCollider);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
otherCollider.node?.destroy();
|
console.log('怪物已消失');
|
||||||
|
otherCollider.node.destroy();
|
||||||
|
|
||||||
if (this.hasWinTimes === 7) {
|
if (this.hasWinTimes === 7) {
|
||||||
this.isWin = true
|
this.isWin = true;
|
||||||
this.showBonusPopup()
|
this.showBonusPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
}, 1);
|
}, 1);
|
||||||
|
|||||||
Reference in New Issue
Block a user