GMap.ts 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import { _decorator, easing, MeshRenderer, Node, tween, Vec3 } from 'cc';
  2. import { BaseExp } from '../core/base/BaseExp';
  3. import { autoBind } from '../extend/AutoBind';
  4. import { Utils } from '../utils/Utils';
  5. const { ccclass, property } = _decorator;
  6. //埋伏点接口类
  7. export class AmbushPoint {
  8. //埋伏点位置节点数组
  9. public standPosArr: Vec3[] = [];
  10. //中间路径节点
  11. public roadPosArr: Vec3[] = [];
  12. //掩体点位置节点
  13. public ambushPosArr: Vec3[] = [];
  14. //逃跑点位置节点
  15. public escapePosArr: Vec3[] = [];
  16. //是否已经有人在此站位了
  17. public isVacancy: boolean = false;
  18. }
  19. @ccclass('GMap')
  20. export class GMap extends BaseExp {
  21. @autoBind({ type: Node, tooltip: "埋伏点配置节点" })
  22. public ambush_points: Node = null;
  23. @autoBind({type:Node,tooltip:"敌人出生区域"})
  24. public enemy_born_area: Node = null;
  25. @autoBind({type:Node,tooltip:"进门内线,用于敌人是否在门内"})
  26. public miidle_inline: Node = null;
  27. @autoBind({type:Node,tooltip:"进门外线,用于敌人是否在门外"})
  28. public miidle_outline: Node = null;
  29. @autoBind({type:Node,tooltip:"进去的大门"})
  30. public doors: Node = null;
  31. @autoBind({type:Node,tooltip:"杂物节点,处理连环爆炸"})
  32. public sundries: Node = null;
  33. //埋伏点配置数组
  34. public ambushPoints: AmbushPoint[] = [];
  35. //游戏速度
  36. public game_speed: number = 1;
  37. start() {
  38. /*测试时使用 玩家坐标转换
  39. let n: Node = this.node.getChildByName('player_points');
  40. let pwww:Vec3 = Utils.convertPosition(this.node.getChildByName("player"),n);
  41. console.log("GGGGGGG = " + pwww);*/
  42. //区域隐藏
  43. const nodes:Node[] = this.ambush_points.children.flatMap(child => child.children);
  44. [this.enemy_born_area,this.miidle_inline,this.miidle_outline]
  45. .concat(nodes).forEach(e => {
  46. e.active = false;
  47. });
  48. }
  49. /**
  50. * 开门动画
  51. */
  52. public openDoor(){
  53. const left: Node = this.doors.children[0];
  54. if(left){//左门动画
  55. tween(left)
  56. .delay(0.2)
  57. .to(0.7, { eulerAngles: new Vec3(90, 0, 0) }, {
  58. easing: easing.elasticOut,
  59. onUpdate: (target, ratio: number) => {
  60. target.setRotationFromEuler(target.eulerAngles);
  61. }
  62. })
  63. .start();
  64. }
  65. const right: Node = this.doors.children[1];
  66. if(right){//右门动画
  67. tween(right)
  68. .to(0.7, { eulerAngles: new Vec3(90, 0, 0) }, {
  69. easing: easing.elasticOut,
  70. onUpdate: (target, ratio: number) => {
  71. target.setRotationFromEuler(target.eulerAngles);
  72. }
  73. })
  74. .start();
  75. }
  76. }
  77. /**
  78. * 游戏速度
  79. */
  80. public multiplySpeed(): number{
  81. return this.game_speed;
  82. }
  83. /**
  84. * 解析埋伏点
  85. */
  86. private parseAmbushPoints() {
  87. this.ambushPoints = this.ambush_points.children
  88. .filter(e=>e.active)
  89. .map(ambushNode => {
  90. const point = new AmbushPoint();
  91. point.isVacancy = false;
  92. //从节点结构获取坐标配置
  93. point.standPosArr = ambushNode.children
  94. .filter(e => e.name.startsWith('stand_'))
  95. .map(node => node.worldPosition.clone());
  96. point.roadPosArr = ambushNode.children
  97. .filter(e => e.name.startsWith('road_'))
  98. .sort((a, b) => {
  99. //提取数字部分(兼容 road_1 / road_01 / road_001 等所有情况)
  100. const getNumber = (name: string) => {
  101. const numPart = name.split('_').pop(); // 取最后一段
  102. return parseInt(numPart || '0', 10); // 自动忽略前导零
  103. };
  104. return getNumber(a.name) - getNumber(b.name); // 按数值升序
  105. })
  106. .map(node => node.worldPosition.clone());
  107. point.ambushPosArr = ambushNode.children
  108. .filter(e => e.name.startsWith('bunker_'))
  109. .map(node => node.worldPosition.clone());
  110. point.escapePosArr = ambushNode.children
  111. .filter(e => e.name.startsWith('escape_'))
  112. .map(node => node.worldPosition.clone());
  113. return point;
  114. });
  115. }
  116. /**
  117. * 根据敌人信息得到敌人行走路径
  118. * @param eData 敌人数据
  119. * @param size 预制体大小
  120. * @returns
  121. */
  122. public getPaths(eData: any){
  123. let bornPos: Vec3 = this.getRandomBornPosition();
  124. //进入外门时的坐标
  125. const outerPos: Vec3 = this.getRandomPos(eData,this.miidle_outline);
  126. //进入内门时的坐标
  127. const innerPos: Vec3 = this.getRandomPos(eData,this.miidle_inline);
  128. //行走路径
  129. let paths: Array<Vec3> = [bornPos,outerPos,innerPos];
  130. //最后一个点特殊处理 包含(站位点、埋伏点、逃跑点) 随机一个埋伏点
  131. const ambush: AmbushPoint = this.getAmbushClas();
  132. ambush.isVacancy = true;
  133. eData.ambush = ambush;
  134. //查找中间路径点
  135. paths = paths.concat(ambush.roadPosArr);
  136. //随机一个站立点到最后坐标
  137. const endPos:Vec3 = Utils.randomArray(ambush.standPosArr)[0];
  138. endPos.x += Utils.getRandomFloat(0,0.35);
  139. paths.push(endPos);
  140. //测试时使用
  141. /*paths.forEach(e => {
  142. console.log("FFFFFF = " + this.node.getComponent(UITransform).convertToNodeSpaceAR(e));
  143. });*/
  144. return paths;
  145. }
  146. /**
  147. * 得到一个站位点
  148. */
  149. private getAmbushClas(){
  150. if(!this.ambushPoints
  151. || this.ambushPoints.length <= 0){
  152. //埋伏点类解析
  153. this.parseAmbushPoints();
  154. }
  155. //获取所有可用的埋伏点(未被占用的)
  156. const availablePoints = this.ambushPoints.filter(p => !p.isVacancy);
  157. if (availablePoints.length > 0) {
  158. //随机返回一个可用埋伏点
  159. return Utils.randomArray(availablePoints)[0];
  160. }
  161. //当所有点位都被占用时,随机返回任意一个
  162. if(this.ambushPoints.length > 0) {
  163. return Utils.randomArray(this.ambushPoints)[0];
  164. }
  165. return null;
  166. }
  167. /**
  168. * 根据两个坐标点产生一个两个坐标点之前的随机点
  169. */
  170. public getRandomPos(eData:any,target: Node): Vec3 {
  171. //只有坦克走中间
  172. const isTan: boolean = eData.id == 20003;
  173. if(isTan){
  174. return target.worldPosition.clone();
  175. }
  176. let basePos: Vec3 = target.children[0].worldPosition.clone();
  177. if(target.children.length >= 2){
  178. let pos1: Vec3 = target.children[0].worldPosition.clone();
  179. let pos2: Vec3 = target.children[1].worldPosition.clone();
  180. //生成0-1的随机比例因子
  181. const ratio = Utils.getRandomFloat(0, 1);
  182. //分别在x和z轴进行线性插值 这儿为了看起来暂时保留x轴上的距离随机
  183. basePos.x = pos1.x + (pos2.x - pos1.x) * ratio;
  184. //y轴就是左边的间隔的距离
  185. basePos.z = pos1.z + (pos2.z - pos1.z) * ratio;
  186. }
  187. return basePos;
  188. }
  189. /**
  190. * 获取随机出生点位置
  191. */
  192. public getRandomBornPosition(): Vec3 {
  193. if (!this.enemy_born_area) return Vec3.ZERO;
  194. //获取3D节点的世界缩放
  195. const worldScale = this.enemy_born_area.getWorldScale();
  196. //使用X和Z轴缩放作为区域尺寸
  197. const areaWidth = worldScale.x;
  198. const areaDepth = worldScale.z;
  199. //在XZ平面生成随机坐标(Y轴保持地面高度)
  200. const randomX = (Math.random() - 0.5) * areaWidth;
  201. const randomZ = (Math.random() - 0.5) * areaDepth;
  202. //基于节点原点位置生成世界坐标 保持与出生区域相同高度
  203. const basePos = this.enemy_born_area.worldPosition;
  204. return new Vec3(
  205. basePos.x + randomX,
  206. basePos.y,
  207. basePos.z + randomZ
  208. );
  209. }
  210. /**
  211. * 还原数据
  212. */
  213. public resetData(){
  214. this.ambushPoints.forEach(e => {
  215. e.isVacancy = false;
  216. });
  217. }
  218. }