您的位置:首页 > 移动开发 > Cocos引擎

Cocos2d-x:学习笔记(2017.05.12更新)

2017-05-01 20:41 387 查看

1.参考链接汇总

官方接口文档

关于Cocos2d-x中addchild和removeChild方法的参数的解析

Cocos2d-x3.2 Menu菜单的创建

cocos 中熟练运用场景的切换

cocos2dx一个场景添加多个层

Cocos2d-x Layer锚点设置

cocos2d-x convertToWorldSpace 和 convertToNodeSpace

cocos2d-x 延迟执行一段代码1 顺序执行动作+延迟动作+CallFunc

Cocos2d-x v3.6制作射箭游戏(三)

菜鸟学习Cocos2d-x 3.x——浅谈动画

cocos2d-x“无法打开源文件”

cocos2d-x 坐标研究

深入理解 cocos2d-x 坐标系

Cocos2d-x解析XML文件,解决中文乱码

Cocos2d-x 通过虚拟按键控制人物移动

【平凡晓声 Cocos2d-x】虚拟按键控制精灵移动2

android Drawbitmap 画一个图片(Rect 的作用)

C++中数字与字符串之间的转换

Cocos2d-X中使用ProgressTimer实现一些简单的效果

菜鸟学习Cocos2d-x 3.x——浅谈动作Action

Cocos2dx学习笔记12:cocos2dx进度条(ProgressTimer)

cocos2dx[3.4](25)——瓦片地图TiledMap

cocos2dx 中 如果一个精灵被击中了,需要消失,用什么函数来实现呢?

Cocos2d-x v3.3中UserDefault保存的XML文件位置

2.创建Sprite

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


使用plist:

auto spritecache = SpriteFrameCache::getInstance();
spritecache->addSpriteFramesWithFile("level-sheet.plist");
mouse = Sprite::createWithSpriteFrameName("gem-mouse-0.png");
mouse->setPosition(Vec2(origin.x + visibleSize.width / 2, 0));


使用动画第一帧:

// 创建一张贴图
auto texture = Director::getInstance()->getTextureCache()->addImage("$lucia_2.png");
// 从贴图中以像素单位切割,创建关键帧
auto frame0 = SpriteFrame::createWithTexture(texture, CC_RECT_PIXELS_TO_POINTS(Rect(0, 0, 113, 113)));
// 使用第一帧创建精灵
player = Sprite::createWithSpriteFrame(frame0);
player->setPosition(Vec2(origin.x + visibleSize.width / 2,
origin.y + visibleSize.height/2));
addChild(player, 3);


3.创建MenuItem

auto closeItem = MenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));

closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
origin.y + closeItem->getContentSize().height/2));
auto menu = Menu::create(closeItem, NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 1);


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

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}


4.创建Layer

stoneLayer = Layer::create();
stoneLayer->setPosition(Vec2(0, 0));
stoneLayer->setAnchorPoint(Vec2(0, 0));
stoneLayer->ignoreAnchorPointForPosition(false);
stoneLayer->addChild(stone);

mouseLayer = Layer::create();
mouseLayer->setPosition(Vec2(0, origin.y + visibleSize.height / 2));
mouseLayer->setAnchorPoint(Vec2(0, 0));
mouseLayer->ignoreAnchorPointForPosition(false);
mouseLayer->addChild(mouse);

this->addChild(stoneLayer, 1);
this->addChild(mouseLayer, 1);


5.显示中文字符

CCDictionary* message = CCDictionary::createWithContentsOfFile("Chinese.xml");
auto nameKey = message->valueForKey("Name");
const char* Name = nameKey->getCString();
auto IDKey = message->valueForKey("ID");
const char* ID = IDKey->getCString();
auto label = Label::createWithTTF(Name, "fonts/FZSTK.ttf", 24);
auto label1 = Label::createWithTTF(ID, "fonts/Marker Felt.ttf", 24);
// position the label on the center of the screen
label->setPosition(Vec2(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - label->getContentSize().height));
label1->setPosition(Vec2(origin.x + visibleSize.width / 2,
origin.y + visibleSize.height
- label->getContentSize().height-label1->getContentSize().height));


<?xml version="1.0" encoding="UTF-8"?>

<dict>

<key>Name</key>

<string>名字</string>

<key>ID</key>

<string>学号</string>

</dict>


6. 播放背景英语

#include <SimpleAudioEngine.h>
#define MUSIC_FILE "666.mp3"


以下是menuItem的触发函数,点击一下播放音乐,再点击一下停止音乐

void HelloWorld::display_music(Ref* pSender) {
CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadBackgroundMusic(MUSIC_FILE);
CocosDenshion::SimpleAudioEngine::sharedEngine()->setBackgroundMusicVolume(0.5);
if (count % 2 == 0)
CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic(MUSIC_FILE, true);
else
CocosDenshion::SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();
count++;
}


7.定义动画(使用plist)

在AppDelegate.cpp中,

SpriteFrameCache::getInstance()->addSpriteFramesWithFile("level-sheet.plist");
char _totalFrames = 7;
char _frameName[40];
Animation* diamondAnimation = Animation::create();

for (int i = 0; i < _totalFrames; i++) {
sprintf(_frameName, "pulled-diamond-%d.png", i);
diamondAnimation->addSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(_frameName));
}
diamondAnimation->setDelayPerUnit(0.1);
AnimationCache::getInstance()->addAnimation(diamondAnimation, "diamondAnimation");


在GameSence.cpp中,

Animate* diamondAnimate = Animate::create(AnimationCache::getInstance()->getAnimation("diamondAnimation"));
diamond->runAction(RepeatForever::create(diamondAnimate));


通过texture定义动画:

// 定义存储动画帧的vector
cocos2d::Vector<SpriteFrame*> attack;
// 创建一张贴图
auto texture = Director::getInstance()->getTextureCache()->addImage("$lucia_2.png");
// 攻击动画
attack.reserve(17);
for (int i = 0; i < 17; i++) {
auto frame = SpriteFrame::createWithTexture(texture, CC_RECT_PIXELS_TO_POINTS(Rect(113*i,0,113,113)));
attack.pushBack(frame);
}
auto attack_animation = Animation::createWithSpriteFrames(attack, 0.1f);
attack_animation->setRestoreOriginalFrame(true);
AnimationCache::getInstance()->addAnimation(attack_animation, "attackAnimation");


8.触摸监听器

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


bool GameSence::onTouchBegan(Touch *touch, Event *unused_event) {}


9.获得visibleSize与origin

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


10.设置锚点

mouseLayer->setAnchorPoint(Vec2(0, 0));
mouseLayer->ignoreAnchorPointForPosition(false);


11.MoveTo使用

auto moveTo = MoveTo::create(2, mouseLayer->convertToNodeSpace(location));
mouse->runAction(moveTo);


12.世界坐标系与本地坐标系的转换

auto location = mouse->getPosition();
location = mouseLayer->convertToWorldSpace(location);
auto moveTo = MoveTo::create(1, stoneLayer->convertToNodeSpace(location));
stone->runAction(moveTo);


13.延迟函数的实现(异步操作)

auto _delayTime = DelayTime::create(0.5);
auto _func = CallFunc::create([this]() {
stoneLayer->removeChild(stone);
stone = Sprite::create("stone.png");
stone->setPosition(Vec2(560, 480));
stoneLayer->addChild(stone);
});
auto _seq = Sequence::create(_delayTime, _func, NULL);
this->runAction(_seq);


14.设置背景

// 设置背景
auto bg = Sprite::create("background.jpg");
bg->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));
this->addChild(bg, 0);


使用TileMap

// 设置背景
TMXTiledMap* tmx = TMXTiledMap::create("map.tmx");
tmx->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));
tmx->setAnchorPoint(Vec2(0.5, 0.5));
tmx->setScale(Director::getInstance()->getContentScaleFactor());
this->addChild(tmx, 0);


15.创建倒计时

// 创建倒计时
time = Label::createWithTTF("120", "fonts/arial.ttf", 36);
time->setPosition(Vec2(origin.x+visibleSize.width/2, origin.y+visibleSize.height-30));
this->addChild(time);
schedule(schedule_selector(HelloWorld::updateTime), 1);
dtime = 120;


// 事件更新函数
void HelloWorld::updateTime(float delta) {
dtime--;
if (dtime < 0) dtime = 0;
char str[10];
sprintf(str, "%d", dtime); // 将int类型转化为字符串char*类型
time->setString(str);
}


16.游戏的hp条

// 进度条定义
cocos2d::ProgressTimer* pT;
// hp条
Sprite* sp0 = Sprite::create("hp.png", CC_RECT_PIXELS_TO_POINTS(Rect(0, 320, 420, 47))); // 进度条框
Sprite* sp = Sprite::create("hp.png", CC_RECT_PIXELS_TO_POINTS(Rect(610, 362, 4, 16))); // 进度条

// 使用hp条设置progressBar
pT = ProgressTimer::create(sp);
pT->setScaleX(90);
pT->setAnchorPoint(Vec2(0, 0));
pT->setType(ProgressTimerType::BAR); // 定义进度条类型
pT->setBarChangeRate(Point(1, 0));
pT->setMidpoint(Point(0, 1));
pT->setPercentage(100);
pT->setPosition(Vec2(origin.x+14*pT->getContentSize().width,origin.y + visibleSize.height - 2*pT->getContentSize().height));
addChild(pT,1);
sp0->setAnchorPoint(Vec2(0, 0));
sp0->setPosition(Vec2(origin.x + pT->getContentSize().width, origin.y + visibleSize.height - sp0->getContentSize().height));
addChild(sp0,0);


17.游戏方向键WSAD定义

// 方向键
auto buttonW = Button::create("W.png", "W.png");
auto buttonS = Button::create("S.png", "S.png");
auto buttonA = Button::create("A.png", "A.png");
auto buttonD = Button::create("D.png", "D.png");
buttonW->setPosition(Vec2(origin.x + 60, origin.y + 60));
buttonS->setPosition(Vec2(origin.x + 60, origin.y + 20));
buttonA->setPosition(Vec2(origin.x + 20, origin.y + 20));
buttonD->setPosition(Vec2(origin.x + 100, origin.y + 20));

// W键事件处理函数
buttonW->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
switch (type) {
case ui::Widget::TouchEventType::BEGAN:
schedule(schedule_selector(HelloWorld::moveW), 0.3f);
break;
case ui::Widget::TouchEventType::ENDED:
unschedule(schedule_selector(HelloWorld::moveW));
break;
}
});

// S键事件处理函数
buttonS->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
switch (type) {
case ui::Widget::TouchEventType::BEGAN:
schedule(schedule_selector(HelloWorld::moveS), 0.3f);
break;
case ui::Widget::TouchEventType::ENDED:
unschedule(schedule_selector(HelloWorld::moveS));
break;
}
});

// A键事件处理函数
buttonA->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
switch (type) {
case ui::Widget::TouchEventType::BEGAN:
schedule(schedule_selector(HelloWorld::moveA), 0.3f);
break;
case ui::Widget::TouchEventType::ENDED:
unschedule(schedule_selector(HelloWorld::moveA));
break;
}
});

// D键事件处理函数
buttonD->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
switch (type) {
case ui::Widget::TouchEventType::BEGAN:
schedule(schedule_selector(HelloWorld::moveD), 0.3f);
break;
case ui::Widget::TouchEventType::ENDED:
unschedule(schedule_selector(HelloWorld::moveD));
break;
}
});

this->addChild(buttonW);
this->addChild(buttonS);
this->addChild(buttonA);
this->addChild(buttonD);

// 方向键D的移动
void HelloWorld::moveD(float dt) {
//auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),
//                                      MoveBy::create(0.15f, Vec2(10, 0)));
auto location = player->getPosition();
if (location.x + 20 >= visibleSize.width) {
auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(visibleSize.width-location.x-10, 0)),
Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
player->runAction(seq);
return;
}
auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(20, 0)),
Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
player->runAction(seq);
}

// 方向键A的移动
void HelloWorld::moveA(float dt) {
//auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),
//MoveBy::create(0.15f, Vec2(-10, 0)));
auto location = player->getPosition();
if (location.x - 20 <= 0) {
auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(-location.x+10, 0)),
Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
player->runAction(seq);
return;
}
auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(-20, 0)),
Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
player->runAction(seq);
}

// 方向键W的移动
void HelloWorld::moveW(float dt) {
//auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),
//MoveBy::create(0.15f, Vec2(0, 10)));
auto location = player->getPosition();
if (location.y + 20 >= visibleSize.height) {
auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, visibleSize.height-location.y-10)),
Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
player->runAction(seq);
return;
}
auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, 20)),
Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
player->runAction(seq);
}

// 方向键S的移动
void HelloWorld::moveS(float dt) {
//auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),
//MoveBy::create(0.15f, Vec2(0, -10)));
auto location = player->getPosition();
if (location.y - 20 <= 0) {
auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, -location.y+10)),
Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
player->runAction(seq);
return;
}
auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, -20)),
Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
player->runAction(seq);
}


上面的按钮实现的是点击按钮移动,松开按钮停止移动。但是这种实现可能会有bug,莫名其妙人物就不受控制了。所以我将之改为点击一下移动一下,即松开鼠标按钮后人物才会移动:

// 方向键D的移动

void HelloWorld::moveD(float dt) {

//auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),

//                                      MoveBy::create(0.15f, Vec2(10, 0)));

player->setFlipX(false);

auto location = player->getPosition();

if (location.x + 20 >= visibleSize.width) {

//auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(visibleSize.width-location.x-10, 0)),

//Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

//player->runAction(seq);

player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

player->runAction(MoveBy::create(0.6f, Vec2(visibleSize.width - location.x - 10, 0)));

return;

}

//auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(20, 0)),

//Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

//player->runAction(seq);

player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

player->runAction(MoveBy::create(0.6f, Vec2(20, 0)));

}

// 方向键A的移动

void HelloWorld::moveA(float dt) {

//auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),

//MoveBy::create(0.15f, Vec2(-10, 0)));

player->setFlipX(true);

auto location = player->getPosition();

if (location.x - 20 <= 0) {

//auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(-location.x+10, 0)),

//Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

//player->runAction(seq);

player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

player->runAction(MoveBy::create(0.6f, Vec2(-location.x + 10, 0)));

return;

}

//auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(-20, 0)),

//Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

//player->runAction(seq);

player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

player->runAction(MoveBy::create(0.6f, Vec2(-20, 0)));

}

// 方向键W的移动

void HelloWorld::moveW(float dt) {

//auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),

//MoveBy::create(0.15f, Vec2(0, 10)));

auto location = player->getPosition();

if (location.y + 20 >= visibleSize.height) {

//auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, visibleSize.height-location.y-10)),

//Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

//player->runAction(seq);

player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

player->runAction(MoveBy::create(0.6f, Vec2(0, visibleSize.height - location.y - 10)));

return;

}

//auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, 20)),

//Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

//player->runAction(seq);

player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

player->runAction(MoveBy::create(0.6f, Vec2(0, 20)));

}

// 方向键S的移动

void HelloWorld::moveS(float dt) {

//auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),

//MoveBy::create(0.15f, Vec2(0, -10)));

auto location = player->getPosition();

if (location.y - 20 <= 0) {

//auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, -location.y+10)),

//Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

//player->runAction(seq);

player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

player->runAction(MoveBy::create(0.6f, Vec2(0, -location.y + 10)));

return;

}

//auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, -20)),

//Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

//player->runAction(seq);

player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

player->runAction(MoveBy::create(0.6f, Vec2(0, -20)));

}


18.实现动画Animation的回调函数

auto callFunc = CallFunc::create([&] {isDone = true; });
auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("attackAnimation")),
callFunc);


19.通过互斥锁避免动画重叠进行

(1)首先我在类中新添加一个isDone成员,当isDone为false时,说明player正在执行动画;当isDone为true时,说明player已经执行完动画;

(2)将isDone初始为true,即可执行状态;

(3)在X、Y的点击事件处理函数的开始部分(在执行动画之前),添加一个条件判断,判断isDone是否为true。如果为true,则继续执行下面的代码,如果为false,则return函数;

(4)然后利用Sequence的createTwoAction来实现动画完成后的回调函数,回调函数的功能就是将isDone的值赋为true。

    // 技能键X的事件处理函数
buttonX->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
switch (type) {
case ui::Widget::TouchEventType::BEGAN:
break;
case ui::Widget::TouchEventType::ENDED:
if (isDone == false) return; // 动画未完成,不能执行新动画
else isDone = false; // 开始执行动画
if (pT->getPercentage() == 0) return; // 进度条为0时不可再执行该动画
auto callFunc = CallFunc::create([&] {isDone = true; }); // 定义动画执行完毕的回调函数
/*Animate* deadAnimation = Animate::create(AnimationCache::getInstance()->getAnimation("deadAnimation"));
auto action = Sequence::create(callFunc);*/
auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("deadAnimation")),
callFunc);
player->runAction(seq);
//player->runAction(deadAnimation);
if (pT->getPercentage() - 40 >= 0) { // 每次X操作减少进度条40
pT->setPercentage(pT->getPercentage() - 40);
}
else {
pT->setPercentage(0);
}
break;
}
});

// 技能键Y的事件处理函数
buttonY->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
switch (type) {
case ui::Widget::TouchEventType::BEGAN:
break;
case ui::Widget::TouchEventType::ENDED:
if (isDone == false) return;
else isDone = false;
/*Animate* attackAnimation = Animate::create(AnimationCache::getInstance()->getAnimation("attackAnimation"));
player->runAction(attackAnimation);*/
auto callFunc = CallFunc::create([&] {isDone = true; }); auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("attackAnimation")), callFunc);
player->runAction(seq);
if (pT->getPercentage() + 40 <= 100) {
pT->setPercentage(pT->getPercentage() + 40);
}
else {
pT->setPercentage(100);
}
break;
}
});
this->addChild(buttonX);
this->addChild(buttonY);
return true;
}


20.自定义调度器

switch (type) {
case ui::Widget::TouchEventType::BEGAN:
schedule(schedule_selector(HelloWorld::moveS), 0.3f);
break;
case ui::Widget::TouchEventType::ENDED:
unschedule(schedule_selector(HelloWorld::moveS));
break;


21.Lambada函数

buttonA->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
switch (type) {
case ui::Widget::TouchEventType::BEGAN:
schedule(schedule_selector(HelloWorld::moveA), 0.3f);
break;
case ui::Widget::TouchEventType::ENDED:
unschedule(schedule_selector(HelloWorld::moveA));
break;
}
});


22. 单例模式示例

class Factory:public cocos2d::Ref {
public:
//获取单例工厂
static Factory* getInstance();
//生成一个怪物,并存储到容器中管理
Sprite* createMonster();
//让容器中的所有怪物都往角色移动,通过容器管理所有的怪物很方便
void moveMonster(Vec2 playerPos,float time);
//移除怪物
void removeMonster(Sprite*);
//判断碰撞
Sprite* collider(Rect rect);
//初始化怪物帧动画
void initSpriteFrame();
private:
Factory();
Vector<Sprite*> monster;
cocos2d::Vector<SpriteFrame*> monsterDead;
static Factory* factory;
};


// Monster.cpp
Factory* Factory::factory = NULL;
Factory::Factory() {
initSpriteFrame();
}
// 获取单例
Factory* Factory::getInstance() {
if (factory == NULL) {
factory = new Factory();
}
return factory;
}

// 生成monster死亡的动画帧并存入到vector数组中
void Factory::initSpriteFrame() {
auto texture = Director::getInstance()->getTextureCache()->addImage("Monster.png");
monsterDead.reserve(4);
for (int i = 0; i < 4; i++) {
auto frame = SpriteFrame::createWithTexture(texture, CC_RECT_PIXELS_TO_POINTS(Rect(258 - 48 * i, 0, 42, 42)));
monsterDead.pushBack(frame);
}
// 将这个动画加入到AnimationCache中
auto monsterdead_animation = Animation::createWithSpriteFrames(monsterDead, 0.1f);
AnimationCache::getInstance()->addAnimation(monsterdead_animation, "monsterDeadAnimation");
}

// 新建一个monster
Sprite* Factory::createMonster() {
Sprite* mons = Sprite::create("Monster.png", CC_RECT_PIXELS_TO_POINTS(Rect(364,0,42,42)));
monster.pushBack(mons);
return mons;
}

// 遍历删除与参数一致的monster
void Factory::removeMonster(Sprite* sp) {
cocos2d:Vector<Sprite*>::iterator it = monster.begin();
for (; it != monster.end(); it++) {
if (*it == sp) {
monster.erase(it);
return;
}
}
}

// 实现monster朝着player的方向移动
void Factory::moveMonster(Vec2 playerPos,float time){
cocos2d:Vector<Sprite*>::iterator it = monster.begin();
for (; it != monster.end(); it++) {
Vec2 monsterPos = (*it)->getPosition();
Vec2 direction = playerPos - monsterPos;
direction.normalize(); // 得到该向量的单位向量,即向量除以向量的模
(*it)->runAction(MoveBy::create(time, direction*30));
}
}
// 当monster在rect的范围内时,返回指向该monster的指针
Sprite* Factory::collider(Rect rect) {
cocos2d:Vector<Sprite*>::iterator it = monster.begin();
for (; it != monster.end(); it++) {
Vec2 monsterPos = (*it)->getPosition();
if (rect.containsPoint(monsterPos)) {
return (*it);
}
}
return NULL;
}


23.Monster朝Player方向移动

// 实现monster朝着player的方向移动
void Factory::moveMonster(Vec2 playerPos,float time){
cocos2d:Vector<Sprite*>::iterator it = monster.begin();
for (; it != monster.end(); it++) {
Vec2 monsterPos = (*it)->getPosition();
Vec2 direction = playerPos - monsterPos;
direction.normalize(); // 得到该向量的单位向量,即向量除以向量的模
(*it)->runAction(MoveBy::create(time, direction*30));
}
}


24.碰撞检测

// 当monster在rect的范围内时,返回指向该monster的指针
Sprite* Factory::collider(Rect rect) {
cocos2d:Vector<Sprite*>::iterator it = monster.begin();
for (; it != monster.end(); it++) {
Vec2 monsterPos = (*it)->getPosition();
if (rect.containsPoint(monsterPos)) {
return (*it);
}
}
return NULL;
}

// 检测碰撞
// getBoundingBox()用于获取精灵外框区域
void HelloWorld::detectHit(float delta) {
auto factory = Factory::getInstance();
Sprite* collision = factory->collider(player->getBoundingBox());
if (collision != NULL) {
buttonX();
Animate* monsterDead = Animate::create(AnimationCache::getInstance()->getAnimation("monsterDeadAnimation"));
collision->runAction(monsterDead);
//collision->setVisible(false);
// 碰到人物后怪物消失
CCActionInterval* fadeout = CCFadeOut::create(2);
collision->runAction(fadeout);
factory->removeMonster(collision);
}
}


25.生成处于随机位置的精灵

// 生成怪物
void HelloWorld::createMonster(float delta) {
auto factory = Factory::getInstance();
auto monster = factory->createMonster();
monster->setPosition(random(origin.x, origin.x + visibleSize.width), random(origin.y, origin.y + visibleSize.height));
this->addChild(monster, 3);
factory->moveMonster(player->getPosition(), 5);
}


26.同步实现两个动画

// collision 是一个精灵对象
Animate* monsterDead = Animate::create(AnimationCache::getInstance()->getAnimation("monsterDeadAnimation"));
collision->runAction(monsterDead);
//collision->setVisible(false);
// 碰到人物后怪物消失
CCActionInterval* fadeout = CCFadeOut::create(2);
collision->runAction(fadeout);


27. 精灵的翻转

player->setFlipX(true);
player->setFlipX(false);


28. 增加player左右各40的攻击范围

Rect playerRect = player->getBoundingBox();
Rect attackRect = Rect(playerRect.getMinX() - 40, playerRect.getMinY(),
playerRect.getMaxX() - playerRect.getMinX() + 80,
playerRect.getMaxY() - playerRect.getMinY());


Rect 的第一二个参数为左下角的x,y坐标,第三个参数为宽,第四个参数为高。

29. 渐渐淡出消失的动画

CCActionInterval* fadeout = CCFadeOut::create(2);
collision->runAction(fadeout);
factory->removeMonster(collision);


30. 本地存储UserDefault

# define database UserDefault::getInstance()
database->setIntegerForKey("killNum", dtime);
// 当set完后,数据不会马上保存到XML文件中。所以一定要记得用flush()来保存数据,否则会丢失
database->flush();
// 查询xml存放的路径
log("%s", FileUtils::getInstance()->getWritablePath().c_str());


31. HttpClient

POST请求

HttpRequest* request = new HttpRequest();
request->setUrl("http://localhost:8080/login");
request->setRequestType(HttpRequest::Type::POST);
request->setResponseCallback(CC_CALLBACK_2(LoginScene::onHttpRequestComplete, this));
request->setTag("POST test");
String str = "username=" + textField->getString();
const char* postData = str.getCString();
request->setRequestData(postData, strlen(postData));
cocos2d::network::HttpClient::getInstance()->send(request);
request->release();

void LoginScene::onHttpRequestComplete(HttpClient *sender, HttpResponse *response) {
if (!response) {
return;
}
if (!response->isSucceed()) {
log("response fail!");
log("error buffer:%s", response->getErrorBuffer());
return;
}
std::vector<char> *buffer = response->getResponseData();
printf("Http Text, dump data: ");
for (unsigned int i = 0; i < buffer->size(); i++) {
printf("%c", (*buffer)[i]);
}
printf("\n");
string head = "";
std::vector<char> *header = response->getResponseHeader();
for (unsigned int i = 0; i < header->size(); i++) {
head += (*header)[i];
}
// 在登录请求完毕后,获取该用户的gameSessionId
Global::gameSessionId = Global::getSessionIdFromHeader(head);
UserDefault* default = UserDefault::getInstance();
default->setStringForKey("Me", Global::gameSessionId);
}


GET请求

HttpRequest* request = new HttpRequest();
string str = "http://localhost:8080/rank?top=" + rank_str;
request->setUrl(str.c_str());
request->setRequestType(HttpRequest::Type::GET);
request->setTag("GET test");
vector<string> headers;
headers.push_back("Cookie: GAMESESSIONID=" + Global::gameSessionId);
request->setHeaders(headers);
request->setResponseCallback(CC_CALLBACK_2(GameScene::onHttpRequestComplete1, this));
cocos2d::network::HttpClient::getInstance()->send(request);
request->release();

// rank的请求完成函数
void GameScene::onHttpRequestComplete1(HttpClient *sender, HttpResponse *response) {
if (!response) {
return;
}
if (!response->isSucceed()) {
log("response fail!");
log("error buffer:%s", response->getErrorBuffer());
return;
}
std::vector<char> *buffer = response->getResponseData();
printf("Http Text, dump data: ");
string str;
for (unsigned int i = 0; i < buffer->size(); i++) {
printf("%c", (*buffer)[i]);
str += (*buffer)[i];
}
printf("\n");
// rank_field->setString(str);

// 对返回的json进行解析
rapidjson::Document d;
d.Parse<0>(str.c_str());
string info = d["info"].GetString();
str = "";
for (unsigned int i = 1; i < info.size(); i++) {
if (info[i] != '|') {
str += info[i];
}
else {
str += "\n";
}
}
rank_field->setString(str);
}


32. 实现自动化登录

从createScene函数中开刀:

Scene* LoginScene::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
Global::gameSessionId = UserDefault::getInstance()->getStringForKey("Me");
if (Global::gameSessionId != "") {
auto layer = GameScene::create();
scene->addChild(layer);
}
else {
// 'layer' is an autorelease object
auto layer = LoginScene::create();
// add layer as a child to scene
scene->addChild(layer);
}

// return the scene
return scene;
}


33.页面跳转

以跳转GameScene页面为例:

// 页面跳转
auto sc = GameScene::createScene();
Director::getInstance()->pushScene(sc);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息