player.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. import { utils } from "../../common-plugin/Scripts/Utils";
  2. import { cocosz } from "../Framework/CocosZ";
  3. import Constant, { PanelName, ZindexLayer } from "../Framework/Constant";
  4. import Bullet from "./bullet";
  5. import GameDate from "./gameDate";
  6. import { gameMgr } from "./gameMgr";
  7. import Person from "./person";
  8. import { SkillType, upgradeMgr } from "./UpgradeMgr";
  9. import Weapon from "./weapon";
  10. // @ts-ignore
  11. const i18n = require('LanguageData');
  12. const { ccclass, property } = cc._decorator;
  13. @ccclass
  14. export default class Player extends Person {
  15. onLoad() {
  16. this.isPlayer = true;
  17. this.id = 1;
  18. gameMgr.playerTs = this;
  19. if (this.hpSpr) {
  20. this.hpSpr.color = cc.Color.GREEN;
  21. }
  22. if (this.atkBar) {
  23. this.atkBar.node.children[1].color = cc.Color.YELLOW;
  24. }
  25. this.rig = this.node.getComponent(cc.RigidBody);
  26. if (this.rig) { this.rig.linearDamping = 0.2; }
  27. this.playerMess = this.node.getChildByName("playerMess");
  28. this.hpNumNode = this.playerMess.getChildByName("hpNum");
  29. // 光环
  30. this.ghAniNode = this.node.getChildByName("gh");
  31. // 烟尘
  32. this.ycAniNode = this.node.getChildByName("yc");
  33. // 相机跟随
  34. gameMgr.followNode = this.node;
  35. // 防止玩家和僵尸碰撞
  36. if (cocosz.gameMode == 6) {
  37. if (this.rig && this.rig.isValid) {
  38. this.rig.enabledContactListener = true;
  39. }
  40. }
  41. }
  42. start() {
  43. super.start();
  44. this.setProperty();
  45. this.node.zIndex = ZindexLayer.zindex_player;
  46. if (this.ghAniNode && this.ghAniNode.isValid) {
  47. this.ghAniNode.setParent(this.node.parent);
  48. this.ghAniNode.zIndex = ZindexLayer.zinedx_gh;
  49. this.updateGhAni();
  50. }
  51. if (this.ycAniNode && this.ycAniNode.isValid) {
  52. this.ycAniNode.setParent(this.node.parent);
  53. this.ycAniNode.zIndex = ZindexLayer.zinedx_footYc;
  54. this.updateYcAni();
  55. }
  56. // 血条
  57. if (this.hpSpr) {
  58. this.hpSpr.color = cc.Color.GREEN;
  59. }
  60. }
  61. lateUpdate(dt) {
  62. this.curTime++;
  63. if (cocosz.isPause || this.isDeath || gameMgr.isWin || gameMgr.isFail) {
  64. this.rig.linearVelocity = cc.v2(0, 0);
  65. return;
  66. };
  67. if (this.curTime % 15 == 0) {
  68. this.updateAni();
  69. this.creatFootPrint();
  70. }
  71. this.updateAtk();
  72. this.updatePerson();
  73. this.udpateRBody(this.moveDir);
  74. this.updateMess();
  75. this.updateGhAni();
  76. this.updateYcAni();
  77. if (this.atkTarget && this.atkTarget.isValid) {
  78. this.atkEnemy();
  79. }
  80. }
  81. recoverEffect() {
  82. let node = cc.instantiate(gameMgr.itemEffect[0]);
  83. node.parent = this.node;
  84. }
  85. lastTime: number = 0;
  86. checkTarget() {
  87. if (Number(new Date()) - this.lastTime < 500) return;
  88. this.lastTime = Number(new Date());
  89. let num = this.atkList.indexOf(this.atkTarget);
  90. if (num >= 0) {
  91. if (num == this.atkList.length - 1) {
  92. num = 0;
  93. }
  94. else {
  95. num += 1;
  96. }
  97. this.atkTarget = this.atkList[num];
  98. }
  99. else {
  100. this.atkTarget = this.atkList[0];
  101. }
  102. }
  103. lastAtkTime: number = 0;
  104. atkBulletNum: number = 1;
  105. atkEnemy() {
  106. if (!this.curWeapon || !this.curWeapon.isValid || this.isAtk) return;
  107. if (this.curWeapon && this.curWeapon.isRangeWeapon) {
  108. // 是否有子弹
  109. if (this.curWeapon._isReload || this.curWeapon.curBullet <= 0) {
  110. return;
  111. } else {
  112. if (cocosz.gameMode == 6 && this.curWeapon.curBullet == 1) {
  113. cc.game.emit(Constant.E_GAME_LOGIC, { type: Constant.E_Bullet_Last, node: this.node });
  114. }
  115. this.curWeapon.curBullet--;
  116. }
  117. // 抖动效果
  118. let t = (this.atkSpeed > 0.1 ? 0.1 : this.atkSpeed) / 3;
  119. cc.tween(this.rangedWeapon.children[0])
  120. .by(t, { x: -20, angle: 20 })
  121. .by(t, { x: 20, angle: -20 })
  122. .start();
  123. // 攻击效果
  124. let pos = this.startPosNode.getPosition();
  125. if (this.curWeapon.atkEffect) {
  126. let effect = cc.instantiate(this.curWeapon.atkEffect);
  127. if (this.curWeapon.weaponNum == 9 || this.curWeapon.weaponNum == 15) {
  128. this.node.parent.addChild(effect, ZindexLayer.zindex_effect_fire, "effect");
  129. effect.setPosition(this.startPosNode.parent.convertToWorldSpaceAR(pos).sub(cc.v2(cc.winSize.width / 2, cc.winSize.height / 2)));
  130. if (this.body.scaleX > 0) {
  131. effect.angle = this.rangedWeapon.angle;
  132. }
  133. else {
  134. effect.angle = 180 - this.rangedWeapon.angle;
  135. }
  136. }
  137. else {
  138. this.curWeapon.node.addChild(effect, 1, "effect");
  139. effect.setPosition(pos);
  140. }
  141. // 升级开火特效
  142. // if (this.curWeapon.can_effect_hit && this.curWeapon && this.curWeapon.weaponLevel > 0) {
  143. // let effect_fire = cc.instantiate(gameMgr.effect_fire);
  144. // effect_fire.parent = effect.parent;
  145. // effect_fire.setPosition(effect.position);
  146. // effect_fire.angle = effect.angle;
  147. // // 颜色
  148. // let arr = ["", "y", "p", "r"];
  149. // let spAni = effect_fire.children[0].getComponent(sp.Skeleton);
  150. // spAni && spAni.setSkin(arr[this.curWeapon.weaponLevel]);
  151. // }
  152. }
  153. }
  154. else {
  155. gameMgr.shakeEffect(2, 1, false);//屏幕晃动
  156. let ani = this.meleeWeapon.getComponent(cc.Animation);
  157. ani && ani.isValid && ani.play("atk_dao");
  158. this.scheduleOnce(() => {
  159. ani && ani.isValid && ani.play("daiji_dao");
  160. }, 0.18)
  161. }
  162. // 生成子弹
  163. let dir;
  164. if (this.atkDir && !this.atkDir.equals(cc.Vec2.ZERO)) {
  165. dir = this.atkDir;
  166. } else if (this.moveDir && !this.moveDir.equals(cc.Vec2.ZERO)) {
  167. dir = this.moveDir;
  168. } else {
  169. dir = this.body.scaleX > 0 ? cc.Vec2.RIGHT : cc.Vec2.RIGHT.negSelf();
  170. }
  171. if (this.atkBulletNum > 1) {
  172. for (let i = 0; i < this.atkBulletNum; i++) {
  173. let angle = ((this.atkBulletNum - 1) / 2 - i) * 15;
  174. let new_dir: cc.Vec2 = dir.rotate(cc.misc.degreesToRadians(angle));
  175. this.createBullet(new_dir);
  176. }
  177. } else {
  178. this.createBullet(dir);
  179. }
  180. // 攻击表情
  181. let t = this.atkSpeed > 0.1 ? 0.1 : this.atkSpeed;
  182. cc.tween(this.head_atk)
  183. .set({ opacity: 255 })
  184. .delay(t)
  185. .set({ opacity: 0 })
  186. .start();
  187. this.isAtk = true;
  188. if (this.curWeapon.isRangeWeapon && this.curWeapon.curBullet <= 0) {
  189. cc.tween(this.node)
  190. .delay(this.curWeapon.reload)
  191. .call(() => {
  192. this.isAtk = false;
  193. })
  194. .start();
  195. } else {
  196. cc.tween(this.node)
  197. .delay(this.atkSpeed)
  198. .call(() => {
  199. this.isAtk = false;
  200. })
  201. .start();
  202. }
  203. // 攻击音效
  204. let name = Weapon.WeaponName[this.curWeapon.weaponNum - 1];
  205. if (GameDate.Weapon[name] && GameDate.Weapon[name].music) {
  206. gameMgr.playEffect("shot_" + GameDate.Weapon[name].music, this.node);
  207. } else {
  208. gameMgr.playEffect(`shot_${Weapon.WeaponName[this.curWeapon.weaponNum - 1]}`, this.node);
  209. }
  210. }
  211. createBullet(dir: cc.Vec2) {
  212. let bullet = cc.instantiate(this.curWeapon.bullet);
  213. if (this.curWeapon.isRangeWeapon) {
  214. bullet.parent = this.node.parent;
  215. let fromPos = bullet.parent.convertToNodeSpaceAR(this.startPosNode.convertToWorldSpaceAR(cc.Vec2.ZERO));
  216. bullet.setPosition(fromPos);
  217. bullet.angle = -cc.v2(dir).signAngle(cc.v2(1, 0)) / Math.PI * 180;
  218. if (this.curWeapon.weaponNum == 2) {
  219. bullet.angle += (5 - Math.random() * 10);
  220. }
  221. if (this.curWeapon.flySpeed > 0) {
  222. let pos1 = bullet.getPosition();
  223. let pos2 = pos1.add(dir.mul(this.curWeapon.atkRangeNum));
  224. cc.tween(bullet)
  225. .to(pos2.sub(pos1).mag() / this.curWeapon.flySpeed, { position: cc.v3(pos2) })
  226. .call(() => {
  227. let ts = bullet.getComponent(Bullet);
  228. if (ts.boomEffect) {
  229. let boom = cc.instantiate(ts.boomEffect)
  230. boom.parent = ts.node.parent;
  231. boom.setPosition(ts.node.getPosition());
  232. let curBullet = boom.getComponent(Bullet);
  233. curBullet.atk = ts.atk;
  234. curBullet.atker = ts.atker;
  235. curBullet.id = ts.id;
  236. gameMgr.playEffect("explo", boom);
  237. if (ts.hitEffect) {
  238. let pos = bullet.getPosition();
  239. let node = cc.instantiate(ts.hitEffect);
  240. node.parent = bullet.parent;
  241. node.setPosition(pos);
  242. node.zIndex = ZindexLayer.zindex_effect_hit;
  243. }
  244. }
  245. bullet.destroy()
  246. })
  247. .start();
  248. // 弹壳
  249. if (this.curWeapon.shellCall) {
  250. let shellCase = cc.instantiate(this.curWeapon.shellCall);
  251. shellCase.setParent(gameMgr.map);
  252. shellCase.setPosition(this.node.position);
  253. shellCase.scaleX = this.body.scale;
  254. }
  255. } else {
  256. cc.tween(bullet).delay(0.4).call(() => {
  257. bullet.destroy()
  258. }).start();
  259. }
  260. let ts = bullet.getComponent(Bullet);
  261. ts.id = this.id;
  262. ts.atker = this.node;
  263. ts.atk = (this.atkNum + this.personAtk) * this.atkRate;
  264. ts.dir = dir;
  265. }
  266. else {
  267. this.node.addChild(bullet, -1);
  268. bullet.color = this.curWeapon.bulletCollor;
  269. if (this.atkDir.x < 0) {
  270. bullet.scaleX *= -1 / this.node.scaleX;
  271. }
  272. else {
  273. bullet.scaleX /= this.node.scaleX;
  274. }
  275. bullet.scaleY /= this.node.scaleY;
  276. cc.tween(bullet).delay(0.2).call(() => { bullet.destroy() }).start();
  277. let ts = bullet.getComponent(Bullet);
  278. ts.id = this.id;
  279. ts.atker = this.node;
  280. ts.atk = (this.atkNum + this.personAtk) * this.atkRate;
  281. ts.dir = dir;
  282. }
  283. }
  284. hart(atkNum: number, from: cc.Node, dir: cc.Vec2 = null, isAudio: boolean = true) {
  285. if (cocosz.isPause || this.isDeath || this.isAvoidInjury) return;
  286. if (cocosz.gameMode == 6 && upgradeMgr) {
  287. // 移动过程中15%的概率免伤
  288. if (upgradeMgr.isHaveSkill(SkillType.护甲靴子) && this.moveDir.mag() > 0 && Math.random() < 0.4) {
  289. // gameMgr.showRoleTip(this.node, "闪避", cc.Color.YELLOW);
  290. return;
  291. }
  292. else if (upgradeMgr.isHaveSkill(SkillType.神圣守护) && upgradeMgr.hudun && upgradeMgr.hudun.active) {
  293. upgradeMgr.updateHudun();
  294. // gameMgr.showRoleTip(this.node, "免伤", cc.Color.YELLOW);
  295. return;
  296. }
  297. }
  298. // 防止dir过大
  299. if (dir && dir.mag() > 3) dir.normalizeSelf().mulSelf(3);
  300. // 减伤
  301. atkNum = (1 - this.damageReduction) * atkNum;
  302. // 护盾
  303. if (this.Shiled > 0) {
  304. this.Shiled -= atkNum;
  305. if (this.Shiled < 0) {
  306. atkNum = -this.Shiled;
  307. this.Shiled = 0;
  308. } else {
  309. return;
  310. }
  311. }
  312. // 数字
  313. if (cocosz.gameMode != 6) {
  314. gameMgr.showRoleTip(this.node, Math.min(this.HP, atkNum).toFixed(0));
  315. }
  316. this.HP -= atkNum;
  317. // 受伤音效
  318. if (isAudio) {
  319. if (from) {
  320. let ts = from.getComponent(Person);
  321. if (ts && ts.curWeapon && ts.curWeapon.isRangeWeapon) {
  322. gameMgr.playEffect("hurt_range", this.node);
  323. } else {
  324. gameMgr.playEffect("hurt_melee", this.node);
  325. }
  326. } else {
  327. gameMgr.playEffect("hurt", this.node);
  328. }
  329. }
  330. // 屏幕闪红
  331. if (cocosz.gameMode == 6) {
  332. cc.tween(gameMgr.red)
  333. .to(0.5, { opacity: 255 }, { easing: "sineOut" })
  334. .to(0.5, { opacity: 0 }, { easing: "sineIn" })
  335. .start();
  336. }
  337. // 震动
  338. cocosz.vibrate("long");
  339. if (this.HP <= 0) {
  340. if (cocosz.gameMode == 6) cocosz.audioMgr.playEffect("GameOver");
  341. this.death();
  342. if (from) {
  343. let ts = from.getComponent(Person);
  344. ts.killNum++;
  345. ts.curKillNum++;
  346. // 更新最佳成绩
  347. if (ts.curKillNum > ts.maxNum) {
  348. ts.maxNum = ts.curKillNum;
  349. }
  350. this.killer = ts;
  351. this.curKillNum = 0;
  352. }
  353. // 倒飞
  354. if (dir) {
  355. let p1 = this.node.getPosition();
  356. let pTo = p1.add(dir.normalizeSelf().mulSelf(200));
  357. let p2 = cc.v2((p1.x + pTo.x) / 2, p1.y + 200);
  358. cc.tween(this.node)
  359. .bezierTo(0.3, p1, p2, pTo)
  360. .start();
  361. }
  362. // 死亡事件
  363. if (cocosz.gameMode == 6) {
  364. cc.game.emit(Constant.E_GAME_LOGIC, { type: Constant.E_Player_Death })
  365. }
  366. } else {
  367. // 受伤事件
  368. if (cocosz.gameMode == 6) {
  369. this.avoidInjury(2);
  370. cc.game.emit(Constant.E_GAME_LOGIC, { type: Constant.E_Player_Hart })
  371. }
  372. // 效果
  373. if (!this.isAttackedEffect) {
  374. this.isAttackedEffect = true;
  375. // 后退
  376. if (this.rig.type == cc.RigidBodyType.Dynamic && dir) {
  377. // 控制
  378. this.canMove = false;
  379. this.scheduleOnce(() => { this.canMove = true; }, 0.1);
  380. // 后退
  381. let div = dir.mulSelf(400 * dir.mag()).addSelf(this.rig.linearVelocity);
  382. if (div.mag() > 500) {
  383. div.normalizeSelf().mulSelf(500);
  384. }
  385. this.rig.linearVelocity = div;
  386. }
  387. // 晃头
  388. cc.tween(this.head)
  389. .call(() => { this.head_hart.opacity = 255; })
  390. .to(0.05, { angle: 15 })
  391. .to(0.05, { angle: -15 })
  392. .to(0.05, { angle: 15 })
  393. .to(0.05, { angle: 0 })
  394. .call(() => { this.head_hart.opacity = 0; })
  395. .start();
  396. // 人物变色
  397. let spArr = this.body.getComponentsInChildren(cc.Sprite);
  398. cc.tween(this.body)
  399. .call(() => { spArr.forEach((v, i) => { v.isValid && v.setMaterial(0, this.mat_attacked) }) })
  400. .delay(0.1)
  401. .call(() => { spArr.forEach((v, i) => { v.isValid && v.setMaterial(0, this.mat_common) }) })
  402. .delay(0.1)
  403. .union()
  404. .repeat(cocosz.gameMode == 6 ? 5 : 2)
  405. .call(() => { this.isAttackedEffect = false; })
  406. .start();
  407. }
  408. }
  409. }
  410. creatFootPrint() {
  411. if (this.node.opacity == 0) return;
  412. let pos = this.node.getPosition();
  413. if (pos.sub(this.lastPos).mag() < 5) return;
  414. this.lastPos = cc.v2(pos);
  415. this.footNum++;
  416. // 脚步音效
  417. if (this.isPlayer && this.footNum % 3 == 0) {
  418. gameMgr.playEffect("footsteps", this.node);
  419. }
  420. // 脚印(雪地)
  421. if (gameMgr.map.name == "map2") {
  422. let node = new cc.Node();
  423. node.addComponent(cc.Sprite).spriteFrame = gameMgr.jiaoyin;
  424. cc.tween(node).delay(0.5).to(0.5, { opacity: 0 }).call(() => { node.destroy() }).start();
  425. node.parent = this.node.parent;
  426. node.zIndex = ZindexLayer.zinedx_footPrint;
  427. if (this.moveDir.mag() > 0) node.angle = 360 - cc.v2(this.moveDir).signAngle(cc.v2(1, 0)) / Math.PI * 180;
  428. pos.y -= 100 * this.node.scale;
  429. let pos2 = cc.v2(20, 0).rotate(node.angle / 180 * Math.PI).rotate(this.footNum % 2 == 0 ? Math.PI / 2 : -Math.PI / 2)
  430. pos.addSelf(pos2);
  431. node.setPosition(pos);
  432. }
  433. }
  434. // 0:检测碰撞;1:检测子弹;2:检测在层级下,3:检测在层级上
  435. onCollisionEnter(other: cc.Collider, self: cc.Collider) {
  436. if (self.tag == 0) {
  437. // 敌人
  438. if (other.tag == 1) {
  439. let ts = other.node.getComponent(Person);
  440. if (ts && ts.id != this.id) {
  441. this.atkList.push(other.node);
  442. if (!cc.isValid(this.atkTarget) && other.node.isValid) {
  443. this.atkTarget = other.node;
  444. }
  445. }
  446. }
  447. }
  448. }
  449. onCollisionExit(other: cc.Collider, self: cc.Collider) {
  450. if (self.tag == 0) {
  451. let num = this.atkList.indexOf(other.node)
  452. if (other.tag == 1 && num >= 0) {
  453. this.atkList.splice(num, 1);
  454. if (this.atkList.length == 0) {
  455. this.atkTarget = null;
  456. }
  457. else {
  458. if (!cc.isValid(this.atkTarget) || other.node.uuid == this.atkTarget.uuid) {
  459. this.atkTarget = this.atkList[0];
  460. }
  461. }
  462. }
  463. }
  464. }
  465. // 每次将要处理碰撞体接触逻辑时被调用
  466. onPreSolve(contact: cc.PhysicsContact, selfCollider: cc.PhysicsCollider, otherCollider: cc.PhysicsCollider) {
  467. if (otherCollider.node.group == "zombie") {
  468. contact.disabled = true;
  469. }
  470. }
  471. }