cocos做飞机大战笔记【敌机发射子弹】

本文介绍了如何在飞机大战游戏中设置碰撞分组,通过位运算管理不同的碰撞类型,包括玩家飞机、敌机、子弹之间的碰撞。详细讲解了在游戏对象中添加碰撞体,编写碰撞脚本,以及游戏管理类中处理碰撞事件的逻辑,包括玩家飞机被击中掉血、敌机被击中后销毁并加分,以及子弹碰撞后的销毁操作。同时,还展示了敌机子弹的分组设置,以确保正确的碰撞检测。
摘要由CSDN通过智能技术生成

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


设置碰撞分组

主要有敌机、敌机子弹,玩家、玩家子弹之间的互相碰撞

`在这里插入图片描述

飞机与子弹添加碰撞体

  • 玩家飞机
    在这里插入图片描述
  • 子弹
    在这里插入图片描述
  • 敌机
    在这里插入图片描述

碰撞脚本

1. 在Constant文件中创建碰撞类型

在这里插入图片描述

/**
     * 碰撞类型
     */
    public static CollisionType = {// 这里顺序对应面板设置碰撞分组的类型
        SELF_PLANE: 1 << 1,//玩家飞机类型
        ENEMY_PLANE: 1 << 2,//敌方飞机类型
        SELF_BULLET: 1 << 3,//玩家子弹类型
        ENEMY_BULLET: 1 << 4,//敌机子弹类型
    };

这里的位运算是根据引擎内部碰撞组是位运算得来的

2. 在玩家与敌机脚本中添加碰撞

在这里插入图片描述
总体来看差不多,主要区别就是玩家飞机被碰撞了需要掉血,敌机被碰撞了不仅要掉血还要加分

  • 玩家脚本

import { _decorator, Component, Node, Collider, ITriggerEvent } from 'cc';
import { Constant } from '../framework/Constant';
const { ccclass, property } = _decorator;

@ccclass('SelfPlane')
export class SelfPlane extends Component {

    //监听事件
    onEnable() {
        const collider = this.getComponent(Collider);//获取碰撞组件
        collider.on('onTriggerEnter', this._onTriggerEnter, this);//碰撞到了立马处理逻辑
    }

    //取消事件
    onDisable() {
        const collider = this.getComponent(Collider);//获取碰撞组件
        collider.off('onTriggerEnter', this._onTriggerEnter, this);
    }

    // update (deltaTime: number) {
    //     // [4]
    // }

    private _onTriggerEnter(event: ITriggerEvent) {
        const collisionGroup = event.otherCollider.getGroup();//获取分组
        if (collisionGroup === Constant.CollisionType.ENEMY_PLANE || collisionGroup === Constant.CollisionType.ENEMY_BULLET) {//敌方飞机或者敌方子弹判断掉血
            console.log('reduce blood');//TODO:
        }
    }

}


  • 敌机脚本
 //监听事件
    onEnable() {
        const collider = this.getComponent(Collider);//获取碰撞组件
        collider.on('onTriggerEnter', this._onTriggerEnter, this);//碰撞到了立马处理逻辑
    }

    //取消事件
    onDisable() {
        const collider = this.getComponent(Collider);//获取碰撞组件
        collider.off('onTriggerEnter', this._onTriggerEnter, this);
    }
 private _onTriggerEnter(event: ITriggerEvent){
        const collisionGroup = event.otherCollider.getGroup();//获取分组
        if(collisionGroup === Constant.CollisionType.SELF_PLANE || collisionGroup === Constant.CollisionType.SELF_BULLET){//玩家飞机或者玩家子弹判断掉血
            console.log('trigger enemy destroy');
            this.node.destroy();
            this._gameManager.addScore();//获得分数
        }
    }

3. 游戏管理类中添加个记分函数

暂时这里先不写逻辑,创建就是为了后续方便
在这里插入图片描述
到这里感兴趣的话就可以运行游戏试试飞机碰撞的效果了

4. 子弹碰撞脚本

这里倒是没啥花哨的操作,就是子弹碰撞直接销毁即可
在这里插入图片描述

 //监听事件
    onEnable() {
        const collider = this.getComponent(Collider);//获取碰撞组件
        collider.on('onTriggerEnter', this._onTriggerEnter, this);//碰撞到了立马处理逻辑
    }

    //取消事件
    onDisable() {
        const collider = this.getComponent(Collider);//获取碰撞组件
        collider.off('onTriggerEnter', this._onTriggerEnter, this);
    }
 /**
     * 子弹碰撞销毁
     * @param event:ITriggerEvent
     */
    private _onTriggerEnter(event: ITriggerEvent){
        console.log('trigger  bullet destroy');
        this.node.destroy();
    }

5.游戏管理脚本再给敌机子弹分个组

在这里插入图片描述

完整代码

  • EnemyPlane.ts

import { _decorator, Component, Node, Collider, ITriggerEvent } from 'cc';
import { Constant } from '../framework/Constant';
import { GameManager } from '../framework/GameManager';
const { ccclass, property } = _decorator;


// 敌机销毁位置
const OUTOFBOUNCE = 50

@ccclass('EnemyPlane')
export class EnemyPlane extends Component {
    /** 子弹发射周期 */
    @property
    public createBulletTime = 0.5
    // 敌机速度
    private _enemySpeed = 0;
    private _needBullet = false//当前是否发射子弹
    private _gameManager: GameManager = null
    private _currCreateBulletTime = 0
    // // 敌机类型
    // public enemyType = Constant.EnemyType.TYPE1
    start() {
        // [3]
    }

    //监听事件
    onEnable() {
        const collider = this.getComponent(Collider);//获取碰撞组件
        collider.on('onTriggerEnter', this._onTriggerEnter, this);//碰撞到了立马处理逻辑
    }

    //取消事件
    onDisable() {
        const collider = this.getComponent(Collider);//获取碰撞组件
        collider.off('onTriggerEnter', this._onTriggerEnter, this);
    }

    update(deltaTime: number) {
        const pos = this.node.position
        const movePos = pos.z + this._enemySpeed
        // 因为敌机向西飞所以为正向
        this.node.setPosition(pos.x, pos.y, movePos)

        if (this._needBullet) {//发射子弹逻辑
            this._currCreateBulletTime += deltaTime
            if (this._currCreateBulletTime > this.createBulletTime) {
                this._gameManager.createEnemyBullet(this.node.position)
                this._currCreateBulletTime = 0
            }
        }

        if (movePos > OUTOFBOUNCE) {//超出边界销毁
            this.node.destroy()
        }
    }
    /**
     * 设置飞机移动速度
     * @param speed 移动速度
     */
    show(gameManager: GameManager, speed: number, needBullet: boolean) {
        this._gameManager = gameManager
        this._enemySpeed = speed
        this._needBullet = needBullet
    }

    private _onTriggerEnter(event: ITriggerEvent){
        const collisionGroup = event.otherCollider.getGroup();//获取分组
        if(collisionGroup === Constant.CollisionType.SELF_PLANE || collisionGroup === Constant.CollisionType.SELF_BULLET){//玩家飞机或者玩家子弹判断掉血
            console.log('trigger enemy destroy');
            this.node.destroy();
            this._gameManager.addScore();//获得分数
        }
    }
}


  • SelfPlane.ts

import { _decorator, Component, Node, Collider, ITriggerEvent } from 'cc';
import { Constant } from '../framework/Constant';
const { ccclass, property } = _decorator;

@ccclass('SelfPlane')
export class SelfPlane extends Component {

    //监听事件
    onEnable() {
        const collider = this.getComponent(Collider);//获取碰撞组件
        collider.on('onTriggerEnter', this._onTriggerEnter, this);//碰撞到了立马处理逻辑
    }

    //取消事件
    onDisable() {
        const collider = this.getComponent(Collider);//获取碰撞组件
        collider.off('onTriggerEnter', this._onTriggerEnter, this);
    }

    // update (deltaTime: number) {
    //     // [4]
    // }

    private _onTriggerEnter(event: ITriggerEvent) {
        const collisionGroup = event.otherCollider.getGroup();//获取分组
        if (collisionGroup === Constant.CollisionType.ENEMY_PLANE || collisionGroup === Constant.CollisionType.ENEMY_BULLET) {//敌方飞机或者敌方子弹判断掉血
            console.log('reduce blood');//TODO:
        }
    }

}


  • GameManager.ts

import { _decorator, Component, Node, Prefab, instantiate, math, Vec3, BoxCollider } from 'cc';
import { Bullet } from '../bullet/Bullet';
import { EnemyPlane } from '../plane/EnemyPlane';
import { Constant } from './Constant';
const { ccclass, property } = _decorator;



@ccclass('GameManager')
export class GameManager extends Component {
    // 关联玩家飞机
    @property(Node)
    public playerPlane: Node = null;
    // 关联所有子弹
    @property(Prefab)
    public bullet01: Prefab = null;
    @property(Prefab)
    public bullet02: Prefab = null;
    @property(Prefab)
    public bullet03: Prefab = null;
    @property(Prefab)
    public bullet04: Prefab = null;
    @property(Prefab)
    public bullet05: Prefab = null;
    // 射击周期
    @property
    public shootTime = 0.3;
    // 子弹移动速度
    @property
    public bulletSpeed = 1;

    /** 关联敌机 */
    @property(Prefab)
    public enemy01: Prefab = null;
    @property(Prefab)
    public enemy02: Prefab = null;
    @property
    public createEnemtTime = 1;//创建敌机时间
    @property
    public enemy1Speed = 0.5;//敌机1速度
    @property
    public enemy2Speed = 0.7;//敌机2速度

    //子弹管理节点
    @property(Node)
    public bulletRoot: Node = null;

    private _currShootTime = 0;
    // 是否触摸屏幕
    private _isShooting = false;
    private _currCreateEnemyTime = 0//当前创建的敌机时间
    private _combinationInterval = Constant.Combination.PLAN1//组合间隔状态
    start() {
        this._init();
    }

    update(deltaTime: number) {
        // 这步加时间是为了发射子弹
        this._currShootTime += deltaTime;
        // 判断是触摸状态 并且射击时间大于我们的周期 发射子弹
        if (this._isShooting && this._currShootTime > this.shootTime) {
            this.createPlayerBullet();
            this._currShootTime = 0;
        }

        this._currCreateEnemyTime += deltaTime
        //判断组合方式
        if (this._combinationInterval == Constant.Combination.PLAN1) {
            //只创建单一的飞机 0-10秒飞机创建
            if (this._currCreateEnemyTime > this.createEnemtTime) {//普通飞机创建
                this.createEnemyPlane()
                this._currCreateEnemyTime = 0
            }

        } else if (this._combinationInterval == Constant.Combination.PLAN2) {
            // 10-20秒飞机创建
            if (this._currCreateEnemyTime > this.createEnemtTime * 0.9) {//0.9飞机组合间隔
                const randomCombination = math.randomRangeInt(1, 3)//随机1,2飞机
                if (randomCombination === Constant.Combination.PLAN2) {
                    this.createCombination1()
                } else {
                    this.createEnemyPlane()
                }

                this._currCreateEnemyTime = 0
            }
        } else {
            //20+ 飞机创建
            if (this._currCreateEnemyTime > this.createEnemtTime * 0.8) {//0.8飞机组合间隔
                const randomCombination = math.randomRangeInt(1, 4)//随机1,2,3飞机
                if (randomCombination === Constant.Combination.PLAN2) {
                    this.createCombination1()
                } else if (randomCombination === Constant.Combination.PLAN3) {
                    this.createCombination2()
                } else {
                    this.createEnemyPlane()
                }

                this._currCreateEnemyTime = 0
            }
        }
    }

    /**
     * 加分
     */
    public addScore() {

    }

    /**
     * 创建子弹
     */
    public createPlayerBullet() {
        // 子弹实例化
        const bullet = instantiate(this.bullet01);
        // 将子弹放在子弹管理节点下面
        bullet.setParent(this.bulletRoot);
        // 获取飞机位置
        const pos = this.playerPlane.position;
        // 设置子弹位置
        bullet.setPosition(pos.x, pos.y, pos.z - 7);
        // 设置子弹速度
        const bulletComp = bullet.getComponent(Bullet);
        bulletComp.show(this.bulletSpeed, false)
    }
    /**
     * 创建敌机子弹
     * @param targetPos 敌机子弹位置
     */
    public createEnemyBullet(targetPos: Vec3) {
        // 子弹实例化
        const bullet = instantiate(this.bullet01);
        // 将子弹放在子弹管理节点下面
        bullet.setParent(this.bulletRoot);
        // 设置子弹位置
        bullet.setPosition(targetPos.x, targetPos.y, targetPos.z + 6);
        // 设置子弹速度
        const bulletComp = bullet.getComponent(Bullet);
        bulletComp.show(1, true)

        /**
         * 敌机子弹分组
         */
         const colliderComp = bullet.getComponent(BoxCollider);
         colliderComp.setGroup(Constant.CollisionType.ENEMY_BULLET);
         colliderComp.setMask(Constant.CollisionType.SELF_PLANE);//设置掩码
    }
    /**
     * 创建敌机
     *
     */
    public createEnemyPlane() {
        // 两架飞机随机选一(1,2)
        const whichEnemy = math.randomRangeInt(1, 3)
        let prefab: Prefab = null
        let speed = 0
        // 创建敌机1或2
        if (whichEnemy == Constant.EnemyType.TYPE1) {
            prefab = this.enemy01
            speed = this.enemy1Speed
        } else {
            prefab = this.enemy02
            speed = this.enemy2Speed
        }

        // 预制实例化
        const enemy = instantiate(prefab)
        console.log(enemy);

        enemy.setParent(this.node)
        const enemyComp = enemy.getComponent(EnemyPlane)
        enemyComp.show(this, speed, true)//单架敌机需要发射子弹

        // 设置飞机位置 
        const randomPos = math.randomRangeInt(-25, 26)
        enemy.setPosition(randomPos, 0, -50)
    }
    /**
     * 组合1创建 横向排列 z轴50,x轴从-20开始
     *
     */
    public createCombination1() {
        const enemyArray = new Array<Node>(5)//飞机数组
        for (let i = 0; i < enemyArray.length; i++) {
            // 敌机资源实例化
            enemyArray[i] = instantiate(this.enemy01)
            const element = enemyArray[i]
            element.parent = this.node
            element.setPosition(-20 + i * 10, 0, -50)//-20起始左位置,10飞机间隔,其实创建位置
            //设置飞机速度
            const enemyComp = element.getComponent(EnemyPlane)
            enemyComp.show(this, this.enemy1Speed, false)//组合飞机不需要发射子弹
        }
    }
    /**
     * 组合2创建 V字排列
     *
     */
    public createCombination2() {
        const enemyArray = new Array<Node>(7)//飞机数组
        // 位置数组
        const combinationPos = [
            -21, 0, -60,
            -14, 0, -55,
            -7, 0, -50,
            0, 0, -45,
            7, 0, -50,
            14, 0, -55,
            21, 0, -60
        ]

        for (let i = 0; i < enemyArray.length; i++) {
            // 敌机资源实例化
            enemyArray[i] = instantiate(this.enemy02)
            const element = enemyArray[i]
            element.parent = this.node
            const startIndex = i * 3//因为位置数组有7个 但是位置有3×7 21个  所以每架飞机位置偏移是3
            element.setPosition(combinationPos[startIndex], combinationPos[startIndex + 1], combinationPos[startIndex + 2])
            //设置飞机速度
            const enemyComp = element.getComponent(EnemyPlane)
            enemyComp.show(this, this.enemy2Speed, false)//组合飞机不需要发射子弹
        }
    }
    /**
     * 触摸状态设置
     * @param value  true/false
     */
    public isShooting(value: boolean) {
        this._isShooting = value;
    }
    /**
     * 默认发射子弹
     */
    private _init() {
        this._currShootTime = this.shootTime;
        this._changePlanMode();
    }

    /**
     * 设计定时器 
     */
    private _changePlanMode() {
        /**
         * 每10秒改变一次状态,执行三次,根据状态就能决定采用什么组合
         */
        this.schedule(this._modeChanged, 10, 3);//组件自带定时器(回调函数,间隔时间,重复次数,延迟时间)
    }

    private _modeChanged() {
        this._combinationInterval++
    }
}



  • Bullet.ts

import { _decorator, Component, Node, Collider, ITriggerEvent } from 'cc';
const { ccclass, property } = _decorator;




@ccclass('Bullet')
export class Bullet extends Component {
    // 子弹速度
    private _bulletSpeed = 0;
    private _isEnemyBullet = false;//判断是否是敌机子弹

    //监听事件
    onEnable() {
        const collider = this.getComponent(Collider);//获取碰撞组件
        collider.on('onTriggerEnter', this._onTriggerEnter, this);//碰撞到了立马处理逻辑
    }

    //取消事件
    onDisable() {
        const collider = this.getComponent(Collider);//获取碰撞组件
        collider.off('onTriggerEnter', this._onTriggerEnter, this);
    }

    update(deltaTime: number) {
        // 子弹移动
        const pos = this.node.position;
        let moveLength = 0

        // 敌机子弹
        if (this._isEnemyBullet) {
            moveLength = pos.z + this._bulletSpeed;
            this.node.setPosition(pos.x, pos.y, moveLength);
            // 超出屏幕销毁
            if (moveLength > 50) {//敌机子弹移动的最大位置范围为50
                this.node.destroy();
            }

        } else {//玩家子弹
            moveLength = pos.z - this._bulletSpeed;
            this.node.setPosition(pos.x, pos.y, moveLength);
            // 超出屏幕销毁
            if (moveLength < -50) {//玩家子弹移动的最大位置范围为-50
                this.node.destroy();
            }
        }

    }

    /**
     * 设置子弹移动速度即判断子弹是谁发出的
     * @param speed  子弹速度
     * @param isEnemyBullet 是否是敌机子弹
     */
    show(speed: number, isEnemyBullet: boolean) {
        this._bulletSpeed = speed
        this._isEnemyBullet = isEnemyBullet
    }

    /**
     * 子弹碰撞销毁
     * @param event:ITriggerEvent
     */
    private _onTriggerEnter(event: ITriggerEvent) {
        console.log('trigger  bullet destroy');
        this.node.destroy();
    }
}



  • Constant.ts
export class Constant{
    /**
     * 敌机类型
     */
    public static EnemyType = {
        TYPE1:1,
        TYPE2:2,
    }
    /**
     * 组合类型
     */
    public static Combination = {
        PLAN1:1,
        PLAN2:2,
        PLAN3:3,
    }
    /**
     * 碰撞类型
     */
    public static CollisionType = {// 这里顺序对应面板设置碰撞分组的类型
        SELF_PLANE: 1 << 1,//玩家飞机类型
        ENEMY_PLANE: 1 << 2,//敌方飞机类型
        SELF_BULLET: 1 << 3,//玩家子弹类型
        ENEMY_BULLET: 1 << 4,//敌机子弹类型
    };
}
在使用cocos2d-x开发飞机大战游戏时,敌机发射子弹的逻辑可以分解为以下几个步骤: 1. 创建子弹类:首先需要创建一个子弹的类,继承自cocos2d-x中的`Sprite`类,用于管理子弹的属性和行为。 ```cpp class Bullet : public cocos2d::Sprite { public: Bullet(); // 构造函数 virtual ~Bullet(); // 析构函数 // 初始化子弹位置等属性的方法 void init(float x, float y); // 子弹移动的逻辑 void update(float delta); }; ``` 2. 在敌机类中添加子弹发射功能:敌机类中应该有一个方法用于控制子弹发射。这个方法可以被定时调用,比如每一秒钟发射一次。 ```cpp class Enemy : public cocos2d::Sprite { public: virtual void onEnter(); // 敌机进入屏幕时的逻辑 virtual void shoot(); // 发射子弹的方法 // ... 其他敌机相关的方法和属性 }; ``` 3. 实现子弹发射和移动:在子弹类中实现`update`方法来控制子弹的移动,比如让它向左上方移动一定的速度。 ```cpp void Bullet::update(float delta) { // 更新子弹的位置,使其向上和向左移动 this->setPosition(cocos2d::Vec2(getPositionX() - SPEED * delta, getPositionY() - SPEED * delta)); // 检查子弹是否出界,如果出界则移除子弹 if (getPositionX() < 0 || getPositionY() < 0) { removeFromParentAndCleanup(true); } } ``` 4. 控制敌机发射子弹:在敌机类中,实现`shoot`方法,让敌机定期生成子弹。 ```cpp void Enemy::shoot() { if (shouldShoot) { // 根据某种逻辑判断是否发射子弹 // 创建一个子弹实例 Bullet *bullet = Bullet::create(); // 初始化子弹位置在敌机的下方中心位置 bullet->init(getPositionX(), getPositionY() + this->getContentSize().height / 2); // 将子弹添加到游戏中,比如可以添加到Layer或者Director中 this->getParent()->addChild(bullet); // 让子弹开始移动 bullet->runAction(cocos2d::MoveBy::create(BULLET_DURATION, cocos2d::Vec2(0, -BULLET_SPEED))); } } ``` 5. 调度敌机发射子弹:在敌机的`onEnter`方法中设置定时器来定期调用`shoot`方法。 ```cpp void Enemy::onEnter() { // ... 省略其他初始化代码 // 设置定时器,每1秒发射一次子弹 this->schedule_selector(Enemy::shoot, 1.0f); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值