import { _decorator, Node, Vec3, tween, director} from 'cc'; import { PoolManager } from '../../core/manager/PoolManager'; import { Game } from '../../game/Game'; import { uiMgr } from '../../core/manager/UIManager'; import { Constants } from '../../data/Constants'; import { GunfightShootUI } from '../../ui/GunfightShootUI'; import { Bullet2 } from './Bullet2'; import { GunBase } from '../base/GunBase'; import { Enemy } from '../../game/Enemy'; import { Player } from '../../game/Player'; import { audioMgr } from '../../core/manager/AudioManager'; const { ccclass, property } = _decorator; //玩家所使用的枪 步枪 可以按住镜头一直开枪(M416 AKM) @ccclass('Gun2') export class Gun2 extends GunBase { @property({type: Node,tooltip:"子弹节点"}) public bulletNode: Node = null!; @property({type: Node,tooltip:"开火特效节点"}) fireEffect: Node = null; //枪的拥有者 public holder: Player|Enemy = null; //开枪结束回调 public endCb: Function = null!; //换弹匣的回调 public ammoCb: Function = null; //触发间隔时间统计 private curTime: number = 0; //所有的烟雾 public smokes: Array = []! onLoad() { this.bulletNode.active = false; this.muzzleNode.active = false; } /** * 设置枪的数据 * @param data 枪的数据 * @param endCB 结束回调 * @param ammoCb 换弹匣回调 */ public init(data: any,holder: any,endCb?: Function,ammoCb?: Function){ this.data = data; this.shotBullets = 0; this.isFire = false; this.holder = holder; this.endCb = endCb; this.ammoCb = ammoCb; } //开火 public fire() { this.isFire = true; this.curTime = 0.0; } //结束开火 public endFire(){ this.isFire = false; this.endCb?.(this.data); this.recycle(); } /** * 直接开抢射杀敌人 */ public killEnemy(e: Enemy){ if(e.isDead ||Game.I.isPause){ return; } const destPos: Vec3 = e.node.worldPosition.clone(); const bullet: Bullet2 = this.getBulleNode(); bullet.init(this,true); tween(bullet.node) .to(0.3, {worldPosition:destPos}) .call(() => { bullet.isDead = true; PoolManager.putNode(bullet.node); //直接打死 最大血量乘以2倍 e.subHP(e.data.hp * 2,this.data); }) .start(); } /** * 展示子弹 */ public createBullet() { if(!this.holder ||this.holder.isDead ||!this.isFire ||Game.I.isPause ||Game.I.isGameOver){ return; } audioMgr.playOneShot(this.data.gun_sound); this.playParticle(this.fireEffect); this.getBulleNode(); this.shotBullets ++; //换弹夹的操作 if(this.shotBullets >= this.data.magazine){ this.shotBullets = 0; this.ammoCb?.(this.data); } } /** * 初始化一个子弹 * @param isGuaranteedHit 子弹是否必中(必中的时候targetNode不能为空) * @param targetNode 射击的目标对象 * @returns 返回一颗子弹 */ public getBulleNode(isGuaranteedHit: boolean = true, targetNode: Node = null): Bullet2{ //从对象池获取子弹节点 const bulletNode: Node = PoolManager.getNode(this.bulletNode, director.getScene()); const bullet: Bullet2 = bulletNode.getComponent(Bullet2); bullet.init(this); bulletNode.worldPosition = this.muzzleNode.worldPosition.clone(); //计算基准方向(瞄准目标或准星位置) const shootUI:GunfightShootUI = uiMgr.getPageComponent(Constants.popUIs.gunfightShootUI); const targetPos = targetNode ? targetNode.worldPosition : shootUI.getCrossHairPos(); const baseDirection = Vec3.subtract(new Vec3(), targetPos, 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 { let player: Player = Game.I.player; if(!player ||player.isDead ||!this.isFire ||Game.I.isPause ||Game.I.isGameOver){ return; } if(Game.I.player.isReloadMagazine){ return; } if(!Game.I.player.shootUI.isScopeOpen){ this.endFire(); return; } //每0.4秒攻击一次 发射一颗子弹 this.curTime += dt; if(this.curTime >= 0.2) { //播放射击帧动画 this.createBullet(); this.curTime = 0; } } /** * 回收烟雾 */ public recycle(){ this.smokes.forEach(e => { if(e && e.parent){ PoolManager.putNode(e); } }); this.smokes = []; } }