Cocos2d-x简易黄金矿工

新版黄金矿工

作业要求

新版黄金矿工游戏,共有两个界面:主界面与游戏界面

  • 主界面:在demo代码基础上完善场景,添加开始按钮(MenuItem),点
    击进入游戏界面。
  • 游戏界面:两个Layer,StoneLayer锚点位于左下角,坐标设为(0,0),其上 有一石头精灵,初始坐标为(560,480);MouseLayer锚点位于左下角, 坐标设为(0,屏幕高度的一半),其上有一老鼠精灵,初始坐标为(屏幕宽度的 一半,0)。有一个Label,作为shoot按钮。
  • 游戏要求:游戏开始后,点击屏幕任意位置,在该位置添加一块奶酪,老鼠 跑到该位置吃掉奶酪;点击shoot按钮,石头发射到老鼠所在的位置,老鼠 跑开,留下钻石。
  • 加分项:尝试添加一两个动画
  • 作业提交:提交实验报告(文档),Classes(文件夹),Resources(文件 夹)。实验报告要求有截图。

实现效果

实现效果

具体实现

GameScene.cpp

#include "GameScene.h"

USING_NS_CC;

Scene* GameSence::createScene()
{
    //这个地方写Sence::create()不会报错,但是没法显示整个页面。
    return GameSence::create();
}

// on "init" you need to initialize your instance
bool GameSence::init()
{

    // 1. super init first
    if (!Scene::init())
    {
        return false;
    }

    //add touch listener
    EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create();
    listener->setSwallowTouches(true);
    listener->onTouchBegan = CC_CALLBACK_2(GameSence::onTouchBegan, this);
    Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);


    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();
    //设置背景图片
    auto levelBackGround = Sprite::create("level-background-0.jpg");
    levelBackGround->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));
    this->addChild(levelBackGround, 0);
    //设置石头层
    auto stoneLayer = Layer::create();
    stoneLayer->setPosition(0, 0);
    stoneLayer->setName("stoneLayer");
    this->addChild(stoneLayer, 1);
    //向石头层添加石头
    auto stone = Sprite::create("stone.png");
    stone->setPosition(600, 480);
    stone->setName("stone");
    stoneLayer->addChild(stone, 1);
    //设置老鼠层
    auto mouseLayer = Layer::create();
    mouseLayer->setPosition(0, visibleSize.height / 2);
    mouseLayer->setName("mouseLayer");
    this->addChild(mouseLayer, 1);
    //向老鼠层添加老鼠
    //这个地方巨坑,因为level-sheet.plist文件里面给了不止一个老鼠的动画
    //一开始看到老鼠的动画是老鼠和钻石在一起,所以想到先生成老鼠,再生成钻石
    //这样的话,发现老鼠是动的,钻石是不动的,不符合要求
    //所以把钻石作为老鼠的子类,这样钻石就可以和老鼠一起动
    //但是仔细看demo的示例,老鼠是抱着钻石的,而且钻石是覆盖掉肚子的,这是完全不可能的
    //因为老鼠是一个层面的,钻石是一个层面的,要么老鼠覆盖钻石,要么钻石覆盖老鼠,
    //所以事情的真相只有一个,老鼠抱着钻石本身就是一张图片。。。。。
    const std::string mouseFrameName = "gem-mouse-0.png";
    auto mouse = Sprite::createWithSpriteFrameName("gem-mouse-0.png");
    Animate* mouseAnimate = Animate::create(AnimationCache::getInstance()->getAnimation("mouseAnimation"));
    mouse->runAction(RepeatForever::create(mouseAnimate));
    mouse->setPosition(visibleSize.width / 2, 0);
    mouse->setName("mouse");
    mouseLayer->addChild(mouse, 1);

    //生成shoot文字
    const char *shootName = "shoot";
    auto shootText = Label::createWithTTF(shootName, "fonts/Marker Felt.ttf", 72);
    shootText->setPosition(Vect(origin.x + visibleSize.width - shootText->getContentSize().width, 480));
    shootText->setName("shootText");
    this->addChild(shootText, 1);

    return true;
}

bool GameSence::onTouchBegan(Touch *touch, Event *unused_event) {
    //得到鼠标点击的地方
    Size visibleSize = Director::getInstance()->getVisibleSize();
    auto location = touch->getLocation();
    //很好的控制台输出语句,比uwp方便多了
    CCLOG("location == %f, location == %f", location.x, location.y);
    //获得每个实例,有两种方法getChildByName,或者getChildByTag
    //个人觉得getChildByName更直观一些,需要在前面设置setName
    //Tag,是int型的,需要在addChild的时候设置
    auto stoneLayer = this->getChildByName("stoneLayer");
    auto stone = stoneLayer->getChildByName("stone");
    auto mouseLayer = this->getChildByName("mouseLayer");
    auto mouse = mouseLayer->getChildByName("mouse");
    auto shootText = this->getChildByName("shootText");

    //判断是否点击了shoot文字
    bool isInShootLabel = shootText->getBoundingBox().containsPoint(location);
    if (isInShootLabel) {
        //这里先生成一个stone,然后用生成的stone发射
        //stone移动到老鼠的世界坐标,然后消失,用的是动作序列,不要忘记addChild,否则没有任何反应
        auto stoneTempMoveTo = MoveTo::create(0.5, mouseLayer->convertToWorldSpace(mouse->getPosition()));
        auto stoneTemp = Sprite::create("stone.png");
        stoneTemp->setPosition(600, 480);
        stoneLayer->addChild(stoneTemp);
        //石头渐渐消失
        auto stoneTempFadeOut = FadeOut::create(0.5);
        //将生成的stone删除掉,节约资源
        auto callBackRemove = CallFunc::create([this, &stoneTemp]() {
            this->removeChild(stoneTemp);
        });
        auto stoneTempSequence = Sequence::create(stoneTempMoveTo, stoneTempFadeOut,callBackRemove,nullptr);
        stoneTemp->runAction(stoneTempSequence);

        //随机产生一个新位置,因为容易出界,所以各取了1/2
        auto mouseNewPosition = Vec2(CCRANDOM_0_1() * visibleSize.width*0.5, CCRANDOM_0_1() * visibleSize.height*0.5);
        auto mouseMoveTo = MoveTo::create(0.5, mouseNewPosition);
        mouse->runAction(mouseMoveTo);
        //被石头攻击,老鼠移动会留下钻石,留在老鼠的世界坐标系下
        auto diamond = Sprite::create("diamond.png");
        diamond->setPosition(mouseLayer->convertToWorldSpace(mouse->getPosition()));
        this->addChild(diamond);
    }
    else {
        //当点击的时候不是shoot,就会产生cheese,cheese位置是鼠标点击位置
        auto cheese = Sprite::create("cheese.png");
        cheese->setPosition(location);
        this->addChild(cheese);
        //老鼠移动到cheese位置,需要把cheese转成mouseLayer的相对坐标
        auto mouseMoveTo = MoveTo::create(0.5, mouseLayer->convertToNodeSpace(location));
        mouse->runAction(mouseMoveTo);
        //cheese渐渐消失
        auto cheeseFadeOut = FadeOut::create(0.5);
        //删除cheese节省资源
        auto callBackRemove = CallFunc::create([this, &cheese]() {
            this->removeChild(cheese);
        });
        auto cheeseSequence = Sequence::create(DelayTime::create(0.5), cheeseFadeOut, nullptr);
        cheese->runAction(cheeseSequence);
    }
    return true;
}

GameScene.h

#pragma once
#include <stdio.h>
#include "cocos2d.h"
USING_NS_CC;

class GameSence : public cocos2d::Scene
{
public:
    static cocos2d::Scene* createScene();

    virtual bool init();

    virtual bool onTouchBegan(Touch *touch, Event *unused_event);

    //virtual void shootMenuCallback(Ref* pSender);

    CREATE_FUNC(GameSence);

private:
    Sprite * mouse;

    Sprite* stone;

    Layer* mouseLayer;

    Layer* stoneLayer;
    //感觉私有变量没什么作用啊,init之后,虽然初始化了
    //但是在其他函数,还是要通过tag或者name获取实例
    Label* shootText;
};
#include "MenuScene.h"
//GameScene.h还是要包含的,否则无法调用它的init函数
#include "GameScene.h"
#include "SimpleAudioEngine.h"

USING_NS_CC;

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

// Print useful error message instead of segfaulting when files are not there.
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 HelloWorldScene.cpp\n");
}

// on "init" you need to initialize your instance
bool MenuScene::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !Scene::init() )
    {
        return false;
    }

    auto visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();

    auto bg_sky = Sprite::create("menu-background-sky.jpg");
    bg_sky->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y + 150));
    this->addChild(bg_sky, 0);

    auto bg = Sprite::create("menu-background.png");
    bg->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y - 60));
    this->addChild(bg, 0);

    auto miner = Sprite::create("menu-miner.png");
    miner->setPosition(Vec2(150 + origin.x, visibleSize.height / 2 + origin.y - 60));
    this->addChild(miner, 1);

    auto leg = Sprite::createWithSpriteFrameName("miner-leg-0.png");
    Animate* legAnimate = Animate::create(AnimationCache::getInstance()->getAnimation("legAnimation"));
    leg->runAction(RepeatForever::create(legAnimate));
    leg->setPosition(110 + origin.x, origin.y + 102);
    this->addChild(leg, 1);
    //从这里开始,基本操作
    auto goldMinerText = Sprite::create("gold-miner-text.png");
    goldMinerText->setPosition(Vect(origin.x + visibleSize.width / 2, origin.y + visibleSize.height - goldMinerText->getContentSize().height));
    this->addChild(goldMinerText);

    auto menuStartGold = Sprite::create("menu-start-gold.png");
    menuStartGold->setPosition(Vec2(origin.x + visibleSize.width - menuStartGold->getContentSize().width / 2, origin.y + menuStartGold->getContentSize().width / 2));
    this->addChild(menuStartGold, 0);
    //菜单项,有一个点击调用函数,replaceScene,后续的init会直接调用
    auto startItem = MenuItemImage::create(
        "start-0.png",
        "start-1.png",
        CC_CALLBACK_1(MenuScene::menuStartCallBack, this));
    startItem->setPosition(Vec2(origin.x+150, origin.y+180));
    auto menu = Menu::create(startItem, NULL);
    menu->setPosition(Vec2::ZERO);
    menuStartGold->addChild(menu, 0);

    return true;
}

void MenuScene::menuStartCallBack(Ref* pSender) {
    Director::getInstance()->replaceScene(GameSence::createScene());
}

AppDelegate.cpp

//预读老鼠的动画
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("level-sheet.plist");
    char mouseTotalFrames = 7;
    char mouseFrameName[20];
    Animation* mouseAnimation = Animation::create();

    for (int i = 0; i < mouseTotalFrames; i++)
    {
        sprintf(mouseFrameName, "gem-mouse-%d.png", i);
        mouseAnimation->addSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(mouseFrameName));
    }
    mouseAnimation->setDelayPerUnit(0.1);
    AnimationCache::getInstance()->addAnimation(mouseAnimation, "mouseAnimation");

资源以及视频演示

资源以及视频演示

猜你喜欢

转载自blog.csdn.net/yaoxh6/article/details/80373129