Sundries.ts 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import { _decorator, Collider, Enum, Node, RigidBody, Animation, Vec3 } from 'cc';
  2. import { BaseExp } from '../core/base/BaseExp';
  3. import { PoolManager } from '../core/manager/PoolManager';
  4. import { userIns } from '../data/UserData';
  5. import { autoBind } from '../extend/AutoBind';
  6. import { Logger } from '../extend/Logger';
  7. import { ResUtil } from '../utils/ResUtil';
  8. import { Game } from './Game';
  9. import { Enemy, EPartType } from './Enemy';
  10. import { audioMgr } from '../core/manager/AudioManager';
  11. import { Constants } from '../data/Constants';
  12. import MsgHints from '../utils/MsgHints';
  13. const { ccclass, property } = _decorator;
  14. //沙袋堆动画
  15. const sandbge_take = "take"
  16. /**
  17. * 战场障碍物类型
  18. */
  19. export enum ObstacleType {
  20. /** 沙袋堆 */
  21. SANDBAG_PILE = "沙袋堆",
  22. /** 油桶 */
  23. OIL_BARREL = "油桶",
  24. /** 军车 */
  25. MILITARY_TRUCK = "军车",
  26. /** 小沙袋 */
  27. SMALL_SANDBAG = "小沙袋"
  28. }
  29. /**
  30. * 杂物建筑物类
  31. */
  32. @ccclass('Sundries')
  33. export class Sundries extends BaseExp {
  34. @property({ type: Enum(ObstacleType), tooltip: "沙袋堆:SANDBAG_PILE 油桶:OIL_BARREL 军车: MILITARY_TRUCK 小沙袋:SMALL_SANDBAG", displayName: "障碍物类型"})
  35. public obstacleType: ObstacleType = ObstacleType.SANDBAG_PILE;
  36. //杂物信息数据
  37. public data: any = null;
  38. //杂物是否被打报废
  39. private isDead: boolean = false;
  40. //杂物当前的总血量
  41. private totalHp: number = 0;
  42. start() {
  43. //给碰撞体绑定数据
  44. this.setupColliders(this.node);
  45. //根据障碍物类型设置总血量
  46. let sundrie_id: number = -1;
  47. switch (this.obstacleType) {
  48. case ObstacleType.SANDBAG_PILE:
  49. sundrie_id = 11001;
  50. break;
  51. case ObstacleType.OIL_BARREL:
  52. sundrie_id = 11002;
  53. break;
  54. case ObstacleType.MILITARY_TRUCK:
  55. sundrie_id = 11003;
  56. break;
  57. case ObstacleType.SMALL_SANDBAG:
  58. sundrie_id = 11004;
  59. break;
  60. }
  61. if(sundrie_id !== -1){
  62. const data: any = userIns.sundriesTable.find(e=>e.id == sundrie_id);
  63. this.data = data;
  64. this.totalHp = data.hp;
  65. }else{
  66. Logger.log('未找到对应的杂物信息');
  67. }
  68. }
  69. /**
  70. * 杂物被打掉血
  71. * @param hp 血
  72. * @param pData 玩家数据
  73. */
  74. public subHP(hp: number, pData:any){
  75. if(Game.I.isPause
  76. ||this.isDead
  77. ||hp == null
  78. ||this.totalHp <= 0){
  79. return;
  80. }
  81. MsgHints.show(`${this.node.name} HP:`+hp)
  82. this.totalHp -= hp;
  83. //杂物打打死报废
  84. if(this.totalHp <= 0
  85. && !this.isDead){
  86. this.isDead = true;
  87. this.scrap();
  88. }
  89. }
  90. /**
  91. * 杂物被打报废
  92. */
  93. public scrap(){
  94. switch (this.obstacleType) {
  95. case ObstacleType.SANDBAG_PILE:{//沙袋堆
  96. let skeletal:Animation = this.node.getComponent(Animation);
  97. if(!skeletal)return;
  98. //沙袋掀开的动画
  99. skeletal.play(sandbge_take);
  100. skeletal.scheduleOnce(()=>{
  101. skeletal.pause();
  102. },0.9);
  103. }
  104. break;
  105. case ObstacleType.OIL_BARREL:{//油桶
  106. //油漆桶音效
  107. audioMgr.playOneShot(Constants.audios.Oildrum_explosion);
  108. //爆炸后生成爆炸特效 粒子路径、自动回收时间、外部设置回调
  109. ResUtil.playParticle(
  110. `effects/Prefabs/OilBoom`,
  111. 4,
  112. (particle) => {
  113. particle.position = new Vec3(0.2,0.2,0.2);
  114. particle.parent = Game.I.map.node;
  115. const targetPos: Vec3 = this.node.worldPosition.clone();
  116. particle.worldPosition = targetPos;
  117. particle.active = true;
  118. this.recycle();
  119. //爆炸后生成爆炸伤害
  120. this.explosionDamage(targetPos);
  121. }
  122. );
  123. }
  124. break;
  125. case ObstacleType.MILITARY_TRUCK:{//军车
  126. //加载报废的军车
  127. ResUtil.loadRes(`enemy/sundries/scrap_car`, this.node)
  128. .then((military: Node | null) => {
  129. if(!military)return;
  130. military.active = true;
  131. military.parent = this.node.parent;
  132. const targetPos: Vec3 = this.node.worldPosition.clone();
  133. military.worldPosition = targetPos;
  134. military.eulerAngles = this.node.eulerAngles.clone();
  135. military.scale = this.node.scale.clone();
  136. //回收原有的军车
  137. this.recycle();
  138. //播放爆炸过后的浓烟
  139. ResUtil.playParticle(
  140. `effects/Prefabs/HeavySmoke`,
  141. 3,
  142. (particle) => {
  143. particle.parent = Game.I.map.node;
  144. particle.worldPosition = targetPos;
  145. particle.active = true;
  146. //爆炸后生成爆炸伤害
  147. this.explosionDamage(targetPos);
  148. }
  149. );
  150. });
  151. }
  152. break;
  153. case ObstacleType.SMALL_SANDBAG:{//小沙袋
  154. //获取刚体组件
  155. const rigidBody = this.node.getComponent(RigidBody);
  156. if (!rigidBody) return;
  157. //计算抛射方向
  158. const startPos = this.node.worldPosition.clone();
  159. const playerPos = Game.I.player.node.worldPosition.clone();
  160. const direction = startPos.subtract(playerPos).normalize();
  161. //随机抛射参数 水平力1500-2500N
  162. const horizontalForce = 1500 + Math.random() * 1000;
  163. //垂直力800-1500N
  164. const verticalForce = 800 + Math.random() * 700;
  165. //旋转扭矩50-150
  166. const torqueForce = 50 + Math.random() * 100;
  167. //施加作用力
  168. rigidBody.applyForce(new Vec3(
  169. direction.x * horizontalForce,
  170. verticalForce,
  171. direction.z * horizontalForce
  172. ));
  173. //施加旋转扭矩
  174. rigidBody.applyTorque(new Vec3(0, torqueForce, 0));
  175. }
  176. break;
  177. }
  178. }
  179. /**
  180. * 爆炸物产生爆炸伤害
  181. * @param targetPos 爆炸物的位置
  182. */
  183. public explosionDamage(targetPos: Vec3){
  184. //爆炸半径
  185. const eRadius: number = this.data.explosion_radius / 10;
  186. const allEnemys = Game.I.buildEnemys.allEnemys.filter(e=>!e.isDead);
  187. if(allEnemys.length <= 0)return;
  188. //爆炸伤害
  189. const damage: number = this.data.explosion_injury;
  190. allEnemys.forEach((e: Enemy) => {
  191. const ePos: Vec3 = e.node.worldPosition;
  192. const distance = ePos.clone().subtract(targetPos).length();
  193. if(distance <= eRadius) {
  194. e.subHP(damage, this.data);
  195. }
  196. })
  197. }
  198. /**
  199. * 递归设置所有子节点的Collider参数
  200. * @param node 起始节点
  201. */
  202. private setupColliders(node: Node) {
  203. const collider = node.getComponent(Collider);
  204. if(collider){
  205. collider["args"] = [EPartType.sundries, this];
  206. }
  207. //递归处理所有子节点
  208. node.children.forEach(child => {
  209. this.setupColliders(child);
  210. });
  211. }
  212. /**
  213. * 杂物回收
  214. */
  215. public recycle(){
  216. if(this.node.parent){
  217. this.isDead = true;
  218. PoolManager.putNode(this.node);
  219. }
  220. }
  221. }