Role.ts 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. import { _decorator, Asset, Collider, Collider2D, Component, Contact2DType, RigidBody2D, sp, Tween, tween, Vec2, Vec3 } from 'cc';
  2. import { endPos } from '../../../ui/main/UI_Main';
  3. import { LvData } from '../../LvData/LvData';
  4. const { ccclass, property } = _decorator;
  5. export enum CollisionGroups {
  6. DEFAULT = 0,
  7. wall = 1,//墙
  8. role = 2,//人
  9. stone = 3,//石头
  10. push = 4,//推墙
  11. block = 5//方块
  12. }
  13. @ccclass('Role')
  14. export class Role extends Component {
  15. spin: sp.Skeleton;
  16. speed = 5;
  17. roleBady
  18. roleNode
  19. currentState: 'normal' | 'ku' = 'normal';
  20. private elapsedTime: number = 0;
  21. @property([sp.SkeletonData])
  22. private SkeletonData: sp.SkeletonData[] = [];
  23. private spineSkeleton: sp.Skeleton = null;
  24. reviveMoveDistance: number = 200; // 复活移动距离
  25. reviveMoveDuration: number = 1; // 移动持续时间
  26. // 新增:记录上一帧的位置
  27. private lastPosition: Vec3 = new Vec3();
  28. // 新增:记录是否处于异常移动状态
  29. private isAbnormalMovement: boolean = false;
  30. // 新增:异常移动计数器
  31. private abnormalCounter: number = 0;
  32. async start() {
  33. // 记录初始位置
  34. this.lastPosition = this.node.position.clone();
  35. this.spin = this.getComponent(sp.Skeleton);
  36. this.roleBady = this.getComponent(RigidBody2D)
  37. this.roleNode = this.getComponent(Collider2D);
  38. if (this.roleNode) {
  39. this.roleBady.enabledContactListener = true;
  40. this.roleNode.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
  41. this.roleNode.on(Contact2DType.END_CONTACT, this.onEndContact, this);
  42. }
  43. this.spineSkeleton = this.node.getComponent(sp.Skeleton);
  44. let skinId = LvData.instance.rwpf;
  45. this.changeSkin(skinId);
  46. this.startAnimationSequence();
  47. }
  48. public async reviveMove() {
  49. // 停止当前所有动作
  50. Tween.stopAllByTarget(this.node);
  51. this.elapsedTime = 0;
  52. this.currentState = 'normal';
  53. this.isAbnormalMovement = false;
  54. this.abnormalCounter = 0;
  55. this.roleBady.enabledContactListener = true;
  56. this.roleBady.enabled = true;
  57. // 获取当前位置并应用位置限制
  58. const startPos = this.node.position.clone();
  59. startPos.x = Math.min(startPos.x, 110); // 确保起始位置不越界
  60. startPos.y = Math.min(startPos.y, 135); // 确保起始位置不越界
  61. this.node.position = startPos; // 立即应用限制
  62. // 计算目标位置(带边界限制)
  63. const targetPos = startPos.clone();
  64. targetPos.x += this.reviveMoveDistance;
  65. // 应用位置限制(确保目标位置不超过110,135)
  66. targetPos.x = Math.min(targetPos.x, 110);
  67. targetPos.y = Math.min(targetPos.y, 135);
  68. // 执行移动动画
  69. await new Promise<void>((resolve) => {
  70. tween(this.node)
  71. .to(this.reviveMoveDuration,
  72. { position: targetPos },
  73. {
  74. easing: 'linear',
  75. // 添加每帧位置限制(可选,根据实际需求决定)
  76. onUpdate: (target: any, ratio: number) => {
  77. const pos = this.node.position;
  78. const newPos = new Vec3(
  79. Math.min(pos.x, 110),
  80. Math.min(pos.y, 135),
  81. pos.z
  82. );
  83. this.node.setPosition(newPos);
  84. }
  85. }
  86. )
  87. .call(() => {
  88. // 最终位置确认(防止浮点误差)
  89. const finalPos = new Vec3(
  90. Math.min(this.node.position.x, 110),
  91. Math.min(this.node.position.y, 135),
  92. this.node.position.z
  93. );
  94. this.node.setPosition(finalPos);
  95. // 恢复角色动画
  96. this.doXianJie();
  97. resolve();
  98. })
  99. .start();
  100. });
  101. this.roleBady.enabledContactListener = true;
  102. }
  103. onBeginContact(other: Collider2D, self: Collider2D) {
  104. if (other.group === (1 << CollisionGroups.stone)) {
  105. this.doPush();
  106. }
  107. }
  108. public changeSkin(newSkinId: number): void {
  109. if (newSkinId - 1 >= 0 && newSkinId - 1 < this.SkeletonData.length) {
  110. this.spineSkeleton.skeletonData = this.SkeletonData[newSkinId - 1]
  111. this.spineSkeleton.setAnimation(0, "anim_xuixi", true);
  112. }
  113. else {
  114. console.error("骨骼资源索引l越界")
  115. }
  116. }
  117. init(time) {
  118. if (!time) {
  119. time = 1
  120. }
  121. let s = this.node.position.clone().subtract(endPos.role).length()
  122. this.speed = s / time
  123. }
  124. doMove(dt: number) {
  125. // debugger
  126. // 忽略无效帧时间
  127. if (dt <= 0) return;
  128. // 计算剩余距离和剩余时间
  129. const remainingDistance = Math.max(0, this.node.position.x - endPos.role.x);
  130. const remainingTime = Math.max(0, endPos.time - this.elapsedTime);
  131. // 动态调整速度(避免除零)
  132. const dynamicSpeed = remainingTime > 0 ? remainingDistance / remainingTime : 0;
  133. const move = dynamicSpeed * dt
  134. // 记录当前位置
  135. const currentPos = this.node.position.clone();
  136. // 检查是否出现异常移动
  137. if (this.lastPosition.x > currentPos.x && this.speed > 0) {
  138. this.abnormalCounter++;
  139. if (this.abnormalCounter > 3) {
  140. this.isAbnormalMovement = true;
  141. // 尝试重置物理状态
  142. this.roleBady.linearVelocity = new Vec2(0, 0);
  143. this.roleBady.angularVelocity = 0;
  144. }
  145. } else {
  146. this.abnormalCounter = 0;
  147. this.isAbnormalMovement = false;
  148. }
  149. // 正常移动逻辑
  150. if (!this.isAbnormalMovement) {
  151. this.node.setPosition(this.node.position.x - move, this.node.position.y);
  152. } else {
  153. this.node.setPosition(this.node.position.x - move * 1.5, this.node.position.y);
  154. // 短暂禁用碰撞检测以尝试解决卡住问题
  155. this.roleBady.enabledContactListener = false;
  156. setTimeout(() => {
  157. this.roleBady.enabledContactListener = true;
  158. }, 500);
  159. }
  160. // 更新上一帧位置
  161. this.lastPosition = this.node.position.clone();
  162. //console.log("角色位置: " + this.node.position.x);
  163. }
  164. onEndContact() {
  165. // 重置异常状态
  166. this.abnormalCounter = 0;
  167. this.isAbnormalMovement = false;
  168. }
  169. startAnimationSequence() {
  170. this.doRelex();
  171. }
  172. roleDie() {
  173. if (this.node.position.x < endPos.role.x) {
  174. // 禁用物理组件
  175. this.roleBady.enabledContactListener = false;
  176. //this.roleBady.enabled = false;
  177. // 播放死亡动画
  178. this.spin.loop = false;
  179. this.spin.animation = 'ku';
  180. }
  181. }
  182. doDie() {
  183. this.spin.animation = 'anim_ku';
  184. this.spin.loop = false; // 只播放一次
  185. this.spin.setCompleteListener(() => {
  186. });
  187. }
  188. doPush() {
  189. this.spin.animation = 'anim_tui';
  190. this.spin.loop = true; // 持续循环推动动画
  191. }
  192. doRelex() {
  193. this.currentState = 'normal';
  194. this.spin.animation = 'anim_xuixi';
  195. this.spin.loop = false; // 不循环
  196. this.spin.setCompleteListener(() => {
  197. this.doXianJie(); // 休息完成后接衔接动画
  198. });
  199. }
  200. doXianJie() {
  201. this.spin.animation = 'anim_xianjie';
  202. this.spin.loop = false; // 不循环
  203. this.spin.setCompleteListener(() => {
  204. this.doPush(); // 衔接完成后进入持续推动状态
  205. });
  206. }
  207. doFlose() {
  208. this.spin.animation = 'anim_f'
  209. this.spin.loop = true;
  210. this.spin.setCompleteListener(() => {
  211. this.doPush()
  212. })
  213. }
  214. doWin() {
  215. this.spin.animation = 'anim_v'
  216. this.spin.loop = true;
  217. this.spin.setCompleteListener(() => {
  218. this.doPush()
  219. })
  220. }
  221. doJieMian() {
  222. this.spin.animation = "anim_jiemian"
  223. this.spin.loop = true;
  224. }
  225. update(deltaTime: number) {
  226. // 正常移动逻辑
  227. this.doMove(deltaTime);
  228. // 时间累计检测
  229. if (this.currentState === 'normal') {
  230. this.elapsedTime += deltaTime;
  231. // 当剩余时间不足30秒时触发
  232. if (endPos.time - this.elapsedTime < 30) {
  233. this.currentState = 'ku';
  234. this.doDie(); // 切换到哭泣动画
  235. }
  236. }
  237. }
  238. }