import { _decorator, Asset, Collider, Collider2D, Component, Contact2DType, RigidBody2D, sp, Tween, tween, Vec2, Vec3 } from 'cc'; import { endPos } from '../../../ui/main/UI_Main'; import { LvData } from '../../LvData/LvData'; const { ccclass, property } = _decorator; export enum CollisionGroups { DEFAULT = 0, wall = 1,//墙 role = 2,//人 stone = 3,//石头 push = 4,//推墙 block = 5//方块 } @ccclass('Role') export class Role extends Component { spin: sp.Skeleton; speed = 5; roleBady roleNode currentState: 'normal' | 'ku' = 'normal'; private elapsedTime: number = 0; @property([sp.SkeletonData]) private SkeletonData: sp.SkeletonData[] = []; private spineSkeleton: sp.Skeleton = null; reviveMoveDistance: number = 200; // 复活移动距离 reviveMoveDuration: number = 1; // 移动持续时间 // 新增:记录上一帧的位置 private lastPosition: Vec3 = new Vec3(); // 新增:记录是否处于异常移动状态 private isAbnormalMovement: boolean = false; // 新增:异常移动计数器 private abnormalCounter: number = 0; async start() { // 记录初始位置 this.lastPosition = this.node.position.clone(); this.spin = this.getComponent(sp.Skeleton); this.roleBady = this.getComponent(RigidBody2D) this.roleNode = this.getComponent(Collider2D); if (this.roleNode) { this.roleBady.enabledContactListener = true; this.roleNode.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); this.roleNode.on(Contact2DType.END_CONTACT, this.onEndContact, this); } this.spineSkeleton = this.node.getComponent(sp.Skeleton); let skinId = LvData.instance.rwpf; this.changeSkin(skinId); this.startAnimationSequence(); } public async reviveMove() { // 停止当前所有动作 Tween.stopAllByTarget(this.node); this.elapsedTime = 0; this.currentState = 'normal'; this.isAbnormalMovement = false; this.abnormalCounter = 0; this.roleBady.enabledContactListener = true; this.roleBady.enabled = true; // 获取当前位置并应用位置限制 const startPos = this.node.position.clone(); startPos.x = Math.min(startPos.x, 110); // 确保起始位置不越界 startPos.y = Math.min(startPos.y, 135); // 确保起始位置不越界 this.node.position = startPos; // 立即应用限制 // 计算目标位置(带边界限制) const targetPos = startPos.clone(); targetPos.x += this.reviveMoveDistance; // 应用位置限制(确保目标位置不超过110,135) targetPos.x = Math.min(targetPos.x, 110); targetPos.y = Math.min(targetPos.y, 135); // 执行移动动画 await new Promise((resolve) => { tween(this.node) .to(this.reviveMoveDuration, { position: targetPos }, { easing: 'linear', // 添加每帧位置限制(可选,根据实际需求决定) onUpdate: (target: any, ratio: number) => { const pos = this.node.position; const newPos = new Vec3( Math.min(pos.x, 110), Math.min(pos.y, 135), pos.z ); this.node.setPosition(newPos); } } ) .call(() => { // 最终位置确认(防止浮点误差) const finalPos = new Vec3( Math.min(this.node.position.x, 110), Math.min(this.node.position.y, 135), this.node.position.z ); this.node.setPosition(finalPos); // 恢复角色动画 this.doXianJie(); resolve(); }) .start(); }); this.roleBady.enabledContactListener = true; } onBeginContact(other: Collider2D, self: Collider2D) { if (other.group === (1 << CollisionGroups.stone)) { this.doPush(); } } public changeSkin(newSkinId: number): void { if (newSkinId - 1 >= 0 && newSkinId - 1 < this.SkeletonData.length) { this.spineSkeleton.skeletonData = this.SkeletonData[newSkinId - 1] this.spineSkeleton.setAnimation(0, "anim_xuixi", true); } else { console.error("骨骼资源索引l越界") } } init(time) { if (!time) { time = 1 } let s = this.node.position.clone().subtract(endPos.role).length() this.speed = s / time } doMove(dt: number) { // debugger // 忽略无效帧时间 if (dt <= 0) return; // 计算剩余距离和剩余时间 const remainingDistance = Math.max(0, this.node.position.x - endPos.role.x); const remainingTime = Math.max(0, endPos.time - this.elapsedTime); // 动态调整速度(避免除零) const dynamicSpeed = remainingTime > 0 ? remainingDistance / remainingTime : 0; const move = dynamicSpeed * dt // 记录当前位置 const currentPos = this.node.position.clone(); // 检查是否出现异常移动 if (this.lastPosition.x > currentPos.x && this.speed > 0) { this.abnormalCounter++; if (this.abnormalCounter > 3) { this.isAbnormalMovement = true; // 尝试重置物理状态 this.roleBady.linearVelocity = new Vec2(0, 0); this.roleBady.angularVelocity = 0; } } else { this.abnormalCounter = 0; this.isAbnormalMovement = false; } // 正常移动逻辑 if (!this.isAbnormalMovement) { this.node.setPosition(this.node.position.x - move, this.node.position.y); } else { this.node.setPosition(this.node.position.x - move * 1.5, this.node.position.y); // 短暂禁用碰撞检测以尝试解决卡住问题 this.roleBady.enabledContactListener = false; setTimeout(() => { this.roleBady.enabledContactListener = true; }, 500); } // 更新上一帧位置 this.lastPosition = this.node.position.clone(); //console.log("角色位置: " + this.node.position.x); } onEndContact() { // 重置异常状态 this.abnormalCounter = 0; this.isAbnormalMovement = false; } startAnimationSequence() { this.doRelex(); } roleDie() { if (this.node.position.x < endPos.role.x) { // 禁用物理组件 this.roleBady.enabledContactListener = false; //this.roleBady.enabled = false; // 播放死亡动画 this.spin.loop = false; this.spin.animation = 'ku'; } } doDie() { this.spin.animation = 'anim_ku'; this.spin.loop = false; // 只播放一次 this.spin.setCompleteListener(() => { }); } doPush() { this.spin.animation = 'anim_tui'; this.spin.loop = true; // 持续循环推动动画 } doRelex() { this.currentState = 'normal'; this.spin.animation = 'anim_xuixi'; this.spin.loop = false; // 不循环 this.spin.setCompleteListener(() => { this.doXianJie(); // 休息完成后接衔接动画 }); } doXianJie() { this.spin.animation = 'anim_xianjie'; this.spin.loop = false; // 不循环 this.spin.setCompleteListener(() => { this.doPush(); // 衔接完成后进入持续推动状态 }); } doFlose() { this.spin.animation = 'anim_f' this.spin.loop = true; this.spin.setCompleteListener(() => { this.doPush() }) } doWin() { this.spin.animation = 'anim_v' this.spin.loop = true; this.spin.setCompleteListener(() => { this.doPush() }) } doJieMian() { this.spin.animation = "anim_jiemian" this.spin.loop = true; } update(deltaTime: number) { // 正常移动逻辑 this.doMove(deltaTime); // 时间累计检测 if (this.currentState === 'normal') { this.elapsedTime += deltaTime; // 当剩余时间不足30秒时触发 if (endPos.time - this.elapsedTime < 30) { this.currentState = 'ku'; this.doDie(); // 切换到哭泣动画 } } } }