/* 说明:
**1.本次游戏实例是《cocos2d-x游戏开发之旅》上的最后一个游戏,这里用3.0重写并做下笔记
**2.我也问过木头本人啦,他说:随便写,第一别完全照搬代码;第二可以说明是学习笔记---好人
**3.这里用cocos2d-x 3.0版本重写,很多地方不同,但是从重写过程中也很好的学习了cocos2d-x
*/
***每一步对应的所有代码以及用到的资源都会打包在最后给出
***为避免代码过多,每一步的代码都做了标记--一看就晓得是第几步实现的避免出错改不回去(难不成还用Git?)
***可以根据设计思路(好吧,那名字太高大上。实际就是这一步要干啥)先自己实现---cocos2d-x本来就是如此,相同的功能有许多不同实现方法;先自己折腾是蛮不错的。
***为了方便移植到手机上,对于每一步都进行编译android测试;因为很多时候代码在win32下可以,编译就会出错,给出的代码会是测试过后的。
本次笔记内容:
1、设计思路&问题注意
2、效果图
3、跟随设计思路看代码
4、下节知识预览
一:设计思路&问题注意
一步步来
(1)为了响应MainScene中的编辑按钮,需要一个PosEditorScene,然而这个Scene里面需要做的事比较多;所以这里把Scene单独抽离出来,然后在里面添加各种Layer
(2)先来一个万能的GetBackLayer;为什么是万能的呢?这个层的作用很简单,里面有一按钮,Back; 通过这个按钮,你可以在任何地方回到MainScene。你Start之后进行关卡选择,发现自己要重编辑怪物路线,你就Back,游戏中你不想玩了Back,编辑场景中,编辑好了想要测试?Back。到这,你就可以测试一下了
(3)来一个PosEditorLayer,这个层我们来编辑怪物路线和炮台位置,那么通过屏幕触摸,可以添加一个Pos,就需要我们给这个Layer触摸事件,到这,你也可以在触摸事件中测试一下
(4)既然触摸是添加一个点,那么我们就需要PosBase,继承自Node,然后重写draw 函数,屏幕触摸之后,添加这个点,这个点draw出来。然而这里需要注意的就是我们分Tower和 Monster两种点;木头的做法是抽离一个PosBase基类,然后分别继承。这样的话是方便以后扩充,如果又有一种点,那么同样可以继承;我这里看两种点的功能差不多,就偷了懒,干脆只用PosBase,然后用一个枚举类来区分当前点是Tower 还是Monster
(5)需要注意的是枚举类是必要的,在编辑层中你也需要改变不同的Type 来进行编辑
(6)这里的GetBackLayer中的按钮用了Extension库,有一点点问题需要处理--比较简单
(7)那么这里的点重写draw函数的话,不知道为什么,会被背景挡住,N多方法都试过;最后机智的想到,把背景图片设置透明度;还果然就看到了;不过问过木头大哥啦,他测试的解决方法是:draw函数最先被画,那么PosBase就不要添加到有背景的层,可以单独抽离一个层,就可以啦;
(8)编辑器的内容比较多,这一步先到这里
二:最后效果图
点击屏幕任意位置,出现一个Tower,同时PosEditorLayer 中有一个枚举成员,初始化为Tower,也可以弄成Monster 测试
三:跟随设计思路看代码
首先是PosEditorScene.h
class PosEditorScene{
public:
static Scene* createScene();
};/**/
是的,就这么简单,我们这里只要获取一个Scene即可,其他的Layer在createScene里面
.cpp
Scene* PosEditorScene::createScene(){
Scene* scene = Scene::create();
//auto posEditorLayer = PosEditorLayer::create();
//scene->addChild(posEditorLayer);
auto getBackLayer = GetBackLayer::create();
scene->addChild(getBackLayer);
return scene;
}
然后看看GetBackLayer.h
#include "cocos2d.h"
#include "cocos-ext.h"
USING_NS_CC;
USING_NS_CC_EXT;
class GetBackLayer : public Layer{
public:
CREATE_FUNC(GetBackLayer);
virtual bool init();
private:
void getBack(Ref* pSender, Control::EventType event);
};/**/
CREATE_FUNC实际是一个宏定义的create函数,后面在Scene中的添加Layer的时候create,然后会调用Layer的 init 函数,这里我们只需要virtual bool init 函数的实现
.cppbool GetBackLayer::init(){
auto visibleSize = Director::getInstance()->getVisibleSize();
auto btnTitle = Label::create("Back","Arial",30);
auto norSprite = Scale9Sprite::create("Button/public_ui_blue_btn.png");
auto highLightSprite = Scale9Sprite::create("Button/public_ui_green_btn.png");
auto outPutBtn = ControlButton::create(btnTitle,norSprite);
outPutBtn->setBackgroundSpriteForState(highLightSprite,Control::State::HIGH_LIGHTED);
outPutBtn->setPosition(
ccp(visibleSize.width-norSprite->getContentSize().width/2,
visibleSize.height - norSprite->getContentSize().height));
outPutBtn->addTargetWithActionForControlEvents(
this,
cccontrol_selector(GetBackLayer::getBack),
Control::EventType::TOUCH_UP_INSIDE);
this->addChild(outPutBtn,20);
return true;
}
void GetBackLayer::getBack(Ref* pSender,Control::EventType event){
CCLOG("Back to MainScene");
auto scene = MainScene::createScene();
Director::getInstance()->replaceScene(scene);
}
这里由于用到了Extension,会遇到些问题:解决方法之前提到过:
也就三步三个添加:之前也有过 图文解释
到这里,就可以测试一下Back按钮的使用,那么GetBackLayer可以添加到很多Scene中那么现在来看看PosEditorLayer.h
class PosEditorLayer : public Layer{
public:
PosEditorLayer();
~PosEditorLayer();
CREATE_FUNC(PosEditorLayer);
virtual bool init();
private:
//**2**当前关卡级别
int _curLevel;
//------------成员&函数分割线----------------------
//**2**预加载内容
void preLoad();
};.cpp
PosEditorLayer::PosEditorLayer(){
_curLevel = 1;
}
PosEditorLayer::~PosEditorLayer(){
}
bool PosEditorLayer::init(){
//**2**---------------触摸事件----------------------------
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = [](Touch* touch, Event* event){
return true;
};
listener->onTouchMoved = [](Touch* touch, Event* event){
};
listener->onTouchEnded = [=](Touch* touch, Event* event){
auto touchPos = touch->getLocationInView();
auto pos = Director::getInstance()->convertToUI(touchPos);
CCLOG("Touch pos.X is %f, Touch pos.Y is %f",pos.x, pos.y);
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this);
//------------------------------------------------------------
//**2**
preLoad();
return true;
}
void PosEditorLayer::preLoad(){
//**2**add map
auto visibleSize = Director::getInstance()->getVisibleSize();
auto sBg = __String::createWithFormat("game/level_%d.jpg",_curLevel);
auto mapBg = Sprite::create(sBg->getCString());
mapBg->setPosition(ccp(visibleSize.width/2,visibleSize.height/2));
mapBg->setOpacity(150);
this->addChild(mapBg);
}然后把这个层添加到PosEditorScene中,为了不挡住getBackLayer,你可以在GetBackLayer之前 加入scene里面
然后F5测试,输出中可以看到你触摸屏幕的位置
触摸屏幕是为了添加点,那么来看看PosBase
enum EnumPosType{
enTowerPos,
enMonsterPos
};
class PosBase : public Node{
public:
PosBase();
~PosBase();
//**2**
static PosBase* create(Point pos, EnumPosType posType, bool isDebug);
//**2**
bool init(cocos2d::Point pos, EnumPosType posType, bool isDebug);
//**2**
virtual void draw(cocos2d::Renderer *renderer, const kmMat4& transform, bool transformUpdated);
protected:
CC_SYNTHESIZE(Point,_pos,Pos);
//**2**
bool _isDebug;
EnumPosType _posType;
};/**/这里是根据 位置,点类型,是否调试;三个变量来创建一个PosBase的;依据_isDebug来判断是否调试,是的话,就将点画出来 ,这里的CC_SYNTHESIZE 也是一个宏,就是添加私有成员,等价于:
private:
Point _pos;
public:
void setPos(Point pos) { _pos = pos ; };
Point getPos() { return _pos; };
.cpp
#define Tower_Radius 32
#define Monster_Radius 10
PosBase::PosBase(){
_pos = CCPointMake(0,0);
_isDebug = false;
_posType = enTowerPos;
}
PosBase::~PosBase(){
}
PosBase* PosBase::create(Point pos, EnumPosType posType, bool isDebug){
PosBase* tPos = new PosBase();
if(tPos && tPos->init(pos, posType,isDebug)){
tPos->autorelease();
}else{
CC_SAFE_DELETE(tPos);
}
return tPos;
}
bool PosBase::init(Point pos, EnumPosType posType, bool isDebug){
//**2** _SYNTHESIZE(Point,_pos,Pos); 的方法
setPos(pos);
_posType = posType;
_isDebug = isDebug;
return true;
}
void PosBase::draw(Renderer *renderer, const kmMat4& transform, bool transformUpdated){
if(_isDebug){
glLineWidth(5);
//根据posMode 设置判断的半径
float radius;
if(_posType == enTowerPos){
radius = Tower_Radius;
}
else{
radius = Monster_Radius;
}
//draw TowerPos
if(_posType == enTowerPos){
Point srcPos = Point(_pos.x-radius, _pos.y+radius);
Point destPos = Point(_pos.x+radius, _pos.y-radius);
ccDrawRect(srcPos,destPos);
}
else{ //draw MonsterPos
ccDrawCircle(_pos, radius, 360, 20, false);
}
glLineWidth(1);
}
}
然后测试:在PosEditorLayer中添加成员函数 editorPos
void PosEditorLayer::editPos(Point pos){
//**2**test
auto posBase = PosBase::create(pos, _posType, true);
this->addChild(posBase);
}
然后在触摸事件中添加函数,就能任意点击屏幕添加点;
四:下节知识点预览
既然要编辑,只能添加点不然删除算什么?要在代码中改变PosType算什么?难道只能编辑一级的关卡吗?这些点不保存?
下面解决
------------------------------------------------资源&代码
------------------------------------------------
个人愚昧观点,欢迎指正与讨论
cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第二步---编辑器(1)--触摸添加点
原文:http://blog.csdn.net/zyy173533832/article/details/38775293