| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 | import { _decorator, Animation, AnimationClip, AnimationState, BoxCollider2D, Component, find, instantiate, ITriggerEvent, Node, ObjectCurve, PhysicsSystem2D, SpriteFrame, Vec2, Vec3 } from 'cc';import { Tools } from '../Tools/Tools';import { RoleData } from '../../DataItem/ItemData';import { resMgr } from '../../Frames/ResourcesMgr';import { Bullet } from './GameScene/Bullet';import { LifeBar } from './GameScene/LifeBar';import { BulletPool } from './GameScene/BulletPool';const { ccclass, property } = _decorator;export enum RoleState {    Attack,    Move,    Idle,    Die}@ccclass('Role')export class Role extends Component {    //基础数据    hp: number = null; //血量    atk: number = null; //攻击力    atkLength: number = null; //攻击距离    moveSpeed: number = null; //移速    //向左-1 向右1    direction: number = 1;    //是否停下    //isStop: boolean = true;    //攻击目标    targetNode: Node = null;    //战斗系统    private _attackTimer: number = 0;    private _attackInterval: number = 3;//攻击间隔    private currentTarget: Role | null = null;//当前目标    //子弹    private _bullet: Node | null = null;    private _bulletLayer: Node | null = null;    private _bulletPool: BulletPool = null;    //动画管理    private _animations: Map<RoleState, string> = new Map();    private _moveFrames: SpriteFrame[] = [];    private _atkFrames: SpriteFrame[] = [];    private _idleFrames: SpriteFrame[] = [];    private _dieFrames: SpriteFrame[] = [];    private _explodeframes: SpriteFrame[] = [];    private _bulletFrames: SpriteFrame[] = [];    private _animation: Animation = null;    //角色数据    private _roleData: RoleData = null;    //状态管理    _state: RoleState = null;    protected init(name: string, pos: Vec3, roleDatas: RoleData[], dir?: number) {        this._bulletPool = this.node.getComponent(BulletPool);        this._bulletPool.init();        this._animation = this.node.getComponent(Animation) || this.node.addComponent(Animation);        this.direction = dir;        let whichData: number = -1;        for (let i = 0; i < roleDatas.length; i++) {            if (!roleDatas[i]) {                console.log(null)            }            if (roleDatas[i].imgName === name) {                this._roleData = roleDatas[i];                whichData = i;                break;            }        }        if (whichData != -1) {            //获取move精灵帧            this._getFrames(this._roleData.moveCount, this._moveFrames, this._roleData.moveImg, 1);            //attack            this._getFrames(this._roleData.atkCount, this._atkFrames, this._roleData.atkImg, 1);            //idle            this._getFrames(this._roleData.idleCount, this._idleFrames, this._roleData.idleImg, 1)            //die            this._getFrames(this._roleData.dieCount, this._dieFrames, this._roleData.dieImg, 1)            //动画            this._collectAni();            //子弹精灵帧            this._getFrames(this._roleData.bulletCount, this._bulletFrames, this._roleData.bulletImg, 1)            //子弹爆炸精灵帧            this._getFrames(this._roleData.bulletCount, this._explodeframes, this._roleData.bulletExplodeImg, 1)            //设置基础数据            this._setRoleData(this._roleData);            this.playAnimation(RoleState.Move);        }        //位置        this.node.setWorldPosition(pos);        this._bulletLayer = find("Canvas/GameRoot/BulletLayer");        this._setupPhysics();    }    private _setRoleData(roleData: RoleData) {        this.hp = roleData.hp;        this.atk = roleData.atk;        this.atkLength = roleData.atkLength + 100;        this.moveSpeed = roleData.moveSpeed;    }    private _setupPhysics() {        //确保有碰撞组件        const collider2D = this.getComponent(BoxCollider2D) || this.addComponent(BoxCollider2D);        collider2D.group = this._getCollisionGroup();        collider2D.apply();    }    //获取精灵帧组     /*    count -> 精灵帧的数量     imgType -> 图片类型(atk、walk、idle、die)    startIdx -> 索引起始数    */    private _getFrames(count: number, frames: SpriteFrame[], imgType: string, startIdx: number) {        for (let i = startIdx; i <= count; i++) {            if (count > 1) {                frames.push(resMgr.getSpriteFrame(imgType + ' (' + i + ')'));            }            else {                frames.push(resMgr.getSpriteFrame(imgType + ' (1)'));            }        }    }    update(deltaTime: number) {        if (this._state === RoleState.Die) return;        if (!this.currentTarget) {            this._handleMovement(deltaTime);            this._detectEnemies();        } else {            this._handleAttack(deltaTime);        }    }    //移动    private _handleMovement(dt: number) {        if (this._state !== RoleState.Move) return;        let x = this.node.position.x;        let y = this.node.position.y;        let z = this.node.position.z;        x = x + this.moveSpeed * this.direction * dt        this.node.setPosition(x, y, z);        this.stop();    }    //寻敌    private _detectEnemies() {        if (!this.node.isValid) return;        //const startPos = new Vec2(this.node.position.x, this.node.position.y);        const startPos = this.node.position.clone();        const endPos = new Vec2((this.direction * this.atkLength) + this.node.position.x, this.node.position.y);        const results = PhysicsSystem2D.instance.raycast(startPos, endPos);        if (results?.length) {            for (const result of results) {                const target = result.collider.node.getComponent(Role);                if (target && this._isValidTarget(target)) {                    this._setTarget(target);                    break;                }            }        }    }    //设置攻击目标    private _setTarget(target: Role) {        this.currentTarget = target;        this.playAnimation(RoleState.Attack);        // 使得第一次update就会触发attackTimer >= attackInterval条件        this._attackTimer = this._attackInterval - 0.001;        //监听目标销毁事件        target.node.once(Node.EventType.NODE_DESTROYED, this._onTargetDestroyed, this);    }    //攻击    private _handleAttack(deltaTime: number) {        //目标是否可以攻击        if (!this._validateTarget()) {            this._clearTarget();            return;        }        /*        //立即攻击判断        if (this._attackTimer === 0) {            this._createBullet();            this._attackTimer += deltaTime;            return;        }        //后续间隔攻击        this._attackTimer += deltaTime;        if (this._attackTimer >= this._attackInterval) {            this._createBullet();            this._attackTimer = 0; //重置计时器        }            */        // this._createBullet();        // this.schedule(() => {        //     this._createBullet();        // }, this.attackInterval);    }    //目标是否可以攻击 hp大于0 并且 在攻击范围内 -> 可以攻击    private _validateTarget(): boolean {        return !!this.currentTarget?.node?.isValid &&            this.currentTarget.hp > 0 &&            this._getDistanceToTarget() <= this.atkLength;    }    //攻击目标与自身的距离    private _getDistanceToTarget(): number {        return Math.abs(this.node.getWorldPosition().x - this.currentTarget.node.getWorldPosition().x);    }    //销毁目标    private _onTargetDestroyed() {        this._clearTarget();        if (this.node === null) return;        this._detectEnemies();//立即检测新目标    }    //清除目标 关闭触发事件 当前目标置空 设置移动状态 播放移动动画    private _clearTarget() {        this.currentTarget?.node.off(Node.EventType.NODE_DESTROYED, this._onTargetDestroyed, this);        this.currentTarget = null;        this.playAnimation(RoleState.Move);    }    stop() {    }    //将各个动画存储起来    private _collectAni() {        // const moveAni: Animation = Tools.createAnimation(this._moveFrames, 8, this.node, AnimationClip.WrapMode.Loop)        // this._animations.set(RoleState.Move, moveAni);        // const atkAni: Animation = Tools.createAnimation(this._atkFrames, 8, this.node, AnimationClip.WrapMode.Loop)        // this._animations.set(RoleState.Attack, atkAni);        // const idleAni: Animation = Tools.createAnimation(this._idleFrames, 8, this.node, AnimationClip.WrapMode.Loop)        // this._animations.set(RoleState.Idle, idleAni);        // const dieAni: Animation = Tools.createAnimation(this._dieFrames, 8, this.node, AnimationClip.WrapMode.Normal)        // this._animations.set(RoleState.Die, dieAni);        this._createClip(RoleState.Move, this._moveFrames, 8);        this._createClip(RoleState.Attack, this._atkFrames, 8);        this._createClip(RoleState.Idle, this._idleFrames, 8);        this._createClip(RoleState.Die, this._dieFrames, 9);    }    //创建动画剪辑 fps越大 速度越快    private _createClip(state: RoleState, frames: SpriteFrame[], fps: number) {        const clip: AnimationClip = AnimationClip.createWithSpriteFrames(frames, fps);        clip.name = RoleState[state];        clip.wrapMode = state === RoleState.Die ?            AnimationClip.WrapMode.Normal :            AnimationClip.WrapMode.Loop;        if(clip.name === 'Attack'){            clip.events = [{                frame: 0.5,                func: "onTriggered",                params: ["a"] //向func传递的参数            }]        }        this._animation.addClip(clip, clip.name);        this._animations.set(state, clip.name);    }    onTriggered(){        this._createBullet();    }    //设置动画    public playAnimation(state: RoleState) {        if (!this._animation || this._state === state) return;        const clipName = this._animations.get(state);        if (!clipName) return;        this._state = state;        this._animation.stop();        this._animation.play(clipName);        if (state === RoleState.Die) {            this.node.removeAllChildren();            this._animation.once(Animation.EventType.FINISHED, () => {                this.node.destroy();            });        }        // if (this._animations === null) {        //     Error("No found" + state);        //     return;        // }        // if (this._state === state) return;        // this._state = state;        // this._animations.get(state).play();        // if (state === RoleState.Die) {        //     this._animations.get(state).once(Animation.EventType.FINISHED, () => {        //         this.node.destroy();        //     })        // }        // this._animations.forEach((anim, key) => {        //     if(key === state){        //         anim.play();        //         if(key === RoleState.Die){        //             anim.once(Animation.EventType.FINISHED,()=>{        //                 this.node.destroy();        //             })        //         }        //     }        //     //key === state ? anim.play() : anim.stop();        // })    }    //判断是否攻击    // getEnemiesAhead(parent: Node) {    //     for (const node of parent.children) {    //         const enemyY = node.getWorldPosition().y;    //         const enemyX = node.getWorldPosition().x;    //         const y = this.node.getWorldPosition().y;    //         const x = this.node.getWorldPosition().x;    //         if (enemyY === y) {    //             const distance = Math.abs(enemyX - x);    //             if (distance <= this.atkLength) {    //                 //开始攻击    //                 this.isAttacking = true;    //                 //设置攻击目标    //                 this.targetNode = node;    //                 //停止移动    //                 this.isStop = true;    //                 //开始开火    //                 this.isFire = true;    //                 this.attack(this.targetNode, this.isFire);    //                 break;    //             }    //         }    //     }    // }    // attack(targetNode: Node, isFire: boolean) {    //     if (!targetNode) return;    //     const targetNodeTS = targetNode.getComponent(Role);    //     if (isFire && targetNodeTS.hp > 0) {    //         this._createBullet();    //         this.schedule(() => {    //             this._createBullet();    //         }, 3)    //     }    // }    //创建子弹    private _createBullet() {        // if (this.direction === -1) {        //     this._bullet = instantiate(resMgr.getPrefab("BulletEnemy"));        // } else if (this.direction === 1) {        //     this._bullet = instantiate(resMgr.getPrefab("Bullet"));        // }        const isEnemy = this.direction === -1;        this._bullet = this._bulletPool.getBullet(isEnemy);        this._bullet.parent = this._bulletLayer;        this._bullet.setWorldPosition(this.node.getWorldPosition());        const bulletTS = this._bullet.getComponent(Bullet);        bulletTS.reset({            pool: this._bulletPool,            isEnemy: isEnemy,            direction: this.direction,            bulletFrames: this._bulletFrames,            explodeFrames: this._explodeframes,            targetNode: this.currentTarget.node,            atk: this.atk,        })        // bulletTS.direction = this.direction;        // bulletTS.bulletFrames = this._bulletFrames;        // bulletTS.explodeframes = this._explodeframes;        // bulletTS.targetNode = this.currentTarget.node;        // bulletTS.atk = this.atk;    }    //要求子类实现的碰撞分组和阵营判断方法,确保不同阵营角色可以正确交互    protected _getCollisionGroup(): number {        throw new Error("Method not implemented");    }    protected _isValidTarget(target: Role): boolean {        throw new Error("Method not implemented");    }}
 |