AIBase.ts 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. import CMath from "../../../../util/CMath";
  2. import FSprite, { SpriteActionType } from "../FSprite";
  3. import SkillBase from "../skill/SkillBase";
  4. /**
  5. * 基础AI
  6. */
  7. const {ccclass, property} = cc._decorator;
  8. /**
  9. * 基础AI设定
  10. * 1.范围巡逻
  11. * 2.攻击进入范围内的敌人
  12. * 3.距离超出后脱离战斗
  13. */
  14. @ccclass
  15. export default class AIBase extends cc.Component {
  16. /**
  17. * AI灵敏度
  18. * 发现敌人后多久开始行动
  19. */
  20. @property({
  21. displayName: '灵敏度(毫秒)'
  22. })
  23. public AI_CD:number = 1000;
  24. /**
  25. * 攻击间隔 ms
  26. * 一次攻击后间隔多久开始下次攻击
  27. */
  28. @property({
  29. displayName: '攻击间隔(毫秒)'
  30. })
  31. public atk_CD = 3000;
  32. /**
  33. * 每次攻击几颗子弹
  34. */
  35. @property({
  36. displayName: '每次攻击子弹数量'
  37. })
  38. public atk_count = 1;
  39. /**
  40. * 移动速度
  41. */
  42. @property({
  43. displayName: '移动速度'
  44. })
  45. public speed = 50;
  46. /**
  47. * 当前AI拥有的全部技能
  48. */
  49. public skills:Array<SkillBase> = null;
  50. /**
  51. * 当前AI控制的精灵
  52. */
  53. public sprite:FSprite;
  54. /**
  55. * 攻击目标
  56. */
  57. public target:FSprite;
  58. /**
  59. * 最后一次执行AI事件
  60. */
  61. public AI_Time = 0;
  62. /**
  63. * 最后一次执行攻击事件
  64. */
  65. public atk_Time = 0;
  66. /**
  67. * 是否可以释放技能
  68. */
  69. public canSkill = true;
  70. onLoad () {
  71. this.sprite = this.node.getComponent(FSprite);
  72. this.sprite.SPEED_WALK = this.speed;
  73. this.skills = this.node.getComponents(SkillBase);
  74. }
  75. public setTarget(target:FSprite){
  76. if(target != this.target){
  77. this.target = target;
  78. }
  79. }
  80. /**
  81. * 查询目标
  82. */
  83. public checkTarget():FSprite{
  84. if(this.target){
  85. if(this.target.isValid && this.target.hp > 0){
  86. }else{
  87. //死亡或者销毁后查询新的目标
  88. this.target = this.sprite.findEnemy(500).sprite;
  89. }
  90. }else{
  91. this.target = this.sprite.findEnemy(500).sprite;
  92. }
  93. return this.target;
  94. }
  95. update (dt) {
  96. if(this.sprite && this.sprite.isActive){
  97. if(this.sprite.gamePause){
  98. return;
  99. }
  100. this.AI();
  101. }
  102. }
  103. public AI(){
  104. //查询是否有可攻击目标
  105. //查询是否有可用技能
  106. //查询可用技能是否在当前技能攻击范围以内
  107. //超出范围,执行AI移动
  108. //执行巡逻任务
  109. if(!this.canSkill){
  110. return;
  111. }
  112. let time = new Date().getTime();
  113. let target = this.checkTarget();
  114. if(target){
  115. if(this.skills.length > 0){
  116. let skill = this.checkSkill(target);
  117. if(skill){
  118. // cc.log('开始使用技能 :',skill)
  119. this.canSkill = false;
  120. skill.exe(target,()=>{
  121. this.canSkill = true;
  122. // cc.log('技能使用结束 :',skill)
  123. });
  124. }else{
  125. if(this.AI_Time == 0){
  126. this.AI_Time = time;
  127. }else if(time - this.AI_Time > this.AI_CD){
  128. this.AI_Time = time;
  129. this.walk(this.sprite.mButtleDis);
  130. }
  131. }
  132. } else{
  133. if(time - this.atk_Time > this.atk_CD){
  134. this.atk_Time = time;
  135. this.fire(target);
  136. }
  137. }
  138. }else{
  139. if(this.AI_Time == 0){
  140. this.AI_Time = time;
  141. }else if(time - this.AI_Time > this.AI_CD){
  142. this.AI_Time = time;
  143. this.walk(this.sprite.mButtleDis);
  144. }
  145. }
  146. }
  147. /**
  148. * 查询可用技能
  149. */
  150. public checkSkill(target:FSprite):SkillBase{
  151. let lists:Array<SkillBase> = [];
  152. for (let i = 0; i < this.skills.length; i++) {
  153. const element = this.skills[i];
  154. if(element.ready()){
  155. lists.push(element);
  156. }
  157. }
  158. if(lists.length <= 0){
  159. return null;
  160. }else{
  161. let p1 = this.node.getPosition();
  162. let p2 = target.node.getPosition();
  163. let dis = cc.Vec2.distance(p1,p2);
  164. let fList = [];
  165. for (let i = 0; i < lists.length; i++) {
  166. const element = lists[i];
  167. if(dis < element.range){
  168. fList.push(element);
  169. }
  170. }
  171. if(fList.length <= 0){
  172. this.moveToTarget(target);
  173. return null;
  174. }else{
  175. this.sprite.playAction(SpriteActionType.stand,true)
  176. let index = CMath.getRandom(0,fList.length-1);
  177. return fList[index];
  178. }
  179. }
  180. }
  181. /**
  182. * 向目标移动
  183. * @param target
  184. */
  185. private moveToTarget(target:FSprite){
  186. this.sprite.playAction(SpriteActionType.move,true)
  187. let p1 = target.node.getPosition();
  188. let p2 = this.sprite.node.getPosition();
  189. this.atk_Time = 0;
  190. let tmp = {
  191. x:0,
  192. y:0
  193. }
  194. let px1 = p1.x - p2.x;
  195. if(Math.abs(px1) < 50){
  196. tmp.x = 0;
  197. }else if(px1 > 0){
  198. tmp.x = 1;
  199. }else{
  200. tmp.x = -1;
  201. }
  202. let py1 = p1.y - p2.y;
  203. if(Math.abs(py1) < 50){
  204. tmp.y = 0;
  205. }else if(py1 > 0){
  206. tmp.y = 1;
  207. }else{
  208. tmp.y = -1;
  209. }
  210. this.sprite.setDir(tmp);
  211. }
  212. public fire(target:FSprite){
  213. //判断是否在攻击范围内
  214. let mts = this.sprite.mButtleDis;
  215. let p1 = target.node.getPosition();
  216. let p2 = this.sprite.node.getPosition();
  217. let dis = cc.Vec2.distance(p1,p2);
  218. if(dis > mts){
  219. this.moveToTarget(target);
  220. }else{
  221. this.sprite.setDir({x:0,y:0});
  222. this.sprite.setShooting(true);
  223. let count = 0;
  224. this.canSkill = false;
  225. this.sprite.setFireCallback(()=>{
  226. count ++;
  227. if(count >= this.atk_count){
  228. this.sprite.setShooting(false);
  229. this.sprite.setFireCallback(null);
  230. cc.tween(this).delay(0.7).call(()=>{
  231. this.walk(this.sprite.mButtleDis);
  232. }).start();
  233. }
  234. });
  235. }
  236. }
  237. /**
  238. * 远程怪物的闲逛
  239. */
  240. public walk(distance){
  241. cc.tween(this).delay(0).call(()=>{
  242. this.sprite.setDir(this.getRandState(distance));
  243. this.sprite.playAction(SpriteActionType.move,true)
  244. }).delay(0.5).call(()=>{
  245. this.canSkill = true;
  246. this.sprite.setDir({x:0,y:0});
  247. this.sprite.playAction(SpriteActionType.stand,true)
  248. }).start();
  249. }
  250. public getRandState(distance){
  251. if(this.target && this.target.isValid && this.target.hp > 0){//如果有目标
  252. let p1 = this.target.node.getPosition();
  253. let p2 = this.sprite.node.getPosition();
  254. let distance = this.sprite.mButtleDis;
  255. let dis = CMath.getDistance(p1,p2);
  256. if(dis > 150){
  257. let tmp = {
  258. x:0,
  259. y:0
  260. }
  261. let px1 = p1.x - p2.x;
  262. if(Math.abs(px1) < 50){
  263. tmp.x = 0;
  264. }else if(px1 > 0){
  265. tmp.x = 1;
  266. }else{
  267. tmp.x = -1;
  268. }
  269. let py1 = p1.y - p2.y;
  270. if(Math.abs(py1) < 50){
  271. tmp.y = 0;
  272. }else if(py1 > 0){
  273. tmp.y = 1;
  274. }else{
  275. tmp.y = -1;
  276. }
  277. return tmp;
  278. }
  279. // else if(dis < 100){
  280. // let tmp = {
  281. // x:0,
  282. // y:0
  283. // }
  284. // let px1 = p1.x - p2.x;
  285. // if(Math.abs(px1) < 50){
  286. // tmp.x = 0;
  287. // }else if(px1 > 0){
  288. // tmp.x = -1;
  289. // }else{
  290. // tmp.x = 1;
  291. // }
  292. // let py1 = p1.y - p2.y;
  293. // if(Math.abs(py1) < 50){
  294. // tmp.y = 0;
  295. // }else if(py1 > 0){
  296. // tmp.y = -1;
  297. // }else{
  298. // tmp.y = 1;
  299. // }
  300. // return tmp;
  301. // }
  302. }
  303. let rand = CMath.getRandom(1,80);
  304. if(rand < 10){
  305. return {x:1,y:0};
  306. }else if(rand < 20){
  307. return {x:1,y:1};
  308. }else if(rand < 30){
  309. return {x:1,y:-1};
  310. }else if(rand < 40){
  311. return {x:0,y:1};
  312. }else if(rand < 50){
  313. return {x:0,y:-1};
  314. }else if(rand < 60){
  315. return {x:-1,y:0};
  316. }else if(rand < 70){
  317. return {x:-1,y:1};
  318. }else{
  319. return {x:-1,y:1};
  320. }
  321. }
  322. }