123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- import { _decorator, Animation, AnimationState, Collider, Enum, Node, RigidBody, Vec3 } from 'cc';
- import { BaseExp } from '../core/base/BaseExp';
- import { PoolManager } from '../core/manager/PoolManager';
- import { userIns } from '../data/UserData';
- import { Logger } from '../extend/Logger';
- import { ResUtil } from '../utils/ResUtil';
- import { Game } from './Game';
- import { audioMgr } from '../core/manager/AudioManager';
- import { Constants } from '../data/Constants';
- import { Enemy } from './Enemy';
- import { GameEnums } from '../data/GameEnums';
- 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;
-
- //浓烟节点 只有军车的时候血量低于30%才会有
- public heavySmoke: Node = null;
- //添加爆炸队列和标记
- private static explosionQueue: {
- target: Enemy | Sundries,
- damage: number,
- source: any,
- explosionTarget:any}[] = [];
- //标记是否正在处理爆炸队列
- private static isProcessingQueue = false;
- //杂物信息数据
- 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 玩家数据
- * @param target 这儿指的是谁打的我
- */
- public subHP(hp: number, pData:any,target:Node){
- if(!this.node
- ||Game.I.isPause
- ||this.isDead
- ||hp == null
- ||this.totalHp <= 0){
- return;
- }
- this.totalHp -= hp;
- //军车在生命值低于30%时触发动画1黑烟效果 在生命值为0时触发动画 2爆炸效果
- this.milityaryTruckHeavySmoke();
- //杂物打打死报废
- if(this.totalHp <= 0
- && !this.isDead){
- this.isDead = true;
- this.scrap(target);
- }
- }
-
- /**
- * 军车冒浓烟
- */
- public milityaryTruckHeavySmoke(){
- if(this.obstacleType != ObstacleType.MILITARY_TRUCK)return;
- if(this.heavySmoke)return;
- //血量过低冒浓烟
- if(this.totalHp < this.data.hp * 0.3){
- ResUtil.playParticle(
- `effects/Prefabs/HeavySmoke`,
- 0,
- new Vec3(0.18,0.18,0.18),
- (heavySmoke) => {
- heavySmoke.parent = this.node.parent;
- heavySmoke.worldPosition = this.node.worldPosition.clone();
- heavySmoke.active = true;
- this.heavySmoke = heavySmoke;
- }
- );
- }
- }
- /**
- * 杂物被打报废
- */
- public scrap(target:Node){
- switch (this.obstacleType) {
- case ObstacleType.SANDBAG_PILE:{//沙袋堆
- //沙袋掀开的动画
- let anim:Animation = this.node.getComponent(Animation);
- if(!anim)return;
- //参考物位置坐标 用于计算查沙袋旋开的的方向
- let refePos: Vec3 = target.worldPosition.clone();
- let selfPos: Vec3 = this.node.worldPosition.clone();
- //计算方向向量
- let direction = new Vec3();
- Vec3.subtract(direction, refePos, selfPos).normalize();
- //根据方向调整沙袋的旋转
- let relativeAngle = Math.atan2(direction.x, direction.z) * 180 / Math.PI;
- const initialRotation = this.node.eulerAngles.y;
- this.node.setRotationFromEuler(0, initialRotation + relativeAngle - 85, 0);
- //播放动画
- let animState:AnimationState = anim.getState(sandbge_take);
- animState.speed = 1;
- animState.repeatCount = 1;
- anim.play(sandbge_take);
- }
- break;
- case ObstacleType.OIL_BARREL:{//油桶
- //油漆桶音效
- audioMgr.playOneShot(Constants.audios.Oildrum_explosion);
- //爆炸后生成爆炸特效 粒子路径、自动回收时间、外部设置回调
- ResUtil.playParticle(
- `effects/Prefabs/OilBoom`,
- 4,
- new Vec3(0.1,0.1,0.1),
- (particle) => {
- particle.parent = this.node.parent;
- 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/TankBoom`,
- 3,
- new Vec3(0.1,0.1,0.1),
- (particle) => {
- particle.parent = this.node.parent;
- particle.worldPosition = targetPos;
- particle.active = true;
- //爆炸后生成爆炸伤害
- this.explosionDamage(targetPos);
- },
- () => {//爆炸完成后 回收浓烟
- this.scheduleOnce(()=>{
- if(this.heavySmoke && this.heavySmoke.parent){
- PoolManager.putNode(this.heavySmoke);
- this.heavySmoke = null;
- }
- },3);
- }
- );
- });
- }
- 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;
- }
- }
- /**油桶半径的5倍2.24 车5车的半径 10.2
- * 爆炸物产生爆炸伤害
- * @param targetPos 爆炸物的位置
- */
- public explosionDamage(targetPos: Vec3){
- if(!this.data
- || !this.data.explosion_radius
- || !this.data.explosion_injury) {
- Logger.error('爆炸物数据异常', this.data);
- return;
- }
- //爆炸半径
- const eRadius: number = this.data.explosion_radius;
- //查找不是自身的所有杂物 然后去看看是否有连续爆炸
- const allSundries: Sundries[] = Game.I.map.sundries.children
- .filter(node => node.active && node.parent && node != this.node)
- .map(node => node.getComponent(Sundries))
- .filter(comp =>
- comp && !comp.isDead
- ) as Sundries[];
- const allEnemys = [...Game.I.buildEnemys.allEnemys.filter(e=>!e.isDead && e.node.active),
- ...allSundries];
- if(allEnemys.length <= 0)return;
- //爆炸伤害
- const damage: number = this.data.explosion_injury;
- allEnemys.forEach((e: any) => {
- if(e.node && e.node.parent){
- const ePos: Vec3 = e.node.worldPosition;
- const hDistance = Vec3.distance(
- new Vec3(targetPos.x, 0, targetPos.z),
- new Vec3(ePos.x, 0, ePos.z)
- );
- if(hDistance <= eRadius) {
- if(e instanceof Enemy){//敌人直接扣血
- e.subHP(damage, this.data);
- }else if(e instanceof Sundries){//爆炸物 如果队列未在处理则开始处理 将爆炸目标加入队列而不是立即触发
- Sundries.explosionQueue.push({
- target: e,
- damage: damage,
- source: this.data,
- explosionTarget: this.node
- });
- if(!Sundries.isProcessingQueue) {
- this.processExplosionQueue();
- }
- }
- }
- }
- })
- }
- /**
- * 处理爆炸队列
- */
- private processExplosionQueue() {
- if (Sundries.explosionQueue.length == 0) {
- Sundries.isProcessingQueue = false;
- return;
- }
- Sundries.isProcessingQueue = true;
- const explosion = Sundries.explosionQueue.shift()!;
- //触发当前爆炸
- explosion.target.subHP(explosion.damage, explosion.source,explosion.explosionTarget);
- //添加0.2秒延迟后处理下一个爆炸
- this.scheduleOnce(()=>{
- this.processExplosionQueue();
- },0.2)
- }
- /**
- * 递归设置所有子节点的Collider参数
- * @param node 起始节点
- */
- private setupColliders(node: Node) {
- const collider = node.getComponent(Collider);
- if(collider){
- collider["args"] = [GameEnums.enemyPartType.sundries, this];
- }
- //递归处理所有子节点
- node.children.forEach(child => {
- this.setupColliders(child);
- });
- }
- /**
- * 杂物回收
- */
- public recycle(){
- this.isDead = true;
- this.node.active = false;
- /*if(this.node.active){
- this.isDead = true;
- PoolManager.putNode(this.node);
- }*/
- }
- }
|