1. 代碼文件格式由utf8不簽名改成utf8簽名格式
cocos2d-x從手機遊戲到PC端遊
這幾天一直在想,cocos2d-x跨平臺這麼牛X,爲什麼沒有人用cocos2d-x來作PC的端遊呢,如果用cocos2d-x作2D的端遊,那豈不是windows,linux,Mac,ios,android全平臺通吃了。當然了,這只是cocos2d-x,但是如果我們使用的是cocos3d那豈不是,一個遊戲引擎,可以在任何平臺上運行,所有平臺通喫。並且是2D遊戲,3D遊戲都通喫的遊戲引擎,而且還使用的是GPU渲染的遊戲,而且遊戲運行的性能大家就可想而知了。
想到這裏,自已便開始興奮的快要跳起來了。
我們先來分析一下理論上的可行性。
1.用過cocos2d-x的人都知道,cocos2d-x是使用的標準c++語法寫成。所以c++本身就是windows,linux,mac通行的。
2.然後,我要說一下游戲使用的圖形渲染引擎,cocos2d-x使用的是OpenGL ES,之所以使用從OpenGL裁剪的OpenGL ES是因爲手機端使用完全的OpenGL性能有問題,但讓我們高興的是OpenGL ES的代碼可以完全運行與OpenGL顯卡。而且性能不比手機的GPU差。還有一個更好的消息就是OpenGL和OpenGL ES的協議正在被OpenGL組織設法合併爲一個協議。
3.支持windows系統的顯卡硬件提供商因爲受到微軟的軟件協議管控,不能自行開發性能更高的顯示硬件,所以一般顯卡的生產商都會全力支持OpenGL協議,以顯示他們新硬件的性能。所以,幾乎所有可以跑windows系統的顯卡都可以找到OpenGL驅動。換句話說,就是windwos,linux,mac都支持OpenGL硬件協議。
結合上邊的三條分析,我們沒有理由不相信cocos2d-x或者cocos3d-x不會成爲所有平臺通喫的遊戲開發引擎。
下邊是對cocos2d-x引擎全屏顯示的一些修改。linux和Mac應該也會很方便。因爲你可以看到cocos2dx的cocos2dx\platform目錄下有很多操作系統相關的文件夾。如下圖:
HWND hDesk; RECT rc; hDesk = GetDesktopWindow(); GetWindowRect( hDesk, &rc ); SetWindowLong( m_hWnd, GWL_STYLE, WS_BORDER ); SetWindowPos( m_hWnd, HWND_TOPMOST,0,0, rc.right, rc.bottom,SWP_SHOWWINDOW);
ShowWindow(hDesk,SW_SHOWMAXIMIZED);
加入後的樣子如下圖:(記得改完了,要再把cocos2dlib項目再編譯一下)
2.再修改你自已的cocos2d-x項目中的main.cpp:
把原來代碼中的
eglView->setFrameSize(480, 320);
改成下邊代碼
RECT rcWindow; HWND xxtmp = eglView->getHWnd(); GetWindowRect(xxtmp,&rcWindow); int w = (int)rcWindow.right; int h = (int)rcWindow.bottom; eglView->setFrameSize(w, h);
改過之後的效果如下圖:
pEGLView->setDesignResolutionSize(480,320, kResolutionExactFit);
kResolutionExactFit:這個參數表示自動拉申以適合屏幕大小。
Cocos2d-x win32 版本,其中的HelloWorld演示項目的CPU佔用率一直很高,有時候高達100%,所以在一番排查後,發現是由於在主循環裏使用了 Sleep(0),它位於 cocos2dx\platform\win32\CCApplication.cpp,大致長像如下:
1 2 3 4 5 6 7 | while (
1 ) { if (
有消息 ) { if (
時間到 ) 更新計時, call 主循環函數; else Sleep(0); } //
其他跳出循環判斷代碼 } |
也就是說,該循環除了執行 mainLoop 以外,花了大量時間在檢查消息和 Sleep(0) 上面。
並且,我還發現一個奇怪的現象(暫時還不清楚是爲什麼),即:
HelloCPP 項目的 AppDelegate.cpp 文件中有一行代碼:
1 2 | //
set FPS. the default value is 1.0/60 if you don't call this pDirector->setAnimationInterval(1.0
/ 60); |
上面的 60 ,如果改大,不起任何作用,幀速始終是 60 不會變。但如果改到小於60,是可以起作用的。
於是,解決 CPU 佔用的思路,始於 “是否可以降低循環精度” 的念頭。
已知正常情況下,執行 Sleep(1) ,會睡大概 1/50 秒,這個時間並不精確也不準確,看上去無法滿足 60 fps 這個流暢度需求。不過,如果遊戲運行幀速不需要這麼高,比如 30 fps,則該方案大爲可行。
經實際測試,將 Sleep(0) 改成 Sleep(1), 再將上面代碼中的 60 改成 25, 效果非常顯著。但另一個問題來了:如果每遊戲循環做的事有點多,時間有點長,那麼遊戲將被拖慢。
原engine中,同步時間的代碼如下:
1 2 3 | QueryPerformanceCounter(&nNow); if (nNow.QuadPart
- nLast.QuadPart > m_nAnimationInterval.QuadPart) { nLast.QuadPart
= nNow.QuadPart; |
因爲每次在 nLast 中記錄 nNow 時間,並用時間差與設定間隔作比較,時間差往往會比設定間隔要大,如果是在不精確的 Sleep(1) 以及每循環負擔比較大的情況下,將導致每幀實際所花的時間,會超出設定間隔不少,從而拖慢遊戲速度(如果遊戲按幀步進計時的話)。
爲解決這個問題,我用的是時間對齊的方式。其實就是改了一下更新nLast 的表達式:
1 | nLast.QuadPart
= nNow.QuadPart - (nNow.QuadPart % m_nAnimationInterval.QuadPart); |
這樣每幀的總消耗時間就相當的恆定了。
至於在保持 60 fps的情況下,也能讓 cpu佔用率在0%,可以修改 Sleep(1) 的精度。
通過查找資料,發現 Winmm.lib 庫中有timeBeginPeriod(1); timeEndPeriod(1); 函數可以用於該目的,令 Sleep(1) 的精度提升到1毫秒級別,遂動手改之:
1. 添加 Winmm.lib 庫的引用。我在這裏採取了在 CCApplication.cpp 頭部添加 #pragma comment(lib, "Winmm.lib") 語句的方式。
2. 在 while(1) 代碼段的前後,分別放上 timeBeginPeriod(1); timeEndPeriod(1); 語句
這樣基本就搞定了。
網上搜到下面的參考資料,但可能因爲Cocos2d-x版本不同,已經不好按這種方式修改了。於是自己想到了解決辦法。
參考資料:
http://download.csdn.net/detail/chenzhizs/4813602
其實Win32想弄成全屏不難,兩個步驟搞定:1.去掉標題欄;2. 設置爲想要的分辨率。
1. 在CCEGLView.cpp的CreateWindowEx中,把WS_CAPTION 這個屬性註釋掉或刪掉,即可沒有標題欄。
2. 在main.cpp中設置eglView->setFrameSize(1920, 1080);
這樣基本就可以了,應該在各版本中都可以用。
本人使用的cocos2dx版本爲cocos2d-x_v2.1.5b,之前查到一些解決全屏的辦法,但是這些方法對新版本已經不再適用,經過辛苦查詢,總算是皇天不負有心人,找到了新版本的解決辦法。參考原文:http://www.cocos2d-x.org/forums/6/topics/24432
方法如下:(親測可行)
1、在目錄cocos2dx\platform\win32下找到CCEGLView.h和CCEGLView.cpp,用記事本打開,在CCEGLView.h中添加如下代碼
- bool enterFullscreen(int fullscreenWidth=0, int fullscreenHeight=0);
- bool exitFullscreen(int windowX, int windowY, int windowedWidth, int windowedHeight, int windowedPaddingX, int windowedPaddingY);
- int getFullscreenWidth();
- int getFullscreenHeight();
2、在CCEGLView.cpp中添加如下代碼
- int CCEGLView::getFullscreenWidth()
- {
- return GetDeviceCaps(m_hDC, HORZRES);
- }
- int CCEGLView::getFullscreenHeight()
- {
- return GetDeviceCaps(m_hDC, VERTRES);
- }
- bool CCEGLView::enterFullscreen(int fullscreenWidth, int fullscreenHeight)
- {
- DEVMODE fullscreenSettings;
- bool isChangeSuccessful;
- if(fullscreenWidth == 0 || fullscreenHeight == 0)
- {
- fullscreenWidth = GetDeviceCaps(m_hDC, HORZRES);
- fullscreenHeight = GetDeviceCaps(m_hDC, VERTRES);
- }
- int colourBits = GetDeviceCaps(m_hDC, BITSPIXEL);
- int refreshRate = GetDeviceCaps(m_hDC, VREFRESH);
- EnumDisplaySettings(NULL, 0, &fullscreenSettings);
- fullscreenSettings.dmPelsWidth = fullscreenWidth;
- fullscreenSettings.dmPelsHeight = fullscreenHeight;
- fullscreenSettings.dmBitsPerPel = colourBits;
- fullscreenSettings.dmDisplayFrequency = refreshRate;
- fullscreenSettings.dmFields = DM_PELSWIDTH |
- DM_PELSHEIGHT |
- DM_BITSPERPEL |
- DM_DISPLAYFREQUENCY;
- SetWindowLongPtr(m_hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_TOPMOST);
- SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
- SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, fullscreenWidth, fullscreenHeight, SWP_SHOWWINDOW);
- isChangeSuccessful = ChangeDisplaySettings(&fullscreenSettings, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL;
- ShowWindow(m_hWnd, SW_MAXIMIZE);
- resize(fullscreenWidth, fullscreenHeight);
- return isChangeSuccessful;
- }
- bool CCEGLView::exitFullscreen(int windowX, int windowY, int windowedWidth, int windowedHeight, int windowedPaddingX, int windowedPaddingY)
- {
- bool isChangeSuccessful;
- SetWindowLongPtr(m_hWnd, GWL_EXSTYLE, WS_EX_LEFT);
- SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
- isChangeSuccessful = ChangeDisplaySettings(NULL, CDS_RESET) == DISP_CHANGE_SUCCESSFUL;
- SetWindowPos(m_hWnd, HWND_NOTOPMOST, windowX, windowY, windowedWidth + windowedPaddingX, windowedHeight + windowedPaddingY, SWP_SHOWWINDOW);
- ShowWindow(m_hWnd, SW_RESTORE);
- return isChangeSuccessful;
- }
3、如何使用
在main.cpp中添加
- // Create the application instance
- AppDelegate app;
- CCEGLView* eglView = CCEGLView::sharedOpenGLView();
- // Set the frame size to the full screen value
- //eglView->setFrameSize(eglView->getFullscreenWidth(), eglView->getFullscreenHeight());
- eglView->enterFullscreen(0, 0);
- int ret = CCApplication::sharedApplication()->run();
這樣就能夠實現全屏了!
解決方案:
第一:
若你的.fla源文件中不帶有骨骼動畫,則你可以使用TexturePacker結合AnimatePacker來解決這個問題。
a.把.fla文件導出爲.swf
b.把.swf文件直接丟到TexturePacker中,它會自動幫你解析出所有的幀,並導出爲.plist文件,它附帶一張.png圖
c.把.plist文件丟到AnimatePacker中,它也會自動幫你解析出所有的幀,然後根據需要,製作你動畫,AnimatePacker不知道怎麼使用的,可以看我前面的文章。
這樣你的Falsh動畫就能轉移到Cocos2d-x使用了。
這種方案在b這個步驟的時候經常會遇到一個問題,就是你丟進去的.swf文件只能幫你解析出來一幀,接下來我們來分析這種情況。
出現這種情況的原因:大部分的Flash動畫都是比較複雜的,它包含了多套的動畫方案,而且它們一般都不是設計在主場景中的,而是綁定在各個元件中的,主場景中只是丟了一張圖片。這樣就帶來了問題了,因爲TexturePacker只會解析你主場景中的幀動畫,所以,你就只解析到了一張圖片。
那這個問題我們要怎麼解決呢?跟TexturePacker的作者商量一下吧。能不能把元件中的幀動畫也解析了呢。或許以後可以,但是至少目前是不行的。所以,我們能做的就是如下:
a.在Flash cs6中文件->新建->ActionScript 3.0,新建一個.fla文件,假設我們命名爲new.fla
b.選中原.fla文件中元件裏面綁定的幀動畫,右鍵複製幀,黏貼到new.fla的主場景中,你可以把所有元件中的動畫都黏貼到new.fla中,這不會影響我們之後的讀取。都完成之後,右鍵另存爲new.swf。
c.然後把new.swf文件丟到TexturePacker中,怎麼樣,是不是所有幀都出來了?而且一樣的幀TexturePacker還會自動幫你合併到一起,可以減少生成的.png圖片大小。導出爲.plist文件,附帶一張.png圖。
d.把.plist文件丟到AnimatePacker中,它也會自動幫你解析出所有的幀,然後根據需要,製作你動畫。
這種方案或許比較繁瑣,但是是目前我能實現的不帶骨骼動畫的.fla文件的移植到Cocos2d-x中使用的方法。接下來介紹一下帶骨骼動畫的.fla文件又是如何導出爲Cocos2d-x可以使用的文件
第二:
第二個方案我們是要使用到的一個工具叫Flash2Cocos2d-x,至於安裝方面問題,也可以看看我前面的文章。
當我們的.fla文件中不帶骨骼數據的時候,我們使用的上面的方案。我也嘗試使用Flash2Cocos2d-x來導出,但是在Import選項上面時,第一個和第二個都沒有反映,第三個提示不包含骨骼數據,或許這個工具只能用來導出骨骼動畫吧!
所以,你也可以把這個方案當作Flash2Cocos2d-x的一點資料吧。
大體步驟如下:
打開.fla文件,窗口->其他面板->SkeletonSWFPanel,打開面板,點擊import(默認爲All library items),若你有封裝了骨骼信息的.swf文件,也可以選擇第三項。waiting......然後所有的骨骼信息就都出來了。
至於具體的這個工具怎麼做骨骼動畫,可以參考作者的文章。
然後Export導出文件,
這邊有4個選項,第一個會直接導出一張封裝了骨骼信息的PNG圖片,第二個導出帶有骨骼信息的swf動畫,第三個暫時不明白,第四個導出許多單張的PNG圖片和XML文件。據論壇上面使用過這個工具的朋友說(這個方案本人沒在Cocos2d-x中引用過),一般都是使用第四個選項,然後再使用TexturePacker工具,把所有的單張圖片生成圖片集.plist文件,這樣需要放入到Cocos2d-x 資源文件夾中的文件就有.png .plist .xml 3個文件,跟第一種方案最後是一樣的。但是它們在Cocos2d-x中引用需要使用不同的類庫(關於類庫在cocos2d-x2.0.4中報錯的問題,應該改一下類的路徑就可以了)。這邊需要用到的類庫就是在下載的工具裏面的Flash2Cocos2d-X子文件夾中的類(大概有40+,是不是全部需要用到,我沒實踐過)。
最後在代碼方面的實現:
這個工具對於骨骼動畫的支持還是挺好的,很期待作者繼續更新。
當然我們也可以使用CocosBuilder來做骨骼動畫,在CocosBuilder做骨骼動畫的時候,遇到了一個骨骼動畫和Cocos2d-x裏面的action結合出現action只運行固定時間的異常,比如我action設置的是2s,但是它只運行0.5s就停止了,至於這個問題是什麼導致的,暫時還沒解決,以後解決了會在我的博客上面補上。如果有哪位朋友懂的,麻煩指導一下!
總結一下:
第一:PC上面的不帶骨骼動畫的.fla文件我們導出爲.swf文件後,結合TexturePacker和AnimatePacker來開發
第二:帶骨骼動畫的.fla文件或者是分裝了骨骼信息的.png和.swf文件,我們可以使用Flash2Cocos2d-x結合TexturePacker來開發。
第三:製作骨骼動畫可以使用Flash2Cocos2d-x,也可以使用Cocosbuilder來製作,關於使用Cocosbuilder如何製作骨骼動畫,可以看我前面的博客。
原文鏈接:http://momowing.diandian.com/post/2012-11-22/40042074075