cocos2dx3.2开发 RPG《Flighting》(九)必不可少的子弹

一、前言
上一节我们讲完了攻击,其实也只是攻击者一方一厢情愿地播放自己的攻击动画罢了,被攻击的那一方根本不知道发生了什么,攻击者和被攻击者还没有联系起来。
所以,我们就引入了子弹这个东东。

二、正文
一开始我在开发的时候想到用物理引擎,后来想了想还是算了,一是难控制,二是可能会遇到一些问题(例如两个人之间可能会发生碰撞。。)
所以还是将错就错,直接用update函数解决问题吧。
子弹,顾名思义,就是子弹啊。

class Role;  
class Bullet : public Node{  
public:  
    static Bullet* createWithTarget(Role* sender,Role** target);  
    bool initWithTarget(Role* sender,Role** target);  
    void setDamage(int damage);  
    ~Bullet();  
private:  
    Sprite* m_bullet;  
    Role* m_target;  
    Role** m_targetPtr;  
    virtual void update(float dt);  
    int m_damage;  
    int m_speed;  
    Role* m_sender;  
  
};  

```

从头文件里面就可以知道,子弹的实现很简单。
主要还是看create和update函数
Bullet* Bullet::createWithTarget(Role* sender,Role** targetPtr){  
    Bullet* ret = new Bullet();  
    if(ret && ret->initWithTarget(sender,targetPtr)){  
        ret->autorelease();  
        return ret;  
    }  
    CC_SAFE_DELETE(ret);  
    return nullptr;  
}  
  
bool Bullet::initWithTarget(Role* sender,Role** targetPtr){  
    m_damage = 0;  
    m_bullet = Sprite::create("Bullet/" + sender->getBulletImg());  
    setDamage(sender->getAtk());  
      
      
    setPosition(sender->getPosition() + Point(0,sender->getContentSize().height/2));  
      
    this->addChild(m_bullet);  
  
    m_speed = sender->getBulletSpeed();  
      
    m_targetPtr = targetPtr;  
    m_sender = sender;  
    this->scheduleUpdate();  
    return true;  
}  

```

create函数就是这样,注意的是子弹的图片是根据每个不同的角色而定的。(近战角色没有子弹,我们可以把素材用一张透明的小块代替)
其实Role类里面还有很多属性的。这里大家通过命名应该知道怎么一回事。
create函数设置好子弹的攻击者和被攻击者之后。update负责处理
void Bullet::update(float dt){  
    m_target = *m_targetPtr;  
    if(!m_target){  
        this->removeFromParentAndCleanup(true);  
        return;  
    }  
    if(!m_target->getBoundingBox().containsPoint(this->getPosition())){  
        float distance = ccpDistance(getPosition(),m_target->getPosition()+Vec2(0,m_target->getContentSize().height));  
        float t = distance / m_speed;  
        float speed_x = (m_target->getPositionX() - getPositionX()) / t;  
        float speed_y = (m_target->getPositionY()+ m_target->getContentSize().height/2 - getPositionY()) / t;  
        setPositionX(getPositionX() + speed_x);  
        setPositionY(getPositionY() + speed_y);  
    }else{  
        CCLOG("BULLET->ARR");  
        m_target->injured(m_effect,m_damage);  
        this->removeFromParentAndCleanup(true);  
    }  
}  

```

如果目标死了,就清除子弹
如果子弹没有达到目标的区域,就一直更新xy,跟Role的是差不多的
如果到达了,触发目标的injured函数,并且清除自己(子弹)

好了,介绍完子弹,我们看一下一个角色怎么发送子弹
还记得Role类的onBondAnimationFinish函数是干嘛用的吧?不清楚的可以看上一节。
void Role::onBondAnimationFinish(Armature* arm,MovementEventType type,const std::string& name){  
    if(type == COMPLETE){  
        if(name == "attack"){  
            CCLOG("ATTACK COMPLETE");  
            //恢复速度  
            m_speed = m_initSpeed;  
            m_arm->getAnimation()->setSpeedScale(1.0f);  
            this->stand();  
        }  
    }  
    if(type == START){  
        if(name == "attack"){  
            CCLOG("SEND BULLET");  
            sendBullet();  
        }  
    }  
}  

```

这里我们只是在攻击动画播放前,调用sendBullet函数
void Role::sendBullet(){  
    if(m_attackTarget && m_layer){  
        m_layer->addBullet(this,m_attackTargetPtr);  
    }  
}  

```

而sendBullet函数也只是让m_layer(其实就是FlightLayer)调用addBullet函数
void FlightLayer::addBullet(Role* sender,Role_Ptr targetPtr){  
    Bullet* bullet = Bullet::createWithTarget(sender,targetPtr);  
      
    this->addChild(bullet);  
}  

```

好了,这里我们能够自动移动到目标的子弹已经做出来了。

剩下的就是被击打的那一方,的injured函数了,在injured函数里面我们可以添加受伤效果(上一节没讲的),还有进行血量值的计算。这些都很自由。这里给出我的injured函数供大家参考
void Role::injured(int effect,int damage){  
    runSkillEffect(effect);  
    if(damage < 0){  
        m_hp -= damage;  
    }else{  
        int real_damage = (damage-m_defence > 0)?damage - m_defence : 1;  
        m_hp-= real_damage;  
    }  
    if(m_hp > m_initHp){  
        m_hp = m_initHp;  
    }  
    if(m_hp <= 0){  
        die();  
        return;  
    }  
    if(en_stat == ROLE_MOVE){  
        return;  
    }  
    MoveBy* toR = MoveBy::create(0.2f,Vec2(10,0));  
    MoveBy* toL = MoveBy::create(0.2f,Vec2(-10,0));  
    Sequence* seq;  
    if(m_armFaceTo){  
        seq = Sequence::create(toR,toL,NULL);  
    }else{  
        seq = Sequence::create(toL,toR,NULL);  
    }  
    m_arm->runAction(seq);  
}  

```

effect这个参数是播放特效的,可以忽略。

本节到此结束。
我的csdn地址:http://blog.csdn.net/hezijian22
邮箱地址:578690286@qq.com
如有问题或指教,欢迎与我交流,谢谢。