现在的位置: 首页 > 综合 > 正文

三国SLG手机网游技术分析

2013年10月13日 ⁄ 综合 ⁄ 共 19927字 ⁄ 字号 评论关闭

三国手机网游的技术分析

一、聊天

效果图

功能描述:玩家可以根据不同的频道,在输入框输入文字聊天,点击玩家名字可以私聊,在设置里面可以屏蔽对应的频道,文字内容有不同颜色,自动换行,输入屏蔽字后会自动屏蔽为***,可以插入表情,输入框文字超过显示宽度后会自动定位到当前输入位置。

 

技术难点:

1正确获取输入字符串长度

含有中英文数字的字符串比如String sz_str"a和",用sz_str.length()得到的字符长度是3,不正确,

使用下面的函数

static const
char
utf8_skip_data[256] = {

    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

    1, 1, 1, 1, 1, 1, 1,

    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

    1, 1, 1, 1, 1, 1, 1,

    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

    1, 1, 1, 1, 1, 1, 1,

    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

    1, 1, 1, 1, 1, 1, 1,

    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

    1, 1, 1, 1, 1, 1, 1,

    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

    1, 1, 1, 1, 1, 1, 1,

    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,2, 2, 2, 2, 2, 2, 2, 2, 2, 2,

    2, 2, 2, 2, 2, 2, 2,

    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,3, 4, 4, 4, 4, 4, 4, 4, 4, 5,

    5, 5, 5, 6, 6, 1, 1

};

static const
char
*constg_utf8_skip = utf8_skip_data;

#define cc_utf8_next_char(p) (char*)((p) + g_utf8_skip[*(unsigned
char *)(p)])

 

long StringUtil::cc_utf8_strlen (const
char * p, int max)

{

    long len =0;

    const char *start = p;

 

    if (!(p !=NULL || max == 0))

    {

        return0;

    }

    if (max <0)

    {

      while (*p)

    {

      p = cc_utf8_next_char (p);

      ++len;

    }

    }

    else

    {

        if (max== 0 || !*p)

        {

            return0;

        }

         p= cc_utf8_next_char (p);

         while (p - start < max && *p)

        {

          ++len;

          p = cc_utf8_next_char (p);

        }

          /* only do the last len increment if we got a complete

           * char (don't count partial chars)

           */

          if (p - start == max)

         {

             ++len;

         }

    }

    return len;

}

int ilength = StringUtil::cc_utf8_strlen(str.c_str(),-1);可以正确得到输入的字数

2屏蔽敏感字

逻辑实现:定义一个屏蔽字工具类,同时通过使用extern CReadBadWords g_CReadBadWords;实现全局调用该类,其中定义2个函数,分别为读取字库ReadWords,替换字符串ReplaceBadWords;

根据策划提供的敏感字库,txt文件,在创建登录游戏窗口的时候读取txt文件,把每一行读取的内容存储到向量中, 然后在输入文字的时候点击"确定"按钮后就开始检查是否有敏感字。

性能优化:

(1)内存优化

在读取txt文件时使用

         ifstream fin(BADWORDS);

         const int WORD_LENGTH= 128;

         char *szStr = new char[WORD_LENGTH]; 

         memset(szStr, 0, sizeof(szStr));

         while(!fin.eof())

         {                     

                   fin.getline(szStr, WORD_LENGTH, '\n');

/*               m_vcWords.push_back(szStr);          */

                   m_listWords.push_back(szStr);

                   szStr = new char[WORD_LENGTH];

                   memset(szStr, 0, sizeof(szStr));

         }

         fin.close();

         delete []szStr;

在模拟器上运行速度很快,正常,但是在手机上运行的时候就会出现闪退,分析后发现是在手机上长时间操作文件会导致内存增加很多,解决思路是把文件内容一次性加载到内存中,避免长时间操作文件,修改后的程序如下: 

FILE* pFile;

         long lSize;

         char *pszbuffer;

         size_t result;

         pFile = fopen ( BADWORDS, "rb" );

         if (pFile==NULL)

         {

                   return;

         }

         //obtain file size:

         fseek (pFile , 0 , SEEK_END);

         lSize = ftell (pFile);

         rewind (pFile);

         //allocate memory to contain the whole file:

         pszbuffer = (char*)malloc (sizeof(char)*lSize);

         if (pszbuffer== NULL)

         {

                   return;

         }

         //copy the file into the buffer:

         result = fread(pszbuffer,1,lSize,pFile);

         if (result !=lSize)

         {

                   return;

         }

         /*the whole file is now loaded in the memory buffer. */

         char * pszch;

         pszch = strtok (pszbuffer,"\n");

         m_listWords.push_back(pszch);

         while (pszch !=NULL)

         {

                   pszch = strtok (NULL, "\n");

                   if(pszch!= NULL)

                   {

                            m_listWords.push_back(pszch);

                   }

         }

         //terminate

         fclose (pFile);

         free (pszbuffer);

但是在android手机上还是不行,查找资料分析后发现Android手机系统默认是UTF8,

换行符是"\r\n");而不是"\n"

(2)使用高级匹配算法,因为字库内容有1w5千条,担心在读取或者查找匹配敏感字时候会太慢,导致在android平台上程序长时间无法响应,出现ANR现象退出程序,

尝试了

AC多模匹配(AC自动机),sunday算法,kmp算法,trietree

尝试上面算法后发现速度并没有明显提高,改为用最普通的循环,降低了程序的复杂度,速度也能达到满意的效果

上面2个问题具体实现如下:

voidCReadBadWords::ReadWords(vector<string> & vc_words)

{

    //获得文件在系统的绝对路径

    constchar *pFileName = BADWORDS;

    constchar *pPath =CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(pFileName);

    if(pPath== NULL)

    {

       return;

    }

    //读取的字节数,读取失败则为0

    unsignedlong len = 0;

    //读取的内容

    unsignedchar *pszbuffer = CCFileUtils::sharedFileUtils()->getFileData(pPath,"rb", &len);

    if(pszbuffer== NULL)

    {

       return;

    }

    char*pszch= strtok ((char *)pszbuffer,"\r\n");

    if(pszch!=NULL)

    {

       stringstrContent(pszch);

       vc_words.push_back(strContent);

    }

    while(pszch!=NULL)

    {

       pszch= strtok (NULL, "\r\n");

       if(pszch!=NULL)

       {

           stringstrContent(pszch);

           vc_words.push_back(strContent);

       }

    }

    //记得释放内存

    if(len>0 && pszbuffer) delete[] pszbuffer;

}

 

void CReadBadWords::ReplaceBadWords(string& strWords)

{

    if(strWords.empty()|| strcmp(strWords.c_str(), "") == 0)

    {

       return;

    }

    if(!m_vcWords.empty())

    {

       for(inti=0; i<m_vcWords.size(); i++)

       {

           StringUtil::replace_all_distinct(strWords,m_vcWords.at(i), "***");

       }

    }

}

 

//替换指定字符串中出现的字符串,返回处理后的字符串

voidStringUtil::replace_all_distinct(string&  str,const   string&   old_value,const   string&  new_value)  

{  

    for(string::size_type   pos(0);  pos!=string::npos;  pos+=new_value.length())   {  

       if(  (pos=str.find(old_value,pos))!=string::npos   )  

           str.replace(pos,old_value.length(),new_value);  

       else   break;  

    }  

 

 

3输入框文字超过指定长度的时候会超出显示,比如输入框背景图是500,输入的文字宽度是600,那么会超出100显示,

解决办法:裁剪输入框控件的可视区域和显示宽度一样宽

4文字换行时需要截取指定长度的含有中英文的字符串

方法一根据中文在ASCII中的范围判断
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
 
int _tmain(int argc, _TCHAR* argv[])
{
string s = "
你好CSDN,我的";
string t;
for(int i=0; i<s.length(); i++)
{
if(s<255 && s>0)//
扩充的ASCII字符范围为0-255,如是,处理一个字节
{
t.append(s.substr(i,1));
t.append("/");
}
else//<0,>255
的是汉字,处理两个字节
{
t.append(s.substr(i,2));
t.append("/");
++i;
}
}
cout << t << endl;//
输出符合要求
return 0;
}

方法二string转成wstring

wstring str2wstr(string str)
{
    size_t len = str.size();
    wchar_t * b = (wchar_t *)malloc((len+1)*sizeof(wchar_t));
    MBCS2Unicode(b,str.c_str());
    wstring r(b);
    free(b);
    return r;
}

string wstr2str(wstring wstr)
{
    size_t len = wstr.size();
    char * b = (char *)malloc((2*len+1)*sizeof(char));
    Unicode2MBCS(b,wstr.c_str());
    string r(b);
    free(b);
    return r;
}

 

方法三 把string转成UTF8编码格式,然后再转成Unicode

wchar_t *UTF8ToUnicode( const char* str )
{
     int textlen ;
     wchar_t *result;
     textlen =MultiByteToWideChar( CP_UTF8, 
0, str,-1,
NULL,
0 ); 
     result =(wchar_t *)malloc((textlen+
1)*sizeof(wchar_t)); 
     memset(result,
0,(textlen+1)*sizeof(wchar_t)); 
    MultiByteToWideChar(CP_UTF8, 
0,str,-1,(LPWSTR)result,textlen
); 

     return result; 
}

char *UnicodeToUTF8( const wchar_t* str )
{
     char* result;
     int textlen;
     textlen =WideCharToMultiByte( CP_UTF8, 0, str, -1,
NULL, 
0, NULL, NULL );
     result=(char *)malloc((textlen+
1)*sizeof(char));
     memset(result, 
0, sizeof(char) * (textlen + 1 )
);

     WideCharToMultiByte(CP_UTF8, 
0, str, -1,
result, textlen, NULL, NULL );

     return result;

}

尝试后上面3种方法在电脑上都可以正常运行,但是在android手机上不行,分析后发现android的操作系统默认是UTF8编码,尝试了用UTF8中中英文所占字节,比如中文判断位数是2位,3位,4位,还是不行,程序如果没有正确截取对,同时,android的容错性比较差,会导致闪退,查看CCLabelIBMFont后,尝试了cc_utf8_strlen,cc_utf8_next_char

解决问题,具体实现如下:

void XLabelView::getStrByLen(intiLen , string strSource ,
int iFontSize, string&szDes1, string &szDes2)

{

    strSource =CG2U::g2u(strSource.c_str()).c_str();

    string strText = strSource;

    LPCSTR source = strSource.c_str();

    int ilength= StringUtil::cc_utf8_strlen(source, -1);

    LPCSTR target = source;

    char buf[16]= {0};

    memset(buf, 0, sizeof(buf));

    int width =0;

    int k=0;

    for(int i =0; i<ilength; i++)

    {

        source = cc_utf8_next_char(target);

        memset(buf, 0, sizeof(buf));

        memcpy(buf, target, source - target);

        k+= strlen(buf);

        CCLabelTTF* pLabelTTF =  CCLabelTTF::create(buf, m_fontName,iFontSize);

        width +=pLabelTTF->getContentSize().width;

        if(width> iLen)

        {

            szDes1 = strText.substr(0, k);

            szDes2 = strText.substr(k);

            return;

        }

        target = source;

    }

    return;

}

5文字换行

逻辑实现:文字显示的控件都带有前后指针,Front,next分别指向前后一个控件;根据输入的字符串显示宽度和指定宽度比较,如果超出指定宽度,就把指定宽度的字符串所在的显示控件都保持X坐标不变,Y坐标向上平移,继续显示下一行的文字

具体实现如下

   

    //前面的Item位置往上升

                XLineItem* pItem = lineItem;

                CCPoint pt =pItem->getPosition();

                while(pItem != NULL)

                {

                    pt =pItem->getPosition();

                    //根据是否有图片LineItem抬高的高度不同

                    if(isHasImg)

                    {

                        pt =ccpAdd(pt,ccp(0,iHight));

                    }

                    else

                    {

                        pt = ccpAdd(pt,ccp(0,pItem->GetContentSize().height));

                        if(pItem->GetBackGroundBitmap()!=NULL)

                        {

                            pt =ccpAdd(pt,ccp(0,iHeightTmp));

                        }

                    }

                    pItem->setPosition(pt);

                    pItem = pItem->m_pFront;

                }      

 

6发送接收信息

实现原理:把输入的字符串按照下面的格式组装,然后发送,接收到后用TinyXml解析

<msg>

<ch font="字体名称" fontsize ="字体大小" fontcolor = "字体颜色"IsP="是否私聊标志">频道名称内容</ch>

<S font="字体名称" fontsize ="字体大小" fontcolor = "字体颜色">发送者用户名</S>

<n font="字体名称" fontsize ="字体大小" fontcolor = "字体颜色">接收者用户名</n>

<t font="字体名称" fontsize ="字体大小" fontcolor = "字体颜色">文本内容</t>

<img>图片地址</img>

</msg>

 

7玩家名字添加下划线

具体实现:

void XLineItem::setUnderLineColor(ccColor4Bcolor)//设置下划线颜色

{

    CCLayerColor*clayercolor = CCLayerColor::create(color);

    clayercolor->setPosition(ccp(m_pLabelTTF->getPositionX(),m_pLabelTTF->getPositionY()-0.5));

    clayercolor->setContentSize(CCSizeMake(m_pLabelTTF->getContentSize().width,3));

    m_pLabelTTF->addChild(clayercolor,1);

}

 

二、整个系统音效

音效主要分为战斗音乐(战斗中攻击的技能和普通攻击音效),非战斗音乐(比如抽奖,点击按钮,箱子开启等)

实现思路:

设计2张声音配置XML,

Soundsource.XML

内容简介

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

<sounds>

<!--游戏中所有声音的配置,用于预加载声音,sound.xml中的声音以这里的为主-->

<sound id= "1" name=  "login.ogg"   />

<sound id= "2" name=  "clickbtn.ogg"    />

 

sound.xml

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

<!--id 如果是战斗的技能,ID就是和配置表一致,其他的是自定义; soundname1声音文件名;soundname2声音文件名;soundname3声音文件名;-->

<sounds>

<sound id= "1" soundname1=   "clickbtn.ogg"    soundname2=""     soundname3=""     />

<sound id= "2" soundname1=   "choujiang.ogg"   soundname2=""     soundname3=""     />

<sound id= "15"   soundname1=   "zhuchengkejishenjiok.ogg"  soundname2=""     soundname3=""     />

<sound id= "0" soundname1=   "jinzhanputong.ogg"  soundname2=   ""  soundname3=    "arrow_normal.ogg"   />

<sound id= "98"   soundname1=   "jinzhanputong.ogg"  soundname2=   ""  soundname3=   ""  />

<sound id= "99"   soundname1=   "fashiputong.ogg" soundname2=   ""  soundname3=   ""  />

 

在游戏启动时解析上面的xml内容,加载到全局数据配置类中,

设计一个声音工具类,底层封装了cocos2dx的SimpleAudioEngine对应函数,比如下面的

unsigned intSoundUtil::playEffect(LPCSTR pszFilePath)

{

    if(!IsEnableEffectMusic())

    {

        return-1;

    }

    if(pszFilePath== NULL)

    {

        return-1;

    }

    LPCSTR pStr =CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(pszFilePath);

    if(pStr ==NULL)

    {

        return-1;

    }

    returnCocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect(pszFilePath);

}

其中boolSoundUtil::IsEnableEffectMusic()

{

    returnm_bEnableEffectMusic;

}

是游戏启动时从CCUserDefault中读取的是否播放音乐的选项内容

 

性能优化:考虑声音是加载到内存中,尽可能减少内存的占用量,所以只在需要使用时提前加载对应的声音,使用完后切换到其他窗口时卸载声音,

 

技术难点

1卸载音效和播放音效之间的切换

在播放音效前,卸载上一个音效,结果导致音效无法播放,分析后发现卸载音效后要过一段时间才能播放音效,改为在每个播放音效的类中的析构函数卸载对应的音效,在构造函数中加载对应的音效,然后在使用音效时直接调用播放函数,同时也解决了每次第一次播放音效的时候无法播放的问题

2播放战斗时,声音和动画无法同步

尝试过在runAction之前和之后播放声音,都无法实现同步,分析后在CCSequence::create中添加回调函数CCCallFunc::create(this,callfunc_selector(CFightPlay::PlayEffectMusic)),即可解决

3按手机音量键调节声音大小

在android平台上的实现:

监听音量键,调用对应的声音工具类

    @Override

    public
boolean
onKeyDown(int keyCode, KeyEvent event) {

        AudioManager mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);

        intcurrentVolume =
mAudioManager

                .getStreamVolume(AudioManager.STREAM_MUSIC);

        switch (keyCode){

        case KeyEvent.KEYCODE_VOLUME_UP://
音量增大

            mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,

                    currentVolume + 1, 1);

            break;

        case KeyEvent.KEYCODE_VOLUME_DOWN://
音量减小

            mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,

                    currentVolume - 1, 1);

            break;

        default:

            break;

        }

        return
true
;

        // returnsuper.onKeyDown(keyCode, event);

    }

 

三 背包

效果图

功能描述:玩家有5个背包和一个VIP背包,显示所有物品,包括装备,法器,碎片,点击对应装备,在右边显示对应的信息,可以出售,使用,自动整理背包排序,

 

 

技术难点

1自动整理背包排序

实现思路:先获取所有物品存储到向量中,然后根据物品的穿戴等级,品质,装备(兵器,防具,坐骑,兵书等)进行比较,然后再进行排序

具体实现:

获取所有物品

vector<IContainerGoods*>CPackSackWnd::__GetAllGoods()

{

    vector<IContainerGoods*>v_AllGoods;

    //普通背包

    IContainer*pContainer = m_pPacketContainer;

    if(pContainer == NULL)

    {

       returnv_AllGoods;

    }

    intiSize = pContainer->GetSize();

    for(intiIndex=0; iIndex < iSize; iIndex++)

    {

       IContainerGoods*pContainerGoods = pContainer->GetGoods(iIndex);

       if(pContainerGoods== NULL)                            

       {

           continue;

       }

       v_AllGoods.push_back(pContainerGoods);

    }

    //VIP背包

    pContainer= m_pVipPacketContainer;

    if(pContainer == NULL)

    {

       returnv_AllGoods;

    }

    iSize= pContainer->GetSize();

    for(intiIndex=0; iIndex < iSize; iIndex++)

    {

       IContainerGoods*pContainerGoods = pContainer->GetGoods(iIndex);

       if(pContainerGoods== NULL)                             

       {

           continue;

       }

       v_AllGoods.push_back(pContainerGoods);

    }

    returnv_AllGoods;

}

根据条件比较

bool greatermark(IContainerGoods*pContainerGoods1,IContainerGoods* pContainerGoods2)

{

    //穿戴等级

    if(pContainerGoods1->GetPropNum(en_Goods_PropID_NeedLevel)> pContainerGoods2->GetPropNum(en_Goods_PropID_NeedLevel))

    {

       returntrue;

    }

    elseif(pContainerGoods1->GetPropNum(en_Goods_PropID_NeedLevel) <pContainerGoods2->GetPropNum(en_Goods_PropID_NeedLevel))

    {

       returnfalse;

    }

    //品质

    if(pContainerGoods1->GetPropNum(en_Goods_PropID_Quality)> pContainerGoods2->GetPropNum(en_Goods_PropID_Quality))

    {

       returntrue;

    }

    elseif(pContainerGoods1->GetPropNum(en_Goods_PropID_Quality) <pContainerGoods2->GetPropNum(en_Goods_PropID_Quality))

    {

       returnfalse;

    }

    //装备

    UIDuidGoods1 = pContainerGoods1->GetUID();

    IThing*pThing1 = g_GlobalClient.GetThingByUID(uidGoods1);

    if(pThing1 != NULL && pThing1->GetThingClass()->IsEquipment())

    {

       UIDuidGoods2 = pContainerGoods2->GetUID();

       IThing*pThing2 = g_GlobalClient.GetThingByUID(uidGoods2);

       if(pThing2 != NULL && pThing2->GetThingClass()->IsEquipment())

       {

           if(pContainerGoods1->GetPropNum(en_Goods_PropID_SubClass)> pContainerGoods2->GetPropNum(en_Goods_PropID_SubClass))

           {

              returntrue;

           }

           elseif(pContainerGoods1->GetPropNum(en_Goods_PropID_SubClass) <pContainerGoods2->GetPropNum(en_Goods_PropID_SubClass))

           {

              returnfalse;

           }

       }

    }

    returnfalse;

};

对物品排序

void CPackSackWnd::__Sort()

{

    m_AllGoods= __GetAllGoods();

    if(m_AllGoods.empty())

    {

       return;

    }

    sort(m_AllGoods.begin(),m_AllGoods.end(), greatermark);

}

四布阵

五新手引导

创建手指箭头

functionLUA_Create_ArrowFinger(pDirection,iPosX, iPosY, iWidth, iHeight)  ---------pDirection  0 up 1 down 2 left 3 right

   pArrowSprite = CCSprite:create(fingerStr)

   pArrowSprite:setAnchorPoint(ccp(0.5,0.5))

   local ASwidth = pArrowSprite:getContentSize().width

   local pos = nil

   if(pDirection == 0) then

       pArrowSprite:setRotation(90)

       pArrowSprite:setFlipY(true)

       pArrowSprite:setPosition(ccp(iPosX+iWidth/2,iPosY-ASwidth/2-10))

       pos=ccp(0,10)

   end

   if(pDirection == 1) then

       pArrowSprite:setRotation(-90)

       pArrowSprite:setPosition(ccp(iPosX+iWidth/2,iPosY+iHeight+ASwidth/2+10))

       pos=ccp(0,-10)

   end

   if(pDirection == 2) then

       pArrowSprite:setRotation(0)

       pArrowSprite:setPosition(iPosX+iWidth+ASwidth/2+10,iPosY+iHeight/2)

       pos = ccp(-10,0)

   end

   if(pDirection == 3) then

       pArrowSprite:setFlipX(true)

       pArrowSprite:setPosition(iPosX-ASwidth/2-10,iPosY+iHeight/2)

       pos = ccp(10,0)

   end

   if(pos == nil) then

       return

   end

   pActionMove = CCMoveBy:create(0.5,pos)

   pActionBack = pActionMove:reverse()

   pSequenMoves = CCSequence:createWithTwoActions(pActionMove,pActionBack)

   pArrowSprite:runAction(CCRepeatForever:create(pSequenMoves))

   return pArrowSprite

end

 

创建遮罩层,整个屏幕只有下面的矩形区域才可以点击,并且可以传递回调函数

--------------------遮罩层--------------------------------

function LUA_CreateShadeLayer20(iPosX,iPosY, iWidth, iHeight, functionCallBack)

   cclog('LUA_CreateShadeLayer')

    localpLayerShade = CCLayer:create()

    localsRect = LUA_GetThroughRect20()

    if(sRect~= nil) then

         cclog('sRect ~= nil')

         return nil

    end

    sRect= CCRectMake(iPosX*fScanX, iPosY*fScanY, iWidth*fScanX, iHeight*fScanY)   

    LUA_SetThroughRect20(sRect)

    localfunction onTouchBegan(x, y)

        sRect = LUA_GetThroughRect20()

         if(sRect == nil) then

            return 0

         end

        local sPoint = ccp(x, y)

        cclog('onTouchBegan:(x='..x..',y='..y..')')

       if(sRect:containsPoint(sPoint) == true) then  

           cclog('in sRect')            

           if(functionCallBack ~= nil and type(functionCallBack) == 'function')then

               functionCallBack()

            end

           return 0

       else        

           return 1

       end  

    end

    localfunction onTouchMoved(x, y)

    end

    localfunction onTouchEnded(x, y)    

       return

    end

    localfunction onTouch(eventType, x, y)

       ifeventType == CCTOUCHBEGAN then

           returnonTouchBegan(x, y)

       elseifeventType == CCTOUCHMOVED then

           returnonTouchMoved(x, y)

       else

           returnonTouchEnded(x, y)

       end

    end

    pLayerShade:setTag(iLayerTag)

    pLayerShade:registerScriptTouchHandler(onTouch,false, -128, true)

    pLayerShade:setTouchEnabled(true)

    returnpLayerShade

end

 

 

 

六退出游戏对话框,调用android平台的原生对话框

技术难点

1cocos2dx jni和android之间的交互

实现步骤

(1)在android项目中的mainActivitiy创建一个handler,并且在handler处理信息中创建一个对话框

    private Handler
mHandler
= new Handler(){

        @Override

        public
void
handleMessage(Message msg) {

 

            switch (msg.what) {

            case SHOW_DIALOG:

                newAlertDialog.Builder(sanguo0524.this)

                        .setTitle("退出游戏")

                        .setMessage("是否退出游戏?")

                        .setNegativeButton("取消",

                                new DialogInterface.OnClickListener(){

 

                                    @Override

                                    public
void
onClick(DialogInterface dialog,

                                            int which) {

                                        dialog.dismiss();

                                    }

                                })

                        .setPositiveButton("确定",

                                newDialogInterface.OnClickListener() {

 

                                    @Override

                                    public
void
onClick(DialogInterface dialog,

                                            int which) {

                                        dialog.dismiss();

                                        XJniHelper.exitApp();

                                    }

                                }).create().show();

                break;

            }

        }

    };

(2)创建一个工具类,提供原生函数的声明,handle接收来自C++层面的消息处理函数

public
class
XJniHelper {

    private
static
Handler mHandler;

    public
static
native
void
exitApp();

   

    public
static
void
init(Handler handler) {

        XJniHelper.mHandler =handler;

    }

   

    private
static
void
showTipDialog(final String title,
final Stringtext)

    {

    Messagemsg = mHandler.obtainMessage();

    msg.what =sanguo0524.SHOW_DIALOG;

    msg.sendToTarget();

    }

}

 

3在cocos2dx项目中,在每个场景类里面添加判断是否android平台

#if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)

#include "../proj.android/jni/hellocpp/ExitGameDialog.h"

#endif

并实现CCLayer的监听返回键函数

virtual void            keyBackClicked();                   //接收手机返回按钮事件

void CAreaScene::keyBackClicked()//接收手机返回按钮事件

{

    #if(CC_TARGET_PLATFORM ==CC_PLATFORM_ANDROID)

        showTipDialog("退出窗口","是否退出游戏?");

    #endif

    #if (CC_TARGET_PLATFORM== CC_PLATFORM_IOS)

        exit(0);

    #endif

}

其中showTipDialog函数是和android项目中对应的调用接收信息,显示对话框的函数

 

5在ExitGameDialog.h中定义showTipDialog和Java_com_xy_sanguo_uc_XJniHelper_exitApp

6在XJni.h中定义退出游戏函数

void exitApp()

{

    CCDirector::sharedDirector()->end();

}

 

 

七抽奖

通过改变schedule的时间实现慢,快,慢的转动效果

if(m_iRandNum <5)  
//
y

    {

        schedule(schedule_selector(CActivityLotteryWnd::__ChangeImgBrightness),3 * 0.1);

    }

    else if(m_iRandNum >=5 && m_iRandNum <20)//¨¬

    {

        schedule(schedule_selector(CActivityLotteryWnd::__ChangeImgBrightness),5 * 0.01);

    }

    else if(m_iRandNum >=20)//¨¬

    {

        schedule(schedule_selector(CActivityLotteryWnd::__ChangeImgBrightness),3 * 0.1);

    }

    

抱歉!评论已关闭.