import { _decorator, Animation, AnimationClip, Component, Node, Sprite, SpriteFrame, UITransform, Vec3 } from 'cc'; import { LifeBar } from './LifeBar'; import { BulletPool } from './BulletPool'; const { ccclass, property } = _decorator; export enum BulletState { Normal, Explode, } @ccclass('Bullet') export class Bullet extends Component { //对象池 private _pool: BulletPool = null!; private _isEnemyBullet: boolean = false; private _animation: Animation = null; private _animations: Map = new Map(); private _explodeframes: SpriteFrame[] = []; private _bulletFrames: SpriteFrame[] = []; //是否爆炸 true -> 爆炸 isExplode: boolean = false; //子弹速度 bulletSpeed: number = 100; //子弹方向 direction: number = 1; //攻击力 atk: number = null; //被攻击的节点 targetNode: Node = null; //是否碰撞 private _hasCollided: boolean = false; private _initPos: Vec3 = null; protected onLoad(): void { this._animation = this.node.addComponent(Animation); this._createClip(BulletState.Normal, [], 10); this._createClip(BulletState.Explode, [], 10); } start() { this._initPos = this.node.position.clone(); this._collectAni(); this._playAnimation(BulletState.Normal); console.log(this._explodeframes , this._bulletFrames); } public reset(config: { pool: BulletPool, isEnemy: boolean, direction: number, bulletFrames: SpriteFrame[], explodeFrames: SpriteFrame[], targetNode: Node, atk: number, }) { //重置状态 this._pool = config.pool; this._isEnemyBullet = config.isEnemy; this.direction = config.direction; this._bulletFrames = config.bulletFrames; this._explodeframes = config.explodeFrames; this.targetNode = config.targetNode; this.atk = config.atk; this._hasCollided = false; this.isExplode = false; this.bulletSpeed = this._isEnemyBullet ? 100 : 90; this._initPos = this.node.position.clone(); this._collectAni(); this._playAnimation(BulletState.Normal); //重置位置和动画 this.node.active = true; } private _recycle() { if (this._pool) { //停止所有动画和事件 this._animation.stop(); this._animation.off(Animation.EventType.FINISHED); this.unscheduleAllCallbacks(); this.node.active = false; //回收到对象池 this._pool.recycle(this.node, this._isEnemyBullet); } else { console.log("destroy"); this.node.destroy(); } } update(deltaTime: number) { this.move(deltaTime); this.onBulletCollision(this.targetNode); this._checkDistance(); } // 处理子弹碰撞 private onBulletCollision(targetNode: Node) { if (this._hasCollided || !targetNode.isValid) return; const boxBullet = this.node.getComponent(UITransform).getBoundingBoxToWorld(); const boxTarget = targetNode.getComponent(UITransform).getBoundingBoxToWorld(); if (boxTarget.intersects(boxBullet)) { const targetLifeBar = targetNode.getComponent(LifeBar); const curHp: number = targetLifeBar._curHp - this.atk; targetLifeBar.updateProgressBar(curHp); if (curHp <= 0) { this._recycle(); } this._hasCollided = true; this._playAnimation(BulletState.Explode); } } move(dt: number) { let x = this.node.getWorldPosition().x; let y = this.node.getWorldPosition().y; let z = this.node.getWorldPosition().z; x = x + this.bulletSpeed * this.direction * dt; this.node.setWorldPosition(x, y, z) } private _checkDistance() { const currentPos: Vec3 = this.node.position; const distance: number = Vec3.distance(currentPos, this._initPos); if (distance >= 250) { this._recycle(); } } private _collectAni() { this._createClip(BulletState.Explode, this._explodeframes, 10); this._createClip(BulletState.Normal, this._bulletFrames, 10); } private _createClip(state: BulletState, frames: SpriteFrame[], fps: number) { const clip: AnimationClip = AnimationClip.createWithSpriteFrames(frames, fps); clip.name = BulletState[state]; clip.wrapMode = state === BulletState.Explode ? AnimationClip.WrapMode.Normal : AnimationClip.WrapMode.Loop; this._animation.addClip(clip, clip.name); this._animations.set(state, clip.name); } private _playAnimation(state: BulletState) { if (!this._animation) return; const clipName = this._animations.get(state); if (!clipName) return; this._animation.stop(); this._animation.play(clipName); if (state === BulletState.Explode) { this.bulletSpeed = 0; this._animation.once(Animation.EventType.FINISHED, () => { this._recycle(); }) } } }