• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            colorful

            zc qq:1337220912

             

            cocos2dx使用了第三方庫照樣移植android平臺-解決iconv庫的移植問題

            http://www.cocoachina.com/bbs/read.php?tid=195310
            當我寫這篇文章的時候我是懷著激動的心情的,因為我又解決了一個技術問題。你可能對題目還一知半解,這是什么意思,我之所以要寫這篇文章就是要解決當我們在cocos2dx中使用了第三方庫的時候,移植到android平臺的過程中是會報錯的問題,典型的例子就是我在上幾篇博客中使用了編碼轉換的庫iconv,在我移植到android平臺測試的時候就出現了錯誤,各種各樣的錯誤,網上搜了一下,但是網上的方法感覺都很老了,有的也沒說明白,今天通過摸索馬上分享給大家,讓大家也少走歪路。


            如 果你還不會移植android平臺,請先看我上一篇的博客,先換個其他的不包含iconv庫的工程,移植成功了再來做今天的事情。今天我們不需要準備任何 工具,需要做的就是理解.mk文件的含義,知道怎么改。我們先來看一下我字體和字符編碼這篇博客GBKToUTF8的頭文件是怎么包含iconv庫的。


            1
            2
            3
            4
            5
            #if(CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
            #include "iconv\iconv.h"
            #else
            #include "../../../../libiconv/include/iconv.h"
            #endif


            如果是win32平臺的話就用引擎里邊的第三方庫,這個iconv庫所在的路徑是:
            E:\cocos2d-x-2.2\cocos2d-x-2.2\cocos2dx\platform\third_party\win32\iconv。但如果是移植到android平臺的你需要加上你android平臺的庫的路徑,也就是說你需要先下載好iconv的庫,放到一個你的路徑,這里我放到的是我引擎的根目錄下,所以寫的就是上邊的代碼,大家下去下載這個庫,然后按我說的改了代碼。然后我們就來看看這個.mk文件改怎么改,我們要修改的是jni目錄下的.mk文件,我先截上幾張圖片,說說里邊代碼的含義。

            上邊的這張圖片網上有不少的教程都說需要修改,但在我看來根本不是,因為當我在這里加了iconv.h的路徑以后編譯的時候任然報錯,說找不到iconv.h這個文件。所以以后大家也不要改這里,沒用的。


            上 邊的第一張圖片看到了劃線的地方了嗎?這個是我加上去的,你需要改嗎?答案是需要的,但是名字可以和我不一樣,那名字改成什么樣的呢,這得看另一個文件 了,我們等等再說。上面的第二張圖片那個劃線的地方也是我加上去的,你也需要修改,改成什么也需要看另一個文件。好了現在我們就來說到底看哪個文件。這個文件就是你下載的iconv庫的根目錄下的Android.mk文件,我再來截張圖。

            這個是文件中的倆句話,你要和上邊我說的改的那倆個地方對照起來改。好了其實就是這么簡單,Android.mk文件只需要對照的改上倆個地方就可以了,程序中的那個頭文件包含也要修改。現在我們就來導入到工程中構建一下工程吧。在構建的時候也會出現一個問題,我想這個問題的原因可能是因為iconv庫里邊實現的函數不一樣吧,出現的錯誤的語句是這句:
            1
            -1 == iconv(iconvH, pin, &strLength, &outbuf, &outLength)

            我們需要做如下的修改,就是在pin的前邊加個強轉,因為Android下函數需要傳入的參數是char**,而我們程序中的pin是const char **類型的。


            1
            -1 == iconv(iconvH, (char **)pin, &strLength, &outbuf, &outLength)

            有了以上的這些操作問題就解決了,這里提醒一下大家,在eclipse中構建工程的時候如果可以編譯通過了,但是工程中有錯誤提示(其實是沒有錯誤的,也不知道這個eclipse是怎么回事),大家就重新導入工程一遍,問題就解決了,還有什么問題就給我留言吧。
            本帖有小塔原創,轉載請注明出處!

            android 下添加iconv支持

            NDK自帶的iconv的 查看 android-ndk-r9d/sources/android/support/include/iconv.h

            在Android.mk中加入
            LOCAL_WHOLE_STATIC_LIBRARIES += android_support

            $(call import-module,android/support)


            如:

            LOCAL_PATH := $(call my-dir)

            include $(CLEAR_VARS)
            LOCAL_MODULE := mylib
            LOCAL_SRC_FILES := mylib.cpp

            LOCAL_WHOLE_STATIC_LIBRARIES += android_support
            LOCAL_CXXFLAGS += -std=c++11 -fexceptions


            include $(BUILD_SHARED_LIBRARY)
            $(call import-module, android/support)

            posted @ 2014-12-13 15:56 多彩人生 閱讀(1319) | 評論 (0)編輯 收藏

            如何在真機上調試Android應用程序

                 摘要: http://www.cnblogs.com/lanxuezaipiao/archive/2013/03/11/2953564.html1、首先將手機設置為調試模式 方法:設置——應用程序——開發——USB調試,打上√即可     2、用數據線連接至電腦,在電腦上安裝豌豆莢,此時豌豆莢會幫你安裝...  閱讀全文

            posted @ 2014-12-12 15:49 多彩人生 閱讀(628) | 評論 (0)編輯 收藏

            一步一步了解Cocos2dx 3.0 正式版本開發環境搭建(Win32/Android)

            http://www.cnblogs.com/ShadowLoki/p/3679929.html

             cocos2d-x 3.0發布有一段時間了,作為一個初學者,我一直覺得cocos2d-x很坑。每個比較大的版本變動,都會有不一樣的項目創建方式,每次的跨度都挺大……

              但是憑心而論,3.0RC版本開始 環境搭建、項目創建、編譯的方式更加人性化了。

              現在我們進入正題,一步一步搭建cocos2dx的開發環境

              

             

              cocos2d-x很多tools都是需要使用Python的,因此我們需要先安裝Python環境

              

              python下載:點這里

                這里需要下載Python 2.X版本。曾經以為要下載3.x版本 后來裝上發現cocos2d-x提供的python運行報錯,所以卸載以后重新裝的python2.X版本

              

              python安裝的時候使用默認安裝方式即可,但是安裝完畢后我們需要配置環境變量

                在我的電腦(右鍵)->屬性->高級系統設置->高級 選項卡->環境變量->系統變量 中找到Path 變量,并在其值中增加 指向Python的環境變量。格式為 [Python安裝路徑]; 例如我安裝在C盤 我的環境變量就新增為 C:\Python27;

                配置完畢后記得注銷再重新登陸系統環境變量才會生效

                

             

              下一步,我們要下載最新版本的cocos2d-x,到目前為止 cocos2d-x已經更新到 3.0rc2版本

              

              cocos2d-x官網: 點這里

              

              在下載完畢后我們解壓縮到磁盤上,并打開cocos2d-x 文件夾找到setup.py這個文件,運行,會出現控制臺如下

              

              由于現在不配置Android環境,因此只需要一直回車即可,這時候這段python腳本會幫助我們設置cocos2d-x運行所需要的環境變量。繼續注銷……重新登陸……

              在配置完這一切后 我們打開CMD 運行cocos命令,1來檢查整個開發環境是否搭建成功,2來可以熟悉下命令行,如果設置沒問題的情況下 會出現如下界面

              這里我們可以看到cocos.py這段腳本可以執行4個命令,每個命令的作用已經說明的很清楚了。

             

              下面,我們來使用new 命令創建我們的項目

              

              這里舉個栗子,比如我要創建一個叫simple的項目,我們可以這么寫 cocos new -p com.game.simple -l cpp -d e:\  simple 簡單吧 運行這條命令會在E盤根目錄下生成一個叫simple的文件夾里面放著我們的項目。

              

              這個時候我們就可以用VS2012打開proj.win32中的SLN項目文件進行我們愉快的編碼和調試工作了。

             

              如果我們要運行我們剛剛由模板生成的項目,我們需要用到cocos run 命令 格式為 cocos run -p [平臺]    栗如:cocos run -p win32 表示win32平臺

              我們在執行這條命令時候需要注意一點 執行命令的目錄 必須是游戲項目的根目錄 如果不在根目錄 需要使用 -s指定游戲根目錄的位置

              

              現在我們在cmd中執行 cocos run -p win32 -s e:\simple 運行結果如下

              

              如果在編譯過程中沒有錯誤的話 編譯完成會打開這個HelloWorld的DEMO

              至此在WIN32中的環境搭建以及調試發布就全部OK了 下面我們來看Android部分。

              
            Android:

              Android的編譯環境在3.0RC里也有了很大的改觀,部署和編譯方式比之前方便了很多。現在我們來做下準備工作。

              Android編譯環境需要用到Andorid_SDK  Android_NDK   Ant 與JDK

              Android_SDK下載: 點這里

              Android_NDK下載: 點這里

              Android_JDK下載:  點這里

              Ant下載:         點這里

              

              其中除了JDK需要安裝,其它的是綠色版 直接解壓即可

                我們將SDK NDK 和ANT解壓縮到同一個文件夾中 并修改sdk的文件夾名為ADT,NDK的NDK,ANT的為ANT 這是為了方便以后使用。 我解壓后文件都放在了e:\Android文件夾下

              

              

              解壓完后我們先來配置JDK

                在JDK安裝完畢之后,需要手動進行環境變量的配置

              

                 1)在系統變量里新建JAVA_HOME變量,變量值為:C:\Program Files\Java\jdk1.6.0_14(根據自己的安裝路徑填寫)

                2)新建classpath變量,變量值為:.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar (注意前面的. 不要忘記了)

                3)在path變量(已存在不用新建)添加變量值:%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin(注意變量值之間用“;”隔開)

                4、重新注銷系統并重新登陸后 “開始”-->“運行”-->輸入“javac”-->"Enter",如果能正常打印用法說明配置成功!

                補充環境變量的解析:

                  JAVA_HOME:jdk的安裝路徑

             

                  classpath:java加載類路徑,只有類在classpath中java命令才能識別,在路徑前加了個"."表示當前路徑。

             

                  path:系統在任何路徑下都可以識別java,javac命令。

              

             

              

               現在我們來配置ANT的環境變量。將[ANT目錄]\bin文件夾添加到path中  如圖

              

             

              至此準備工作就做完了,下面我們運行setup.py關聯SDK NDK 和ANT

             

              

              在這里我們輸入了ndk和sdk的路徑 其中ndk指向根目錄即可  而sdk需要指向adt中的sdk目錄

              

              在由setup.py添加了這兩個環境變量之后 會要求我們輸入Ant的路徑 這里我們需要指向ant中的bin文件夾 如下:

              

              這時候 基本環境已經搭建完成了,記得注銷重新登陸使環境變量生效

               重新運行setup.py確認下所有的配置是否正確 如果全部正確 如圖所示

              

             

              然后我們就可以在項目目錄下使用 cocos compile -p android方式編譯APK文件了

              

              注意:在打包apk之前需要修改proj.android/jni文件夾下的Android.mk文件 添加自己新增的CPP文件

             

              最后我們來看看編譯好的APK文件吧,位置在[項目文件夾]\bin\debug\android\文件夾下

              

            posted @ 2014-10-15 15:35 多彩人生 閱讀(371) | 評論 (0)編輯 收藏

            用VS2010編譯luabind

            http://m.shnenglu.com/eros/archive/2009/04/29/81508.aspx

                 學了一段時間Lua,顯然直接在項目中使用是很不方便,google了一下,似乎大家都對luabind這個lua包裝類青睞有加,于是我也隨大勢想用用看。
                 先做好準備工作,下載了luabin 0.8.1源碼,Boost 1.3.8源碼和lua 5.1.4源碼,編譯環境是VS2008 SP1。之前在網上看到一些文章說這些開源軟件之間的版本依賴比較敏感,可能會有這樣那樣的問題,動手之前有些惶恐。
                 幸運的是,編譯過程很順利,如下:
                 1.編譯lua 5.1.4
                 進入VS2008的命令行工具,定位到lua的源碼目錄下,執行命令etc\luavs.bat,沒什么問題的話很快就可以編譯好lua,得到lua51.lib和lua51.dll。
                 2.編譯luabind
                 解壓下載回來的luabind壓縮包,假設解壓到d:\luabind-0.8.1\,Boost解壓到d:\boost 1_38_0\,lua解壓到d:\lua 5.1.4\
                 在 VS中新建一個靜態庫項目,將d:\luabind-0.8.1\src下的源碼全部添加到項目中,然后在項目中新建luabind和luabind \detail\兩個虛擬文件夾,對應的將d:\luabind-0.8.1\luabind和d:\luabind-0.8.1\luabind \detail下的文件添加到文件夾中。
                 然后為項目添加附加包含目錄,右鍵點擊項目節點->屬性->配置屬性->C\C++標簽下,在附加包含目錄中填入d: \luabind-0.8.1\;d:\boost 1_38_0\k;d:\lua 5.1.4\src\。然后修改項目字符集為多字節字符集。
                 準備就緒,生成項目。在我的環境中編譯很順利,沒有出現任何問題,成功后會得到luabind.lib。

                 接下來就按照慣例來寫一個hello world程序作為使用luabind的第一步。
                 在VS中新建一個控制臺項目,類型為DLL,命名項目為Hello World,然后鍵入以下代碼:

             1#include "stdafx.h"
             2#include <iostream>
             3#include <luabind/luabind.hpp>
             4
             5void greet()
             6{
             7    std::cout << "hello world!\n";
             8}

             9
            10extern "C" int __declspec(dllexport) init(lua_State* L)
            11{
            12    using namespace luabind;
            13
            14    open(L);
            15
            16    module(L)
            17    [
            18        def("greet"&greet)
            19    ];
            20
            21    return 0;
            22}


               注意,在Windows環境下init函數之前是要加 __declspec(dllexport)才能將函數導出的,而luabind的文檔中的環境是linux,默認不用加 __declspec(dllexport)也可以導出(就因為這個折騰了我半天才把hello word成功運行)。
               編譯項目,(記得將luabind.lib和lua51.lib添加到鏈接選項中:項目屬性->連接器->輸入->附加依賴文件,加入luabind.lib和lua51.lib)。
               將hello world.dll放到lua51.dll和lua.exe所在的目錄下。
               打開lua命令行,鍵入:
                
               測試成功,enjoy。

            posted @ 2014-09-02 17:56 多彩人生 閱讀(374) | 評論 (0)編輯 收藏

            常函數與重載

            關于常函數
            1》常對象只能調用常函數,常函數里面不能對數據成員做出更改,否則編譯出錯
            2》非常對象可以調用常函數
            3》常量成員可以在構造函數的成員函數初始化列表初始化。
            4》const關鍵字可以用于參與重載函數的區分。例如:
                void Print();
                void Print() const;
                這兩個函數可以用于重載。重載的原則是:常對象調用常成員函數,一般對象調用一般成員函數。
            5》在const成員函數中:  
              可以修改被定義成mutable的成員變量
            6》函數重載要求編譯器能夠唯一地確定調用一個函數時應執行哪個函數代碼,即采用哪個函數實現。確定函數實現時,要求從函數參數的個數和類型上來區分。這就是說,進行函數重載時,要求同名函數在參數個數上不同,或者參數類型上不同。否則,將無法實現重載。

            posted @ 2014-08-29 20:56 多彩人生 閱讀(642) | 評論 (0)編輯 收藏

            淺析Lua中table的遍歷

            http://rangercyh.blog.51cto.com/1444712/1032925

            當我在工作中使用lua進行開發時,發現在lua中有4種方式遍歷一個table,當然,從本質上來說其實都一樣,只是形式不同,這四種方式分別是:

            1. for key, value in pairs(tbtest) do  
            2. XXX  
            3. end 
            4.  
            5. for key, value in ipairs(tbtest) do  
            6. XXX  
            7. end 
            8.  
            9. for i=1, #(tbtest) do  
            10.     XXX  
            11. end 
            12.  
            13. for i=1, table.maxn(tbtest) do  
            14.     XXX  
            15. end 

            前兩種是泛型遍歷,后兩種是數值型遍歷。當然你還會說lua的table遍歷還有很多種方法啊,沒錯,不過最常見的這些遍歷確實有必要弄清楚。

            這四種方式各有特點,由于在工作中我幾乎每天都會使用遍歷table的方法,一開始也非常困惑這些方式的不同,一段時間后才漸漸明白,這里我也是把 自己的一點經驗告訴大家,對跟我一樣的lua初學者也許有些幫助(至少當初我在寫的時候在網上就找了很久,不知道是因為大牛們都認為這些很簡單,不需要 說,還是因為我笨,連這都要問)。

            首先要明確一點,就是lua中table并非像是C/C++中的數組一樣是順序存儲的,準確來說lua中的table更加像是C++中的map,通 過Key對應存儲Value,但是并非順序來保存key-value對,而是使用了hash的方式,這樣能夠更加快速的訪問key對應的value,我們 也知道hash表的遍歷需要使用所謂的迭代器來進行,同樣,lua也有自己的迭代器,就是上面4種遍歷方式中的pairs和ipairs遍歷。但是lua 同時提供了按照key來遍歷的方式(另外兩種,實質上是一種),正式因為它提供了這種按key的遍歷,才造成了我一開始的困惑,我一度認為lua中關于 table的遍歷是按照我table定義key的順序來的。

            下面依次來講講四種遍歷方式,首先來看for k,v in pairs(tbtest) do這種方式:

            先看效果:

            1. tbtest = {  
            2.     [1] = 1,  
            3.     [2] = 2,  
            4.     [3] = 3,  
            5.     [4] = 4,  
            6.  
            7. for key, value in pairs(tbtest) do  
            8.     print(value)  
            9. end 

            我認為輸出應該是1,2,3,4,實際上的輸出是1,2,4,3。我因為這個造成了一個bug,這是后話。

            也就是說for k,v in pairs(tbtest) do 這樣的遍歷順序并非是tbtest中table的排列順序,而是根據tbtest中key的hash值排列的順序來遍歷的。

             

            當然,同時lua也提供了按照key的大小順序來遍歷的,注意,是大小順序,仍然不是key定義的順序,這種遍歷方式就是for k,v in ipairs(tbtest) do。

            for k,v in ipairs(tbtest) do 這樣的循環必須要求tbtest中的key為順序的,而且必須是從1開始,ipairs只會從1開始按連續的key順序遍歷到key不連續為止。

            1. tbtest = {  
            2. [1] = 1,  
            3. [2] = 2,  
            4. [3] = 3,  
            5. [5] = 5,  
            6.  
            7. for k,v in ipairs(tbtest) do  
            8. print(v)  
            9. end 

            只會打印1,2,3。而5則不會顯示。

            1. local tbtest = {  
            2. [2] = 2,  
            3. [3] = 3,  
            4. [5] = 5,  
            5.  
            6. for k,v in ipairs(tbtest) do  
            7. print(v)  
            8. end 

            這樣就一個都不會打印。

             

            第三種遍歷方式有一種神奇的符號'#',這個符號的作用是是獲取table的長度,比如:

            1. tbtest = {  
            2. [1] = 1,  
            3. [2] = 2,  
            4. [3] = 3,  
            5. }  
            6. print(#(tbtest)) 

            打印的就是3

            1. tbtest = {  
            2. [1] = 1,  
            3. [2] = 2,  
            4. [6] = 6,  
            5. }  
            6. print(#(tbtest)) 

            這樣打印的就是2,而且和table內的定義順序沒有關系,無論你是否先定義的key為6的值,‘#’都會查找key為1的值開始。

            如果table的定義是這樣的:

            1. tbtest = {  
            2. ["a"] = 1,  
            3. [2] = 2,  
            4. [3] = 3,  
            5.  
            6. print(#(tbtest)) 

            那么打印的就是0了。因為‘#’沒有找到key為1的值。同樣:

            1. tbtest = {  
            2. [“a”] = 1,  
            3. [“b”] = 2,  
            4. [“c”] = 3,  
            5. }  
            6. print(#(tbtest)) 

            打印的也是0

            所以,for i=1, #(tbtest) do這種遍歷,只能遍歷當tbtest中存在key為1的value時才會出現結果,而且是按照key從1開始依次遞增1的順序來遍歷,找到一個遞增不是1的時候就結束不再遍歷,無論后面是否仍然是順序的key,比如:

             

            table.maxn獲取的只針對整數的key,字符串的key是沒辦法獲取到的,比如:

            1. tbtest = {  
            2. [1] = 1,  
            3. [2] = 2,  
            4. [3] = 3,  
            5. }  
            6. print(table.maxn(tbtest)) 
            7.  
            8.  
            9. tbtest = {  
            10. [6] = 6,  
            11. [1] = 1,  
            12. [2] = 2,  
            13. }  
            14. print(table.maxn(tbtest)) 

            這樣打印的就是3和6,而且和table內的定義順序沒有關系,無論你是否先定義的key為6的值,table.maxn都會獲取整數型key中的最大值。

            如果table的定義是這樣的:

            1. tbtest = {  
            2. ["a"] = 1,  
            3. [2] = 2,  
            4. [3] = 3,  
            5. }  
            6. print(table.maxn(tbtest)) 

            那么打印的就是3了。如果table是:

            1. tbtest = {  
            2. [“a”] = 1,  
            3. [“b”] = 2,  
            4. [“c”] = 3,  
            5. }  
            6. print(table.maxn(tbtest))  
            7. print(#(tbtest)) 

            那么打印的就全部是0了。

             

             

            換句話說,事實上因為lua中table的構造表達式非常靈活,在同一個table中,你可以隨意定義各種你想要的內容,比如:

            1. tbtest = {  
            2. [1] = 1,  
            3. [2] = 2,  
            4. [3] = 3,  
            5. ["a"] = 4,  
            6. ["b"] = 5,  

            同時由于這個靈活性,你也沒有辦法獲取整個table的長度,其實在coding的過程中,你會發現,你真正想要獲取整個table長度的地方幾乎沒有,你總能采取一種非常巧妙的定義方式,把這種需要獲取整個table長度的操作避免掉,比如:

            1. tbtest = {  
            2. tbaaa = {  
            3. [1] = 1,  
            4. [2] = 2,  
            5. [3] = 3,  
            6. },  
            7. ["a"] = 4,  
            8. ["b"] = 5,  

            你可能會驚訝,上面這種table該如何遍歷呢?

            1. for k, v in pairs(tbtest) do  
            2. print(k, v)  
            3. end 

            輸出是:a 4 b 5 tbaaa table:XXXXX。

            由此你可以看到,其實在table中定義一個table,這個table的名字就是key,對應的內容其實是table的地址。

            當然,如果你用

            1. for k, v in ipairs(tbtest) do  
            2. print(k,v)  
            3. end 

            來遍歷的話,就什么都不會打印,因為沒有key為1的值。但當你增加一個key為1的值時,ipairs只會打印那一個值,現在你明白ipairs是如何工作的吧。

            既然這里談到了遍歷,就說一下目前看到的幾種針對table的遍歷方式:

            for i=1, #tbtest do --這種方式無法遍歷所有的元素,因為'#'只會獲取tbtest中從key為1開始的key連續的那幾個元素,如果沒有key為1,那么這個循環將無法進入

            for i=1, table.maxn(tbtest) do --這種方式同樣無法遍歷所有的元素,因為table.maxn只會獲取key為整數中最大的那個數,遍歷的元素其實是查找 tbtest[1]~tbtest[整數key中最大值],所以,對于string做key的元素不會去查找,而且這么查找的效率低下,因為如果你整數 key中定義的最大的key是10000,然而10000以下的key沒有幾個,那么這么遍歷會浪費很多時間,因為會從1開始直到10000每一個元素都 會查找一遍,實際上大多數元素都是不存在的,比如:

            1. tbtest = {  
            2. [1] = 1,  
            3. [10000] = 2,  
            4. }  
            5. local count = 0  
            6. for i=1, table.maxn(tbtest) do  
            7. count = count + 1  
            8. print(tbtest[i])  
            9. end  
            10. print(count) 

            你會看到打印結果是多么的坑爹,只有1和10000是有意義的,其他的全是nil,而且count是10000。耗時非常久。一般我不這么遍歷。但是有一種情況下又必須這么遍歷,這個在我的工作中還真的遇到了,這是后話,等講完了再談。

            1. for k, v in pairs(tbtest) do 

            這個是唯一一種可以保證遍歷tbtest中每一個元素的方式,別高興的太早,這種遍歷也有它自身的缺點,就是遍歷的順序不是按照tbtest定義的順序來遍歷的,這個前面講到過,當然,對于不需要順序遍歷的用法,這個是唯一可靠的遍歷方式。

            1. for k, v in ipairs(tbtest) do 

            這個只會遍歷tbtest中key為整數,而且必須從1開始的那些連續元素,如果沒有1開始的key,那么這個遍歷是無效的,我個人認為這種遍歷方 式完全可以被改造table和for i=1, #(tbtest) do的方式來代替,因為ipairs的效果和'#'的效果,在遍歷的時候是類似的,都是按照key的遞增1順序來遍歷。

            好,再來談談為什么我需要使用table.maxn這種非常浪費的方式來遍歷,在工作中, 我遇到一個問題,就是需要把當前的周序,轉換成對應的獎勵,簡單來說,就是從一個活動開始算起,每周的獎勵都不是固定的,比如1~4周給一種獎勵,5~8 周給另一種獎勵,或者是一種排名獎勵,1~8名給一種獎勵,9~16名給另一種獎勵,這種情況下,我根據長久的C語言的習慣,會把table定義成這個樣 子:

            1. tbtestAward = {  
            2. [8] = 1,  
            3. [16] = 3,  

            這個代表,1~8給獎勵1,9~16給獎勵3。這樣定義的好處是獎勵我只需要寫一次(這里的獎勵用數字做了簡化,實際上獎勵也是一個大的 table,里面還有非常復雜的結構)。然后我就遇到一個問題,即我需要根據周序數,或者是排名序數來確定給哪一種獎勵,比如當前周序數是5,那么我應該 給我定義好的key為8的那一檔獎勵,或者當前周序數是15,那么我應該給獎勵3。由此讀者看出,其實我定義的key是一個分界,小于這個key而大于上 一個key,那么就給這個key的獎勵,這就是我判斷的條件。邏輯上沒有問題,但是lua的遍歷方式卻把我狠狠地坑了一把。讀者可以自己想一想我上面介紹 的4種遍歷方式,該用哪一種來實現我的這種需求呢?這個函數的大致框架如下:

            1. function GetAward(nSeq)  
            2. for 遍歷整個獎勵表 do  
            3. if 滿足key的條件 then  
            4. return 返回對應獎勵的key  
            5. end  
            6. end  
            7. return nil  
            8. end 

            我也不賣關子了,分別來說一說吧,首先因為我的key不是連續的,而且沒有key為1的值,所以ipairs和'#'遍歷是沒用的。這種情況下理想 的遍歷貌似是pairs,因為它會遍歷我的每一個元素,但是讀者不要忘記了,pairs遍歷并非是按照我定義的順序來遍歷,如果我真的使用的條件是:序數 nSeq小于這個key而大于上一個key,那么就返回這個key。那么我無法保證程序執行的正確性,因為key的順序有可能是亂的,也就是有可能先遍歷 到的是key為16的值,然后才是key為8的值。

            這么看來我只剩下table.maxn這么一種方式了,于是我寫下了這種代碼:

            1. for i=1, table.maxn(tbtestAward) do  
            2. if tbtestAward[i] ~= nil then  
            3. if nSeq <= i then  
            4. return i  
            5. end  
            6. end  
            7. end  

            這么寫效率確實低下,因為實際上還是遍歷了從key為1開始直到key為table.maxn中間的每一個值,不過能夠滿足我上面的要求。當時我是 這么實現的,因為這個獎勵表會不斷的發生變化,這樣我每次修改只需要修改這個獎勵表就能夠滿足要求了,后來我想了想,覺得其實我如果自己再定義一個序數轉 換成對應的獎勵數種類的表就可以避免這種坑爹的操作了,不過如果獎勵發生修改,我需要統一排查的地方就不止這個獎勵表了,權衡再三,我還是沒有改,就這么 寫了。沒辦法,不斷變化的需求已經把我磨練的忘記了程序的最高理想。我甚至愿意犧牲算法的效率而去追求改動的穩定性。在此哀悼程序員的無奈。我這種時間換 空間的做法確實不知道好不好。

            后來我在《Programming In Lua》中看到了一個神奇的迭代器,使用它就可以達到我想要的這種遍歷方式,而且不需要去遍歷那些不存在的key。它的方法是把你所需要遍歷的table 里的key按照遍歷順序放到另一個臨時的table中去,這樣只需要遍歷這個臨時的table按順序取出原table中的key就可以了。如下:

            首先定義一個迭代器:

            1. function pairsByKeys(t)  
            2.     local a = {}  
            3.     for n in pairs(t) do  
            4.         a[#a+1] = n  
            5.     end  
            6.     table.sort(a)  
            7.     local i = 0  
            8.     return function()  
            9.         i = i + 1  
            10.         return a[i], t[a[i]]  
            11.     end  
            12. end 

            然后在遍歷的時候使用這個迭代器就可以了,table同上,遍歷如下:

            1. for key, value in pairsByKeys(tbtestAward) do  
            2.  if nSeq <= key then  
            3. return key  
            4. end  
            5. end 

            并且后來我發現有了這個迭代器,我根本不需要先做一步獲取是哪一檔次的獎勵的操作,直接使用這個迭代器進行發獎就可以了。大師就是大師,我怎么就沒想到呢!

            還有些話我還沒有說,比如上面數值型遍歷也并非是像看起來那樣進行遍歷的,比如下面的遍歷:

            1. tbtest = {  
            2.     [1] = 1,  
            3.     [2] = 2,  
            4.     [3] = 3,  
            5.     [5] = 5,  
            6.  
            7. for i=1, #(tbtest) do  
            8.     print(tbtest[i])  
            9. end 

            打印的順序是:1,2,3。不會打印5,因為5已經不在table的數組數據塊中了,我估計是被放到了hash數據塊中,但是當我修改其中的一些key時,比如:

            1. tbtest = {  
            2.     [1] = 1,  
            3.     [2] = 2,  
            4.     [4] = 4,  
            5.     [5] = 5,  
            6.  
            7. for i=1, #(tbtest) do  
            8.     print(tbtest[i])  
            9. end 

            打印的內容卻是:1,2,nil,4,5。這個地方又遍歷到了中間沒有的key值,并且還能繼續遍歷下去。我最近正在看lua源碼中table的實 現部分,已經明白了是怎么回事,不過我想等我能夠更加清晰的闡述lua中table的實現過程了再向大家介紹。用我師傅的話說就是不要使用一些未定義的行 為方法,避免在工作中出錯,不過工作外,我還是希望能明白未定義的行為中那些必然性,o(︶︿︶)o 唉!因果論的孩子傷不起。等我下一篇博文分析lua源碼中table的實現就能夠更加清晰的說明這些了。

            posted @ 2014-08-25 14:29 多彩人生 閱讀(300) | 評論 (0)編輯 收藏

            lua require dofile loadfile區別

            http://blog.163.com/hbu_lijian/blog/static/126129153201422902256778/

            1.dofile與loadfile
            dofile 當作Lua運行代碼的chunk的一種原始的操作。dofile實際上是一個輔助的函數。真正完成功能的函數是loadfile;與dofile不同的是 loadfile編譯代碼成中間碼并且返回編譯后的chunk作為一個函數,而不執行代碼;另外loadfile不會拋出錯誤信息而是返回錯誤代。我們可 以這樣定義dofile:
            function dofile (filename)
            local f = assert(loadfile(filename))
            return f()
            end
            如 果loadfile失敗assert會拋出錯誤。loadfile更加靈活。在發生錯誤的情況下,loadfile返回nil和錯誤信息,這樣我們就可以 自定義錯誤處理。另外,如果我們運行一個文件多次的話,loadfile只需要編譯一次,但可多次運行。dofile卻每次都要編譯。
            2.loadstring與loadfile
            loadstring與loadfile相似,只不過它不是從文件里讀入chunk,而是從一個串中讀入。
            f = loadstring("i = i + 1")
            loadstring 函數功能強大,但使用時需多加小心。確認沒有其它簡單的解決問題的方法再使用。loadfile和loadstring都不會拋出錯誤,如果發生錯誤他們 將返回nil加上錯誤信息。另外,loadfile和loadstring都不會有邊界效應產生,他們僅僅編譯chunk成為自己內部實現的一個匿名函 數。通常對他們的誤解是他們定義了函數。Lua中的函數定義是發生在運行時的賦值而不是發生在編譯時。
            loadstring通常用 于運行程序外部的代碼,比如運行用戶自定義的代碼。注意:loadstring期望一個chunk,即語句。如果想要加載表達式,需要在表達式前加 return,那樣將返回表達式的值。loadstring返回的函數和普通函數一樣,可以多次被調用。
            print "enter your expression:"
            local l = io.read()
            local func = assert(loadstring("return " .. l))
            print("the value of your expression is " .. func())
            3.require與dofile
            。粗略的說require和dofile完成同樣的功能但有兩點不同:
            1. require會搜索目錄加載文件
            2. require會判斷是否文件已經加載避免重復加載同一文件。由于上述特征,require在Lua中是加載庫的更好的函數。
            require 使用的路徑和普通我們看到的路徑還有些區別,我們一般見到的路徑都是一個目錄列表。require的路徑是一個模式列表,每一個模式指明一種由虛文件名 (require的參數)轉成實文件名的方法。更明確地說,每一個模式是一個包含可選的問號的文件名。匹配的時候Lua會首先將問號用虛文件名替換,然后 看是否有這樣的文件存在。如果不存在繼續用同樣的方法用第二個模式匹配。例如,路徑如下:?;?.lua;c:\windows\?;/usr/local/lua/?/?.lua 
            調用過程如下:
            lili
            lili.lua
            c:\windows\lili
            /usr/local/lua/lili/lili.lua
            還會有so/dll文件。
            為了確定路徑,Lua首先檢查全局變量LUA_PATH是否為一個字符串,如果是則認為這個串就是路徑;否則require檢查環境變量LUA_PATH的值,如果兩個都失敗require使用固定的路徑(典型的"?;?.lua")
            一個路徑中的模式也可以不包含問號而只是一個固定的路徑,比如:?;?.lua;/usr/local/default.lua。這種情況下,require沒有匹配的時候就會使用這個固定的文件(當然這個固定的路徑必須放在模式列表的最后才有意義)

            posted @ 2014-08-22 09:24 多彩人生 閱讀(1291) | 評論 (0)編輯 收藏

            lua中的require機制

            http://blog.chinaunix.net/uid-552961-id-2736410.html

            lua中的require機制

                為了方便代碼管理,通常會把lua代碼分成不同的模塊,然后在通過require函數把它們加載進來。
            現在看看lua的require的處理流程。

            1、require機制相關的數據和函數
                package.path:保存加載外部模塊(lua中"模塊"和"文件"這兩個概念的分界比較含糊,因為這個值在不同的時刻會扮演不同的角色)的搜索 路徑,這種路徑是"模板式的路徑",它里面會包含可替代符號"?",這個符號會被替換,然后lua查找這個文件是否存在,如果存在就會調用其中特定的接 口。典型的值為:
                "./?.lua;./?.lc;/usr/local/?/init.lua"
                如果lua代碼中調用:require("hello.world")
                那么lua會依次查找:
                ./hello/world.lua ==>這里"hello.world"變成了"hello/world",并替換了模型"./?.lua"
                ./hello/world.lc
                .....
                (這種處理方式和python類似,只不過不需要__init__.py,也有調用python中的__init__.py)
                package.path在虛擬機啟動的時候設置,如果存在環境變量LUA_PATH,那么就用該環境變量作為
                它的值,并把這個環境變量中的";;"替換為luaconf.h中定義的默認值,如果不存在該變量就直接使用
                luaconf.h定義的默認值
                
                package.cpath:作用和packag.path一樣,但它是用于加載第三方c庫的。它的初始值可以通過環境變量
                LUA_CPATH來設置
                
                package.loadlib(libname, func):相當與手工打開c庫libname, 并導出函數func返回,loadlib其實是ll_loadlib
                

            2.require的處理流程:
               require(modelname)
               require(在lua中它是ll_require函數)的查找順序如下:
                   a.首先在package.loaded查找modelname,如果該模塊已經存在,就直接返回它的值
                   b.在package.preload查找modelname, 如果preload存在,那么就把它作為loader,調用loader(L)
                   c.根據package.path的模式查找lua庫modelname,這個庫是通過module函數定義的,對于頂層的lua庫,文件名和庫名是一 樣的而且不需要調用顯式地在lua文件中調用module函數(在ll_require函數中可以看到處理方式),也就是說lua會根據lua文件直接完 成一個loader的初始化過程。
                   d.根據package.cpath查找c庫,這個庫是符合lua的一些規范的(export具有一定特征的函數接口),lua先已動態的方式加載該c庫,然后在庫中查找并調用相應名字的接口,例如:luaopen_hello_world
                   e.已第一個"."為分割,將模塊名劃分為:(main, sub)的形式,根據package.cpath查找main,如果存在,就加載該庫并查詢相應的接口:luaopen_main_sub,例如:先查找 hello庫,并查詢luaopen_hello_world接口
                   f.得到loder后,用modname作為唯一的參數調用該loader函數。當然參數是通過lua的棧傳遞的,所以loader的原型必須符合lua的規范:int LUA_FUNC(lua_State *L)
                     
                   ll_require會將這個loader的返回值符給package.loaded[modelname],如果loader不返回值同時 package.loaded[modelname]不存在時, ll_require就會把package.loaded[modelname]設為true。最后ll_reuqire把package.loaded [modelname]返回給調用者。
                

            3.module的處理流程
                module(name, cb1, cb2, ...)
                
                a.如果package.loaded[name]是一個table,那么就把這個table作為一個mod
                b.如果全局變量name是一個table,就把這個全局變量作為一個mod
                c.創建table:t = {[name]=package.loaded[name], ["_NAME"]=name, ["_M"]=t, ["_PACKAGE"]=*name*(刪除了最后的".XXXX"部分)}. 如果name是一個以點分割的串,那么得到的mod類似這個樣子:
                  hello.world==> {["hello"]={["world"]={XXXXXXX}}}
                d.依次調用cbs:
                  cb1(mod), cb2(mod),...
                  
                e.將當前模塊的環境設置為mod,同時把package.loaded[name] = mod    
                

              清楚了lua關于模塊的處理,就比較容易理解寫lua擴展的細節了^_^。

            posted @ 2014-08-21 17:08 多彩人生 閱讀(355) | 評論 (0)編輯 收藏

            cocos2dx3.2

            新建項目
            cocos new

            編譯so文件
            cocos compile -p android

            posted @ 2014-08-20 21:45 多彩人生 閱讀(236) | 評論 (0)編輯 收藏

            lua學習

            ----------------------------------------------------------------------------------

            頭文件lua.h定義了Lua提供的基礎函數。其中包括創建一個新的Lua環境的函數(如lua_open),調用 Lua函數(如lua_pcall)的函數,讀取/寫入Lua環境的全局變量的函數,注冊可以被Lua代碼調用的新函數的函數,等等。所有在lua.h中 被定義的都有一個lua_前綴。

            頭文件lauxlib.h定義了輔助庫(auxlib)提供的函數。同樣,所有在其中定義的函數等都以luaL_打頭(例如,luaL_loadbuffer)。輔助庫利用lua.h中提供的基礎函數提供了更高層次上的抽象;所有Lua標準庫都使用了auxlib。


            ----------------------------------------------------------------------------------

            在控制臺 使用 require 老是失敗

            后來發現要修改一下 package.path

            require搜索模塊時是根據package.path設的路徑來搜索的


            require搜索路徑

            package.path   -- lua模塊路徑

            package.cpath    -- dll so 庫路徑


            package.path = package.path..';d:\?.lua'


            // require mylua.lua

            require 'mylua' 


            ------------------------------------------------------------------------------------

            posted @ 2014-08-08 17:01 多彩人生 閱讀(348) | 評論 (0)編輯 收藏

            僅列出標題
            共25頁: 1 2 3 4 5 6 7 8 9 Last 

            導航

            統計

            常用鏈接

            留言簿(3)

            隨筆分類

            隨筆檔案

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            久久国产精品一区二区| 国内精品久久久久久久久| 久久精品综合网| 久久AV高潮AV无码AV| 欧美熟妇另类久久久久久不卡| 伊人久久大香线蕉av一区| 久久免费国产精品一区二区| 久久久久久极精品久久久| 婷婷久久综合九色综合九七| 久久久久99精品成人片| 久久青青草原精品国产软件| 精品久久久久久无码专区不卡| 精品国产青草久久久久福利| 国产成人精品久久| 一本色道久久综合狠狠躁篇| 国产精品九九九久久九九| 女同久久| 大美女久久久久久j久久| 亚洲色大成网站www久久九| 国产精品无码久久久久| 综合网日日天干夜夜久久| 久久www免费人成看国产片 | 久久99精品久久久久久| 久久久久一级精品亚洲国产成人综合AV区 | 久久香蕉一级毛片| 欧美日韩成人精品久久久免费看| 日本人妻丰满熟妇久久久久久| 国产成人久久精品二区三区| 久久亚洲精品无码播放| 99久久99这里只有免费的精品| 2019久久久高清456| 精品久久8x国产免费观看| 亚洲va久久久噜噜噜久久天堂| 久久精品这里只有精99品| 天天综合久久久网| 99久久精品免费看国产一区二区三区| 99精品国产综合久久久久五月天| 中文精品99久久国产| 人人狠狠综合88综合久久| 久久精品国产福利国产琪琪| 91精品国产综合久久香蕉|