新年游戏制作插曲,继续进阶。

新年如何写一个小游戏代码。

花了2周,研究一下重新研究Cocos2d 的游戏代码,里边没有刚体,也没有物理引擎。 只是用Sprite精灵和, 数组写一个小程序。
刚刚上传了。 最大的愿望是今年能赚到钱。 我觉得我又有进步了。不知道可以用它谋生吗?

首先我凭空写一个控制按钮。

控制按钮分为上下左右,左上, 右上,左下、右下。

在这里插入图片描述

这是个复合的 按钮,分为,中心点 和8个点。 跟大部分的游戏的控制杆差不多。 计算 圆心圆球,移动以后和中心点的弧度,去判断上下左右。

//获得弧度
float HRocker::getRad(Vec2 pos1, Vec2 pos2){
    float px1 =pos1.x;
    float py1 =pos1.y;
    float px2 =pos2.x;
    float py2 =pos2.y;
    
    float x=px2-px1;
    float y=py2-py1;
    
    float xie=sqrt(pow(x,2)+pow(y,2));
    float cosAngle=x/xie;
    float rad=acos(cosAngle);
    if(py2<py1){
        rad=-rad;
    }
    return rad;
}

如果你想变成角度的化。只要

    float angle_1=angle *180.0/PI;

也可以通过角度去判断。

枚举或者数字,控制杆的值,然后在控制主角运动的时候,根据控制杆的值,去左判断。

typedef  enum {
    rocker_stay=0,
    rocker_left=1,
    rocker_right=2,
    rocker_up=3,
    rocker_down=4,
    rocker_LeftUp=5,
    rocker_RightUp=6,
    rocker_LeftDown=7,
    rocker_RightDown=8
}tagDirection;
\\把rocker的状态传进去。
    baseFSM->switchMoveState(rocker->rockerDirection);

剩下的就是上下左右。 自己加自己。 当时我想用Camera 去制作地图的移动。 但是当我用了Camera移动的同时。游戏杆不会跟着移动,而且就算移动,也会浪费内存。没有意义。
最后只要让地图跟着移动。

void BaseFSM::changeUp(){
    mapLayer->setPosition(Vec2(mapLayer->getPositionX(),mapLayer->getPositionY()-SPEED));
};
void BaseFSM::changeDown(){
    mapLayer->setPosition(Vec2(mapLayer->getPositionX(),mapLayer->getPositionY()+SPEED));
};

上下是地图移动,左右是主角移动。剩下的混合移动。
其实有的时候可以让主角更加灵活的移动。 通过精确计算,中心小球的弧度,算出上下左右的移动比例。现在仅仅是纯粹的左右上下移动。

核心代码

有些时候用std::Vector 总是很麻烦,以前也是这么使用的。 问题是 首先查找一个特定的元素,很麻烦, 然后删除它。删除特定的元素。首先遍历他们 ,然后根据指针查找到类, 然后什么的。我遍历了。 删除了特定的 元素。其实很麻烦。

	vector<int>::iterator   iter   =   vec.begin()+5;
	 for(;it != vec.end();)
    {
        if(*it == 5)
            //删除指定元素,返回指向删除元素的下一个元素的位置的迭代器
            it = vec.erase(it);
        else
            //迭代器指向下一个元素位置
            ++it;
    }

其实 Cocos2d 里边有自带的Vector,

Vector < Sprite *>

这个Vector,只要
vector.eraseObject(sprite1); 

就可以做到上述的事情。 我最开始找了eraseObject 在std::Vector 里,后来才发现找错了。

这个Vector的作用充分发挥中。

子弹的发射

首先对于子弹的发射 很重要。 我设置了一个发射按钮 。 这个很简单。 然后,我在主角中间的位置创建了一个子弹。
最开始我创建子弹的时候,仅仅是用 MoveTo 到固定的坐标。 但是我发现回收的时候很不好弄。 当碰撞到了敌人,且超过预定界面以后 子弹精灵并不能,随时随地的计算 和删除。

所有我在创建子弹的时候,把子弹放进这个动态数组中, 然后持续遍历这个数组,当数组满足了条件。就对他进行调整。
首先创建的是 子弹的 发射数组

     for(int i=0;i<bean_vector.size();i++){
          if(bean_vector.at(i)!=nullptr){
              Sprite *sprite = bean_vector.at(i);
              sprite->setPosition(sprite->getPositionX()+f_x,sprite->getPositionY()+f_y);
              }
          }

其实可以调整发射的速度。 但是默认固定的,也可以调整发射。速度和方向。
当子弹碰撞到了敌人以后, 删除敌人,且删除子弹。

        Sprite *sprite1=mapLayer->_data.at(j);
                //取出敌人的大小
                float spri= sprite1->getContentSize().width;
                float spriH=sprite1->getContentSize().height;
                //取出子弹的大小
                float spriteBulletW=sprite->getContentSize().width/2;
                float spriteBulletH=sprite->getContentSize().height/2;
            
//----------------------------------------------------------------------------------------------------------
//---- 这里要注意是 敌人的位置需要减去 主角移动的方向。这点遇到过坑
                if((abs(sprite->getPositionX()-sprite1->getPositionX()+spriteBulletW)<spri/2)
                   && (abs(sprite->getPositionY()-sprite1->getPositionY()-mapLayer->getPositionY()+spriteBulletH)<spriH/2)){
                   }
---//当然最重要的是把元素从集合中删除                       
 bean_vector.eraseObject(sprite); 

这并没有什么难点。 如果面试的时候问难点,我也会忘记。
然后是敌人的攻击与移动了。

//创建瓦片 获取位置信息 和属性。
	    auto tileMap = TMXTiledMap::create("untitled.tmx");
    
    TMXObjectGroup *group = tileMap->getObjectGroup("enemy");
    ValueVector group1 = group->getObjects();
    for(int i=0;i<group1.size();i++){
        ValueMap spawnPoint = group1[i].asValueMap();
        std::string name = spawnPoint["enemy"].asString();
        float pro = spawnPoint["x"].asFloat();
        float pro_y=spawnPoint["y"].asFloat();
        EnemySprite *sprite = EnemySprite::create();
        sprite->setProperty(spawnPoint["gift"].asString());
        sprite->setMapLayer(this);
        sprite->setGameRole(gameRole);
        sprite->setAnchorPoint(Vec2(0.5, 0.5));
        sprite->setPosition(pro, pro_y);
//        CCLOG("精灵。。。。。。。。。。。%f",pro);
//        CCLOG("精灵。。。。。。。。。。。%f",pro_y);
        addChild(sprite);
        _data.pushBack(sprite);

从瓦片中取出敌人。 和各种需要的元素。放入一数组中 再遍历敌人。 首先敌人的攻击是需要延迟的。 不能像冲锋枪一样嘟嘟嘟。 在 更新状态的时候 ,每20毫秒 ,启动一次。虽然还是很快,但是可以调整。

    if(a>20){
        moveEnemy();
        a=0;
    }
        a++;

然后进入 最重要的两个核心代码中的其中之一。如何让子弹不停的追踪主角。 这需要测算一下。敌人和主角之间的 sin 和cos值。 计算他们的初始化位置。 去攻击主角。

我在子弹的类里 把主角引用进去。

//首先计算弧度
void BulletLayer::move_init(){
    float angle = getRed(gameRole->getPosition(),this->getPosition()) *180.0/PI;
    float angle_1 = 2* PI/360 * (angle+180);
    x_x1=   30 *cos(angle_1);
    y_y1=   30 * sin(angle_1);
    this->schedule(schedule_selector(BulletLayer::updateMove));
}
void BulletLayer::updateMove(float dt)
{
     this->setPosition(this->getPositionX()+x_x1,this->getPositionY()+y_y1);
}

核心代码2

如何仅仅是简单的子弹攻击敌人,然后敌人消失,这个游戏的没有任何可玩性。所以 射击游戏最 主要一个卖点就是 礼物包。武器包。

我把属性写在了敌人里边。

\\如果检测到了gift属性
  EnemySprite *sprite = EnemySprite::create();
  sprite->setProperty(spawnPoint["gift"].asString());
 if(spriteEnemy->str=="1"){
   Sprite *sprite = Sprite::create("gift.png");
   sprite->setTag(21);
   sprite->setPosition(spriteEnemy->getPositionX()
    ,spriteEnemy->getPositionY()+mapLayer->getPositionY());
     addChild(sprite);
//动力源
 gift_vector.pushBack(sprite);
                    }

当特定敌人受到了碰撞,gift精灵 放进 gift_vector动态数组Vector。

                if(sprite1->getTag()==21){
                    float game_Gouyin=gameRole->gouyin;
                    gameRole->gouyin=game_Gouyin+1;
                    gameRole->setControlLayer(this);
                    CCLOG("gouyin %f",gameRole->gouyin);
                    this->removeChild(sprite1);
                    gift_vector.eraseObject(sprite1);
                }

当获得Gift以后。如果被 主角碰撞,那么 主角当 一个特定当变化就会打开。

在这里插入图片描述

主角周围,有两颗球围绕着变化。这两个球,可以充当子弹去攻击敌人。礼物的增多,这个小球就会增多。
圆环的公式是
x2 y2是半径的坐标,x0 y0是圆心坐标。

            float _x=(_x2-x0)*cos(angle_2) - (_y2-y0)*sin(angle) +x0;
            float _y=(_x2-x0)*sin(angle_2) + (_y2-y0)*cos(angle_2) +y0;

只要不断的更新弧度,就可以让小球不断的围着圆心修改位置。

本来核心代码有3个的。

失败的位置。
首先我想让敌人的移动就像有刚体 一样。 然后追击这主角。 在没有刚体的情况下,所有的精灵都会以最短的距离攻击主角。然后就会形成一块区域叠加这好几层精灵。 但是我需要让敌人之间有碰撞的距离,当敌人相互碰撞的时候不是重合。而是相互挤在一起。由于敌人的属性是相同的,只能识别与自己不相同的主角。发生了很多抖动,就像烂的物理引擎一样。所有放弃了。或许是懒得写吧。 刚体的具体原理我还没有清楚,所有以后再说吧。

游戏结束

这个游戏结束的标准是 打败所有敌人。 或者被敌人打败。
#判断被敌人打死。 我写了一个血条类,当被子弹攻击到,血条下降%1的血。
所有当攻击完所有敌人。或者被打败就会发出对话框。 内容是success 和Fail 。 然后弹出按钮表示是否重启,或者退出。

void WinSuccessLayer::Fail(){
    Director::sharedDirector()->end();
    exit(0);
}

总结:

  • 射击类,游戏。
  • 首先,创建主角。
  • 利用动态数组去管理 所有的运动精灵。
  • 弧度和角度的换算。 float angle_1=angle *180.0/PI;
  • 圆环的计算。 半径和弧度要找对。不需要更新半径和圆心。 而是更新角度。!!!!
  • 增加一定要增加攻击时候的音乐。 auto audio = SimpleAudioEngine::getInstance();
  • 在管理每一个精灵的动态选择中。要在精灵类的内部进行管理。而不是在数组上。尽量少迭代数组。
  • 地图的移动尽量移动地图类。而不是用Gamera。 管理好层级管关系。按钮不能被盖住。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

昏暗的夜晚

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

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

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

打赏作者

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

抵扣说明:

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

余额充值