GameController.ts 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. import { AnimationComponent, CameraComponent, director, find, GraphicsComponent, instantiate, loader, Node, Prefab, Vec3, _decorator } from 'cc';
  2. import { EventDispatcher } from '../../../engines/events/EventDispatcher';
  3. import { GUIManager } from '../../../engines/gui/GUIManager';
  4. import { CameraUtils } from '../../../engines/utils/CameraUtils';
  5. import GameConfigManager from '../../models/GameConfigManager';
  6. import { GameModel } from '../../models/GameModel';
  7. import { FightingScene } from '../../scenes/FightingScene';
  8. import { UIConst } from '../UIConst';
  9. import { FenceBase } from './fences/FenceBase';
  10. import { FightingMediator } from './FightingMediator';
  11. import { MonsterBase } from './monsters/MonsterBase';
  12. import { MonsterHPUIPool } from './monsters/MonsterHPUIPool';
  13. import { SkillBase } from './skills/SkillBase';
  14. import SkillManager from './skills/SkillManager';
  15. import AutomaticFifleWeapon from './weapons/AutomaticFifleWeapon';
  16. import { SingleShotWeapon } from './weapons/SingleShotWeapon';
  17. import { WeaponBase } from './weapons/WeaponBase';
  18. const { ccclass, property } = _decorator;
  19. export class GameController extends EventDispatcher{
  20. public weapon:WeaponBase;
  21. public fence:FenceBase;
  22. public camera:CameraComponent;
  23. public leftEndNode:Node;
  24. public middleEndNode:Node;
  25. public rightEndNode:Node;
  26. public leftStartNode:Node;
  27. public middleStartNode:Node;
  28. public rightStartNode:Node;
  29. /**
  30. * 当前正在运行的技能
  31. */
  32. public currentSkill:SkillBase;
  33. /**
  34. * 游戏结束
  35. */
  36. public GameOver:boolean=true;
  37. public leftMonsterList:MonsterBase[];
  38. public middleMonsterList:MonsterBase[];
  39. public rightMonsterList:MonsterBase[];
  40. /**
  41. * 怪物弹痕预制体
  42. */
  43. public monsterZhouDanPrefab:Prefab;
  44. /**
  45. * 怪物血条层
  46. */
  47. public monsterHPUILayer:Node;
  48. /**
  49. * 关卡配置
  50. */
  51. public levelConfig:any;
  52. private monstersConfig:any[];
  53. /**
  54. * 这一关怪物数量
  55. */
  56. public monsterTotalCount:number;
  57. /**
  58. * 本局游戏时间
  59. */
  60. private runTime:number=0;
  61. private fightingMediator:FightingMediator;
  62. constructor()
  63. {
  64. super();
  65. this.leftMonsterList=[];
  66. this.middleMonsterList=[];
  67. this.rightMonsterList=[];
  68. }
  69. /**
  70. * 初始化
  71. * @param leftHand
  72. * @param rightHand
  73. */
  74. Init(uiMediator:FightingMediator):void{
  75. this.fightingMediator=uiMediator;
  76. let sceneNode:Node=find("FightingScene");
  77. if(sceneNode==null){
  78. throw new Error("找不到战斗场景节点!");
  79. }
  80. let sceneScript:FightingScene=sceneNode.getComponent(FightingScene);
  81. if(sceneNode==null){
  82. throw new Error("战斗场景上没有挂载FightingScene脚本!");
  83. }
  84. this.camera=sceneScript.camrea;
  85. this.leftStartNode=sceneScript.LeftStartPos;
  86. this.middleStartNode=sceneScript.MiddleStartPos;
  87. this.rightStartNode=sceneScript.RightStartPos;
  88. this.leftEndNode=sceneScript.LeftEndPos;
  89. this.middleEndNode=sceneScript.MiddleEndPos;
  90. this.rightEndNode=sceneScript.RightEndPos;
  91. this.monsterZhouDanPrefab=sceneScript.monsterZhouDanPrefab;
  92. this.weapon=this.CreateWeapon(sceneScript.leftHand,sceneScript.rightHand);
  93. this.StartGame();
  94. }
  95. /**
  96. * 改变栅栏
  97. */
  98. ChangeFence():void{
  99. this.GameOver=true;
  100. this.paused=true;
  101. let config:any=GameConfigManager.GetFenceConfig(GameModel.single.fenceId);
  102. // let prefab:Prefab=loader.getRes(config.prefab);
  103. // if(prefab==null){
  104. // throw new Error("栅栏资源未加载!");
  105. // }
  106. loader.loadRes(config.prefab,Prefab,(err,prefab:Prefab)=>{
  107. if(err!=null){
  108. throw new Error("栅栏加载出错!");
  109. }
  110. //如果老的存在,先清理
  111. if(this.fence&&this.fence.node!=null){
  112. this.fence.node.destroy();
  113. this.fence=null;
  114. }
  115. let fenceNode:Node=instantiate(prefab);
  116. this.fence=fenceNode.getComponent(FenceBase);
  117. this.fence.config=config;
  118. this.fence.node.setPosition(new Vec3(0,0,-2));
  119. this.scene.addChild(fenceNode);
  120. this.GameOver=false;
  121. this.paused=false;
  122. });
  123. }
  124. /**
  125. * 开始游戏
  126. */
  127. StartGame():void{
  128. GameModel.single.killCount=0;
  129. GameModel.single.angerCount=0;
  130. GameModel.single.integral=0;
  131. //重置技能
  132. this.SkillReset();
  133. this.levelConfig=GameConfigManager.GetLevelConfig(GameModel.single.currentLevel);
  134. this.runTime=0;
  135. //复制一份配置
  136. this.monstersConfig=GameConfigManager.CreateMonsterByList(this.levelConfig.monsters,this.runTime);
  137. this.monsterTotalCount=this.monstersConfig.length;
  138. //直接重置子弹数量
  139. this.weapon.bulletCount=GameConfigManager.GetWeaponConfig(GameModel.single.currentWeaponId).clip;
  140. //初始化栅栏
  141. this.ChangeFence();
  142. }
  143. /**
  144. * 游戏结束
  145. * @param state 0 胜利 1 失败 2正常退出
  146. */
  147. OnGameOver(state:number):void{
  148. //清理怪物
  149. this.ClearMonsters();
  150. //清理武器
  151. this.weapon.Destroy();
  152. //销毁栅栏
  153. if(this.fence.node){
  154. this.fence.node.destroy();
  155. }
  156. if(state==0){
  157. GUIManager.single.Show(UIConst.GAME_OVER_UI,true);
  158. }else if(state==1)
  159. {
  160. GUIManager.single.Show(UIConst.GAME_OVER_UI,false);
  161. }
  162. GUIManager.single.Hide(UIConst.FIGHTING_UI);
  163. this.GameOver=true;
  164. }
  165. paused:boolean;
  166. /**
  167. * 暂停游戏
  168. */
  169. PauseGame():void{
  170. this.paused=true;
  171. }
  172. /**
  173. * 继续游戏
  174. */
  175. PlayGame():void{
  176. this.paused=false;
  177. }
  178. /**
  179. * 重玩
  180. */
  181. Replay():void{
  182. this.StartGame();
  183. GUIManager.single.Show(UIConst.FIGHTING_UI);
  184. }
  185. /**
  186. * 开始下一关
  187. */
  188. PlayNextLevel():void{
  189. //清空试用栅栏
  190. GameModel.single.trialFenceId=-1;
  191. console.log(GameModel.single.currentLevel);
  192. this.StartGame();
  193. GUIManager.single.Show(UIConst.FIGHTING_UI);
  194. }
  195. /**
  196. * 清理怪物
  197. */
  198. ClearMonsters():void{
  199. this.clearMonsterList(this.leftMonsterList);
  200. this.clearMonsterList(this.middleMonsterList);
  201. this.clearMonsterList(this.rightMonsterList);
  202. }
  203. private clearMonsterList(list:MonsterBase[]):void{
  204. if(list.length>0){
  205. list.forEach(element => {
  206. if(element.node!=null&&element.node.isValid){
  207. element.node.destroy();
  208. }
  209. });
  210. }
  211. list.length=0;
  212. }
  213. TryFire(fireKey:number):void{
  214. if(this.currentSkill!=null&&this.currentSkill.unController){
  215. return;
  216. }
  217. if(fireKey==0){
  218. this.weapon.StopFire();
  219. }else{
  220. this.weapon.StartFire(fireKey);
  221. }
  222. }
  223. /**
  224. * 使用技能
  225. */
  226. UseSkill():void{
  227. if(this.currentSkill!=null){
  228. return;
  229. }
  230. //重置子弹数量
  231. this.weapon.bulletCount=this.weapon.maxBulletCount;
  232. this.currentSkill=SkillManager.single.Create(this.weapon.weaponConfig.skill);
  233. this.currentSkill.config=GameConfigManager.GetSkillConfig(this.weapon.weaponConfig.skill);
  234. this.currentSkill.AddEvent(SkillBase.SKILL_COMPLETE,this,this.SkillReset,0);
  235. this.currentSkill.UseSkill(this.weapon,this);
  236. GameModel.single.angerCount=0;
  237. }
  238. /**
  239. * 清除技能
  240. */
  241. private SkillReset():void{
  242. if(this.currentSkill!=null){
  243. this.currentSkill.RemoveEvent(SkillBase.SKILL_COMPLETE,this,this.SkillReset);
  244. this.currentSkill.Dispose();
  245. this.currentSkill=null;
  246. }
  247. }
  248. Update(dt:number):void{
  249. if(this.paused){
  250. return;
  251. }
  252. if(this.GameOver){
  253. return;
  254. }
  255. if(this.currentSkill!=null){
  256. this.currentSkill.Update(dt);
  257. }
  258. this.runTime+=dt*1000;
  259. this.weapon.Update(dt);
  260. this.CheckMonster();
  261. }
  262. get drawingBoard():GraphicsComponent{
  263. return this.fightingMediator.DrawingBoard;
  264. }
  265. /**
  266. * 检测怪物
  267. */
  268. CheckMonster():void{
  269. if(this.monstersConfig.length>0){
  270. let config:any;
  271. let monster:Node;
  272. for (let index = 0; index < this.monstersConfig.length; index++) {
  273. config = this.monstersConfig[index];
  274. if(this.runTime>=config.createTime){
  275. //根据配置创建怪物
  276. monster=this.CreateMonster(config);
  277. this.scene.addChild(monster);
  278. this.monstersConfig.splice(index,1);
  279. index--;
  280. }
  281. }
  282. }
  283. if(this.monstersConfig.length==0&&this.leftMonsterList.length==0&&this.middleMonsterList.length==0&&this.rightMonsterList.length==0){
  284. //全部怪物死亡
  285. console.log("通关");
  286. GameModel.single.currentLevel++;
  287. if(GameModel.single.currentLevel>=GameConfigManager.MaxLevel){
  288. GameModel.single.currentLevel=GameConfigManager.MaxLevel;
  289. }
  290. this.OnGameOver(0);
  291. }
  292. }
  293. /**
  294. * 怪物攻击
  295. * @param damage 伤害
  296. */
  297. MonsterAttack(attackType:number,damage:number):void{
  298. if(this.GameOver){
  299. return;
  300. }
  301. if(attackType==0){
  302. if(this.fence.IsDie==false){
  303. this.fence.Damage(damage);
  304. let cameraUtils:CameraUtils=this.camera.getComponent(CameraUtils);
  305. if(cameraUtils!=null){
  306. cameraUtils.shake(500,new Vec3(-0.01,-0.01,0),new Vec3(0.01,0.01,0));
  307. }
  308. }
  309. }else{
  310. this.OnGameOver(1);
  311. }
  312. }
  313. /**
  314. * 是否有怪物可攻击 -1没有可攻击怪 0 左边 1中间 2右边
  315. */
  316. public get FindAttackMonsterPosType():number{
  317. let leftDis:number=this.NearestDistance(this.leftMonsterList);
  318. let middleDis:number=this.NearestDistance(this.middleMonsterList);
  319. let rightDis:number=this.NearestDistance(this.rightMonsterList);
  320. if(leftDis<middleDis&&leftDis<rightDis){
  321. return 0;
  322. }
  323. if(middleDis<leftDis&&middleDis<rightDis){
  324. return 1;
  325. }
  326. if(rightDis<leftDis&&rightDis<middleDis){
  327. return 2;
  328. }
  329. return -1;
  330. }
  331. /**
  332. * 就算这一路中可攻击怪的最近距离
  333. * @param monsterList
  334. */
  335. private NearestDistance(monsterList:MonsterBase[]):number{
  336. let monster:MonsterBase;
  337. let endNode:Node;
  338. let minDis:number=Number.MAX_VALUE;
  339. let dis:number;
  340. for (let index = 0; index < monsterList.length; index++) {
  341. monster = monsterList[index];
  342. if(monster.config.startPos==0){
  343. endNode=this.leftEndNode;
  344. }else if(monster.config.startPos==1){
  345. endNode=this.middleEndNode;
  346. }else{
  347. endNode=this.rightEndNode;
  348. }
  349. dis=Vec3.distance(monster.node.worldPosition,endNode.worldPosition);
  350. if(dis<=this.weapon.weaponConfig.attackDistance){
  351. if(dis<minDis){
  352. minDis=dis;
  353. }
  354. }
  355. }
  356. return minDis;
  357. }
  358. /**
  359. * 武器攻击
  360. */
  361. WeaponAttack():void{
  362. //只要开了第一枪就不算新玩家了
  363. GameModel.single.isNewPlayer=false;
  364. let monsterList:MonsterBase[];
  365. let monsterLists:Array<Array<MonsterBase>>=[];
  366. //攻击1条路
  367. if(this.weapon.weaponConfig.attackRange==1){
  368. if(this.weapon.fireKey==1){
  369. monsterList=this.leftMonsterList;
  370. }else if(this.weapon.fireKey==2){
  371. monsterList=this.middleMonsterList;
  372. }else{
  373. monsterList=this.rightMonsterList;
  374. }
  375. if(monsterList.length==0){
  376. return;
  377. }
  378. monsterList.sort(this.monsterSortFunc);
  379. monsterLists.push(monsterList);
  380. }else if(this.weapon.weaponConfig.attackRange==2){//攻击2条路
  381. //左
  382. if(this.weapon.fireKey==1){
  383. if(this.leftMonsterList.length>0){
  384. this.leftMonsterList.sort(this.monsterSortFunc);
  385. monsterLists.push(this.leftMonsterList);
  386. }
  387. if(this.middleMonsterList.length>0){
  388. this.middleMonsterList.sort(this.monsterSortFunc);
  389. monsterLists.push(this.middleMonsterList);
  390. }
  391. }else if(this.weapon.fireKey==2){//中
  392. if(this.middleMonsterList.length>0){
  393. this.middleMonsterList.sort(this.monsterSortFunc);
  394. monsterLists.push(this.middleMonsterList);
  395. }
  396. //随机左边/右边
  397. let random:number=Math.random();
  398. if(random>0.5){
  399. if(this.rightMonsterList.length>0){
  400. this.rightMonsterList.sort(this.monsterSortFunc);
  401. monsterLists.push(this.rightMonsterList);
  402. }
  403. }else{
  404. if(this.leftMonsterList.length>0){
  405. this.leftMonsterList.sort(this.monsterSortFunc);
  406. monsterLists.push(this.leftMonsterList);
  407. }
  408. }
  409. }else{//右
  410. if(this.rightMonsterList.length>0){
  411. this.rightMonsterList.sort(this.monsterSortFunc);
  412. monsterLists.push(this.rightMonsterList);
  413. }
  414. if(this.middleMonsterList.length>0){
  415. this.middleMonsterList.sort(this.monsterSortFunc);
  416. monsterLists.push(this.middleMonsterList);
  417. }
  418. }
  419. }else{//攻击3条路
  420. if(this.leftMonsterList.length>0){
  421. this.leftMonsterList.sort(this.monsterSortFunc);
  422. monsterLists.push(this.leftMonsterList);
  423. }
  424. if(this.middleMonsterList.length>0){
  425. this.middleMonsterList.sort(this.monsterSortFunc);
  426. monsterLists.push(this.middleMonsterList);
  427. }
  428. if(this.middleMonsterList.length>0){
  429. this.middleMonsterList.sort(this.monsterSortFunc);
  430. monsterLists.push(this.middleMonsterList);
  431. }
  432. }
  433. //没有任何怪物可以攻击
  434. if(monsterLists.length==0){
  435. return;
  436. }
  437. //攻击怪物
  438. let monster:MonsterBase;
  439. let endNode:Node;
  440. let index:number=0;
  441. let total:number=0;
  442. let dis:number=0;
  443. monsterLists.forEach(monsterList => {
  444. //攻击怪物
  445. index=0;
  446. total=Math.min(this.weapon.weaponConfig.attackCount,monsterList.length);
  447. while(index<total){
  448. monster=monsterList[index];
  449. if(monster.config.startPos==0){
  450. endNode=this.leftEndNode;
  451. }else if(monster.config.startPos==1){
  452. endNode=this.middleEndNode;
  453. }else{
  454. endNode=this.rightEndNode;
  455. }
  456. if(Vec3.distance(monster.node.worldPosition,endNode.worldPosition)<=this.weapon.weaponConfig.attackDistance){
  457. if(this.currentSkill!=null){
  458. monster.Damage(this.weapon.weaponConfig.damage*this.currentSkill.damage);
  459. }else{
  460. monster.Damage(this.weapon.weaponConfig.damage);
  461. }
  462. }else{
  463. console.log("超出枪械攻击距离Miss");
  464. }
  465. index++;
  466. total=Math.min(this.weapon.weaponConfig.attackCount,monsterList.length);
  467. }
  468. for (let index = 0; index < monsterList.length; index++) {
  469. monster = monsterList[index];
  470. //怪物死亡
  471. if(monster.isDie){
  472. //增加怒气
  473. GameModel.single.angerCount+=monster.config.anger;
  474. //增加击杀量
  475. GameModel.single.killCount++;
  476. //增加积分
  477. if(monster.config.integral>0){
  478. GameModel.single.integral+=monster.config.integral;
  479. }
  480. //从列表中删除
  481. monsterList.splice(index,1);
  482. index--;
  483. }
  484. }
  485. });
  486. }
  487. private monsterSortFunc(a:MonsterBase,b:MonsterBase):number{
  488. if(a.node.position.z>b.node.position.z){
  489. return -1;
  490. }else if(a.node.position.z<b.node.position.z){
  491. return 1;
  492. }
  493. return 0;
  494. }
  495. /**
  496. * 根据配置生成怪物
  497. * @param config
  498. */
  499. private CreateMonster(config:any):Node{
  500. let monsterConfig:any=GameConfigManager.GetMonsterConfig(config.monsterId);
  501. if(monsterConfig==null){
  502. throw new Error("找不到怪物配置:"+config.monsterId);
  503. }
  504. let prefab:Prefab=loader.getRes(monsterConfig.prefab);
  505. let monster:Node=instantiate(prefab);
  506. monster.name="Monster"+config.mId;
  507. let monsterScript=monster.addComponent(MonsterBase);
  508. monsterScript.config=config;
  509. //左
  510. if(config.startPos==0){
  511. monster.setPosition(this.leftStartNode.worldPosition);
  512. this.leftMonsterList.push(monsterScript);
  513. }else if(config.startPos==1){//中
  514. monster.setPosition(this.middleStartNode.worldPosition);
  515. this.middleMonsterList.push(monsterScript);
  516. }else{//右
  517. monster.setPosition(this.rightStartNode.worldPosition);
  518. this.rightMonsterList.push(monsterScript);
  519. }
  520. //创建血条
  521. monsterScript.hpView=MonsterHPUIPool.Create();
  522. monsterScript.hpView.monster=monsterScript;
  523. return monster;
  524. }
  525. private CreateWeapon(leftHand:AnimationComponent,rightHand:AnimationComponent):any{
  526. let config:any=GameConfigManager.GetWeaponConfig(GameModel.single.currentWeaponId);
  527. if(config.fireType==0){
  528. return new SingleShotWeapon(leftHand,rightHand);
  529. }else if(config.fireType==1){
  530. return new AutomaticFifleWeapon(leftHand,rightHand);
  531. }
  532. return new SingleShotWeapon(leftHand,rightHand);;
  533. }
  534. /**
  535. * 判断是否需要提示射击
  536. */
  537. FireTip(type:number):boolean{
  538. switch (type) {
  539. case 1:
  540. this.leftMonsterList.forEach(element => {
  541. if(element.monsterConfig.fireTip>0){
  542. return true;
  543. }
  544. });
  545. break;
  546. case 2:
  547. this.middleMonsterList.forEach(element => {
  548. if(element.monsterConfig.fireTip>0){
  549. return true;
  550. }
  551. });
  552. break;
  553. case 3:
  554. this.rightMonsterList.forEach(element => {
  555. if(element.monsterConfig.fireTip>0){
  556. return true;
  557. }
  558. });
  559. break;
  560. }
  561. return false;
  562. }
  563. get scene(){
  564. return director.getScene();
  565. }
  566. private static instance:GameController;
  567. public static get single(){
  568. if(this.instance==null){
  569. this.instance=new GameController();
  570. }
  571. return this.instance;
  572. }
  573. }