Cocos2dx元素探索

游戏各元素

声音

  1. 特别注意,声音素材不要有海报和歌词,以免造成没有声音的意外。

  2. 要添加声音相关的头文件SimpleAudioEngine.h。

  3. 音乐文件放在Resources文件夹下。

  4. 代码如下。

可拉伸图片功能-九妹图

  1. 可任意缩小放大拉伸图片,并且不会失真,会对图片进行自动填充。

  2. 添加头文件cocos-ext.h和using namespace cocos2d::extension命名空间。

  3. Cocos2d-x将此功能封装在Scanle9Sprite中,如下。

  4. 完成。

九妹与按钮

  1. 利用九妹图的拉伸功能配合标签和按钮实现功能。

  2. 正常状态按钮运行如下。

  3. 单击状态按钮运行如下。

  4. ControlButton相当于一个空壳,具有很多按钮具备的功能,九妹图和标签就是空壳里的东西。

  5. newButton->setPreferredSize(Size(50,60)); //强制设置按钮大小,如果标题大小超过则还是标题设置的大小不会有影响…没啥子用

  6. 完成。

探索UI-CocoStudio

  1. CocoStudio是一套专业的永久免费的游戏开发工具集 。

  2. CocoStudio包含了游戏开发的UI编辑器、动画编辑器、场景编辑器、数据编辑器。

  3. 高效率,高质量,低风险,低成本。

  4. HelloWorld实例如下。

  5. 与vs关联使用方法详解。

    1. 第一种,直接使用法,直接进入proj.win32文件夹使用.sln文件。
    2. 第二种,进入Resources文件夹下的res复制里面内容到已创建的Coco2dx工程的Resources文件夹下。


按钮监听事件

  1. 将用到的头文件和命名空间放在HelloWorld.h中,并声明一个监听回调函数和一个变量,如下。

    #ifndef __HELLOWORLD_SCENE_H__
    #define __HELLOWORLD_SCENE_H__
    
    #include "cocos2d.h"
    #include "cocostudio/CocoStudio.h"
    #include "ui/CocosGUI.h"
    
    USING_NS_CC;
    
    using namespace cocos2d::ui;
    
    using namespace cocostudio::timeline;
    
    class HelloWorld : public cocos2d::Layer
    {
    public:
        // there's no 'id' in cpp, so we recommend returning the class instance pointer
        static cocos2d::Scene* createScene();
    
        // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
        virtual bool init();
    
    	void onClick(Ref*,TouchEventType type); //单击监听事件
    	ImageView* imageviews;
    
      
        CREATE_FUNC(HelloWorld);
    };
    
    #endif // __HELLOWORLD_SCENE_H__
    



2. 使用getChildByName()函数获取UI按钮,并添加监听和定义监听回调函数,如下。

#include "HelloWorldScene.h"

Scene* HelloWorld::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();
    
    // 'layer' is an autorelease object
    auto layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
   
    if ( !Layer::init() )
    {
        return false;
    }
    
	//启动UI
    auto rootNode = CSLoader::createNode("MainScene.csb");

    addChild(rootNode);

	//获取控件对象
	Button* button1 = (Button*)rootNode->getChildByName("Button_1"); //通过getChildByName()函数获取UI按钮
	Button* button2 = (Button*)rootNode->getChildByName("Button_2"); //通过getChildByName()函数获取UI按钮
	button2->setTitleText("Begin"); //改变按钮标题
	imageviews = (ImageView*)rootNode->getChildByName("Image_1");


	//添加按钮单击监听,需要宏函数toucheventselector传递参数
	button1->addTouchEventListener(this, toucheventselector(HelloWorld::onClick));

    return true;
}

void HelloWorld::onClick(Ref*, TouchEventType type)
{
	switch (type)
	{
	case TouchEventType::TOUCH_EVENT_BEGAN: //单击事件开始时触发(按下的时候)
		break;
	case TouchEventType::TOUCH_EVENT_MOVED: //按下之后进行移动操作时触发
		break;
	case TouchEventType::TOUCH_EVENT_ENDED: //按下之后然后松开之后触发
		if (imageviews->isVisible()) //判断图片是否显示
		{
			imageviews->setVisible(false); //隐藏图片
		}
		else
		{
			imageviews->setVisible(true); //显示图片
		}
		break;
	case TouchEventType::TOUCH_EVENT_CANCELED: //因为特殊情况中断时触发
		break;
	}
}



血量条

  1. 例如英雄联盟的英雄血量条。

  2. 代码如下,参照按钮监听事件代码。

    //在.cpp文件中添加如下代码
    bool HelloWorld::init()
    {
       。。。
    	//获取控件对象
    	。。。
    	xueliangtiao = (LoadingBar*)rootNode->getChildByName("xueliang"); //获取血量的进度条
    
    	//添加按钮单击监听,需要宏函数toucheventselector传递参数
    	。。。
    	button2->addTouchEventListener(this, 		    toucheventselector(HelloWorld::onClick2)); //按钮2事件
        return true;
    }
    void HelloWorld::onClick2(Ref*, TouchEventType type)
    {
    	switch (type)
    	{
    	case TouchEventType::TOUCH_EVENT_BEGAN: //单击事件开始时触发(按下的时候)
    		break;
    	case TouchEventType::TOUCH_EVENT_MOVED: //按下之后进行移动操作时触发
    		break;
    	case TouchEventType::TOUCH_EVENT_ENDED: //按下之后然后松开之后触发
    		xueliangtiao->setPercent(xueliangtiao->getPercent() + 1); //单击按钮2血量增加1
    		break;
    	case TouchEventType::TOUCH_EVENT_CANCELED: //因为特殊情况中断时触发
    		break;
    	}
    }
    //在头文件下添加
    LoadingBar* xueliangtiao; //进度条对象
    void onClick2(Ref*, TouchEventType type); //单击监听事件
    
  3. 运行效果如下。

  4. 完成。

活动起来

运动(精灵的移动)

  1. MoveTo

    bool HelloWorld::init()
    {
       
        if ( !Layer::init() )
        {
            return false;
        }
        
    	//启动UI
        auto rootNode = CSLoader::createNode("MainScene.csb");
    
        addChild(rootNode);
    
    	Size newSize = Director::getInstance()->getVisibleSize(); //获取窗口大小
    //创建一个精灵
    	Sprite* newSprite=Sprite::create("name.png");
    	newSprite->setPosition(Point(newSize.width/2, newSize.height / 4)); //设置坐标
    	this->addChild(newSprite);
    
    	//创建MoveTo动作对象,第一个参数是动作要执行的时间,第二个参数是执行到的目的地
    	MoveTo* moveTo = MoveTo::create(0.9f, Point(newSize.width / 2, newSize.height / 2));
        //精灵执行的动作
    	newSprite->runAction(moveTo);
            return true;
    }
    
    
  2. MoveBy

    bool HelloWorld::init()
    {
       
        if ( !Layer::init() )
        {
            return false;
        }
        
    	//启动UI
        auto rootNode = CSLoader::createNode("MainScene.csb");
    
        addChild(rootNode);
       
    	Size newSize = Director::getInstance()->getVisibleSize(); //获取窗口大小
    	//创建一个精灵
    	Sprite* newSprite=Sprite::create("name.png");
    	newSprite->setPosition(Point(newSize.width/2, newSize.height / 4)); //设置坐标
    	this->addChild(newSprite);
    
    	//创建MoveBy动作对象,第一个参数是动作要执行的时间,第二个参数是要移动的距离,这里是向X移动50,Y移动50
    	MoveBy* moveBy = MoveBy::create(0.9f, Point(200,200));
        
    	//精灵执行的动作
    	newSprite->runAction(moveBy);
    
        return true;
    }
    

Blink-精灵的闪烁

直接看代码,如下。

bool HelloWorld::init()
{
   
    if ( !Layer::init() )
    {
        return false;
    }
    
	//启动UI
    auto rootNode = CSLoader::createNode("MainScene.csb");

    addChild(rootNode);

	Size newSize = Director::getInstance()->getVisibleSize(); //获取窗口大小

	//创建一个精灵
	Sprite* newSprite=Sprite::create("name.png");
	newSprite->setPosition(Point(newSize.width/2, newSize.height / 4)); //设置坐标
	this->addChild(newSprite);

	//创建Blink对象,第一个参数是动作持续时间,单位是秒,第二个参数是闪烁次数
	Blink* blink = Blink::create(3.0f,9);

	//精灵执行动作
	newSprite->runAction(blink);
    
    return true;

}

BezierTo和BezierBy-按照指定路线运动

  1. BezierTo

    bool HelloWorld::init()
    {
       
        if ( !Layer::init() )
        {
            return false;
        }
        
    	//启动UI
        auto rootNode = CSLoader::createNode("MainScene.csb");
    
        addChild(rootNode);
    
    	Size newSize = Director::getInstance()->getVisibleSize(); //获取窗口大小
    
    	//创建一个精灵
    	Sprite* newSprite=Sprite::create("name.png");
    	newSprite->setPosition(Point(newSize.width/2, newSize.height / 4)); //设置坐标
    	this->addChild(newSprite);
    
    	//创建贝塞尔曲线配置
    	_ccBezierConfig bezier;
    	bezier.controlPoint_1 = Point(100, 0); //波谷偏向值   相当于sinx的凹进去的部分
    	bezier.controlPoint_2 = Point(200, 300); //波峰偏向值 相当于sinx的凸出来的地方
    	bezier.endPosition = Point(500, 600);  //动作终点
    	
    	//创建CCBezierTo动作对象
    	BezierTo* bezierTo = BezierTo::create(4.0f, bezier);
    
    	//精灵执行动作
    	newSprite->runAction(bezierTo);
    
        return true;
    
    }
    
  2. BezierBy

    	//创建贝塞尔曲线配置
    	_ccBezierConfig bezier;
    	bezier.controlPoint_1 = Point(100, 0); //波谷偏向值  抛物线底部(刚开始弯曲的地方)
    	bezier.controlPoint_2 = Point(200, 300); //波峰偏向值 相当于抛物线高出的凸起
    	bezier.endPosition = Point(500, 600);  //动作终点
    	
    	//创建CCBezierTo动作对象
    	BezierBy* bezierTo = BezierTo::create(4.0f, bezier);
    
    	//精灵执行动作
    	newSprite->runAction(bezierTo);
    

RepeatForever-重复动作

bool HelloWorld::init()
{
   
    if ( !Layer::init() )
    {
        return false;
    }
    
	//启动UI
    auto rootNode = CSLoader::createNode("MainScene.csb");

    addChild(rootNode);

	Size newSize = Director::getInstance()->getVisibleSize(); //获取窗口大小

	//创建一个精灵
	Sprite* newSprite=Sprite::create("name.png");
	newSprite->setPosition(Point(newSize.width/2, newSize.height / 4)); //设置坐标
	this->addChild(newSprite);

	//创建一个JumoBy动作对象,会忘右方向跳动,第一个参数是时间,第二个是每次移动距离,如向
	//X的方向移动50,y的方向移动30,第三个参数是跳的高度,第四个参数是每次跳跳多少下
	JumpBy* jumpBy = JumpBy::create(3.0f, Point(50, 30), 100,1);

	//以jumpby为参数创建一个永久重复性的动作
	RepeatForever* forever = RepeatForever::create(jumpBy);

	//以jumpby为参数创建一个指定次数重复性的动作
	//Repeat* forever = Repeat::create(jumpBy,9);

	//执行动作
	newSprite->runAction(forever);

    return true;

}

多种动作连续进行

bool HelloWorld::init()
{
   
    if ( !Layer::init() )
    {
        return false;
    }
    
	//启动UI
    auto rootNode = CSLoader::createNode("MainScene.csb");

    addChild(rootNode);

	Size newSize = Director::getInstance()->getVisibleSize(); //获取窗口大小

	//创建一个精灵
	Sprite* newSprite=Sprite::create("name.png");
	newSprite->setPosition(Point(newSize.width/2, newSize.height / 4)); //设置坐标
	this->addChild(newSprite);

	//创建一个移动动作对象
	MoveBy* moveBy = MoveBy::create(2.2f, Point(100,200));

	//创建一个弹跳对象,弹跳高度是100,单次弹跳次数是
	JumpBy* jumpBy = JumpBy::create(3.0f, Point(50, 30), 100, 2);
	
	//创建一个旋转动作对象,参数分别是时间,X,Y
	RotateBy* rotateBy = RotateBy::create(2.5f, 200, 200);

	//创建组合动作对象,将上述动作连串起来,Spawn可以让所有动作同时执行
	//Action* action = Spawn::create(moveBy, jumpBy, rotateBy, NULL);
	//Action是所有动作父类,Spawn也是一个动作,不过此动作可包含若干个动作,需要用NULL结束。

	////创建组合动作对象,将上述动作连串起来,Sequence可以让动作一个一个执行
	Action* action = Sequence::create(moveBy, jumpBy, rotateBy, NULL);

	//执行动作
	newSprite->runAction(action);

    return true;

}

动作的监听

动作结束监听

bool HelloWorld::init()
{
   
    if ( !Layer::init() )
    {
        return false;
    }
    
	//启动UI
    auto rootNode = CSLoader::createNode("MainScene.csb");

    addChild(rootNode);

	Size newSize = Director::getInstance()->getVisibleSize(); //获取窗口大小

	//创建一个精灵
	Sprite* newSprite=Sprite::create("name.png");
	newSprite->setPosition(Point(newSize.width/2, newSize.height / 4)); //设置坐标
	this->addChild(newSprite);

	//移动动作
	MoveTo* moveTo = MoveTo::create(10.0f, Point(newSize.width, newSize.height / 2));

	//回调函数,CallFunc也是一个动作,只不过此动作是回调一个函数
	auto back = [&]() {  //[]符号表示要开始一个lambda函数,()里填写函数,{}是函数体内容
		backoo();  //在.h文件中声明void backoo();
	};
	CallFunc* callFunc = CallFunc::create(back);

	//组合两个动作
	Action* action = Sequence::create(moveTo, callFunc, NULL);

	//执行动作
	newSprite->runAction(action);

    return true;

}
void HelloWorld::backoo()
{
	Size vsize = Director::getInstance()->getVisibleSize();
	Label* label = Label::create("I am coming!","Arial",35);
	label->setPosition(Point(vsize.width / 2, vsize.height / 2));
	this->addChild(label);
}

C++的lambada函数

  1. []符号表示要开始一个lambda函数,如动作结束监听代码里的back;
  2. ()符号里表示要填写的函数。
  3. {}符号表示函数体。
  4. []表示不截取任何变量,[&]表示截取外部作用域中所有变量(只要变量没被释放就可在lambda中使用,但局部变量不可使用因为会被释放),[=]截取外部作用域所有变量且即使外部的值变了lambda函数里之前截取复制的值也不变。
  5. [=,&a]和[=]功能相同但只对外部变量a使用引用。
  6. [a]和[=]功能相同,a是外部变量,但是只针对变量a其余变量忽略。

屏幕触摸事件

事件详解如下

  1. 代码。

    bool HelloWorld::init()
    {
    
    	if (!Layer::init())
    	{
    		return false;
    	}
    
    	//启动UI
    	auto rootNode = CSLoader::createNode("MainScene.csb");
    
    	addChild(rootNode);
    
    	//创建一个触摸监听
    	auto listener = EventListenerTouchOneByOne::create();
    
    	//触摸事件开始,相当于玩手机时我们手指按下的时候
    	listener->onTouchBegan = [](Touch* touch, Event* event) {
    		Point pos1 = touch->getLocation(); //获取单击坐标,基于3D
    		Point pos2 = touch->getLocationInView(); //获取单击坐标,基于2D,以左上角为原点
    		Point pos3 = Director::getInstance()->convertToGL(pos2); //获取单击坐标,基于cocos2dx,以左下角为原点
    
    		//打印坐标
    		log("Scene onTouchBeganPoint:pos1 x=%f,y=%f", pos1.x, pos1.y);
    		log("Point:pos2 x=%f,y=%f", pos2.x, pos2.y);
    		log("Point:pos3 x=%f,y=%f", pos3.x, pos3.y);
    		return true;
    	};
    
    	//触摸移动事件,相当于手指在屏幕滑动过程
    	listener->onTouchMoved = [=](Touch* touch, Event* event) {
    		log("Scene onTouchMoved!");
    	};
    
    	//触摸事件结束,相当于手指松开离开屏幕
    	listener->onTouchEnded = [=](Touch* touch, Event* event) {
    		log("Scene onTouchEnded!");
    	};
    	//还有onTouchCancelled触摸事件,其是打断触摸事件发生的事件,一般为系统层的消息,如来电话
    
    	//_eventDispatcher是事件管理器,相当于Director::getInstance()->getEventDispatcher()是一个单例类。
    	//addEventListenerWithSceneGraphPriority函数第一个参数是事件监听对象,当触摸事件发生时回调,第二个是绑定的对象。
    	//addEventListenerWithSceneGraphPriority(EventListener* a,Node* b);当node对象被释放监听事件注册也会被取消
    	_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
    	//注意:当多个事件同时触发会根据node的层次优先回调(越是上面的对象越先回调)
    
    	return true;
    }
    
  2. addEventListenerWithFixedPriority也是用于注册监听事件,但这个函数需要手动指定触摸事件回调的优先级,且需要手动取消监听事件。

多点触摸-多个手指同时操作

  1. 原始代码原理如下。

    bool HelloWorld::init()
    {
    	if (!Layer::init())
    	{
    		return false;
    	}
    
    	//启动UI
    	auto rootNode = CSLoader::createNode("MainScene.csb");
    
    	addChild(rootNode);
    
    	//创建一个触摸监听,EventListenerTouchOneByOne->EventListenerTouchAllAtOnce
    	auto listener = EventListenerTouchAllAtOnce::create();
    
    	//触摸事件开始,相当于玩手机时我们手指按下的时候,onTouchBegan->onTouchesBegan
    	listener->onTouchesBegan = [](const std::vector<Touch*>& touches, Event* event) {};
    
    	//触摸移动事件,相当于手指在屏幕滑动过程
    	listener->onTouchesMoved = [=](const std::vector<Touch*>& touches, Event* event) {};
    
    	//触摸事件结束,相当于手指松开离开屏幕
    	listener->onTouchesEnded = [=](const std::vector<Touch*>& touches, Event* event) {};
    
    	_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
    	
    	return true;
    }
    
  2. 实例如下,来展示多点触摸效果。

    bool HelloWorld::init()
    {
    
    	if (!Layer::init())
    	{
    		return false;
    	}
    
    	//启动UI
    	auto rootNode = CSLoader::createNode("MainScene.csb");
    
    	addChild(rootNode);
    
    	Label* label1 = Label::create("", "Arial", 20);
    	label1->setPosition(Point(400, 100));
    	this->addChild(label1, 1, 1); //添加标签进入场景,后面两个参数是对象绘制层次和对象Tag值
    	//绘制层次数值越小越优先被绘制,对象的Tag值就是一个int类型的数据,不过可用其做简单操作
    
    	Label* label2 = Label::create("", "Arial", 20);
    	label2->setPosition(Point(400, 200));
    	this->addChild(label2, 1, 2);
    
    	Label* label3 = Label::create("", "Arial", 20);
    	label3->setPosition(Point(400, 300));
    	this->addChild(label3, 1, 3);
    
    	//创建一个触摸监听,EventListenerTouchOneByOne->EventListenerTouchAllAtOnce
    	auto listener = EventListenerTouchAllAtOnce::create();
    
    	//触摸事件开始,相当于玩手机时我们手指按下的时候,onTouchBegan->onTouchesBegan
    	listener->onTouchesBegan = [&](const std::vector<Touch*>& touches, Event* event) {
    		auto logLabel = (Label*)this->getChildByTag(1); //用getChildByTag找Tag值
    		int num = touches.size();
    		logLabel->setString(Value(num).asString() + "Touches:");
    	};
    
    	//触摸移动事件,相当于手指在屏幕滑动过程
    	listener->onTouchesMoved = [&](const std::vector<Touch*>& touches, Event* event) {
    		auto logLabel = (Label*)this->getChildByTag(2); 
    		int num = touches.size();
    		std::string text = Value(num).asString() + "Touches"; //创建std::string以打印日志体现多点触摸事件
    		for (auto& touch : touches)
    		{
    			auto lacation = touch->getLocation();
    			text += "[touchID" + Value(touch->getID()).asString() + "],"; //使用touch对象的getID函数确定手指
    		}  //第一个触碰屏幕的手指产生的touch对象的ID就是0
    		logLabel->setString(text);
    	};
    
    	//触摸事件结束,相当于手指松开离开屏幕
    	listener->onTouchesEnded = [&](const std::vector<Touch*>& touches, Event* event) {
    		auto logLabel = (Label*)this->getChildByTag(3);
    		int num = touches.size();
    		logLabel->setString(Value(num).asString() + "Touches:");
    	};
    
    	_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
    	
    
    	return true;
    }
    
  3. 第一个标签表示onTouchesBegan事件,1Touches表示该事件touches参数里只有一个Touch对象。

  4. 第二个标签表示onTouchesMoved事件,5Touches表示该事件touches参数里有5个Touch对象,5个手指同时移动。

  5. 第三行标签表示onToucherEnded事件,1Touches表示同第一个。

  6. 因为触摸事件结束时对onToucherBegan,onTouchesEnded和onTouchesCancelled事件都会判断Touch的ID是否是新的ID,然后进行再传递。所以这些事件是指有新的手指单击或离开才能触发,但onTouchesMoved在屏幕上的手指移动时才触发事件,所以会有多个对象。

End

实例该做还是得做~

~


发布了34 篇原创文章 · 获赞 0 · 访问量 495

猜你喜欢

转载自blog.csdn.net/weixin_44228006/article/details/104095790