import { _decorator, Node, Vec3, director} from 'cc'; import { PoolManager } from '../../core/manager/PoolManager'; import { Game } from '../../game/Game'; import { GunBase } from '../base/GunBase'; import { Bullet14 } from './Bullet14'; import { Utils } from '../../utils/Utils'; import { Enemy } from '../../game/Enemy'; import { Player } from '../../game/Player'; const { ccclass, property } = _decorator; //1006 坦克 @ccclass('Gun14') export class Gun14 extends GunBase { @property({type: Node,tooltip:"子弹节点"}) public bulletNode: Node = null!; @property({type: Node,tooltip:"开火特效节点"}) fireEffect: Node = null; private isCb: boolean = false; //枪的拥有者 public enemy: Enemy = null; //开枪结束回调 public endCb: Function = null!; //换弹匣的回调 public ammoCb: Function = null; //触发间隔时间统计 private curTime: number = 0; //是否是第一次开火 private isFristShot: boolean = false; //所有的烟雾 public smokes: Array = []! //是否是第一次激活开枪 public isFristShoot: boolean = false; //为了戳开子弹产生的时间间隔统计 public diff: number = 0; //随机延迟的时间 public r_delay: number = 0; //继续正常统计时间 public isGo: boolean = true; onLoad() { this.bulletNode.active = false; this.muzzleNode.active = false; } /** * 设置枪的数据 * @param data 枪的数据 * @param endCB 结束回调 * @param ammoCb 换弹匣回调 */ public init(data: any,enemy: any,endCb?: Function,ammoCb?: Function){ this.data = data; this.curTime = 0; this.isFire = false; this.isFristShot = true; this.enemy = enemy; this.endCb = endCb; this.ammoCb = ammoCb; this.node.eulerAngles = new Vec3(0, 180, 0); } //开火 public fire() { this.isFire = true; this.playParticle(this.fireEffect); } //结束开火 public endFire(){ this.isFire = false; this.endCb?.(this.data); this.recycle(); } /** * 展示子弹 */ public createBullet() { if(!this.getNextAllow())return; let delay: number = 0.1; for(let i = 0; i < this.data.bullet_number; i++){ this.scheduleOnce((k: number)=>{ delay += Utils.getRandomFloat(0,0.2); if(!this.getNextAllow())return; //获取射击的精准度 const isHit: boolean = this.enemy.calculateIsHit(); //创建子弹 this.getBulleNode(isHit); },delay * i); } } /** * 初始化一个子弹 * @param isGuaranteedHit 子弹是否必中(必中的时候targetNode不能为空) * @param targetNode 射击的目标对象 * @returns 返回一颗子弹 */ public getBulleNode(isGuaranteedHit: boolean = true): Bullet14{ //从对象池获取子弹节点 const bulletNode: Node = PoolManager.getNode(this.bulletNode, director.getScene()); const bullet: Bullet14 = bulletNode.getComponent(Bullet14); bullet.init(this); bulletNode.setWorldPosition(this.muzzleNode.worldPosition); let playPos: Vec3 = Game.I.player.head.worldPosition.clone(); const baseDirection = Vec3.subtract(new Vec3(), playPos,this.muzzleNode.worldPosition).normalize(); //最终弹道方向 let finalDirection: Vec3; if(isGuaranteedHit) {//100%必中(无偏移) finalDirection = baseDirection; }else{//非必中:在基准方向上添加小范围随机偏移 const maxOffsetAngle = 5; const offsetX = (Math.random() - 0.5) * maxOffsetAngle * Math.PI / 180; const offsetY = (Math.random() - 0.5) * maxOffsetAngle * Math.PI / 180; //应用偏移(保持Z轴主要方向) finalDirection = new Vec3( baseDirection.x + offsetX, baseDirection.y + offsetY, baseDirection.z // 保持主要前进方向 ).normalize(); } //设置子弹方向 bulletNode.forward = finalDirection; bullet.setBulletVector(finalDirection); return bullet; } //激活调用 持续开火 protected update(dt: number): void { if(!this.getNextAllow())return; //每几秒攻击一次 let m: number = this.data.atk_speed; //不是第一次激活 有延迟间隔 if(!this.isFristShoot){ m = this.isFristShoot ? 0 : m; if(this.diff >= this.r_delay && !this.isGo){ this.diff += dt; this.isGo = true; return; }else{ this.curTime += dt; } }else{//第一次激活 就直接开枪不延迟 m = this.isFristShoot ? 0 : m; } //在随机延迟的时间间隔里 发射一颗子弹 if(this.curTime >= m - this.r_delay) { if(this.isFire){ this.isFristShoot = false; this.r_delay = Utils.getRandomFloat(0,0.12); this.diff = 0; this.isGo = false; //audioMgr.playOneShot(this.data.gun_sound); //播放射击帧动画 //this.playShootAnim(); this.createBullet(); this.curTime = 0; this.isCb = false; }else{ if(!this.isFire && !this.isCb){ this.isFire = false; this.endCb?.(this.data.type); this.isCb = true; } } } } /** * 是否可以允许操作 */ private getNextAllow(){ let player: Player = Game.I.player; if(!player ||player.isDead ||!this.isFire ||Game.I.isPause ||Game.I.isGameOver){ return false; } return true; } /** * 回收烟雾 */ public recycle(){ this.smokes.forEach(e => { if(e && e.parent){ PoolManager.putNode(e); } }); this.smokes = []; } }