Level_01.h

  1. #ifdef WIN32
  2. #pragma execution_character_set("utf-8")
  3. #pragma once
  4. #ifndef __LEVEL01_SCENE_H__
  5. #define __LEVEL01_SCENE_H__
  6. #include "cocos2d.h"
  7. #include "ui/CocosGUI.h"
  8. #include "SimpleAudioEngine.h"
  9. #include <string.h>
  10. #include <time.h>
  11. #include "cocos-ext.h"
  12. #include "Stage.h"
  13. #include "GameOver.h"
  14. using namespace cocos2d::ui;
  15. using namespace CocosDenshion;
  16. USING_NS_CC_EXT;
  17. USING_NS_CC;
  18. class Level_01 : public cocos2d::Scene
  19. {
  20. public:
  21. static cocos2d::Scene* createScene();
  22. Stage* stage;
  23. bool touchingSwapping = false; //表示当时是否正在交换
  24. int x1, y1; //用于判断第一个触摸的点
  25. int x2, y2; //用于判断第二个触摸的点
  26. Label* scoreLabel;
  27. LoadingBar* timeBar;
  28. float barLength = 1800.0f;
  29. //void initGameArea(); //初始化游戏区域
  30. void backToGameMenuScene(); //返回主菜单
  31. virtual bool init();
  32. void reSwap(float dl);
  33. void eraseBlocks(float dl);
  34. //与玩家交互的三个监听函数
  35. bool onTouchStart(Touch *touch, Event *event);
  36. void onTouchMove(Touch *touch, Event *event);
  37. void onTouchEnd(Touch *touch, Event *event);
  38. // a selector callback
  39. void menuCloseCallback(cocos2d::Ref* pSender);
  40. void update(float dl);
  41. // implement the "static create()" method manually
  42. CREATE_FUNC(Level_01);
  43. };
  44. #endif // __LEVEL01_SCENE_H__#pragma once
  45. #endif


Level_01.cpp

#include "Level_01.h"

USING_NS_CC_EXT;
USING_NS_CC;

Scene* Level_01::createScene(){
    return Level_01::create();
}

static void problemLoading(const char* filename){
    printf("Error while loading: %s\n", filename);
    printf("Depending on how you compiled you might have to add 'Resources/' in front of filenames in Level_01Scene.cpp\n");
}

bool Level_01::init()
{
    if (!Scene::init()){
        return false;
    }
    // 这两个参数一般用来计算相对位置的
    auto visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();

    //创建背景
    Sprite *backGround = Sprite::create("background.png");
    backGround->setAnchorPoint(Point(0.5, 0.5));
    backGround->setPosition(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y);
    backGround->setScale(1);
    this->addChild(backGround, 0);

    //创建游戏区域
    Sprite *gameArea = Sprite::create("gameArea.png");
    gameArea->setPosition(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y);
    gameArea->setOpacity(200);
    this->addChild(gameArea, 1);

    //创建方块的Stage层,层可以看作是保留了最基础功能的透明精灵,我们可以在它上面挂载新的节点或者监听事件
    stage = Stage::create();
    this->addChild(stage, 2);
    stage->Bartime = 1800;
    stage->score = 0;    //分数
    stage->setPosition(Vec2(-40, 150));


    //创建上方进度条与分数
    scoreLabel = Label::createWithTTF("得分", "fonts/蒙纳简电脑体.ttf", 24);
    scoreLabel->setColor(Color3B::WHITE);
    scoreLabel->setPosition(Vec2(origin.x + visibleSize.width / 2,
        origin.y + visibleSize.height - scoreLabel->getContentSize().height - 75));

    this->addChild(scoreLabel, 1);

    //制作时间进度条
    auto timeBarBorder = Sprite::create("prohressBarBorder.png");
    timeBarBorder->setAnchorPoint(Point(0.5, 0.5));
    timeBarBorder->setPosition(visibleSize.width / 2, visibleSize.height - 150);

    this->addChild(timeBarBorder, 6);
    timeBar = ui::LoadingBar::create("prohressBar.png");
    timeBar->setAnchorPoint(Point(0.5, 0.5));
    timeBar->setPosition(Vec2(visibleSize.width / 2, visibleSize.height - 150));

    timeBar->setDirection(ui::LoadingBar::Direction::LEFT);
    this->addChild(timeBar, 5);

    //update更新函数,用于更新每时每刻的时间减少
    this->scheduleUpdate();


    //创建用户移动方块的代码部分
    //监听器监听图标状态
    auto listener = EventListenerTouchOneByOne::create();
    listener->onTouchBegan = CC_CALLBACK_2(Level_01::onTouchStart, this);
    listener->onTouchMoved = CC_CALLBACK_2(Level_01::onTouchMove, this);
    listener->onTouchEnded = CC_CALLBACK_2(Level_01::onTouchEnd, this);


    auto eventDispatcher = Director::getInstance()->getEventDispatcher();
    eventDispatcher->addEventListenerWithSceneGraphPriority(listener, stage);

    //创建游戏下方的菜单
    MenuItemFont::setFontName("BoLeHuaiShuti");
    MenuItemFont::setFontSize(48);
    auto backToMainScene = MenuItemFont::create("返回游戏主菜单", CC_CALLBACK_0(Level_01::backToGameMenuScene, this));
    backToMainScene->setColor(Color3B(255, 250, 250));
    backToMainScene->setPosition(visibleSize.width / 2, 100);

    auto bottomMenu = Menu::create(backToMainScene, NULL);
    bottomMenu->setPosition(Vec2::ZERO);
    this->addChild(bottomMenu, 5);


    return true;
}

void Level_01::reSwap(float dl) {
    stage->swapBlocks(stage->x1, stage->y1, stage->x2, stage->y2);
    stage->isSwapping = false;
}
void Level_01::eraseBlocks(float dl) {
    stage->removeBlocks();//清除方块
    stage->initNewBlocks();//生成新的方块
    if (stage->moveDownBlocks()) {//落下未清除的方块
        //如果落下后仍可以消除
        scheduleOnce(schedule_selector(Level_01::eraseBlocks), 0.3f);
    }
    else { //说明已经没有可以被消除的方块了
        stage->isSwapping = false;
        touchingSwapping = false;
    }
}

////与玩家交互的三个监听函数
//bool Level_01::onTouchStart(Touch *touch, Event *event) {
//    log("touchStart函数触发次数");
//    for (int i = 1; i <= (stage->n); i++) {
//        for (int j = 1; j <= (stage->m); j++) {
//            //接下来我们需要检测,到底是触碰到了哪一个方块
//            if (stage->tag[i][j] <= 0)
//                continue; //防止触碰到墙壁或者刻意留下的空洞上
//
//            //获取block的碰撞Box,并用这个Box自带的containsPoint函数判断touch的点在不在它的里面
//            if (stage->blocks[i][j]->getBoundingBox().containsPoint(touch->getLocation())) {
//
//                log("方块被触碰的触发次数");
//                if (stage->ifSelected == false) { //表示之前没有选择任何一个方块
//                    log("第一次选择触发次数");
//                    //那么现在选到了一个
//                    stage->ifSelected = true;
//                    //保存选到的方块
//                    stage->setSelectedBlock(stage->blocks[i][j], 1, true);
//    
//                }
//                else if (stage->firstSelectedBlock!=stage->blocks[i][j]) { //已选中条件下,不允许重复选择
//                    log("第二次选择触发次数");
//                    //以下计算表示新的(i,j)与之前选中的是相邻的两个点
//                    if ((abs(stage->firstSelectedBlock->getX() - i) + abs(stage->firstSelectedBlock->getY() - j) == 1)) {
//                        stage->ifSelected = false;
//                        stage->setSelectedBlock(stage->blocks[i][j], 2, true);
//                        //那么就需要交换
//                        if(stage->firstSelectedBlock && stage->secondSelectedBlock)
//                            stage->swapBlocks(stage->firstSelectedBlock->getX(), stage->firstSelectedBlock->getY(), i, j);
//                    }
//                    //但如果第二个不是相邻的方块,那么就把第一次选中的更换为当前选择的
//                    else {
//                        log("非相邻方块被选中");
//                        stage->setSelectedBlock(stage->firstSelectedBlock, 1, false); //把第一次的取消选中
//                        stage->setSelectedBlock(stage->blocks[i][j], 1, true); //把第二次的放进第1号选中位置
//
//                        stage->ifSelected = true;
//                    }
//                }
//                return true; //找到一个就需要中止循环
//            }
//        }
//    }
//    return false; //表示不吞没
//}
//交互的三个监听函数
bool Level_01::onTouchStart(Touch *touch, Event *event) {
    if (stage->isSwapping) {
        log("Swapping!");
        return true;
    }
    log("Touching");
    auto target = static_cast<Sprite *>(event->getCurrentTarget());

    Vec2 touchLocalPosition = target->convertToNodeSpace(touch->getLocation());
    for (int i = 1; i <= (stage-> n); i++) {
        for (int j = 1; j <= (stage->m); j++) {

            if (stage->tag[i][j] <= 0)
                continue;
            if (stage->blocks[i][j]->getBoundingBox().containsPoint(touchLocalPosition)) {
                if (x1 == -1){//我们让横坐标为-1时,表示1号位没有选中物体,所以当前正在点击第一个点
                    x1 = i; y1 = j; //保存第一个点的位置信息
                    stage->setSelectedBlock(stage->blocks[i][j], 1, true); //第一个点被选中
                }
                else if (x1 != i||y1 != j) { //当第二次点击的点跟第一次的位置不一样时
                    x2 = i; y2 = j; //保存第二个点的位置信息
                    if (abs(x1 - x2) + abs(y1 - y2) == 1) {    //这个判断可用于判断是否是相邻两点
                        //交换两点
                        if (stage->swapBlocks(x1, y1, x2, y2))   //如果交换后满足消除,激发对应回调函数清除方块
                            scheduleOnce(schedule_selector(Level_01::eraseBlocks), 0.3f);
                        else  //如果交换后不满足,那么还需要交换回来
                            scheduleOnce(schedule_selector(Level_01::reSwap), 0.3f);

                        x1 = -1; //重置为-1,表示没有一个砖块被选
                    }
                    else{
                        stage->setSelectedBlock(stage->blocks[x1][y1], 1, false);//把原先的点去除选择
                        stage->setSelectedBlock(stage->blocks[i][j], 1,true);//如果不是相邻的两点,就把现在的这个点放入1号位
                        x1 = x2; y1 = y2; //更换一号位的坐标
                    }
                }
                return true;
            }
        }
    }
    return false;    //返回false表示
}
void Level_01::onTouchMove(Touch *touch, Event *event) {
    if (stage->isSwapping) {
        log("正在交换中");
        return;
    }
    auto target = static_cast<Sprite *>(event->getCurrentTarget());
    Vec2 touchLocalPosition = target->convertToNodeSpace(touch->getLocation());
    for (int i = 1; i <= (stage->n); i++) {
        for (int j = 1; j <= (stage->m); j++) {
            if (stage->tag[i][j] <= 0 || touchingSwapping)
                continue; //由于move函数将会被触发多次,所以需要有限制
            if (stage->blocks[i][j]->getBoundingBox().containsPoint(touchLocalPosition)) {
                if ((i == x1&&j == y1) || x1 == -1) //如果是鼠标在同一个点中move,或者第一个点没选中,中止
                    return;

                //只有当第一个点存在,即(x1!=-1)时,我们才进行第二个点的判断
                x2 = i;
                y2 = j;
                if (abs(x1 - x2) + abs(y1 - y2) == 1) {    //相邻两点
                    //交换两点
                    if (stage->swapBlocks(x1, y1, x2, y2)) {   //如果交换后满足消除
                        touchingSwapping = true;
                        scheduleOnce(schedule_selector(Level_01::eraseBlocks), 0.3f);
                    }
                    else  //如果交换后不满足,那么还需要交换回来
                        scheduleOnce(schedule_selector(Level_01::reSwap), 0.3f);
                    x1 = -1;
                }
                else{ //不相邻,就把第二次选择的放入第一个
                    stage->setSelectedBlock(stage->blocks[x1][y1], 1, false);//把原先的点去除选择
                    stage->setSelectedBlock(stage->blocks[i][j], 1, true);
                    x1 = x2; y1 = y2; //更换一号位的坐标
                }

            }

        }
    }
}
void Level_01::onTouchEnd(Touch *touch, Event *event) {
    if (stage->isSwapping) {
        log("正在交换中");
        return;
    }
    //只有当用户抬起鼠标之后,才开放touchingSwapping,防止用户满屏幕乱晃导致的交换时多次移动
    touchingSwapping = false;
}


// 返回原菜单
void Level_01::backToGameMenuScene() {
    //auto scene = GameMenu::createScene();
    Director::getInstance()->popScene();
}

void Level_01::menuCloseCallback(Ref* pSender)
{
    Director::getInstance()->end();
}

void Level_01::update(float dl) {
    char score[64]="";
    if (stage != nullptr) {
        if (stage->Bartime > 0) {
            stage->Bartime--;
            timeBar->setPercent((stage->Bartime / barLength) * 100);
            sprintf(score, "得分:%d", stage->score);
            scoreLabel->setString(score);
        }
        else {
            auto gameOverScene = GameOver::create();
            gameOverScene->setNowScore(stage->score);
            Director::getInstance()->replaceScene(gameOverScene);
        }

    }
}