playerObject.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. import AccountModel from "../../../data/Account/AccountModel";
  2. import npcHelper from "../../../dataManager/npcHelper";
  3. import { AssetsHelper } from "../../../framework/asset/AssetsHelper";
  4. import { BenzAssetManager } from "../../../framework/asset/BenzAssetManager";
  5. import EventManager from "../../../framework/event/EventManager";
  6. import AudioManager from "../../../framework/music/AudioManager";
  7. import utils from "../../../framework/utils/utils";
  8. import Utils from "../../../framework/utils/utils";
  9. import effectManager from "../../../manager/effectManager";
  10. import UITopMenu from "../../../ui/uiview/Interface/UITopMenu";
  11. import LevelLogic from "../../levelLogic";
  12. import gameData from "../../utrl/gameData";
  13. import { ATTACK_MODE, EVENT_TYPE, GAME_OBJECT_TYPE, JOY_STATE, PLAYER_TYPE, ROLE_STATE, WEAPON_TYPE } from "../../utrl/gameEnum";
  14. import gameEventManager from "../../utrl/gameEventManager";
  15. import GameObject from "../gameObject";
  16. import WeaponProp from "../tool/weaponProp";
  17. import ZomBieObject from "../zombie/zombieObject";
  18. import ZombieProp from "../zombie/zombieProp";
  19. import zombieView from "../zombie/zombieView";
  20. import dog_obj from "./dog_obj";
  21. import NodeMove from "./nodeMove";
  22. import PlayerProp from "./playerProp";
  23. import PlayerView from "./playerView";
  24. const { ccclass, requireComponent, property } = cc._decorator;
  25. /**玩家实体类 */
  26. @ccclass
  27. @requireComponent(NodeMove)
  28. export default class PlayerObject extends GameObject {
  29. @property(PlayerView)
  30. /**视图逻辑 */
  31. player_view: PlayerView = null;
  32. /**血条显示 */
  33. @property(cc.Node)
  34. cur_hp_bar: cc.Node = null;
  35. /**逻辑方法组件 */
  36. player_prop: PlayerProp = null;
  37. /**节点控制组件 */
  38. private node_move: NodeMove = null;
  39. /**初始化完成 */
  40. private inited = false;
  41. /**指令模式中 */
  42. private in_cmd_mode = true;
  43. /**待机跟随距离 */
  44. private track_dis_idle = 80;
  45. /**行走跟随距离 */
  46. private track_dis_walk = 50;
  47. /**本身刚体 */
  48. private rigid: cc.RigidBody = null;
  49. /**目标 */
  50. private target: cc.Node = null;
  51. /**玩家类型 */
  52. player_type = PLAYER_TYPE.normal;
  53. /**角色组,0玩家组,1僵尸组 */
  54. private roles: cc.Node[][] = [[], []];
  55. isDie: boolean = false;
  56. isPause = false;
  57. /** */
  58. start() {
  59. this.node.$hp.$lv_bg.$lv_num.getComponent(cc.Label).string = this.player_prop.level.toString();
  60. }
  61. onEnable() {
  62. if (this.node_move == null) {
  63. this.node_move = this.node.getComponent(NodeMove);
  64. }
  65. gameEventManager.on(EVENT_TYPE.attack_mode, this.refreshAttackMode, this);
  66. gameEventManager.on(EVENT_TYPE.joy_stick, this.onJoyStick, this);
  67. gameEventManager.on(EVENT_TYPE.CHANGE_STATUS, this.changeStatue, this)
  68. this.rigid = this.node.getComponent(cc.RigidBody);
  69. this.rigid.type = cc.RigidBodyType.Dynamic;
  70. }
  71. changeStatue(flag) {
  72. this.isPause = flag;
  73. }
  74. onDisable() {
  75. gameEventManager.off(EVENT_TYPE.joy_stick, this.onJoyStick, this);
  76. gameEventManager.off(EVENT_TYPE.CHANGE_STATUS, this.changeStatue, this)
  77. }
  78. //更新玩家血条
  79. updateHpBar() {
  80. let p = this.player_prop.cur_hp / this.player_prop.total_hp;
  81. if (p == 1 || p == 0) {
  82. this.cur_hp_bar.parent.active = false;
  83. }
  84. else {
  85. this.cur_hp_bar.parent.active = true;
  86. this.cur_hp_bar.width = this.cur_hp_bar.parent.width * p;
  87. }
  88. }
  89. //刷新玩家动画状态
  90. updateAnimState() {
  91. if (this.player_prop.refresh_cmd) {
  92. this.player_prop.refresh_cmd = false;
  93. this.player_view.cur_ani_state = null;
  94. let id = null;
  95. if (this.player_prop.cur_weapon != null) {
  96. id = this.player_prop.cur_weapon.id;
  97. }
  98. else if (this.player_prop.close_weapon != null) {
  99. id = this.player_prop.close_weapon.id;
  100. }
  101. switch (this.player_prop.cur_state) {
  102. case ROLE_STATE.idle: {
  103. this.player_view.playIdle(id);
  104. break;
  105. }
  106. case ROLE_STATE.walk: {
  107. this.player_view.playWalk(id);
  108. break;
  109. }
  110. }
  111. }
  112. }
  113. update(dt: number) {
  114. if (this.isPause) {
  115. return;
  116. }
  117. if (this.roles[0] == null || this.roles[1] == null) { return; }
  118. this.updateHpBar();
  119. if (!this.inited || this.player_prop.cur_state == ROLE_STATE.die) {
  120. return;
  121. }
  122. //刷新迷你地图位置
  123. if (this.player_prop.is_leader) {
  124. gameEventManager.emit(EVENT_TYPE.refresh_mini_map_pos, this.node.position);
  125. }
  126. this.updateAnimState();
  127. let leader: cc.Node = null;
  128. for (let c of this.roles[0]) {
  129. if (!c.isValid) { continue; }
  130. if (c.getComponent(PlayerObject).player_prop.is_leader) {
  131. leader = c;
  132. break;
  133. }
  134. }
  135. this.target = null;
  136. this.target = this.runState(dt, this.roles[1], leader);
  137. if (this.target != null) {
  138. if (this.node.x < this.target.x) {
  139. this.player_view.node.scaleX = -1;
  140. this.player_view.node.$upgrade.scaleX = -1;
  141. }
  142. else {
  143. this.player_view.node.scaleX = 1;
  144. this.player_view.node.$upgrade.scaleX = 1;
  145. }
  146. }
  147. else if (!this.in_cmd_mode) {
  148. let o = 5
  149. if (this.rigid.linearVelocity.x > o) {
  150. this.player_view.node.scaleX = -1;
  151. }
  152. else if (this.rigid.linearVelocity.x < -o) {
  153. this.player_view.node.scaleX = 1;
  154. }
  155. }
  156. if (this.node.parent.parent.name.indexOf('dungeon_') < 0) {
  157. let x = this.node.x;
  158. let y = this.node.y;
  159. this.player_prop.pos = cc.v3(x, y);
  160. }
  161. }
  162. /**初始化 */
  163. init(playerID, roles: cc.Node[][]) {
  164. this.type = GAME_OBJECT_TYPE.player;
  165. if (this.player_prop == null) {
  166. this.player_prop = new PlayerProp();
  167. }
  168. this.createDog(playerID);
  169. this.player_prop.init(playerID);
  170. this.roles = roles;
  171. this.isDie = false;
  172. //白壮汉跟黑壮汉特殊缩放
  173. if (playerID == 16 || playerID == 17) {
  174. this.node.scale = 1.3;
  175. }
  176. this.inited = true;
  177. }
  178. createDog(id) {
  179. if (id == 12 && cc.isValid(this.node)) {
  180. let dogAss = BenzAssetManager.getInstance().getAsset(AssetsHelper.PREFAB_DOG);
  181. let dogNode = cc.instantiate(dogAss) as unknown as cc.Node;
  182. dogNode.parent = this.node.parent;
  183. dogNode.x = this.node.x;
  184. dogNode.y = this.node.y;
  185. dogNode.getComponent(dog_obj).setFollowTarget(this.node);
  186. }
  187. }
  188. /**设置成领队
  189. * @param is_leader 是领队
  190. */
  191. setLeader(is_leader: boolean) {
  192. this.player_prop.is_leader = is_leader;
  193. this.node_move.enabled = this.player_prop.is_leader;
  194. // this.rigid.type = is_leader ? cc.RigidBodyType.Animated : cc.RigidBodyType.Dynamic;
  195. if (is_leader) {
  196. this.node.group = 'leader';
  197. }
  198. else {
  199. this.node.group = 'normal';
  200. }
  201. this.node.active = false;
  202. this.node.active = true;
  203. }
  204. /**玩家死亡 */
  205. die() {
  206. if (this.player_prop.cur_state == ROLE_STATE.die) {
  207. return;
  208. }
  209. this.isDie = true;
  210. gameData.peopleDieNum += 1;
  211. this.playDieAnm();
  212. this.player_prop.cur_state = ROLE_STATE.die;
  213. this.rigid.type = cc.RigidBodyType.Animated;
  214. this.node_move.enabled = false;
  215. gameData.curPeopleNum -= 1;
  216. if (this.player_prop.is_leader) {
  217. //console.log('发送随机领队事件')
  218. gameEventManager.emit(EVENT_TYPE.random_leader);
  219. }
  220. this.becomeZombie();
  221. EventManager.emit(EVENT_TYPE.UPDATE_PEOPLE_NUM);
  222. gameEventManager.emit(EVENT_TYPE.player_die);
  223. }
  224. //变僵尸
  225. becomeZombie() {
  226. this.scheduleOnce(() => {
  227. let id = this.player_view.getViewId();
  228. //如果是英雄 直接移除
  229. if (id >= 49 && id <= 52) {
  230. gameEventManager.emit(EVENT_TYPE.RECOVER_PLAYER, this.node);
  231. // this.node.destroy();
  232. return;
  233. }
  234. let z_id = npcHelper.getZombieIdByPlayerId(id);
  235. let pos = this.node.position;
  236. //发送生成僵尸事件
  237. gameEventManager.emit(EVENT_TYPE.add_zombie, z_id, pos);
  238. gameEventManager.emit(EVENT_TYPE.RECOVER_PLAYER, this.node);
  239. //this.node.destroy();
  240. AudioManager.play('shift');
  241. }, 2);
  242. }
  243. //播放死亡
  244. playDieAnm() {
  245. let id = null;
  246. if (this.player_prop.cur_weapon != null) {
  247. id = this.player_prop.cur_weapon.id;
  248. }
  249. else if (this.player_prop.close_weapon != null) {
  250. id = this.player_prop.close_weapon.id;
  251. }
  252. this.player_view.playDie(id);
  253. }
  254. /**刷新攻击模式 */
  255. private refreshAttackMode() {
  256. // console.log('切换攻击模式', gameData.cur_attack_mode);
  257. UITopMenu.getInstance().initSp();
  258. if (gameData.cur_attack_mode == ATTACK_MODE.close) {
  259. this.player_prop.cur_weapon = this.player_prop.close_weapon;
  260. }
  261. else {
  262. this.player_prop.cur_weapon = this.player_prop.remote_weapon;
  263. }
  264. this.player_prop.refreshWeapon();
  265. AudioManager.play('switchting');
  266. }
  267. /**遥感回调
  268. * @param state 当前遥感状态
  269. * @param angle 当前遥感角度
  270. * @param power 当前遥感力度
  271. */
  272. private onJoyStick(state: JOY_STATE, angle: number, power: number) {
  273. if (this.player_prop.cur_state == ROLE_STATE.die) {
  274. return;
  275. }
  276. switch (state) {
  277. case JOY_STATE.start: {
  278. this.in_cmd_mode = true;
  279. break;
  280. }
  281. case JOY_STATE.move: {
  282. if (this.target == null) {
  283. if (angle < 90 || angle > 270) {
  284. this.player_view.node.scaleX = -1;
  285. }
  286. else {
  287. this.player_view.node.scaleX = 1;
  288. }
  289. }
  290. if (!this.player_prop.is_leader) {
  291. return;
  292. }
  293. this.player_prop.cur_state = ROLE_STATE.walk;
  294. let id = null;
  295. if (this.player_prop.cur_weapon != null) {
  296. id = this.player_prop.cur_weapon.id;
  297. }
  298. else if (this.player_prop.close_weapon != null) {
  299. id = this.player_prop.close_weapon.id;
  300. }
  301. this.player_view.playWalk(id);
  302. break;
  303. }
  304. case JOY_STATE.end: {
  305. this.player_prop.cur_state = ROLE_STATE.idle;
  306. let id = null;
  307. if (this.player_prop.cur_weapon != null) {
  308. id = this.player_prop.cur_weapon.id;
  309. }
  310. else if (this.player_prop.close_weapon != null) {
  311. id = this.player_prop.close_weapon.id;
  312. }
  313. this.player_view.playIdle(id);
  314. this.rigid.linearVelocity = cc.v2();
  315. this.in_cmd_mode = false;
  316. break;
  317. }
  318. }
  319. }
  320. /**运行状态机 */
  321. private runState(dt: number, zombie_nds: cc.Node[], leader: cc.Node): cc.Node {
  322. let obj: cc.Node = null;
  323. if (gameData.cur_attack_mode == ATTACK_MODE.remote) {
  324. obj = this.useRemoteWeapon(dt, zombie_nds, leader);
  325. }
  326. else if (!this.in_cmd_mode) {
  327. this.useCloseWeapon(dt, zombie_nds, leader);
  328. }
  329. if (this.in_cmd_mode && !this.player_prop.is_leader) {
  330. this.moveToLeader(leader);
  331. }
  332. return obj;
  333. }
  334. //是否隔墙
  335. isCloseWall(target) {
  336. let v_sub = target.position.sub(this.node.position.add(cc.v3(0, 30, 0))).normalize();
  337. let rad = Math.acos(v_sub.x);
  338. if (v_sub.y < 0) {
  339. rad = Math.PI * 2 - rad;
  340. }
  341. let angle = rad / Math.PI * 180;
  342. let rayCast = Utils.getRayCast(this.node.getPosition(), target.getPosition(), cc.RayCastType.All);
  343. if (rayCast) {
  344. rayCast.sort((a, b) => {
  345. let aDis = target.position.sub(a.collider.node.position).mag();
  346. let bDis = target.position.sub(b.collider.node.position).mag();
  347. if (aDis < bDis) {
  348. return a - b;
  349. }
  350. })
  351. for (let i = 0; i < rayCast.length; ++i) {
  352. if (rayCast[i].collider.node.name == 'player_object') {
  353. break;
  354. }
  355. if (rayCast[i].collider.node.name !== 'zombie_object') {
  356. return true
  357. }
  358. }
  359. return false;
  360. }
  361. }
  362. /**使用远程武器 */
  363. private useRemoteWeapon(dt: number, zombie_nds: cc.Node[], leader: cc.Node): cc.Node {
  364. let obj: cc.Node = null;
  365. if (this.player_prop.remote_weapon != null) {
  366. let range = this.player_prop.remote_weapon.range;
  367. let target = this.getCloseTarget(zombie_nds, range);
  368. if (target != null) {
  369. if (!this.isCloseWall(target)) {
  370. this.player_view.AimZombie(target, this.player_prop.remote_weapon.id);
  371. this.remoteAttack(dt, target);
  372. obj = target;
  373. }
  374. }
  375. else {
  376. this.player_view.resetGunAngle(this.player_prop.cur_weapon.id);
  377. }
  378. if (!this.player_prop.is_leader) {
  379. this.moveToLeader(leader);
  380. }
  381. }
  382. else if (!this.in_cmd_mode) {
  383. this.useCloseWeapon(dt, zombie_nds, leader);
  384. }
  385. return obj;
  386. }
  387. /**使用近战武器 */
  388. private useCloseWeapon(dt: number, zombie_nds: cc.Node[], leader: cc.Node) {
  389. let range = this.player_prop.search_range;
  390. let zombie = this.getCloseTarget(zombie_nds, range);
  391. if (zombie != null) {
  392. if (this.player_prop.close_weapon != null) {
  393. range = this.player_prop.close_weapon.range;
  394. let ts = this.getAliiCloseTargets(zombie_nds, range);
  395. if (ts.length > 0) {
  396. this.closeAttack(dt, ts, this.player_prop.close_weapon.damage + this.player_prop.base_damage);
  397. }
  398. else {
  399. this.moveToTarget(zombie);
  400. }
  401. }
  402. else {
  403. range = this.player_prop.hand_range;
  404. let ts = this.getAliiCloseTargets(zombie_nds, range);
  405. if (ts.length > 0) {
  406. this.closeAttack(dt, ts, this.player_prop.base_damage);
  407. }
  408. else {
  409. this.moveToTarget(zombie);
  410. }
  411. }
  412. }
  413. else {
  414. if (!this.player_prop.is_leader) {
  415. this.moveToLeader(leader);
  416. }
  417. this.player_prop.attack_timer = Number.MAX_VALUE;
  418. }
  419. }
  420. /**进行远程攻击 */
  421. remoteAttack(dt: number, target: cc.Node) {
  422. let cbk = () => {
  423. let v_sub = target.position.sub(this.node.position.add(cc.v3(0, 30, 0))).normalize();
  424. let rad = Math.acos(v_sub.x);
  425. if (v_sub.y < 0) {
  426. rad = Math.PI * 2 - rad;
  427. }
  428. let ev = EVENT_TYPE.bullet0;
  429. if (this.player_prop.remote_weapon.type == WEAPON_TYPE.gun1) {
  430. ev = EVENT_TYPE.bullet1;
  431. }
  432. let damage = this.player_prop.remote_weapon.damage;
  433. let player = this;
  434. //发送远程攻击事件生成对应子弹
  435. gameEventManager.emit(ev, rad, damage, player);
  436. };
  437. this.player_prop.attackRun(dt, cbk);
  438. }
  439. //怪物死亡加经验
  440. addExp(exp: number) {
  441. //let lb = this.node.$hp.$lv_bg.$lv_num.getComponent(cc.Label);
  442. if (this.player_prop.level >= 4) {
  443. return;
  444. }
  445. let curExp = this.player_prop.exp += exp;
  446. let upgreadLimit = this.player_prop.upgradeCondition;
  447. if (curExp >= upgreadLimit) {
  448. this.player_prop.level += 1;
  449. this.player_prop.updateTotalHp();
  450. AudioManager.play('lvup');
  451. this.player_prop.exp = 0;
  452. effectManager.playEff(this.node.$view, 'upgrade', null, false);
  453. this.node.$hp.$lv_bg.$lv_num.getComponent(cc.Label).string = this.player_prop.level.toString();
  454. }
  455. }
  456. /**进行近战攻击 */
  457. private closeAttack(dt: number, ts: cc.Node[], damage: number) {
  458. let cbk = () => {
  459. //console.log('近战攻击', damage);
  460. var curLevel = AccountModel.getInstance().curLevel;
  461. this.scheduleOnce(() => {
  462. if (this.player_prop.cur_state == ROLE_STATE.die) return;
  463. for (let t of ts) {
  464. if (!t.isValid) {
  465. return;
  466. }
  467. let comp = t.getComponent(ZomBieObject);
  468. if(comp.isDie){
  469. return;
  470. }
  471. let bDie = this.player_prop.attack(comp, damage);
  472. let zomView = t.getComponent(zombieView);
  473. zomView.hitEff();
  474. if (bDie) {
  475. this.addExp(comp.zombie_prop.exp);
  476. effectManager.zombieDieEff(this.node.parent.parent.$eff_parent, t.getPosition());
  477. let x = t.x;
  478. let y = t.y;
  479. let pos = cc.v3(x, y);
  480. if (curLevel > 1) {
  481. gameEventManager.emit(EVENT_TYPE.RESET_ZOMBIE, pos);
  482. // console.log('EVENT_TYPE.RESET_ZOMBIE')
  483. }
  484. t.active = false;
  485. gameEventManager.emit(EVENT_TYPE.RECOVER_ZOMBIE, t);
  486. AudioManager.play('zombiedie');
  487. gameEventManager.emit(EVENT_TYPE.zombie_die);
  488. }
  489. }
  490. }, 0.2);
  491. this.player_prop.cur_state = ROLE_STATE.idle;
  492. let id = null;
  493. if (this.player_prop.cur_weapon != null) {
  494. id = this.player_prop.cur_weapon.id;
  495. }
  496. else if (this.player_prop.close_weapon != null) {
  497. id = this.player_prop.close_weapon.id;
  498. }
  499. this.player_view.playAttack(id);
  500. };
  501. this.player_prop.attackRun(dt, cbk);
  502. }
  503. /**向领队移动 */
  504. private moveToLeader(leader: cc.Node) {
  505. if (leader == null || !this.in_cmd_mode) {
  506. return;
  507. }
  508. this.player_view.node.scaleX = leader.getComponent(PlayerObject).player_view.node.scaleX;
  509. let len = leader.position.sub(this.node.position).mag();
  510. if (this.player_prop.cur_state == ROLE_STATE.idle && len > this.track_dis_idle) {
  511. this.moveToTarget(leader);
  512. }
  513. else if (this.player_prop.cur_state == ROLE_STATE.walk && len > this.track_dis_walk) {
  514. this.moveToTarget(leader);
  515. }
  516. else {
  517. this.player_prop.cur_state = ROLE_STATE.idle;
  518. let id = null;
  519. if (this.player_prop.cur_weapon != null) {
  520. id = this.player_prop.cur_weapon.id;
  521. }
  522. else if (this.player_prop.close_weapon != null) {
  523. id = this.player_prop.close_weapon.id;
  524. }
  525. this.player_view.playIdle(id);
  526. }
  527. }
  528. /**范围内最近目标 */
  529. private getCloseTarget(nds: cc.Node[], range: number): cc.Node {
  530. let target: cc.Node = null;
  531. for (let nd of nds) {
  532. if (!nd.isValid) { continue; }
  533. let len = nd.position.sub(this.node.position).mag();
  534. if (len < range) {
  535. range = len;
  536. target = nd;
  537. }
  538. }
  539. return target;
  540. }
  541. /**范围内所有目标 */
  542. private getAliiCloseTargets(nds: cc.Node[], range: number): cc.Node[] {
  543. let targets: cc.Node[] = [];
  544. for (let nd of nds) {
  545. if (!nd.isValid) { continue; }
  546. let len = nd.position.sub(this.node.position).mag();
  547. if (len < range) {
  548. targets.push(nd);
  549. }
  550. }
  551. return targets;
  552. }
  553. /**向目标移动
  554. * @param target 目标
  555. */
  556. private moveToTarget(target: cc.Node) {
  557. this.player_prop.cur_state = ROLE_STATE.walk;
  558. let v_sub = target.position.sub(this.node.position).normalize();
  559. let rad = Math.acos(v_sub.x);
  560. if (v_sub.y < 0) {
  561. rad = Math.PI * 2 - rad;
  562. }
  563. this.setLinearVelocity(rad);
  564. let id = null;
  565. if (this.player_prop.cur_weapon != null) {
  566. id = this.player_prop.cur_weapon.id;
  567. }
  568. else if (this.player_prop.close_weapon != null) {
  569. id = this.player_prop.close_weapon.id;
  570. }
  571. this.player_view.playWalk(id);
  572. }
  573. /**设置刚体线性速度
  574. * @param rad 弧度角
  575. */
  576. private setLinearVelocity(rad: number) {
  577. this.node.getComponent(cc.RigidBody).linearVelocity = cc.v2(Math.cos(rad), Math.sin(rad)).mul(this.node_move.move_speed);
  578. }
  579. }