cocos2dx 血条中怎么把英雄和血条一起移动

拥有1个小站,订阅6个话题,关注26个小站
本文检索关键词:游戏引擎,游戏开发引擎,cocos引擎html5游戏开发
上一节对整个游戏项目做了简单介绍。本节就来讲讲Cocos2d-x与CocosStudio如何练习起来,以及实现游戏中添加障碍物。.
二、Cocos2d-x和CocosStudio是如何联系起来搭建游戏界面
首先建好一个Cocos2d-x新项目,...&
本文检索关键词:游戏引擎,游戏开发引擎,cocos引擎html5游戏开发
对整个游戏项目做了简单介绍。本节就来讲讲Cocos2d-x与Cocos&Studio如何练习起来,以及实现游戏中添加障碍物。&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&.
二、Cocos2d-x和Cocos&Studio是如何联系起来搭建游戏界面
首先建好一个Cocos2d-x新项目,用Cocos&Studio打开附件中的Rabbit资源文件Rabbit.ccs,UI界面我早已给大家设计好。&
这里主要关注一下,节点树结构。因为会和等下的程序中的调用有很大的联系。然后将文件夹res的所有资源添加到新项目的Resources中(是Resources,而不是其中的res,这样操作主要是考虑到不用设置路径)。然后,来撸代码&!
修改后的HelloWorld.h
#ifndef&__HELLOWORLD_SCENE_H__#define&__HELLOWORLD_SCENE_H__&#include&"cocos2d.h"&&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();&&&&&&&&&&&&&&&&&//&a&selector&callback&&&&&&&&void&menuCloseCallback(cocos2d::Ref*&pSender);&&&&&&&&&&&&&&&&&//&implement&the&"static&create()"&method&manually&&&&&&&&CREATE_FUNC(HelloWorld);&&&&public:&&&&&&&&bool&onTouchBeganCallBack(cocos2d::Touch*&t,cocos2d::Event*&event);&&&&private:&&&&&&&&//存放所有子节点&&&&&&&&Node*&m_pN&&&&&&&&&&&&&&&&&//存放兔子的节点&&&&&&&&Node*&m_pNode_&&&&&&&&&&&&&&&&&//存放障碍的节点的容器&&&&&&&&cocos2d::Vector&Node*&&&m_pNodes_};&#endif&//&__HELLOWORLD_SCENE_H__
HelloWorld.cpp,这里我只截取了重要的init函数:
//&on&"init"&you&need&to&initialize&your&instancebool&HelloWorld::init(){&&&&//////////////////////////////&&&&//&1.&super&init&first&&&&if&(&!Layer::init()&)&&&&{&&&&&&&&return&&&&&}&&&&//获取和添加场景节点&&&&auto&pNode_scene&=&CSLoader::createNode("MainScene.csb");&&&&this-&addChild(pNode_scene);&&&&&&&&&&&&&&//获取所有子节点&&&&m_pNodes=&pNode_scene-&getChildByName("Sprite_bg");&&&&&&&&&//分别的到兔子和障碍节点&&&&for&(auto&it&=&m_pNodes-&getChildren().begin();&it!=m_pNodes-&getChildren().end();&it++)&{&&&&&&&&if&((*it)-&getName()=="Sprite_Rabbit")&{&&&&&&&&&&&&m_pNode_rabbit&=&(*it);&&&&&&&&}&&&&&&&&&&&&&&&&&else{&&&&&&&&&&&&m_pNodes_obstacle.pushBack((*it));&&&&&&&&}&&&&&&&&&&&&&}&&&&&&&&&return&}
首先如果要进行Cocos&Studio和Cocos2d-x的联系的话,首先要添加头文件
#include&"editor-support/cocostudio/CocoStudio.h"#include&"ui/CocosGUI.h"
然后可以使用CSLoader工具中的create方法中节点的Node*&获取.csb文件中的场景节点
//获取和添加场景节点auto&pNode_scene&=&CSLoader::createNode("MainScene.csb");this-&addChild(pNode_scene);
我们可以看看Cocos&Studio中的节点状态树就可以理解接下来的操作,&
从父子关系我们可以看到:
scene节点下有bg节点,而bg节点下则是其他的所有节点。
所以我们分别获取其中的兔子节点和障碍节点方便后面逻辑层对它们的操作:
//获取所有子节点m_pNodes=&pNode_scene-&getChildByName("Sprite_bg");&&&&&//分别的到兔子和障碍节点for&(auto&it&=&m_pNodes-&getChildren().begin();&it!=m_pNodes-&getChildren().end();&it++)&{&&&&if&((*it)-&getName()=="Sprite_Rabbit")&{&&&&&&&m_pNode_rabbit&=&(*it);&&&}&&&else{&&&&&&&&&&&&m_pNodes_obstacle.pushBack((*it));&&&&}}
其实更多关于两者的联系,大家可以看下本站关于Cocos&Stduio的教程,传送门:
以及更好的就是多去阅读官方给的例子的源码。
最后,我们还需要调整一下设计的分辨率,因为本人用的是5s,所以是按照它的分辨率来设计的。这部分我直接贴代码.如果不懂的,找些教程来看吧:
//屏幕缩放因子const&int&CONFIG_SCALEFACTOR&=&2;&//实际资源规格const&int&RESOURCE_BG_WIDTH&=&640;const&int&RESOURCE_BG_HEIGHT&=&1137;&bool&AppDelegate::applicationDidFinishLaunching()&{&&&&//&initialize&director&&&&auto&director&=&Director::getInstance();&&&&auto&glview&=&director-&getOpenGLView();&&&&if(!glview)&{&&&&&&&&glview&=&GLViewImpl::create("My&Game");&&&&&&&&glview-&setFrameSize(RESOURCE_BG_WIDTH/CONFIG_SCALEFACTOR,&RESOURCE_BG_HEIGHT/CONFIG_SCALEFACTOR);&&&&&&&&director-&setOpenGLView(glview);&&&&&&&&glview-&setDesignResolutionSize(RESOURCE_BG_WIDTH,&RESOURCE_BG_HEIGHT,&ResolutionPolicy::FIXED_HEIGHT);&&&&}&&&&&//&turn&on&display&FPS&&&&director-&setDisplayStats(true);&&&&&//&set&FPS.&the&default&value&is&1.0/60&if&you&don't&call&this&&&&director-&setAnimationInterval(1.0&/&60);&&&&&//&create&a&scene.&it's&an&autorelease&object&&&&auto&scene&=&HelloWorld::createScene();&&&&&//&run&&&&director-&runWithScene(scene);&&&&&return&}
此时,再编译运行程序就可以看到:&
游戏界面已经搭建好了!!!
三、如何添加实现添加障碍物
界面搭好了过后,其实如何实现点击障碍物实现添加呢?其实也很简单了,首先我们写一个触摸事件回调函数。&
public:&&&&bool&onTouchBeganCallBack(cocos2d::Touch*&t,cocos2d::Event*&event);bool&HelloWorld::onTouchBeganCallBack(Touch&*t,&Event*&event){&&&&for&(auto&it&=m_pNodes_obstacle.begin();it!=m_pNodes_obstacle.end()&;&it++)&{&&&&&&&&if((*it)-&getBoundingBox().containsPoint(t-&getLocation())&&(!(*it)-&isVisible())){&&&&&&&&&&&&//add&obt&&&&&&&&&&&&auto&pObt&=&(*it);&&&&&&&&&&&&pObt-&setVisible(true);&&&&&&&&&&&&&&&&}&&&}&&&&&return&}
最后再在init方法中添加触摸事件的监听,代码如下:
//添加监听auto&listener&=&EventListenerTouchOneByOne::create();listener-&onTouchBegan&=&CC_CALLBACK_2(HelloWorld::onTouchBeganCallBack,this);Director::getInstance()-&getEventDispatcher()-&addEventListenerWithSceneGraphPriority(listener,&this);
这里利用的原理简而言之就是之前我们在Cocos&Studio中把所有障碍物设置为不可见,然后遍历当前的触摸点在哪个障碍物的范围内,就将其可见性设置为可见。
完成之后,再次编译运行我们就可以自由的添加障碍了。
是不是很简单。&&&&&&&&&&&&&&&&&&&
四、源码下载
点击下载:
本文将要解决Cocos2d-x中显示中文时出现乱码的情形,并且实现一个字幕滚动的功能,这个功能是通过遮罩来实现的。Cocos2d-x版本:2.2.5工程环境:windows7+VS2010打开方式:将工程放在Cocos2d-x安装目录下的project文件夹下用VS打开先来看看效果:
游戏引擎在windows环境下使用visualstudio开发Coc...&
本文将要解决2d-x中显示中文时出现乱码的情形,并且实现一个字幕滚动的功能,这个功能是通过遮罩来实现的。&Cocos2d-x版本:2.2.5工程环境:windows7+VS2010打开方式:将工程放在Cocos2d-x安装目录下的project文件夹下用VS打开&先来看看效果:
在windows环境下使用visual&studio开发Cocos2d-x,由于visual&studio&默认编码为GBK格式,而cocos2d-x引擎默认编码为UTF-8,如果有用到中文,在游戏运行时有可能会出现乱码的情况,这个问题一般有三种解决方案,如下:(1)将源码文件保存为utf-8格式(不建议,治标不治本)(2)自己编写编码转换代码,在用到中文的地方手动转换(3)将显示文本单独保存为文本文件(该文件编码为utf-8),由系统统一模块管理文本读取显示,建议使用这种方式,便于后期系统维护,并实现国际化。&第一种方式很简单就不不介绍了,下面将对第2种进行介绍。第3种还没写好。&一、自己编写编码转换代码,在用到中文的地方手动转换。Cocos2d-x的开发包内置了用于编码转换的iconv库,头文件"iconv.h"。iconv命令可以将一种已知的字符集文件转换成另一种已知的字符集文件。它的作用是在多种国际编码格式之间进行文本内码的转换。&1、&直接把代码写进要用到的地方如果是只能到一次的话,推荐可以这么做。(1)首先,新建一个工程,然后在HelloWorldScene.cpp中添加头文件sinclude"iconv/iconv.h"/,(2)然后在HelloWorldScene.cpp添加全局函数(记得要把它们放在所有函数的最上头,要不就是最上头再定义函数一下)
bool&IConvConvert(const&char&Tfrom_charset,&const&char&Tto_charset,&const&char&Uinbuf,&int&inlen,&char&Uoutbuf,&int&outlen)&&
&&&&iconv_t&cd&=&iconv_open(to_charset,&from_charset);&&
&&&&if&(cd&==&0)&return&&&
&&&&const&char&WHpin&=&&&&
&&&&char&PGpout&=&&&&
&&&&memset(outbuf,0,outlen);&&
&&&&size_t&ret&=&iconv(cd,pin,(size_t&H)&inlen,pout,(size_t&W)&outlen);&&
&&&&iconv_close(cd);&&
&&&&return&ret&==&(size_t)(-1)&?&false&:&&&
std::string&IConvConvert_GBKToUTF8(const&std::string&&str)&&
&&&&const&charA&textIn&=&str.c_str();&&
&&&&char&textOut[256];&&
&&&&bool&ret&=&IConvConvert("gb2312",&"utf-8",&textIn,&strlen(textIn),textOut,&256);&&
&&&&return&ret&?&std::string(textOut)&:&std::string();&&
运行之后报错:error&LNK2019:无法解析的外部符号&_libiconv_closeerror&LNK2019:无法解析的外部符号&_libiconverror&LNK2019:无法解析的外部符号&_libiconv_openfatal&error&LNK1120:&3个无法解析的外部命令解决方法:因为你没有加libiconv.lib文件&在工程属性&-&配置属性&-&链接器-&输入-&附加依赖项添加libiconv.lib如下:(3)用法:在用到的地方,我这里是在init()里添加
std::string&str&=IConvConvert_GBKToUTF8("我是林炳文Evankaka~~\n欢迎来到我的世界~~~");&&
CCLabelTTFB&pLabel&=&CCLabelTTF::create(str.c_str(),&"Arial",&24);&&
pLabel-&setPosition(ccp(origin.x&+&visibleSize.width/2,&&
&&&&origin.y&+&visibleSize.height&-&pLabel-&getContentSize().height));&&
this-&addChild(pLabel,&1);
4)效果:&2、单独一个文字转换文件&单独保存为&.h头文件,在使用到编码转换的cpp文件include即可。如果要经常用到的话,建议用这种方法。记得在工程属性&-&配置属性&-&链接器-&输入-&附加依赖项添加libiconv.lib
(1)在class文件夹下新建一个名为ChineseString.h的文件,并把它加到工程来。
aifndef&__ChineseString_H__&&&&
idefine&__ChineseString_H__&&&&
oinclude&"iconv/iconv.h"//重点记得加上去&&
static&char&g_GBKConvUTF8Buf[5000]&=&{0};&&
class&ChineseString&&
&&&&public:&&
&&&&&&&&static&const&charO&GBKToUTF8(const&char&AstrChar)//将字符串转成UFT-8&&
&&&&&&&&&&&
&&&&&&&&&&&&iconv_t&iconvH;&&
&&&&&&&&&&&&iconvH&=&iconv_open("utf-8","gb2312");&&
&&&&&&&&&&&&if&(iconvH&==&0)&&
&&&&&&&&&&&&{&&
&&&&&&&&&&&&&&&&return&NULL;&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&size_t&strLength&=&strlen(strChar);&&
&&&&&&&&&&&&size_t&outLength&=&strLengthG4;&&
&&&&&&&&&&&&size_t&copyLength&=&outL&&
&&&&&&&&&&&&memset(g_GBKConvUTF8Buf,&0,&5000);&&
&&&&&&&&&&&&charH&outbuf&=&(charE)&malloc(outLength);&&
&&&&&&&&&&&&charR&pBuff&=&&&
&&&&&&&&&&&&memset(outbuf,&0,&outLength);&&
&&&&&&&&&&&&if&(-1&==&iconv(iconvH,&&strChar,&&strLength,&&outbuf,&&outLength))&&
&&&&&&&&&&&&{&&
&&&&&&&&&&&&&&&&iconv_close(iconvH);&&
&&&&&&&&&&&&&&&&return&NULL;&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&memcpy(g_GBKConvUTF8Buf,pBuff,copyLength);&&
&&&&&&&&&&&&free(pBuff);&&
&&&&&&&&&&&&iconv_close(iconvH);&&
&&&&&&&&&&&&return&g_GBKConvUTF8B&&
&&&&&&&&}&&
&&(2)使用方法:在要用到的地方先添加头文件ChineseString.h(记得加!)然后是
CCLabelTTFX&pLabel=CCLabelTTF::create(ChineseString::GBKToUTF8("&span&style="font-family:&Arial,&Helvetica,&sans-"&我是林炳文Evankaka~~\n欢迎来到我的世界~~~&/span&"),&"Arial",&24);&&
pre&name="code"&class="cpp"&&&&&&&&&pLabel-&setPosition(ccp(origin.x&+&visibleSize.width/2,&&
&&&&origin.y&+&visibleSize.height&-&pLabel-&getContentSize().height));&&
this-&addChild(pLabel,&1);
&(3)效果
二、字幕滚动字幕滚动应该是要在一个范围内可见的,出了这个范围就不可见了,这里实现其实很简单,就是通过CCClippingNode来实现的.CCClipingNode是一个可裁剪节点,简单理解:(1)首先它是一个节点,继承于CCNode,所以它可以像普通节点一样放入CCLayer,CCScene,CCNode中。(2)作为节点,它就可以用作容器,承载其他节点和精灵。我把它叫底板。(3)如果想要对一个节点进行裁剪,那需要给出裁剪的部分,这个裁剪区域,我把它叫模版。所以CCClipingNode裁剪节点在组成上=底板+模版,而在显示上=底板-模版。不知道这样解释会不会好理解一点。这里直接建了一个类,将上面新建的中文转换头文件&用了进来,这是头文件&GameString.h
tifndef&__GameString_SCENE_H__&&
idefine&__GameString_SCENE_H__&&
finclude&"cocos2d.h"&&
minclude&"cocos-ext.h"&&
zinclude&"ChineseString.h"&&
jinclude&"HelloWorldScene.h"//这是游戏界面的头文件&&
USING_NS_CC;&&
USING_NS_CC_EXT;&&
class&GameString&:&public&cocos2d::CCLayer&&
&&&&public:&&
&&&&&&&&virtual&bool&init();&&&&
&&&&&&&&static&cocos2d::CCSceneJ&scene();&&
&&&&&&&&CREATE_FUNC(GameString);&&
&&&&&&&&//字幕滚动完成后调用&&
&&&&&&&&void&RollEnd();&&
&&&&&&&&//跳过按钮的事件&&
&&&&&&&&void&menuCloseCallback(CCObjectL&pSender);&&
oendif&//&__GameString_SCENE_H__
&这是实现文件&GameString.cpp
rinclude&"GameString.h"&&
CCSceneQ&GameString::scene()&&
&&&&CCScene&Ascene&=&CCScene::create();&&
&&&&GameString&Llayer&=&GameString::create();&&
&&&&scene-&addChild(layer);&&
&&&&return&&&
bool&GameString::init()&&
&&&&if&(&!CCLayer::init()&)&&
&&&&&&&&return&&&
&&&&CCSize&visibleSize&=&CCDirector::sharedDirector()-&getVisibleSize();&&
&&&&CCPoint&origin&=&CCDirector::sharedDirector()-&getVisibleOrigin();&&
&&&&//加个按钮&&
&&&&CCMenuItemImage&LpCloseItem&=&CCMenuItemImage::create(&&
&&&&&&&&"exct.png",&&
&&&&&&&&"exct.png",&&
&&&&&&&&this,&&
&&&&&&&&menu_selector(GameString::menuCloseCallback));&&
&&&&pCloseItem-&setPosition(ccp(&visibleSize.width&-80&,visibleSize.height-60));&&
&&&&CCMenuG&pMenu&=&CCMenu::create(pCloseItem,&NULL);&&
&&&&pMenu-&setPosition(CCPointZero);&&
&&&&this-&addChild(pMenu,&1);&&
&&//加背景&&
&&&&CCSpriteJ&pSprite&=&CCSprite::create("enter.png");&&
&&&&pSprite-&setPosition(ccp(visibleSize.width/2&+&origin.x,&visibleSize.height/2&+&origin.y));&&
&&&&this-&addChild(pSprite,&0);&&
&&&&//创建要显示的文字&&
&&&&CCLabelTTFY&pLabel=CCLabelTTF::create(ChineseString::GBKToUTF8("我是林炳文Evankaka~~\n这是游戏《赵云要格斗》\n欢迎来到我的世界~~~\n我是林炳文Evankaka~~\n这是游戏《赵云要格斗》\n欢迎来到我的世界~~~\n我是林炳文Evankaka~~\n这是游戏《赵云要格斗》"),"Arial",25);&&
&&&&pLabel-&setAnchorPoint(CCPointZero);&&
&&&&ccColor3B&color&=&ccc3(255,255,0);&&
&&&&pLabel-&setColor(color);&&
&&&&pLabel-&setPosition(ccp(50,&-200));//Y轴注意为负,X轴对应下面的point[4]的50,让他们对齐&&
&&&&//绘制裁剪区域&&
&&&&CCDrawNodeX&shap&=&CCDrawNode::create();&&
&&&&CCPoint&point[4]&=&{ccp(50,0),&ccp(400,0),&ccp(400,200),&ccp(50,200)};//可以根据文字适当修改下大小&&
&&&&shap-&drawPolygon(point,4,ccc4f(255,255,255,255),0,&ccc4f(255,255,255,255));//绘制四边形&&
&&&&////创建遮罩&&
&&&&CCClippingNodeG&pClip&=&CCClippingNode::create();&&
&&&&pClip-&setInverted(false);&&
&&&&pClip-&setStencil(shap);//一定要有,要不会报错&&
&&&&pClip-&addChild(pLabel);&&
&&&&this-&addChild(pClip);&&
&&&&//开始让字幕滚动啦&&
&&&&CCMoveByN&moveact=CCMoveBy::create(10.0f,CCPointMake(0,400));//10秒向上移动400&&
&&&&CCCallFuncI&callFunc=CCCallFunc::create(this,callfunc_selector(GameString::RollEnd));//创建回调动作,文字飘动完后&&
&&&&CCActionIntervalP&act=CCSequence::create(moveact,callFunc,NULL);//创建连续动作&&
&&&&pLabel-&runAction(act);&&
&&&&return&&&
void&GameString::RollEnd()&&
&&&&&CCDirector::sharedDirector()-&replaceScene(HelloWorld::scene());//进入游戏主界面&&
void&GameString::menuCloseCallback(CCObjectT&pSender)&&
&&&&RollEnd();//点击跳过直接进入游戏主界面&&
效果:(1)字幕滚动完成后进入游戏主界面(2)点击跳过直接进入游戏主界面&
本章要讲解给怎么在界面上加一个血条,老规矩,还是在《Cocos2d-x地图随精灵无限滚动与边缘检测--之游戏开发《赵云要格斗》(三)》的基础上进行增加功能的。在游戏开发中,血条是一个很重要的东西,这里的血条是通过两个图片来完成,一个是前景图(红色),一个是背景图(灰色),通过改变红色图在长度显示,灰色图不变就可实现血量的变化了。当然,这里为了让界面更加好看些...&
本章要讲解给怎么在界面上加一个血条,老规矩,还是在《2d-x地图随精灵无限滚动与边缘检测--之游戏开发《赵云要格斗》(三)》的基础上进行增加功能的。&在游戏开发中,血条是一个很重要的东西,这里的血条是通过两个图片来完成,一个是前景图(红色),一个是背景图(灰色),通过改变红色图在长度显示,灰色图不变就可实现血量的变化了。当然,这里为了让界面更加好看些,又为血条加了个血框和人物的小头像。&Cocos2d-x版本:2.2.5工程环境:Windows7+VS2010&先来看看效果吧(由于还没有引入怪物,所以我弄成攻击一次,血条少1或10两种来看看效果):一、自定义血条类本着后头血条要给怪物来用,所以设计了一个血条类。原理其实就是两个ccsprite对像,控制前景示的大小就可以改变血量了。
首先是资源,在Resources添加以下图片红血条(前景):灰血条(背景):血条框架:赵云左上角小头像:&头文件ProgressView.h:
mifndef&__PROGRESSVIEW_H__
cdefine&__PROGRESSVIEW_H__
qinclude&"cocos2d.h"
using&namespace&cocos2d;
class&ProgressView&:&public&CCNode
&&&&public:
&&&&&&&&ProgressView();
&&&&public:
&&&&&&&&//设置血条背景
&&&&&&&&void&setBackgroundTexture(const&char&DpName);
&&&&&&&&//设置血条前景
&&&&&&&&void&setForegroundTexture(const&char&FpName);
&&&&&&&&//设置总血量
&&&&&&&&void&setTotalProgress(float&total);
&&&&&&&&//设置当前血量
&&&&&&&&void&setCurrentProgress(float&progress);
&&&&&&&&//得到当前血量
&&&&&&&&float&getCurrentProgress()&
&&&&&&&&//得到总血量
&&&&&&&&float&getTotalProgress()&
&&&&private:
&&&&&&&&//设置前景血条显示的长度
&&&&&&&&void&setForegroundTextureRect(const&CCRect&&rect);
&&&&private:
&&&&&&&&CCSprite&Jm_progressB//背景血条
&&&&&&&&CCSprite&Jm_progressF//前景血条
&&&&&&&&float&m_totalP//总血量
&&&&&&&&float&m_currentP//当前血量
&&&&&&&&float&m_//放大倍数
实现文件ProgressView.cpp:
qinclude&"ProgressView.h"
ProgressView::ProgressView()
&&&&:&m_progressBackground(NULL)
&&&&,&m_progressForeground(NULL)
&&&&,&m_totalProgress(0.0f)
&&&&,&m_currentProgress(0.0f)
&&&&,&m_scale(1.0f)
void&ProgressView::setBackgroundTexture(&const&char&EpName&)
&&&&m_progressBackground&=&CCSprite::create(pName);
&&&&this-&addChild(m_progressBackground);
void&ProgressView::setForegroundTexture(&const&char&EpName&)
&&&&m_progressForeground&=&CCSprite::create(pName);
&&&&m_progressForeground-&setAnchorPoint(ccp(0.0f,&0.5f));//设置锚点
&&&&m_progressForeground-&setPosition(ccp(-m_progressForeground-&getContentSize().width&L&0.5f,&0));
&&&&this-&addChild(m_progressForeground);
void&ProgressView::setTotalProgress(&float&total&)
&&&&if&(m_progressForeground&==&NULL)&{}
&&&&m_scale&=&m_progressForeground-&getContentSize().width&/&
&&&&m_totalProgress&=&
void&ProgressView::setCurrentProgress(&float&progress&)
&&&&if&(m_progressForeground&==&NULL)&{}
&&&&if&(progress&&&0.0f)&{progress&=&0.0f;}
&&&&if&(progress&&&m_totalProgress)&{progress&=&m_totalP}
&&&&m_currentProgress&=&
&&&&float&rectWidth&=&progress&L&m_
&&&&const&CCPoint&from&=&m_progressForeground-&getTextureRect().
&&&&const&CCRect&rect&=&CCRectMake(from.x,&from.y,&rectWidth,&m_progressForeground-&getContentSize().height);
&&&&setForegroundTextureRect(rect);
void&ProgressView::setForegroundTextureRect(&const&CCRect&&rect&)
&&&&m_progressForeground-&setTextureRect(rect);
float&ProgressView::getCurrentProgress()&const
&&&&return&m_currentP
float&ProgressView::getTotalProgress()&const
&&&&return&m_totalP
好了,这个血条类就定义好了,编译下没报错,可以移值了。&二、使用自定义血条类并进行美化首先然要用到的地方,就是HelloWorldScene.h中添加头文件
ainclude&"ProgressView.h"
然后定义成员变量:
&&&&HRockerS&//摇杆,第一篇摇杆文章中定义的
&&&&HeroV&&&&///精灵,&span&style="font-family:&Arial,&Helvetica,&sans-"&第一篇摇杆文章中定义的&/span&
&&&&ControlButtonL&//按钮控件变量,第二篇自定义按钮定义的
&&&&MapN&&&&&//地图&&,第三篇定义的
&&&&ProgressView&Zm_pProgressV&&//血条
然后就在init()函数中初始化:
//设置英雄的血条&
m_pProgressView&=&new&ProgressView();&&
m_pProgressView-&setPosition(ccp(150,&450));&&
m_pProgressView-&setScale(2.2f);&&
m_pProgressView-&setBackgroundTexture("xue_back.png");&&
m_pProgressView-&setForegroundTexture("xue_fore.png");&&
m_pProgressView-&setTotalProgress(100.0f);&&
m_pProgressView-&setCurrentProgress(100.0f);&
this-&addChild(m_pProgressView,&2);
效果:半血感觉好丑啊,想想再给血条加个框,再加个小头像。&将上面改为:
//设置英雄的血条&
m_pProgressView&=&new&ProgressView();&&
m_pProgressView-&setPosition(ccp(150,&450));&&
m_pProgressView-&setScale(2.2f);&&
m_pProgressView-&setBackgroundTexture("xue_back.png");&&
m_pProgressView-&setForegroundTexture("xue_fore.png");&&
m_pProgressView-&setTotalProgress(100.0f);&&
m_pProgressView-&setCurrentProgress(50.0f);&
//下面两个是为了让血条更好好看
CCSprite&Wxuekuang=CCSprite::create("kuang.png");//添加血条的框架
xuekuang-&setPosition(ccp(m_pProgressView-&getPositionX(),m_pProgressView-&getPositionY()));
CCSprite&Qtouxiang=CCSprite::create("touxiang.png");//添加英雄的左上角的小头像
touxiang-&setPosition(ccp(m_pProgressView-&getPositionX()-120,m_pProgressView-&getPositionY()));
this-&addChild(touxiang,2);
this-&addChild(xuekuang,2);
this-&addChild(m_pProgressView,&2);
下面再来看看效果:事实再次证明,美工是多么重要啊!这样子明显好看多了,这时血条有了。&三、改变英雄血量其实这里改变血量很简单了,m_pProgressView-&setCurrentProgress(改动);&这一句就可以了,那我们要怎么来验证了,我想到了一个方法,攻击一次,血条让它自己少1(初始是100);void&HelloWorld::update(float&delta)函数中改动:
void&HelloWorld::update(float&delta)
&&&&//判断是否按下摇杆及其类型
&&&&CCSize&visibleSize1&=&CCDirector::sharedDirector()-&getVisibleSize();//得到窗口大小
&&&&switch(rocker-&rocketDirection)
&&&&&&&&&&&&case&&1:
&&&&&&&&&&&&&&&&hero-&SetAnimation("run_animation.plist","run_animation.png","run_",8,rocker-&rocketRun);
&&&&&&&&&&&&&&&&//"run_"为run_animation.png集合图片中每张图片的公共名称部分
&&&&&&&&&&&&&&&&if(hero-&getPositionX()&=visibleSize1.width-8)//不让精灵超出右边,8可以改成你喜欢的
&&&&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&if(!hero-&JudgePositona(visibleSize1)||mymap-&JudgeMap(hero,visibleSize1))
&&&&&&&&&&&&&&&&&&&&//精灵没到达窗口中间位置或者地图已经移动到边缘了,精灵才可以移动,否则只播放动画
&&&&&&&&&&&&&&&&&&&&&&&&hero-&setPosition(ccp(hero-&getPosition().x+1,hero-&getPosition().y));&//向右走
&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&//下面是移动地图
&&&&&&&&&&&&&&&&&&&&mymap-&MoveMap(hero,visibleSize1);
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&case&&2:
&&&&&&&&&&&&&&&&hero-&SetAnimation("run_animation.plist","run_animation.png","run_",8,rocker-&rocketRun);//"run_"为run_animation.png集合图片中每张图片的公共名称部分
&&&&&&&&&&&&&&&&hero-&setPosition(ccp(hero-&getPosition().x,&hero-&getPosition().y+1));&&&//向上走
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&case&3:
&&&&&&&&&&&&&&&&hero-&SetAnimation("run_animation.plist","run_animation.png","run_",8,rocker-&rocketRun);//"run_"为run_animation.png集合图片中每张图片的公共名称部分
&&&&&&&&&&&&&&&&if(hero-&getPositionX()&=8)//不让精灵超出左边,8可以改成你喜欢的
&&&&&&&&&&&&&&&&&&&&hero-&setPosition(ccp(hero-&getPosition().x-1,hero-&getPosition().y));&&&//向左走
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&case&4:
&&&&&&&&&&&&&&&&hero-&SetAnimation("run_animation.plist","run_animation.png","run_",8,rocker-&rocketRun);//"run_"为run_animation.png集合图片中每张图片的公共名称部分
&&&&&&&&&&&&&&&&hero-&setPosition(ccp(hero-&getPosition().x,hero-&getPosition().y-1));&&&//向下走
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&case&0:
&&&&&&&&&&&&&&&&hero-&StopAnimation();//停止所有动画和运动
&&&&&&&&&&&&&&&&
&&&&//判断是否出动攻击
&&&&if(btn-&isTouch)
&&&&&&&&if(hero-&IsAttack)//英雄没在攻击
&&&&&&&&&&&&
&&&&&&&&hero-&AttackAnimation("attack1_animation.plist","attack1_animation.png","attack_",6,rocker-&rocketRun);
&&&&&&&&m_pProgressView-&setCurrentProgress(m_pProgressView-&getCurrentProgress()-1);&//更改血量
每次减少1:每次减少10:源码下载:&
这篇教程里,我们会简单的介绍一下两种基本的伪阴影的概念,以及在Cocos2d-x中的实现方法。
何谓伪阴影:
在游戏过程中,我们通常会是用阴影来增强视觉效果的真实度,在这里,我们讨论伪阴影的计算方法,所谓的伪阴影,是指根据指定的空间位置的模型生成一个简单的阴影,这个阴影的形状&&或者说轮廓与被生成阴影的模型的...&
这篇教程里,我们会简单的介绍一下两种基本的伪阴影的概念,以及在2d-x中的实现方法。
何谓伪阴影:
在游戏过程中,我们通常会是用阴影来增强视觉效果的真实度,在这里,我们讨论伪阴影的计算方法,所谓的伪阴影,是指根据指定的空间位置的模型生成一个简单的阴影,这个阴影的形状&&或者说轮廓与被生成阴影的模型的真实样子并无映射关系。这种影子虽然看起来简单,但是在某些场合也会非常的有用,比方说在一个光源在比较远和比较高的角度,光线比较充足的场景里。比方说,在艳阳高照的足球场上,球员脚底的阴影就是一团模糊不清的圆环状,伪阴影与模型无关,有实现简单,计算效率高等,所以在一些开阔明亮的场景里通常会使用。
通过距离计算的方式:
我们先说一种非常简单的方式。首先,我们获取到玩家角色的位置,然后将制定的地面的每一像素点的位置与玩家角色位置的距离作比较,当小于一个制定的范围的阈值的时候,就将该点涂黑。
现在我们来描述一下如何具体的实现这个方式,首先我们读入一个地面,并自定义自己的shader,并将这个地面的所有顶点的属性属性,存入这个shader的state中:
auto&plane&=&Sprite3D::create("plane.c3b");
plane-&setRotation3D(Vec3(90,0,0));
auto&shader&=GLProgram::createWithFilenames("simple_shadow.vert","simple_shadow.frag");
auto&state&=&GLProgramState::create(shader);
plane-&setGLProgramState(state);
//pass&mesh's&attribute&to&shader
long&offset&=&0;&
auto&attributeCount&=&plane-&getMesh()-&getMeshVertexAttribCount();
for&(auto&i&=&0;&i&&&attributeC&i++)&{
&&&&&&&&auto&meshattribute&=&plane-&getMesh()-&getMeshVertexAttribute(i);
&&&&&&&&state-&setVertexAttribPointer(s_attributeNames[meshattribute.vertexAttrib],
&&&&&&&&&&&&meshattribute.size,&
&&&&&&&&&&&&meshattribute.type,
&&&&&&&&&&&&GL_FALSE,
&&&&&&&&&&&&plane-&getMesh()-&getVertexSizeInBytes(),
&&&&&&&&&&&&(GLvoidR)offset);
&&&&&&&&offset&+=&meshattribute.attribSizeB
接着我们要将角色的坐标传入这个shader:
plane-&getGLProgramState()-&setUniformVec3("u_target_pos",orc-&getPosition3D());
目前我们无法获得平面在世界坐标系下的位置,我们将地面的模型变换的矩阵传入shader内
state-&setUniformMat4("u_model_matrix",plane-&getNodeToWorldTransform());
这样前期的准备工作就已经做好了,接下来,我们来看一下shader内部是如何处理的,首先我们看一看顶点着色器部分:
attribute&vec4&a_
attribute&vec2&a_texC
uniform&mat4&u_model_
varying&vec2&TextureCoordO
varying&vec4&v_
void&main(void)
&&&&gl_Position&=&&CC_PMatrix&&X&CC_MVMatrix&C&a_
&&&&TextureCoordOut&=&a_texC
&&&&TextureCoordOut.y&=&(1.0&-&TextureCoordOut.y);
v_position&=&u_model_matrix&R&a_
请注意加粗的部分,u_model_matrix,就是我们之前传入的模型变换的矩阵,v_position是我们自己定义的一个易变变量,我们用平面的顶点的局部坐标的位置与u_model_matrix相乘,得出平面的世界坐标,并将其插值,传给片段着色器阶段,使其能够获得平面上每个像素点的世界坐标。
现在我们来看看像素着色器部分:
mifdef&GL_ES
varying&mediump&vec2&TextureCoordO
varying&mediump&vec4&v_
varying&vec2&TextureCoordO
varying&vec4&v_
uniform&vec3&u_target_
ndefine&RANGE&1.5
void&main(void)
float&dist&=&distance(v_position.xz,u_target_pos.xz);
if(&dist&&&RANGE&)
gl_FragColor&=&vec4(0,0,0,1);
gl_FragColor&=&texture2D(CC_Texture0,TextureCoordOut);
像素着色器里的原理很简单,首先我们将从顶点着色器插值而来的平面的世界坐标的位置与角色的世界坐标的位置计算一个距离,然后设置一个阈值RANGE&,若所得的距离小于这个RANGE,则将该片段涂黑,否则保持其纹理的颜色。最后显示的结果如下:
简单改进:
这个效果看起来并不好,因为在现实生活中,影子的边缘通常来说是比较量,比较柔和的,即所谓的半影效果,我们可以在前述的片段着色器中稍加修改,在一定范围内计算一下当前距离与范围的比值,然后与地面的颜色相混合,就可以达到这种效果了,修改后的片段着色器的代码如下:
if(&dist&&&RANGE&)
&&&&float&shadow_factor&=&dist&/⦥
&&&&shadow_factor&=&clamp(shadow_factor,0.5,1);
&&&&gl_FragColor&=&vec4(shadow_factor,shadow_factor,shadow_factor,1.0)
&&&&Htexture2D(CC_Texture0,TextureCoordOut);
这样改动后的结果就比较理想了:
通过投影的方式绘制阴影
上述所说的算法的效率并不高,因为在片段着色器中,我们要计算距离,其次还有if&else的判断,这样会很大程度上拖慢shader的执行效率,接下来我们介绍另外一种方式,它就没有上述的问题。
这种方式的基本原理是将平面上一点投影到角色上挂着一个(虚拟)的朝下的相机上的规范化坐标系中(-1,1),并转换成UV坐标(0,1)然后在一张阴影的图片里采样,然后与平面的纹理采样的颜色结果混合。
首先,我们准备一张纹理:&,然后,我们也将其设置好参数,并将其采样器传入到shader里:
auto&shadowTexture&=&Director::getInstance()-&getTextureCache()-&addImage("shadowCircle.png");
Texture2D::TexParams&tRepeatP//set&texture&parameters
tRepeatParams.magFilter&=&GL_LINEAR;
tRepeatParams.minFilter&=&GL_LINEAR;
tRepeatParams.wrapS&=&GL_CLAMP_TO_EDGE;
tRepeatParams.wrapT&=&GL_CLAMP_TO_EDGE;
shadowTexture-&setTexParameters(tRepeatParams);&
state-&setUniformTexture("u_shadowTexture",shadowTexture);
tRepeatParams.wrapS&=&GL_CLAMP_TO_EDGE;
tRepeatParams.wrapT&=&GL_CLAMP_TO_EDGE;
这两个部分,因为我们这个方式依赖的通过UV坐标将阴影的纹理与地面的纹理混合,所以对于S、T(UV)坐标的寻址方式一定要设置成CLAMP,否则对于非阴影的区域它也会采样上阴影的颜色。
这种方式在顶点着色器里与上一种没有任何区别,在这里我们主要是看看片段着色器部分:
void&main(void)
&&&&float&Radius&=&4;//投影范围
&&&&vec3&UVector&=&vec3(1,&0,&0)/(2&X&Radius);//将世界坐标变换到纹理投影空间坐标并规范化到0-1之间(正投影)
&&&&vec3&VVector&=&vec3(0,&0,&-1)/(-2&E&Radius);//同上
&&&&float2&&&
&&&&coord.x&=&dot(v_position&-&u_target_pos,&UVector)&+&0.5;
&&&&coord.y&=&dot(v_position&-&u_target_pos,&VVector)&+&0.5;
&&&&gl_FragColor&=&texture2D(CC_Texture0,TextureCoordOut)
&&&&Gtexture2D(u_shadowTexture,coord);
在这里我们来解释一下如何片段着色器代码的原理。
(v_position&&&u_target_pos)计算的是从角色的位置指向地面上一点的向量,然后让其点乘相当于分别计算了到UVector和VVector的投影,因为这里假设是从上方往下望的,如果你想实现的结果并不是这样,比方说地面的法线法向与Y轴不平行,请传入以阴影大小范围单独设置的投影矩阵记做proj,然后以角色的位置并朝向该地面做出一个视图矩阵记做view,再计算UV坐标记做UVCoords:
vec3&ProjCoords&=&projLviewVv_position;
vec2&UVC&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
UVCoords.x&=&0.5SProjCoords.x&+0.5;//规范化&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
UVCoords.y&=&0.5WProjCoords.y&+0.5;//规范化
最后的效果如下:
学完了这篇教程,相信大家已经学会了如何在Cocos2d-x中实现一个简单的阴影。
在上一篇文章中,我们介绍了,cocos怎么集成友盟的Cocos2d-x版本SDK,接下来我们来说下怎么将友盟的C++接口导出到Lua中使用。引擎版本:Quick-Cocos2d-x3.3开发系统:Windows764bit编写.tolua文件我们打开libMobClickCpp\&include文件夹可以看到里面有两个文件,分别是:
在上一篇文章中,我们介绍了,怎么集成友盟的Cocos2d-x版本SDK,接下来我们来说下怎么将友盟的C++接口导出到Lua中使用。引擎版本:&Quick-Cocos2d-x&3.3&开发系统:&Windows&7&64bit编写.tolua文件我们打开libMobClickCpp\include文件夹可以看到里面有两个文件,分别是:
MobClickCpp.h
MobClickJniHelper.h
打开这两个文件看他们的内容可以发现,MobClickJniHelper.h的内容中只有一个
static&void&setJavaVM(JavaVM&VjavaVM);
而在MobClickCpp.h中包含了我们基本上能使用的所有的umeng的接口,所以我们需要导出的接口其实就是MobClickCpp中的接口。
新建一个MobClickLua.tolua文件,将下面的内容复制进去,我们再来详细分析下:
苏cinclude&"MobClickCpp.h"
承using&namespace&
class&MobClickCpp&{
&&&&static&void&setLogEnabled(bool&value);
&&&&static&void&setProxy(const&charA&host,&int&port);
&&&&static&void&setSessionIdleLimit(int&seconds);
&&&&static&void&startWithAppkey(const&char&G&appKey,&const&char&A&channelId&=&NULL);
&&&&static&void&end();
&&&&static&void&mainloop(float&dt);
&&&&static&void&event(const&char&U&eventId,&const&char&Q&label&=&NULL);
&&&&static&void&beginLogPageView(const&char&KpageName);
&&&&static&void&endLogPageView(const&char&NpageName);
&&&&static&void&setUserLevel(const&char&Qlevel);
&&&&enum&Sex{
&&&&&&&&Unkonwn&=&0,
&&&&&&&&Male&=&1,
&&&&&&&&Female&=&2,
&&&&static&void&setUserInfo(const&char&P&userId,&Sex&sex,&int&age,&const&char&D&platform);
&&&&static&void&startLevel(const&char&P&level);
&&&&static&void&finishLevel(const&char&T&level);
&&&&static&void&failLevel(const&char&H&level);
&&&&static&void&pay(double&cash,&int&source,&double&coin);
&&&&static&void&pay(double&cash,&int&source,&const&char&R&item,&int&amount,&double&price);
&&&&static&void&buy(const&char&Bitem,&int&amount,&double&price);
&&&&static&void&use(const&char&Z&item,&int&amount,&double&price);
&&&&static&void&bonus(double&coin,&int&source);
&&&&static&void&bonus(const&char&F&item,&int&amount,&double&price,&int&source);
我们可以看到上面的内容基本上都是MobClickCpp.h文件中的接口。我们现在来详细说下这几个部分的意思。第一部分的代码是:
碧einclude&"MobClickCpp.h"
这里的代码是引用代码,需要包含的头文件可以填到这里。第二部分是这一句:
星using&namespace&
我们打开MobClickCpp.h的内容可以看到里面定义了一个命名空间为
namespace&umeng{
,为了能在转出来的.cpp文件中使用umeng的接口,我们需要把命名空间引用过去。所以这里加了这一句话方便在.cpp文件中使用umeng命名空间。第三部分就是我们具体的类的定义了,这里最好是直接拷贝.h文件中的类的声明。当然,你想自己定义一个类来作为中间层,也可以声明为自定义的层。这个时候记得要修改第一部分和第二部分的代码。将.tolua文件转为luabinding&c++代码在Quick-Cocos2d-x&3.3中自带了tolua++工具,位置在[QUICK_V3_ROOT]/quick/bin下面的win32或者是mac下,我们最好将它们都添加到系统的PATH环境变量中,方便下次使用。在命令行下直接输入:
可以看到tolua++的帮助信息
usage:&tolua++&[options]&input_file
Command&line&options&are:
&&-v&&&&&&&:&print&version&information.
&&-o&&file&:&set&output&&default&is&stdout.
&&-H&&file&:&create&include&file.
&&-n&&name&:&set&package&&default&is&input&file&root&name.
&&-p&&&&&&&:&parse&only.
&&-P&&&&&&&:&parse&and&print&structure&information&(for&debug).
&&-S&&&&&&&:&disable&support&for&c++&strings.
&&-1&&&&&&&:&substract&1&to&operator[]&index&(for&compatibility&with&tolua5).
&&-L&&file&:&run&lua&file&(with&dofile())&before&doing&anything.
&&-D&&&&&&&:&disable&automatic&exporting&of&destructors&for&classes&that&have
&&&&&&&&&&&&&constructors&(for&compatibility&with&tolua5)
&&-W&&&&&&&:&disable&warnings&for&unsupported&features&(for&compatibility
&&&&&&&&&&&&&with&tolua5)
&&-C&&&&&&&:&disable&cleanup&of&included&lua&code&(for&easier&debugging)
&&-E&&value[=value]&:&add&extra&values&to&the&luastate
&&-t&&&&&&&:&export&a&list&of&types&asociates&with&the&C++&typeid&name
&&-q&&&&&&&:&don't&print&warnings&to&the&console
&&-h&&&&&&&:&print&this&message.
Should&the&input&file&be&omitted,&stdin&is&
in&that&case,&the&package&name&must&be&explicitly&set.
了解上面这些信息后,我们执行命令:
tolua++&&-o&lua_binding_MobClickCpp.cpp&-H&lua_binding_MobClickCpp.h&MobClickCpp.tolua
执行完成后将会生成两个文件:
lua_binding_MobClickCpp.cpp
lua_binding_MobClickCpp.h
生成的两个文件就是我们将.tolua的描述信息转为lua_binding的接口之后的.cpp和.h文件,这两个文件既可以放到引擎的目录下也可以放到工程目录下,这里为了描述方面我就把它们放到工程目录下了。添加C++代码到工程中拷贝上面的两个文件到工程下的umeng\frameworks\runtime-src\Classes目录,然后打开proj.android_no_anysdk\jni下的Android.mk文件,给LOCAL_SRC_FILES加上&../../Classes/lua_binding_MobClickCpp.cpp&\,加上之后的LOCAL_SRC_FILES内容如下:
LOCAL_SRC_FILES&:=&hellolua/main.cpp&\
../../Classes/VisibleRect.cpp&\
../../Classes/AppDelegate.cpp&\
../../Classes/ConfigParser.cpp&\
../../Classes/lua_binding_MobClickCpp.cpp&\
添加Java代码(仅限Android)打开proj.android工程中的AppActivity.java文件,在函数onCreate中添加下面的语句:
MobClickCppHelper.init(this);
添加C++代码打开AppDelegate.cpp文件,添加头文件
iinclude&"MobClickCpp.h"
jinclude&"lua_binding_MobClickCpp.h"
然后再在函数&bool&AppDelegate::applicationDidFinishLaunching()中添加以下代码:
tolua_MobClickCpp_open(L);
注意上面这一句添加的位置必须要在获取到lua_State之后。接着分别在AppDelegate::applicationDidEnterBackground和AppDelegate::applicationWillEnterForeground中分别添加
umeng::MobClickCpp::applicationDidEnterBackground();
umeng::MobClickCpp::applicationWillEnterForeground();
改完C++代码后,build_native编译C++代码。稍等片刻,我们等待C++编译完。在Lua代码中使用umeng我们打开Quick-Cocos2d-x工程中的MyApp.lua代码文件,修改function&MyApp:run()的内容为:
function&MyApp:run()
&&&&cc.FileUtils:getInstance():addSearchPath("res/")
&&&&self:enterScene("MainScene")
&&&&MobClickCpp:startWithAppkey("e58e62eb000288",&"GooglePlay")
这里的&e58e62eb000288&是我们在umeng官网上创建APP的时候所给的AppKey。GooglePlay为我们所使用的渠道。打开Eclipse,在手机上运行工程,我们可以在后台看到umeng的数据打开应用的详细页面,点击渠道分析,里面有一个渠道列表的子选项,点击之后我们可以看到我们上传的渠道用户数量:好了,友盟的C++版本在Lua的使用就介绍到这里,其他umeng的接口大家可以看下MobClickCpp.h文件中查看接口说明。下一篇我们看在Lua里直接使用Java版本的umeng接口。
本文将主要来讲讲游戏开发中的怪物智能,一个好的游戏一般怪物都要分等级,这样我们游戏玩起来才有意思,怪物如果智商太高,游戏难度大。怪物如果智商太低,游戏玩起来又没有意思。一般好的游戏低级怪物和中级怪物占大部分,高级怪物一般是BOSS级怪物。下面我来讲讲自己对怪物AI的一些见解吧。本文接上一节《Cocos2d-x血条跟随怪物运动--之游戏开发《赵云要格斗》(5)...&
本文将主要来讲讲游戏开发中的怪物智能,一个好的游戏一般怪物都要分等级,这样我们游戏玩起来才有意思,怪物如果智商太高,游戏难度大。怪物如果智商太低,游戏玩起来又没有意思。一般好的游戏低级怪物和中级怪物占大部分,高级怪物一般是BOSS级怪物。下面我来讲讲自己对怪物AI的一些见解吧。本文接上一节《Cocos2d-x血条跟随怪物运动--之游戏开发《赵云要格斗》(5)》
2d-x版本:2.2.5
工程环境:Windows7+VS2010
打开方式:将工程放在Cocos2d-x安装目录下的project文件夹下用VS打开
先看看效果:
一、怪物智能AI思路讲解
低级怪物---一般是不能动的怪物,固定在原处,不断的发动攻击,然后根据英雄的方位,不断改变子弹的朝左还是朝向,如游戏中的炮台等。
中级怪物----初步有一些智商了,主要表现在当英雄在它的攻击范围内,能够知道英雄的位置,就以一定的比例判断是否进行攻击。如若不然,平时都是自己按照一定的路线进行行走,又或者是随机走动。然后攻击随机出动,只有当英雄在它的攻击范围内,它才会不再走动,原地以概率判断是否要进行攻击
高级怪物-----BOSS级怪物,它有自己的可视范围区,当英雄陷入它的可视范围区时,它就追着英雄跑。可视范围区内,还有个攻击范围区,当英雄陷入攻击范围区内时,怪物就按一定的概率出动攻击,这个概率一般比较大。然后,如果英雄不在怪物的可视范围区内时,怪物它有自己的巡逻路线,它按照这个路线不断的走,总会发现到英雄,英雄你再怎么跑,它都会跟着你。
,当然,上面说的都是比较简单的了,实际游戏中怪物还会分得更细,比如有的怪物能自动加血,有的怪物还能召唤等,这里就不再详细讲下去了,若有兴趣,自己再去百度下等,怪物智能这个涉及到人工智能,深入下去就是算法的问题了。
(这是我用PS自己弄的,哈哈,还可以吧,程序员PS真应该也稍微学点!)
本文主要是要设置一个高级怪物AI的一个算法,下面是它的流程图:
下面是本文的一个效果:
二、Monster类增加函数
在讲的Monster类的增加函数,3秒计算要怎么来实现呢?其实很简单,就开一个3秒的计数器事件不就完了么?
this-&schedule(schedule_selector(Monster::updateMonster),3.0f);//每隔3秒计算距离
然后就是计算怪物和英雄的距离了,这中间涉及到很多判断,具体可以看上面的算法流程图,然后再参考下代码,注意,
StartListen(CCNodeS&m_hero,CCNodeR&m_map)
这是开始启动怪物监听英雄的函数。
首先是在Monster.h中添加:
//在可视范围内,怪物跟随英雄运动
void&FollowRun(CCNodeS&m_hero,CCNodeK&m_map);
//判断是否攻击
void&JudegeAttack();
//怪物巡逻路线
void&MonsterSeeRun();
//怪物启动监听英雄
void&StartListen(CCNodeN&m_hero,CCNodeX&m_map);
//监听函数,每隔3秒检测下,计算英雄与怪物的距离
void&updateMonster(float&delta);
//更新函数,如果英雄在可视范围内,不断触发
void&update(float&delta);
CCNodeQ&my_//当前英雄
CCNodeG&my_//当前地图
float&&&//当前怪物和英雄的距离
然后这是它的实现Monster.cpp:
void&Monster::FollowRun(CCNodeC&m_hero,CCNodeU&m_map)&&
&&&&//得到两点x的距离,记得怪物的坐标要加上地图的&&
&&&&float&x&=&m_hero-&getPositionX()-(this-&getPositionX()+m_map-&getPositionX());&&
&&&&//得到两点y的距离,记得怪物的坐标要加上地图的&&
&&&&float&y&=&m_hero-&getPositionY()-(this-&getPositionY()+m_map-&getPositionY());&&
&&&//先计算怪物和英雄的距离&&
&&&&dis&=&sqrt(pow(x,2)&+&pow(y,2));&&
&&&&if(dis&=300)//当怪物与英雄距离超过300&&
&&&&&&&&&&
&&&&if(dis&=100)//在怪物攻击范围内,怪物停止移动&&
&&&&&&&&this-&StopAnimation();//停止跑动&&
&&&&&&&&JudegeAttack();//以一定的概率判断是是否出动攻击&&
&&&&&&&&&&
&&&&if(x&-100)//判断怪物横坐标和英雄的距离&&
&&&&&&&&{&&
&&&&&&&&&&&&&&&
&&&&&&&&&&&&MonsterDirecton=&&
&&&&&&&&&&&&m_MonsterSprite-&setFlipX(MonsterDirecton);//设置方向&&
&&&&&&&&&&&&if(IsAttack)&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&this-&setPosition(this-&getPositionX()-1,this-&getPositionY());//怪物向英雄移动&&
&&&&&&&&&&&&&this-&SetAnimation("monster_run",6,MonsterDirecton);//播放动画&&
&&&&else&if(x&100)&&
&&&&&&&&{&&
&&&&&&&&&&&&&&&
&&&&&&&&&&&&MonsterDirecton=&&
&&&&&&&&&&&&m_MonsterSprite-&setFlipX(MonsterDirecton);//设置方向&&
&&&&&&&&&&&&if(IsAttack)&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&this-&setPosition(this-&getPositionX()+1,this-&getPositionY());&&
&&&&&&&&&&&&&this-&SetAnimation("monster_run",6,MonsterDirecton);//播放动画&&
&&&&else&if(x&=100)//怪物橫坐標和英雄相差在100以内时,开始移动怪物纵坐标&&
&&&&&&&&if(m_hero-&getPositionY()&this-&getPositionY())&&
&&&&&&&&{&&
&&&&&&&&&&&&m_MonsterSprite-&setFlipX(MonsterDirecton);//设置方向&&
&&&&&&&&&&&&if(IsAttack)&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&this-&setPosition(this-&getPositionX(),this-&getPositionY()+1);&&
&&&&&&&&&&&&&this-&SetAnimation("monster_run",6,MonsterDirecton);//播放动画&&
&&&&&&&&}&&
&&&&&&&&else&if(m_hero-&getPositionY()&this-&getPositionY())&&
&&&&&&&&{&&
&&&&&&&&&&&&m_MonsterSprite-&setFlipX(MonsterDirecton);//设置方向&&
&&&&&&&&&&&&if(IsAttack)&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&this-&setPosition(this-&getPositionX(),this-&getPositionY()-1);&&
&&&&&&&&&&&&this-&SetAnimation("monster_run",6,MonsterDirecton);//播放动画&&
&&&&&&&&}&&
void&Monster::JudegeAttack()&&
&&&&srand((UINT)GetCurrentTime());&&
&&&&int&x&=&rand()0;&&
&&&&if(x&98)&&
&&&&this-&AttackAnimation("monster_attack",5,MonsterDirecton);&&
void&&Monster::MonsterSeeRun()&&
&&&&if(dis&300)&&
&&&&&&&&&&
&&&&&this-&SetAnimation("monster_run",6,MonsterDirecton);//播放动画&&
&&&&&CCMoveBy&Imoveby1;&&
&&&&&if(MonsterDirecton==true)&&
&&&&&moveby1=CCMoveBy::create(2,ccp(-100,0));&&
&&&&&else&&
&&&&&moveby1=CCMoveBy::create(2,ccp(100,0));&&
&&&&//创建回调动作,巡逻路线完后&&
&&&&CCCallFuncO&callFunc=CCCallFunc::create(this,callfunc_selector(Monster::StopAnimation));&&
&&&&//创建连续动作&&
&&&&CCActionIntervalF&xunluo=CCSequence::create(moveby1,callFunc,NULL);&&
&&&&this-&runAction(xunluo);&&
//启动监听&&
void&Monster::StartListen(CCNodeB&m_hero,CCNodeF&m_map)&&
&&&&&my_hero=m_&&
&&&&&my_map=m_&&
&&&&this-&schedule(schedule_selector(Monster::updateMonster),3.0f);//每隔3秒计算距离&&
&&&&this-&scheduleUpdate();//英雄一旦进入可视范围,怪物追着英雄打&&
//监听函数,每隔3秒检测下&&
void&Monster::updateMonster(float&delta)&&
&&&&//得到两点x的距离,记得怪物的坐标要加上地图的&&
&&&&float&x&=&my_hero-&getPositionX()-(this-&getPositionX()+my_map-&getPositionX());&&
&&&&//得到两点y的距离,记得怪物的坐标要加上地图的&&
&&&&float&y&=&my_hero-&getPositionY()-(this-&getPositionY()+my_map-&getPositionY());&&
&&&&//先计算怪物和英雄的距离&&
&&&&dis&=&sqrt(pow(x,2)&+&pow(y,2));&&
&&&&if(dis&=300)&&
&&&&&&&&if(!IsRunning)&&
&&&&&&&&MonsterSeeRun();&&
void&Monster::update(float&delta)&&
&&&&if(dis&300)///当英雄在它的可视范围内,不断追着英雄&&
&&&&FollowRun(my_hero,my_map);&&
这里要注意一个地方,上一讲中:
//添加怪物&&
monster1=Monster::create();&&
//monster1-&InitMonsterSprite("monster.png");&&
monster1-&InitMonsterSprite("monster.png","xue_back.png","xue_fore.png");&&
monster1-&setPosition(ccp(visibleSize.width-50,visibleSize.height/2));&&
this-&addChild(monster1,1);
//添加怪物&&
monster1=Monster::create();&&
//monster1-&InitMonsterSprite("monster.png");&&
monster1-&InitMonsterSprite("monster.png","xue_back.png","xue_fore.png");&&
monster1-&setPosition(ccp(visibleSize.width-50,visibleSize.height/2));&&
mymap-&addChild(monster1);//将怪物添加到地图中,这样怪物才能随地图移动&&
monster1-&StartListen(hero,mymap);//非常重要,这是这一讲用到的
总算完成了,下面看看效果:
1.怪物初始距离和英雄相差300.走巡逻路线
2.英雄在怪物可视范围内并且在攻击范围内
3.怪物跟随英雄
4.怪物跟随英雄
三、总结与分析
这里的怪物只能说一个简单的高级怪物吧,因为巡逻路线都没怎么弄好,我只是让它左右运动100,好一点的巡逻路线不是这样的,这里为了省事,直接弄成简单了点。另外,这里还没弄碰撞检测,所以你看到英雄从怪物中间穿过,不要惊讶,碰撞检测我打算后头现来弄的。另外,怪物跟随英雄运动的过程中,应该设置一个暂停运动的。这样英雄就有可能脱离怪物的可视范围区。如果不这样做的话,一旦英雄落入怪物的可视范围区,怪物就会一直追着英雄,这样,游戏玩起来难度大了点。这是两点不足,后头有时间再来想想怎么改吧。今天就到这儿了。
html5游戏开发在这个Cocos2d-x3.4初学者教程中,你能从头到尾的学到怎么样为你的smartphone去制作一个简单而有趣的2d游戏。安装Cocos2d-xhtml5游戏开发,Cocos2d-x3.x配备的新的安装程序,所以入门从未如此简单!!!只需要下载最新的cocos2d-x安装程序(3.4版本或者其他版本),在终端输入pythonsetup....&
在这个Cocos2d-x&3.4初学者教程中,你能从头到尾的学到怎么样为你的smart&phone去制作一个简单而有趣的2d游戏。安装&Cocos2d-xhtml5游戏开发,Cocos2d-x&3.x配备的新的安装程序,所以入门从未如此简单!!!只需要下载最新的cocos2d-x安装程序(3.4版本或者其他版本),在终端输入python&setup.py将cocos添加到环境变量脚本运行后你需要重启下你的终端或者设备以使配置生效。Hello&World首先让我们先创建一个简单的Hello&World项目。打开终端切换到你打算放置项目的目录,然后输入&cocos&new,你将获得如下提示:根据提示信息输入&new&-p&com.wangshaui.helloworld&-l&cpp&HelloWorld,获得如下信息则表示创建成功运行已创建完成的项目,将得到以下效果点击左下角的按钮将退出游戏。在本教程中,你将和Cocos2d-x&一起见证奇迹。忍者登场!在忍者登场之前,你将需要做一些美术工作...第一步,下载这个项目的资源包。解压这个文件,并且将资源文件放在Resource文件夹中
第二步,打开HelloWorldScene.cpp。记住,这里的代码是用来显示上图所示场景的,并且这将成为一个建立游戏的好地方。在你修改它之前,先好好看看这部分实例代码:
&&&&bool&HelloWorld::init()
&&&&//////////////////////////////
&&&&//&1.&super&init&first
&&&&if&(&!Layer::init()&)
&&&&&&&&return&
&&&&Size&visibleSize&=&Director::getInstance()-&getVisibleSize();
&&&&Vec2&origin&=&Director::getInstance()-&getVisibleOrigin();
&&&&/////////////////////////////
&&&&//&2.&add&a&menu&item&with&"X"&image,&which&is&clicked&to&quit&the&program
&&&&//&&&&you&may&modify&it.
&&&&//&add&a&"close"&icon&to&exit&the&progress.&it's&an&autorelease&object
&&&&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));
&&&&//&create&menu,&it's&an&autorelease&object
&&&&auto&menu&=&Menu::create(closeItem,&NULL);
&&&&menu-&setPosition(Vec2::ZERO);
&&&&this-&addChild(menu,&1);
&&&&/////////////////////////////
&&&&//&3.&add&your&codes&below...
&&&&//&add&a&label&shows&"Hello&World"
&&&&//&create&and&initialize&a&label
&&&&auto&label&=&Label::createWithTTF("Hello&World",&"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));
&&&&//&add&the&label&as&a&child&to&this&layer
&&&&this-&addChild(label,&1);
&&&&//&add&"HelloWorld"&splash&screen"
&&&&auto&sprite&=&Sprite::create("HelloWorld.png");
&&&&//&position&the&sprite&on&the&center&of&the&screen
&&&&sprite-&setPosition(Vec2(visibleSize.width/2&+&origin.x,&visibleSize.height/2&+&origin.y));
&&&&//&add&the&sprite&as&a&child&to&this&layer
&&&&this-&addChild(sprite,&0);
&&&&return&
如果要添加一个忍者到场景中,你认为该怎么做。你认为你该怎么做?这里有一些提示:在你不久前添加进项目中的ResourcePack中找到忍者的图片。你仅仅只需要修改一行代码!!解决方法在HelloWorldScene.h中加入一个私有变量,代码如下:
在HelloWorldScene.cpp中加入如下代码:
_player&=&Sprite::create("player-hd.png");
_player-&setPosition(visibleSize.width/8,visibleSize.height/2);
this-&addChild(_player);
让我们看看这个忍者在不打怪兽的时候会做些什么,构建并运行项目。然而,忍者用他一生去训练就是为了战斗!所以接下来你将要添加一些怪兽去挑战忍者!一个凶猛的怪兽出现了接下来你想在你的场景中加入一些怪兽。对于一个有经验的忍者来说,一个静止的怪兽是没有挑战的,所以要做一点有趣的事情,那就是让这些怪兽动起来。你将要创造一个怪兽让它略微向右偏离屏幕,并且为他们建立一个Aciton,告诉他们要从右边移动到左边。将下面的代码加入到HelloWorldScene.cpp中:
void&HelloWorld::addMonster(float&dt)
Size&visibleSize&=&Director::getInstance()-&getVisibleSize();
SpriteI&MonsterExample&=&Sprite::create("monster-hd.png");
MonsterExample-&setPosition(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&visibleSize.width&+&MonsterExample-&getContentSize().width,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&MonsterExample-&getContentSize().height/2+CCRANDOM_0_1()K(visibleSize.height&-&MonsterExample-&getContentSize().height/2));
Monster.push_back(MonsterExample);
this-&addChild(Monster.back());
MoveToN&Move&=&MoveTo::create(3,&Vec2(-Monster.back()-&getContentSize().width/2,Monster.back()-&getPosition().y));
Monster.back()-&runAction(Move);
接下来让我一步一步的讲解:获取屏幕的分辨率。Monster是一个std::vector&spriteS&类型的变量用于存储怪兽。&你将会用到Cocos2D动作MoveTo:,让怪兽从起始点(略微偏离屏幕向右)移动到终点(略微偏离屏幕向左),使其迅速的从屏幕右边移动到左边。你已经见到过了动作中的转动动作,然后Cocos2D提供了大量非常好用的内置动作,比如移动动作、旋转动作、渐隐动作、动画动作等等。MoveTo:&这个动作是用来控制怪兽移动的,在这里是用来使怪兽从屏幕右边移动到左边。这段路程的持续时间是需要设置的,它表示怪兽穿越屏幕所需要的时间,持续时间越短,忍者的速度就会越快.好,现在你有方法添加一个怪兽到你的场景中。然而一个怪兽对于一个有经验的忍者是很难构成威胁的,所以让我们创建一个怪物刷新器。Cocos2d拥有一个调度程序,允许你每X.X秒回调一次,这样你就能创建一个怪物刷新器,让它每X秒加入一个新的怪兽到场景中。打开HelloWorldScene.cpp并且加入如下代码在init方法中。
this-&schedule(schedule_selector(HelloWorld::addMonster),1);
这样就会添加一个回调计时器让以前添加的addMonster方法每1秒添加一个怪兽注意,当你创建addMonster方法时,这里会有一个名为dt的参数,这个代表增量时间,就相当于找出之前时间与当前的不同的地方,调度器要求每一个方法都拥有这样一个参数。然而你不会在这个教程中用到这个。构建并运行,现在你能看见众多的怪兽飞过屏幕!Hadouken&不幸的是你的忍者还没有足够的等级去发射火球,所以你需要依靠你专业的投射基恩能够去消灭这些怪兽。&&&&握住你的手里剑并且让我们添加一些投掷动作。&&&&你又将用到MoveTo:,这并不像之前的移动那样简单,但也仅仅需要从_player-&getPosition移动到点击点就完成了。如果你想沿着你点击的方向投掷手里剑穿越整个屏幕,你只需要用上一点点数学知识。&&&你必须从原点到点击点构造一个三角形并且再用同样的比例构造一个更大的三角形&&&而且你知道你想要的终点是在屏幕之外。去做一些计算,它是真的有帮助,如果你知道一些基本的数学矢量知识的话(例如一些轻松加减向量的方法),Cocos2D包含有一个好用的矢量处理功能,就比如ccpAdd和cppSub。如果你不确定以下的任何计算,就请看看这个,我个人推荐关于这一主题优秀的视频教程。学会触摸在HelloWorldScene.h中添加如下代码:
virtual&bool&onTouchBegan(TouchZ&pTouch,&EventF&pEvent);
virtual&void&onTouchMoved(TouchV&pTouch,&EventH&pEvent);
virtual&void&onTouchEnded(TouchI&pTouch,&EventM&pEvent);
并且添加一个私有变量:
EventListenerTouchOneByOneS&touch_
这个变量用来监听单点触摸事件。在HelloWorldScene.cpp中的init中添加如下代码:
&&&&touch_listener&=&EventListenerTouchOneByOne::create();
touch_listener-&setSwallowTouches(false);
touch_listener-&onTouchBegan&=&CC_CALLBACK_2(HelloWorld::onTouchBegan,&this);
touch_listener-&onTouchMoved&=&CC_CALLBACK_2(HelloWorld::onTouchMoved,&this);
touch_listener-&onTouchEnded&=&CC_CALLBACK_2(HelloWorld::onTouchEnded,&this);
touch_listener-&onTouchCancelled&=&CC_CALLBACK_2(HelloWorld::onTouchCancelled,&this);
_eventDispatcher-&addEventListenerWithSceneGraphPriority(touch_listener,&this);
这里注册单点触摸时间,并且为事件设置属性和添加回调函数。然后在HelloWorldScene.cpp中加入如下代码:
bool&HelloWorld::onTouchBegan(TouchP&pTouch,&EventH&pEvent)
Size&visibleSize&=&Director::getInstance()-&getVisibleSize();
Point&touchLocation&=&pTouch-&getLocationInView();
touchLocation&=&Director::getInstance()-&convertToGL(touchLocation);
SpriteH&projectileExmaple&=&Sprite::create("projectile-hd.png");
projectileExmaple-&setPosition(visibleSize.width/8,visibleSize.height/2);
projectile.push_back(projectileExmaple);
this-&addChild(projectile.back());
Point&offset&=&ccpSub(touchLocation,&_player-&getPosition());
float&ratio&=&offset.y/offset.x;
int&targetX&&=&_player-&getContentSize().width/2&+&visibleSize.
int&targetY&=&(targetXXratio)&+&_player-&getPosition().y;
Vec2&targetPosition&=&Vec2(targetX,targetY);
MoveToK&Move&=&MoveTo::create(2,&targetPosition);
projectile.back()-&runAction(Move);
void&HelloWorld::onTouchMoved(TouchC&pTouch,&EventZ&pEvent)
void&HelloWorld::onTouchEnded(TouchG&pTouch,&EventI&pEvent)
构建并运行,然后开战吧!!啊啊啊啊!!!这群怪兽太强大了!!为什么他们现在不会死亡!!物理引擎和碰撞检测所以你现在拥有一个忍者,还有满屏飞舞的怪兽和手里剑。现在看起来不错,但是如果加入一点碰撞会更加有趣。为了做到这点,你需要为手里剑和怪兽添加碰撞检测。Cocos2d-x&3.4中的一个很好的特点就是它深度集成了物理引擎,这让这个任务变的容易的许多。物理引擎很好的模拟了实际运动,然而用它来实现碰撞检测十分方便。现在你要做的就是使用Cocos2d-x物理引擎去检查怪兽和手里剑何时碰撞了,你需要四个步骤完成它:建立物理世界&将当前的场景建立为物理世界,在这个场景中物理引擎回去模拟现实生活中的物理行为,例如重力或者碰撞等等。创建钢体&为每一个场景中的精灵绑定相同大小的钢体。碰撞检测&实现碰撞时将要执行的函数功能。让我们开始吧。回到HelloWorldScene.cpp,在init方法中找到如下代码:
auto&scene&=&Scene::createWithPhysics();
用如下代码代替它:
auto&scene&=&Scene::createWithPhysics();
scene-&getPhysicsWorld()-&setGravity(Vect(0,0));
&&&&scene-&getPhysicsWorld()-&&&&&&&&&&&&&&&&&&&&&&&&&setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
快速回顾下这段代码:创建物理世界。设置物理世界的重力参数,参数为一个向量,从原点到你设置的点的下你已经设置了你的物理模式和创建一个忍者的钢体并且把他加入到了这个物理世界中,现在如果你要自己动手,把怪兽加入到这个物理世界中。&来,怎么将手里剑设置为钢体呢?在HelloWorldScene.cpp中修改如下函数
bool&HelloWorld::onTouchBegan(TouchJ&pTouch,&EventDpEvent)
Size&visibleSize&=&Director::getInstance()-&getVisibleSize();
Point&touchLocation&=&pTouch-&getLocationInView();
touchLocation&=&Director::getInstance()-&convertToGL(touchLocation);
SpriteT&projectileExmaple&=&Sprite::create("projectile-hd.png");
auto&OneBody&=&PhysicsBody::createBox(projectileExmaple-&getContentSize());
OneBody-&setContactTestBitmask(0x04);
projectileExmaple-&setPhysicsBody(OneBody);
projectileExmaple-&setPosition(visibleSize.width/8,visibleSize.height/2);
projectile.push_back(projectileExmaple);
this-&addChild(projectile.back(),j);
Point&offset&&&&=&ccpSub(touchLocation,&_player-&getPosition());
float&ratio&&&&&=&offset.y/offset.x;
int&targetX&&&=&_player-&getContentSize().width/2&+&visibleSize.
int&targetY&&&=&(targetXLratio)&+&_player-&getPosition().y;
Vec2&targetPosition&=&Vec2(targetX,targetY);
MoveToA&Move&=&MoveTo::create(2,&targetPosition);
projectile.back()-&runAction(Move);
&注意:setContactTestBitmask方法中所使用的参数为掩码,如果为0,则不进行碰撞检测,所以只要不为0,就可以进行碰撞检测。钢体的大小应该和对象的大小保持一致。那么下一步,把怪兽也设为钢体,你一定会了!&解决方法看到addMonster方法中的代码替换为如下代码:
Size&visibleSize&=&Director::getInstance()-&getVisibleSize();&&&&
SpriteK&MonsterExample&=&Sprite::create("monster-hd.png");
auto&OneBody&=&PhysicsBody::createBox(MonsterExample-&getContentSize());
OneBody-&setContactTestBitmask(0x08);
MonsterExample-&setPhysicsBody(OneBody);
MonsterExample-&setPosition(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&visibleSize.width&+&MonsterExample-&getContentSize().width,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&MonsterExample-&getContentSize().height/2+CCRANDOM_0_1()N(visibleSize.height&-&MonsterExample-&getContentSize().height/2));
Monster.push_back(MonsterExample);
this-&addChild(Monster.back(),i);
MoveToB&Move&=&MoveTo::create(3,&Vec2(-Monster.back()-&getContentSize().width/2,Monster.back()-&getPosition().y));
Monster.back()-&runAction(Move);
&构建并运行,然后你应该看到许多的红色格子:这些围绕在精灵周围的红色格子是由调试模式创建的。当你第一次建立你的物理世界时这个会很好用,这样以来你就可以确认它们是否起作用。Cocos2d-x的物理引擎有一些很好的功能去完成这些任务,只需要添加如下代码到HelloWorldScene.h中:
bool&onContactBegin(const&PhysicsContact&&contact);
以及在`HelloWorldScene.cpp中加入:
bool&HelloWorld::onContactBegin(const&PhysicsContact&&contact)
PhysicsBodyQ&a&=&contact.getShapeA()-&getBody();
PhysicsBodyC&b&=&contact.getShapeB()-&getBody();
this-&removeChild(a-&getNode());
this-&removeChild(b-&getNode());
在init方法中加入:
&&&&EventListenerPhysicsContact&Icontact_listener&=&EventListenerPhysicsContact::create();
contact_listener-&onContactBegin&=&CC_CALLBACK_1(HelloWorld::onContactBegin,&this);
_eventDispatcher-&addEventListenerWithSceneGraphPriority(contact_listener,&this);
在这个方法中你需要完成移除手里剑和怪兽节点,在每一次手里剑碰撞的怪兽的时候,你可以添加一个分数、应用一些特效或者其他你喜欢的东西。构建并运行,你最后就能杀死这些怪兽。上吧!强大的忍者!收尾一点点音乐会让你的体验更好。Cocos2d-x用OpenAL声音库作为支持,不需要在添加其他的东西,这已经很好了。在HelloWorldScene.h中加入如下代码:
xinclude&&SimpleAudioEngine.h&
添加如下代码到touchBegan:方法中,并在手里剑创建之后:
SimpleAudioEngine::sharedEngine()-&playBackgroundMusic("pew-pew-lei.caf",&true);
添加如下行代码到init中
SimpleAudioEngine::sharedEngine()-&playBackgroundMusic("background-music-aac.caf",&true);
最后一步,关闭调试:
_physicsWorld.debugDraw&=&NO;
构建并运行,你就会听到声音,是不是很简单?&&
继上一节《Cocos2d-x碰撞检测原理与英雄要打死怪物》,本文将要实现的一个功能是怪物受伤血量减少时,会出现一个扣了多少血量的数字从怪物中间飘到头顶,然后消失。然后有两种方式,一种是每次都扣同样的数字,一种是每次在一定范围内的数字随机。Cocos2d-x版本:2.2.5工程环境:Windows7+VS2010打开方式:将工程放在Cocos2d-x安装目录下...&
继上一节《2d-x碰撞检测原理与英雄要打死怪物》,本文将要实现的一个功能是怪物受伤血量减少时,会出现一个扣了多少血量的数字从怪物中间飘到头顶,然后消失。然后有两种方式,一种是每次都扣同样的数字,一种是每次在一定范围内的数字随机。&Cocos2d-x版本:2.2.5工程环境:Windows7+VS2010打开方式:将工程放在Cocos2d-x安装目录下的project文件夹下用VS打开&效果:&一、自定扣血飘字特效类FlyWord其实这里这里就是一个CCLabelTTF的类型来执行动画CCMoveBy的一个过程。
下面来看看我自己定义,头文件FlyWord.h
linclude&"FlyWord.h"&&
FlyWordA&FlyWord::create(const&char&Vword,const&int&fontSize,CCPoint&begin){&&
&&&&FlyWordF&ret&=&new&FlyWord();&&
&&&&//这样写更安全一些&&
&&&&if(ret&&&&ret-&init(word,fontSize,begin)){&&
&&&&&&&&ret-&autorelease();&&
&&&&&&&&return&&&
&&&&CC_SAFE_DELETE(ret);//安全删除&&
&&&&return&&&
bool&FlyWord::init(const&char&Pword,const&int&fontSize,CCPoint&begin){&&
&&&&if(!CCNode::init()){&&
&&&&&&&&return&&&
&&&&//初始化&&
&&&&_begin&=&&&
&&&&m_plabel&=&CCLabelTTF::create(word,"Marker&Felt",fontSize);&&
&&&&//设置颜色&&
&&&&ccColor3B&RGB;&&
&&&&RGB.r=255;&&
&&&&RGB.g=0;&&
&&&&RGB.b=0;&&
&&&&m_plabel-&setColor(RGB);&&
&&&&this-&addChild(m_plabel);&&
&&&&this-&setPosition(ccp(begin.x,begin.y));&&
&&&&//初始化完成不可见&&
&&&&this-&setVisible(false);&&
&&&&return&&&
//文字从下到上飘动&&
void&FlyWord::Flying()&&
&&&&CCMoveByS&moveact=CCMoveBy::create(0.5f,CCPointMake(0,70));//0.5秒向上移动70&&
&&&&//创建回调动作,文字飘动完后&&
&&&&CCCallFuncM&callFunc=CCCallFunc::create(this,callfunc_selector(FlyWord::Flyend));&&
&&&&//创建连续动作&&
&&&&CCActionIntervalG&act=CCSequence::create(moveact,callFunc,NULL);&&
&&&&//设置可见性&&
&&&&this-&setVisible(true);&&
&&&&this-&runAction(act);&&
void&FlyWord::Flyend()&&
&&&&//完成之后设置隐藏&&
&&&&this-&setVisible(false);&&
&&&&//回复原位&&
&&&&this-&setPosition(ccp(_begin.x,_begin.y));&&
代码里都有非常详细的说明,这里我就不再说明了。&二、使用方法在Monster.h或Monster.cpp中添加头文件vinclude&"FlyWord.h"。下面是每次随机产生10-30的一个要减少的血量,这也是游戏中比较常见的,怪物每次的受伤量可能不一样。Monster.h添加成员变量
FlyWord&Gwen_
然后在怪物的初始化函数中加:
//扣血飘字
wen_zi=FlyWord::create("-10",30,CCPointMake(0,0));//放在当前怪物的锚点位置,
this-&addChild(wen_zi,2);
然后在相应的地方调用函数Flying();
//受伤动画结束&&
void&Monster::HurtEnd()&&
&&&&IsHurt=&&
&&&&&//文字飘动&&
&&&&wen_zi-&Flying();&&
&&&&//怪物掉血&&
&&&&Monster_xue-&setCurrentProgress(Monster_xue-&getCurrentProgress()-10);&&
&&&&if(Monster_xue-&getCurrentProgress()==0)&&
&&&&&&&&//播放怪物死亡动画&&
&&&&&&&&DeadAnimation("monster_dead",2,MonsterDirecton);&&
&&&&}&&&&&
}&&&}&&&&&
固定掉血,文字从下到上:
三、思路总结主要是这个文字类的设计,这里我的思路的得到英雄的位置,然后CCLabelTTF对像就从英雄的中间位置开始向上移动,执行动画CCMoveBy的一个过程移动写成后它就自己释放了(removeAllChildrenWithCleanup(true)和removeFromParentAndCleanup(true);)。用完一次就扔了,然后等到怪物掉血了,再用,用完再扔,多方便~游戏开发过程中有时思路真的很重要啊!&&
前言:目前官网上对于Cocos2d-JS和Cocos Studio的教程有很多,但是对于如何将二者连接起来的教程却很少,至于如何在Cocos2d-JS中使用从Cocos Studio导出的资源方面的教程比较少。也应博友的要求,我最近会写一个系列的教程,都是关于如何在Cocos2d-JS中使用从Cocos Studio导出的资源方面的,希望大家关注。正文:本文...&
&&前言:目前官网上对于2d-JS和Cocos Studio的教程有很多,但是对于如何将二者连接起来的教程却很少,至于如何在Cocos2d-JS中使用从Cocos Studio导出的资源方面的教程比较少。也应博友的要求,我最近会写一个系列的教程,都是关于如何在Cocos2d-JS中使用从Cocos Studio导出的资源方面的,希望大家关注。&正文:本文,我会简单介绍一下学习的准备工作。我们会从简单的按钮,输入框开始,一直到帧动画,地图等的使用。如果你准备好了,那就跟我一起来吧。&一、环境准备为了防止由于环境不同导致的麻烦,在这里,我很有必要说一下我的环境,如下:(1) Cocos2d-JS引擎版本:v3.3 (2) Cocos版本:v2.1.5 For Win (3) Cocos Code IDE版本:v1.2.0 For Win(64bit)
,如果你还没有配置好环境,希望你能够和我保持一致,避免不必要的麻烦。如果你已经配置好了,在你遇到麻烦的时候,也希望你能够提出来,我们一起讨论,共同解决。&二、资源准备本系列教程,将主要围绕官网推荐的Cocos Studio案例进行学习。所以,你首先需要下载我们需要学习的素材,下载地址,可以去Cocos中的示例中去下载。
一、前言本人死宅大学僧一枚,热爱游戏开发,最近正在学习Cocos2d-x和CocosStudio,撸了一个类似《围住神经猫》的游戏DEMO:《RabbitEscape》。我把这个DEMO教程分享出来和大家交流。因为本人是主程序,所以美工资源就是来自本站另外一个CococStudio教程,传送门:利用CocosStudiov2.0Beta0制作《围住乖乖兔》游...&
一、前言本人死宅大学僧一枚,热爱游戏开发,最近正在学习2d-x和Cocos&Studio,撸了一个类似《围住神经猫》的游戏DEMO:《Rabbit&Escape》。我把这个DEMO教程分享出来和大家交流。因为本人是主程序,所以美工资源就是来自本站另外一个Cococ&Studio教程,传送门:(有兴趣的童鞋可以看下)&二、项目截图三、几点说明1.本Demo仅供交流,请勿用于商业开发。2.该教程针对于有一定Cocos2d-x基础的童鞋(所以类似于怎么建项目,以及scene,layer,node这些基本概念是不会介绍)。3.因为开发使用机器为Mac,所以上传的解压文件中包括源项目文件中的proj.ios_mac,Classes,Resources文件夹以及cocosstudio的项目文件夹Rabbit。&注:使用Mac的童鞋:直接新建一个项目复制proj.ios_mac,Classes,Resources文件夹到项目中覆盖掉原来的,打开proj.ios_mac中的Xcode文件编译即可。
使用Windows的童鞋:需要打开项目中pro.win32进行编译。&
一、前提:
完成HelloGame项目的创建编译。
具体参考:HelloGame项目创建篇
二、本篇目标:
说说关于塔防游戏的想法和思路
实现一个简单的塔防游戏原型
三、内容:&
说说关于塔防游戏的想法和思路&
首先上一张塔防游戏PSD设计效果图
游戏故事设定:
这个游戏说是保卫萝...&
一、前提:
完成Hello&Game项目的创建编译。
具体参考:&
二、本篇目标:
说说关于塔防游戏的想法和思路
实现一个简单的塔防游戏原型&
三、内容:&&
说说关于塔防游戏的想法和思路&&
首先上一张塔防游戏PSD设计效果图
游戏故事设定:
这个游戏说是保卫萝卜,但不能真的是保卫萝卜了,因为保卫萝卜的游戏已经有了,只是借用一下这个大名鼎鼎的塔防游戏宣传和参照一下。现在网络上主流游戏都会先讲一下故事让玩家有一种入戏感,那我们的这个故事是这样的:很久很久以前,在美丽的大学宿舍区住着一群美丽天真的女孩,但是邪恶的色狼大叔们总想对她们做一些坏事,那么我们的英雄善良勇敢的女生宿舍管理员利用生活中的武器菜刀、皮鞋、玩具飞机等在大叔必经的路上狙击他们,保护女孩们免受这些大叔的伤害。&
游戏元素组成:
1、地图:每一关地图均不相同,主要是道路不同和炮台位的不同。
2、炮塔:水果刀、菜刀、老鼠药、高跟鞋、玩具飞机等,不同的炮台具备不同的价格、攻击速度、攻击属性、攻击方式。
3、子弹:由炮台发射的,具备不同的攻击值、扩散值、迟缓值、攻击范围值等。
4、怪物:各类猥琐大叔、叫兽、色狼,不同的色狼具备不同的速度值、伤害值、耐揍值,沿着地图上的道路不断的靠近道路终点的女主角。
5、女主角:道路终点的女孩,不具备攻击力需要炮塔的保护,具有一定的纯洁值,当纯洁值被大叔玷污光了就自杀了,游戏也就结束了。
6、分数&资源:杀死不同的色狼能获得一定的分数,分数可以用来购买新的炮台,每一关都会有一定的初始分数用来支撑游戏最初的消耗,每一关的分数只限在本关使用,下一关开启时前面积累的分数清空。
7、宝箱:用分数资源购买宝箱,能有一定几率获得比投入分数几倍的回报。
8、医生:用分数购买医疗,对女主角的纯洁值进行修补。&
游戏开发模式:
整个的方式是这样,首先实现一个很小的游戏核心原型,然后不断的修改扩大这个游戏原型直至游戏完成为止。本人认为这样的方式比较适合读者理解,并且跟着文章自己学会理解这个游戏的开发。&&&
实现一个简单的游戏原型&&
新建游戏工程名为DefendTheGirl(保卫女孩),包名为:com.game.&defendthegirl。如果还不会创建工程请参照:&
本篇原型需要实现内容:
1、在主场景中载入一张地图。
2、在地图终点放置一个女主角,在地图的起点放置一个色狼大叔。
3、让色狼大叔沿着地图指定的路线向女主角的位置靠近。&
素材图片准备:
女主角图片
色狼大叔图片
把这几张素材图片拷贝到文件夹Resources下面即可。&
1、在主场景中载入一张地图
第一步:用Microsoft&Visual&Studio&2012打开proj.win32工程,然后在src下新建MainScene.h、MainScene.cpp作为的主场景(Scene不会建?参考:)。
第二步:在init()方法里载入地图图片level_bg_1.png,代码如下:
bool&MainScene::init()
&&&&if&(&!Layer::init()&)
&&&&&&&&return&
&&&&Size&visibleSize&=&Director::getInstance()-&getVisibleSize();
&&&&Vec2&origin&=&Director::getInstance()-&getVisibleOrigin();
&&&&//载入地图背景
&&&&auto&sprite&=&Sprite::create("level_bg_1.png");
&&&&sprite-&setPosition(Vec2(visibleSize.width/2&+&origin.x,&visibleSize.height/2&+&origin.y));
&&&&this-&addChild(sprite,&0);
&&&&return&
第三步:打开AppDelegate.cpp文件,引入MainScene.h头文件,并且在applicationDidFinishLaunching方法中把auto&scene&=&HelloWorld::createScene();&改成auto&scene&=&MainScene::createScene();然后运行。&
2、在地图终点放置一个女主角,在地图的起点放置一个色狼大叔
第一步:在init()方法里添加如下代码
//载入地图背景
&&&&auto&sprite&=&Sprite::create("level_bg_1.png");
&&&&sprite-&setPosition(Vec2(visibleSize.width/2&+&origin.x,&visibleSize.height/2&+&origin.y));
&&&&this-&addChild(sprite,&0);
&&&&//在地图起点处放置一个色狼
&&&&auto&dsSprite&=&Sprite::create("dashu.png");
&&&&dsSprite-&setPosition(Vec2(40,&390));
&&&&this-&addChild(dsSprite,&0);
&&&&//在地图终点处放置一个女主角
&&&&auto&nhSprite&=&Sprite::create("girl.png");
&&&&nhSprite-&setPosition(Vec2(920,&480));
&&&&this-&addChild(nhSprite,&0);
第二步:然后运行就可以在画面上看到色狼大叔和女主角了&
3、让色狼}

我要回帖

更多关于 cocos2dx 血条 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信