cocos2d-x 游戏创作过程(三) .2

cocos2d-x 游戏创作过程(三) .2

  • 炮弹问题
  • 敌人问题
  • 炮弹与敌人回收问题
  • 梯子问题
  • 数据问题

炮弹问题

这个很难,但是解决了,至少花费了一个月,甚至翻阅的三角函数,来寻找答案。 最终完成了。炮弹的角度问题,和炮弹的发射点问题。 这两样非常重要。

至少对我来说太珍贵了,这几行代码。上一章说到了,骨骼动画 随意控制骨骼,可以控制骨骼的角度,自由的变换。而手枪发射的时候是根据你的胳膊的变化来自由调整角度。 那么问题就来了,如果计算出发射点,是很重要的。 而发射的角度,如果转化成真实发射的角度。 真实发射的角度是 横坐标,和纵坐标。(x,y)之间的比例。 也就是角度转弧度的问题。

其实他们的关系是。 角度 * ((2* pai)/360),就是弧度了。
而枪口的位置也非常重要,虽然我想了很久计算枪口的位置,但是我觉得还不如在骨骼上加一个隐藏的骨骼。当旋转胳膊的时候那条隐藏骨骼也在动。 这样就少了很多麻烦。

//代码的关系是

void BaseFSM::changeToAttack(){
    b2Body *body=role->getb2Body();
    if(role->state!=Role_ATTAK1){
        role->state=Role_ATTAK1;
    }
    b2BodyDef bodyDef;
    bodyDef.type = b2_dynamicBody;
    b2Body *body1 = world->CreateBody(&bodyDef);
//
    spine::SkeletonAnimation *f = role->getSkeletonAnimation();
    spBone *bone1 =f->findBone("rear-upper-arm");
    spBone *bone3 =f->findBone("rear-upper-arm");
    float rotation=bone1->rotation;
    //转换为弧度
    float radian = rotation*(2*3.1415926)/360;
    float rotation_x = 20;
    //转换为纵坐标,横坐标 * tan(弧度)
    float rotation_y = 20*tan(radian);

    float vo= 20;
    float rotation1=bone3->rotation;
    float radian1 = rotation1*(2*3.1415926)/360;
    float rotation_x1 = vo*-1;
//转换为纵坐标,横坐标 * tan(弧度)
    float rotation_y1 = vo*tan(radian1);
    g->clear();
    //隐藏骨骼
    spBone *bone2 =f->findBone("Bullet");
    spBone *bone4 =f->findBone("Bullet");
    if(bone2){
        log("log.....................%f",bone2->worldX/PTM_RATIO);
        log("log.....................%f",bone2->worldY/PTM_RATIO);
        g->clear();
    }else{
        log("log .........................false");
    }
    //子弹
    //这个是右边结构。
    if(role->getSkeletonAnimation()->getSkeleton()->flipX==0){
        g->clear();
        b2Vec2 b2vec2 = b2Vec2((body->GetPosition().x+bone2->worldX/PTM_RATIO),body->GetPosition().y+bone2->worldY/PTM_RATIO);
        CCLOG("%f.............................xxxxxxxxxxxxxxxxxxx",bone1->rotation);
//        g->drawDot(Vec2((b2vec2.x)   *32,(b2vec2.y)  *32),5,Color4F(1, 0, 0, 1));
        initBullet(body,b2vec2,b2Vec2(rotation_x,rotation_y));
//        Bullets(b2vec2,b2Vec2(rotation_x,rotation_y));
    }
    //对称的左边的结构
    else if(role->getSkeletonAnimation()->getSkeleton()->flipX==-1){
//.  这一点很重要,子弹的位置是 骨骼设置好的。 一个隐藏没有图片的骨骼当手臂移动的时候骨骼也会移动,所以这个位置也是枪口位置
        b2Vec2 b2vec1 = b2Vec2((body->GetPosition().x+bone4->worldX/PTM_RATIO),body->GetPosition().y
                               +bone4->worldY/PTM_RATIO);
        CCLOG("%f.............................xxxxxxxxxxxxxxxxxxx",bone1->rotation);
//        g->drawDot(Vec2((b2vec1.x)   *32,(b2vec1.y)  *32),5,Color4F(1, 0, 0, 1));
//.  这一点很重要,子弹的位置是 骨骼设置好的。 一个隐藏没有图片的骨骼当手臂移动的时候骨骼也会移动,所以这个位置也是枪口位置
        initBullet(body,b2vec1,b2Vec2(rotation_x1,rotation_y1));
    }
}

然后是设置子弹模块,上边已经保证了子弹的出弹位置,和出弹方向。 然后需要把子弹的刚体重力取消。 否则就不能以直线打出去了。会形成弧线。落地。 炮弹倒是可以,但是子弹要保证直线。

void BaseFSM::initBullet(b2Body *body,b2Vec2 b2vec,b2Vec2 b2vec1){
   // 设置子弹类型,为了将来炮弹做准备,可以修改子弹的重量和图片,还有大小。有足够的改造空间 
    Sprite *sprite =Sprite::create("zidan.png");
    sprite->setName("zidan");
    sprite->setTag(20);
    sprite->setCameraMask((unsigned short) CameraFlag::USER1);
    this->context->addChild(sprite);
    b2BodyDef bodyDef;
    bodyDef.type = b2_dynamicBody;
    bodyDef.bullet=true;
    b2Body *body1 = world->CreateBody(&bodyDef);
    body1->SetTransform(b2vec,0.0f);
    body1->SetBullet(true);
    body1->SetUserData(sprite);

    b2PolygonShape dynamicBox;
    dynamicBox.SetAsBox(PTM_L*10,PTM_L*6);


    b2FixtureDef fixtureDef;
    fixtureDef.shape = &dynamicBox;
    fixtureDef.density = 1.0f;
    fixtureDef.friction = 0.3f;
    body1->CreateFixture(&fixtureDef);
    body1->SetGravityScale(0);
//-------------------------------------------------------------
CCLOG("x=%f.........y=%f.................xxxxxxxzzzzzzzzzyyyhhhhhheeeeexxxxxxxxxxxx",b2vec1.x,b2vec1.y);
    body1->SetLinearVelocity(b2vec1);
//    body1->SetAwake(true);
}

然后就不是问题了。很基础的问题了。


敌人问题 ,炮弹与敌人回收的问题。

敌人的问题,应该不是很难的问题,基础的ai 和 射线检测上一章就有,现在重要的问题是如何回收敌人。由于碰撞检测类里边无法操作 word的问题。网络上大部分都一笔带过了,所以我想把我的代码摆一下。

思路是在碰撞监听b2ContactListener 里设置设置两个 vector 集合,把需要回收的精灵和刚体全部放在里边

        if(spriteA->getTag()==39 ){
            if(spriteB->getName()=="zidan"){
                log("EndContact 方块消除");
                b2body.push_back(bodyA);
                sprite.push_back(spriteA);
            }
        }
        if(spriteA->getName()=="zidan" ){
            if(spriteB->getTag()==39){
                log("EndContact 方块消除");
                b2body.push_back(bodyB);
                sprite.push_back(spriteB);
            }
        }

主界面中 update 下面进行删除, 删除的时候要注意一点,把Vector里边的内存也清空了,Vector可以自动扩容,但是不能自动缩小。就算删除了里边的元素也不能缩小。

void GameLayer::update(float dt){
    //b2body是我定义的Vector别看错了。
    if(!contactListener->b2body.empty()){
        for(int i=0;i<contactListener->b2body.size();i++){
            b2Body *b=contactListener->b2body[i];
            world->DestroyBody(b);
        }
    }
    //sprite是我定义的Vector别看错了。
    if(!contactListener->sprite.empty()){
        for(int i=0;i<contactListener->sprite.size();i++){
            Sprite *sprite=contactListener->sprite[i];
            this->removeChild(sprite,true);
        }
    }
}

所以需要

    //清理干净
    contactListener->b2body.clear();
    contactListener->sprite.clear();
    //制造一个什么都没有Vector 附在Vecotor 里边,以删除旧的Vector空间。
    vector<b2Body *> f;
    vector<Sprite *> s;
    contactListener->b2body.swap(f);
    contactListener->sprite.swap(s);

梯子问题

刚开始还傻傻的以为很简单,用碰撞检测去做,但是梯子问题,也是地图问题,所以射线是必选的。

思路是在主角中发射射线,如果检测到了梯子,那么上键的作用,就变成向梯子上楼梯,开启线程。 然后整个body进入0重力状态,按下向上,人就会位移向上走,在梯子附近人会持续检测,如果射线一直检测到,那么人就会0重力在梯子上,如果按左,或者按右,达到射线检测不到的位置, 开启的向上爬的线程就会关闭,然后人会落下来。

//检测梯子是否被检测到。 否则取消线程人物直接掉下来。
        if(this->ladder){
        CCLOG("攀爬true1111111111111");
    }else{
        CCLOG("攀爬false");
        this->unschedule(schedule_selector(GameLayer::asyncUpdate2));
    }


     //检测梯子
                if(sprite->getTag()==29){
                //发射10条射线,保证全方位检测。
                    for(int i=0;i<10;i++){
                        auto a=i*20.0;
                        double x=cos(a* b2_pi/180);
                        double y=sin(a* b2_pi/180);
                        Vec2 v(x,y);
                        RaysCastCallback callback;

                        world->RayCast(&callback,b2Vec2(b->GetPosition().x,b->GetPosition().y)
                                       ,b2Vec2(b->GetPosition().x+v.x*2
                                               , b->GetPosition().y+v.y*2));
                        Vec2 pos(b->GetPosition().x*PTM_RATIO,b->GetPosition().y*PTM_RATIO);
                        if(callback.fixture!=nullptr){
                            b2Body *b2= callback.fixture->GetBody();
                            auto sprite=(Sprite *)b2->GetUserData();
                            if(sprite!=nullptr){
                            //梯子的标记是17
                            if(sprite->getTag()==17){
                                g->drawLine(pos,Vec2(callback.point.x * PT_RATIO
                                                     ,callback.point.y *PTM_RATIO)
                                                     ,Color4F(134, 54, 78, 110));
                           //如果检测到跳出循环,甚至关闭线程也没问题。 
                                this->ladder=true;
                                break;
                                }
                            }
                        }else{
//                            CCLOG("不确定------------------------------!");
                            this->ladder=false;
                        }
                    }
                }

至于梯子与顶层的交接点还没写好,也没画好,估计是射线检测到了那个交界点然后直接跳到上层。


数据问题

有点困了,其实数据问题,主要是从 .plist中取出数据,比如人物的初始数据甚至是储存 人物获得的数据。然后实体化这些数据。

把.plist中数据取出来放进Map 里边,然后Map中取出数据,再放进实体里,然后,就可以用这些数据随控制什么了,属性也好,武器,也好。速度也好。名称也好。

具体的代码是

    auto roleMap = FileUtils::getInstance()->getValueMapFromFile("propertyRole.plist");
    //创建对象
    PropertyData *propertyData = PropertyData::create();
    propertyData->setID(roleMap["ID"].asInt());
    propertyData->setHP(roleMap["HP"].asInt());
  //这是血条。 血条的控制完全取决于数据的大小。
    float hp = propertyData->getHP() * 0.01;

然后就没有了。 几个月的成果就这么少。 然后就是设计剧情,人像,音乐什么的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昏暗的夜晚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值