import { _decorator, Collider, Enum, Node, RigidBody, Animation, Vec3 } from 'cc'; import { BaseExp } from '../core/base/BaseExp'; import { PoolManager } from '../core/manager/PoolManager'; import { userIns } from '../data/UserData'; import { autoBind } from '../extend/AutoBind'; import { Logger } from '../extend/Logger'; import { ResUtil } from '../utils/ResUtil'; import { Game } from './Game'; import { Enemy, EPartType } from './Enemy'; import { audioMgr } from '../core/manager/AudioManager'; import { Constants } from '../data/Constants'; import MsgHints from '../utils/MsgHints'; const { ccclass, property } = _decorator; //沙袋堆动画 const sandbge_take = "take" /** * 战场障碍物类型 */ export enum ObstacleType { /** 沙袋堆 */ SANDBAG_PILE = "沙袋堆", /** 油桶 */ OIL_BARREL = "油桶", /** 军车 */ MILITARY_TRUCK = "军车", /** 小沙袋 */ SMALL_SANDBAG = "小沙袋" } /** * 杂物建筑物类 */ @ccclass('Sundries') export class Sundries extends BaseExp { @property({ type: Enum(ObstacleType), tooltip: "沙袋堆:SANDBAG_PILE 油桶:OIL_BARREL 军车: MILITARY_TRUCK 小沙袋:SMALL_SANDBAG", displayName: "障碍物类型"}) public obstacleType: ObstacleType = ObstacleType.SANDBAG_PILE; //杂物信息数据 public data: any = null; //杂物是否被打报废 private isDead: boolean = false; //杂物当前的总血量 private totalHp: number = 0; start() { //给碰撞体绑定数据 this.setupColliders(this.node); //根据障碍物类型设置总血量 let sundrie_id: number = -1; switch (this.obstacleType) { case ObstacleType.SANDBAG_PILE: sundrie_id = 11001; break; case ObstacleType.OIL_BARREL: sundrie_id = 11002; break; case ObstacleType.MILITARY_TRUCK: sundrie_id = 11003; break; case ObstacleType.SMALL_SANDBAG: sundrie_id = 11004; break; } if(sundrie_id !== -1){ const data: any = userIns.sundriesTable.find(e=>e.id == sundrie_id); this.data = data; this.totalHp = data.hp; }else{ Logger.log('未找到对应的杂物信息'); } } /** * 杂物被打掉血 * @param hp 血 * @param pData 玩家数据 */ public subHP(hp: number, pData:any){ if(Game.I.isPause ||this.isDead ||hp == null ||this.totalHp <= 0){ return; } MsgHints.show(`${this.node.name} HP:`+hp) this.totalHp -= hp; //杂物打打死报废 if(this.totalHp <= 0 && !this.isDead){ this.isDead = true; this.scrap(); } } /** * 杂物被打报废 */ public scrap(){ switch (this.obstacleType) { case ObstacleType.SANDBAG_PILE:{//沙袋堆 let skeletal:Animation = this.node.getComponent(Animation); if(!skeletal)return; //沙袋掀开的动画 skeletal.play(sandbge_take); skeletal.scheduleOnce(()=>{ skeletal.pause(); },0.9); } break; case ObstacleType.OIL_BARREL:{//油桶 //油漆桶音效 audioMgr.playOneShot(Constants.audios.Oildrum_explosion); //爆炸后生成爆炸特效 粒子路径、自动回收时间、外部设置回调 ResUtil.playParticle( `effects/Prefabs/OilBoom`, 4, (particle) => { particle.position = new Vec3(0.2,0.2,0.2); particle.parent = Game.I.map.node; const targetPos: Vec3 = this.node.worldPosition.clone(); particle.worldPosition = targetPos; particle.active = true; this.recycle(); //爆炸后生成爆炸伤害 this.explosionDamage(targetPos); } ); } break; case ObstacleType.MILITARY_TRUCK:{//军车 //加载报废的军车 ResUtil.loadRes(`enemy/sundries/scrap_car`, this.node) .then((military: Node | null) => { if(!military)return; military.active = true; military.parent = this.node.parent; const targetPos: Vec3 = this.node.worldPosition.clone(); military.worldPosition = targetPos; military.eulerAngles = this.node.eulerAngles.clone(); military.scale = this.node.scale.clone(); //回收原有的军车 this.recycle(); //播放爆炸过后的浓烟 ResUtil.playParticle( `effects/Prefabs/HeavySmoke`, 3, (particle) => { particle.parent = Game.I.map.node; particle.worldPosition = targetPos; particle.active = true; //爆炸后生成爆炸伤害 this.explosionDamage(targetPos); } ); }); } break; case ObstacleType.SMALL_SANDBAG:{//小沙袋 //获取刚体组件 const rigidBody = this.node.getComponent(RigidBody); if (!rigidBody) return; //计算抛射方向 const startPos = this.node.worldPosition.clone(); const playerPos = Game.I.player.node.worldPosition.clone(); const direction = startPos.subtract(playerPos).normalize(); //随机抛射参数 水平力1500-2500N const horizontalForce = 1500 + Math.random() * 1000; //垂直力800-1500N const verticalForce = 800 + Math.random() * 700; //旋转扭矩50-150 const torqueForce = 50 + Math.random() * 100; //施加作用力 rigidBody.applyForce(new Vec3( direction.x * horizontalForce, verticalForce, direction.z * horizontalForce )); //施加旋转扭矩 rigidBody.applyTorque(new Vec3(0, torqueForce, 0)); } break; } } /** * 爆炸物产生爆炸伤害 * @param targetPos 爆炸物的位置 */ public explosionDamage(targetPos: Vec3){ //爆炸半径 const eRadius: number = this.data.explosion_radius / 10; const allEnemys = Game.I.buildEnemys.allEnemys.filter(e=>!e.isDead); if(allEnemys.length <= 0)return; //爆炸伤害 const damage: number = this.data.explosion_injury; allEnemys.forEach((e: Enemy) => { const ePos: Vec3 = e.node.worldPosition; const distance = ePos.clone().subtract(targetPos).length(); if(distance <= eRadius) { e.subHP(damage, this.data); } }) } /** * 递归设置所有子节点的Collider参数 * @param node 起始节点 */ private setupColliders(node: Node) { const collider = node.getComponent(Collider); if(collider){ collider["args"] = [EPartType.sundries, this]; } //递归处理所有子节点 node.children.forEach(child => { this.setupColliders(child); }); } /** * 杂物回收 */ public recycle(){ if(this.node.parent){ this.isDead = true; PoolManager.putNode(this.node); } } }