GMap.ts 10 KB

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