天天看點

談一談Cocos2d-x中的某些“大小”

這裡說的“大小”,包括了以下一些内容:

(1).視窗的大小

(2).分辨率的大小

(3).影幕的大小

(4).視口的大小

(5).裁剪區域的大小

我們先來看(1),視窗的大小

視窗的大小,即是Windows窗體大小。我們以HelloCpp為例,打開main.cpp,。找到這兩句代碼:

<SPAN style="FONT-FAMILY: SimSun; FONT-SIZE: 14px">CCEGLView* eglView = CCEGLView::sharedOpenGLView();

eglView->setFrameSize(960, 640 );</SPAN>

這裡取得了Opengl視窗類CCEGLView單件執行個體指針傳回給指針變量eglView,并調用其setFrameSize函數設定一個所謂的Frame大小。這個大小是神馬東西?進去看看!

進入到CCEGLView.cpp的相應函數:

<SPAN style="FONT-SIZE: 14px">void CCEGLView::setFrameSize(float width, float height)

{

//我們在這裡看到調用了Create函數,這裡傳入的width,height就是要建立的視窗的大小。

Create((LPCTSTR)m_szViewName, (int)width, (int)height);

//後面調用基類的setFrameSize,一會兒再分析,暫略過。

CCEGLViewProtocol::setFrameSize(width, height);

}</SPAN>

看一下Create函數:

<SPAN style="FONT-SIZE: 14px">bool CCEGLView::Create(LPCTSTR pTitle, int w, int h)

bool bRet = false;

do

//這裡通過判斷m_hWnd是否有效來確定隻Create一次,不允許建立多個窗體。

CC_BREAK_IF(m_hWnd);

//

HINSTANCE hInstance = GetModuleHandle( NULL );

WNDCLASS wc; //視窗類資訊結構

//填充資訊結構

wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;

wc.lpfnWndProc = _WindowProc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

wc.hInstance = hInstance;

wc.hIcon = LoadIcon( NULL, IDI_WINLOGO );

wc.hCursor = LoadCursor( NULL, IDC_ARROW );

wc.hbrBackground = NULL;

wc.lpszMenuName = NULL;

wc.lpszClassName = kWindowClassName;

//注冊視窗類

CC_BREAK_IF(! RegisterClass(&wc) && 1410 != GetLastError());

//取得電腦螢幕大小矩形

RECT rcDesktop;

GetWindowRect(GetDesktopWindow(), &rcDesktop);

//将視窗标題多位元組轉寬字元。

WCHAR wszBuf[50] = {0};

MultiByteToWideChar(CP_UTF8, 0, m_szViewName, -1, wszBuf, sizeof(wszBuf));

// 使用注冊過的視窗類建立視窗

m_hWnd = CreateWindowEx(

WS_EX_APPWINDOW | WS_EX_WINDOWEDGE, // Extended Style For The Window

kWindowClassName, // Class Name

wszBuf, // Window Title

WS_CAPTION | WS_POPUPWINDOW | WS_MINIMIZEBOX, // Defined Window Style

0, 0, // Window Position

0, // Window Width

0, // Window Height

NULL, // No Parent Window

NULL, // No Menu

hInstance, // Instance

NULL );

//通過視窗句柄有效性判斷確定建立成功才能繼續

CC_BREAK_IF(! m_hWnd);

//重點函數,調整視窗大小

resize(w, h);

//初始化OpenGL

bRet = initGL();

//傳回成功判斷

CC_BREAK_IF(!bRet);

//儲存單件執行個體指針

s_pMainWindow = this;

bRet = true;

} while (0);

//傳回成敗

return bRet;

建立視窗時并沒有用到w和h,是以隻有繼續看重點函數才能知道視窗大小是怎麼設定的。

<SPAN style="FONT-SIZE: 14px">void CCEGLView::resize(int width, int height)

//視窗句柄有效性判斷

if (! m_hWnd)

return;

}

//擷取視窗的客戶區大小矩形,這個客戶區其實就是咱們OpenGL視窗的實際大小,不包含一般視窗的菜單,邊框,狀态欄等部分。

RECT rcClient;

GetClientRect(m_hWnd, &rcClient);

//如果目前視窗的客戶區部分大小與參數width,height相同,直接傳回

if (rcClient.right - rcClient.left == width &&

rcClient.bottom - rcClient.top == height)

// 否則重新設定客戶區大小矩形變量的值。

rcClient.right = rcClient.left + width;

rcClient.bottom = rcClient.top + height;

//此函數将使視窗的整體大小(即如果有則包含菜單欄,邊框,底部狀态欄和客戶可視區的整個視窗的大小)按照

指定的客戶區大小rcClient和視窗樣式來自動調整,確定了客戶區就是rcClient指定大小。其中GetWindowLong用來擷取目前視窗的

樣式,GWL_STYLE為基本樣式資訊,GWL_EXSTYLE為擴充欄式資訊。傳回視窗的整體大小再傳給rcClient。

AdjustWindowRectEx(&rcClient, GetWindowLong(m_hWnd, GWL_STYLE), false,

GetWindowLong(m_hWnd, GWL_EXSTYLE));

// 設定視窗的顯示位置并應用rcClient做為視窗的大小。

SetWindowPos(m_hWnd, 0, 0, 0, rcClient.right - rcClient.left,

rcClient.bottom - rcClient.top, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOOWNERZORDER

| SWP_NOZORDER);

</SPAN>

好了,我們看,視窗的大小就是這麼設定的。作者考慮到了不同的樣式視窗對于客戶區大小的影響,故做了相應的處理。是以我們建立指定大小的視窗時其實真正的意思是建立一個指定客戶區大小的視窗。

我們再來看 (2),分辨率的大小和 (3),影幕的大小 (4),視口的大小

分辨率:即是螢幕上圖像的精細度,在Cocos2d-x中其大小為螢幕在橫向和縱向可以容納的邏輯點數量,為了好了解,我們把它想像成投影機的分辨率。

影幕:想想小時候看電影時用到的那塊白布吧,當然也許公司會議室裡也能看到它。也就是投影機用來投射畫面的畫布。

視口:其實就是上面說的投影機投影出來的影片畫面所占的矩形。它如果大于影幕的大小,那麼你就不能看到完整的影片畫面。如果小于影幕的大小。你就可以在它顯示的區域裡看到影片畫面。

我們現在看一下剛才略過的代碼:CCEGLViewProtocol::setFrameSize(width,height);

進入CCEGLViewProtocol.cpp中相應函數定義:

<SPAN style="FONT-SIZE: 14px">void CCEGLViewProtocol::setFrameSize(float width, float height)

//這裡使用參數對兩個變量進行了指派,第一個就是分辨率大小。第二個就是影幕的大小。

m_obDesignResolutionSize = m_obScreenSize = CCSizeMake(width, height);

輕按兩下“m_obDesignResolutionSize”,按下Ctrl+F,在彈出查找對話框裡對目前文檔CCEGLViewProtocol.cpp中查找全部使用。

談一談Cocos2d-x中的某些“大小”

點選第一個查找結果,看一下所在函數setDesignResolutionSize,這個函數是用來設定分辨率大小的。前兩個參數無疑就是設定分辨率橫向縱向的像素數量的。最後一個參數resolutionPolicy我們必須了解一下,進入ResolutionPolicy的定義:

enum ResolutionPolicy

// 擴充填充模式:這裡等于是直接設定投影機的分辨率。如果這個分辨率與畫布大小的比例失調,就會出現失真。

kResolutionExactFit,

// 低調整模式:這個吧,是按照設定的分辨率在橫縱方向上最低值調整視口大小,使投影機投影出來的影片畫面所占的矩形在

畫布上所對應的相應方向上與最低值一緻。

kResolutionNoBorder

// 高調整模式:與上面恰恰相反,按照設定的分辨率在橫縱方向上最高值調整視口大小,使投影機投影出來的影片畫面所占的

矩形在畫布上所對應的相應方向上與最高值一緻。同時這個矩形的另一個方向按最低值進行裁剪,區域外部分填充黑色。

kResolutionShowAll,

//無效值

kResolutionUnKnown,

};

這個枚舉歸結為“分辨率模式”。是不是有點迷糊,得,我們在繼續下面的函數之前,先以例子來說明一下:

打開HelloLua工程的AppDelegate.cpp,看一下這個函數:

<SPAN style="FONT-SIZE: 14px">bool AppDelegate::applicationDidFinishLaunching()

// 取得顯示裝置的單件執行個體指針

CCDirector *pDirector = CCDirector::sharedDirector();

// 設定其使用的OpenGL視窗為單件OpenGL視窗

pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());

//在這裡設定了分辨率為480,320,與視窗客戶區一緻,顯示模式為kResolutionShowAll。

CCEGLView::sharedOpenGLView()->setDesignResolutionSize(480, 320, kResolutionShowAll);

//開始高清顯示模式

// pDirector->enableRetinaDisplay(true);

// 設定顯示FPS相關

pDirector->setDisplayStats(true);

// 設定幀間隔時間

pDirector->setAnimationInterval(1.0 / 60);

// 注冊LUA管理器并設定為目前使用的腳本系統

CCScriptEngineProtocol* pEngine = CCLuaEngine::engine();

CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);

//執行hello.lua腳本啟動遊戲,不懂的可以參見本部落客的博文“HelloLua”深入分析一文

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)

CCString* pstrFileContent = CCString::createWithContentsOfFile("hello.lua");

if (pstrFileContent)

pEngine->executeString(pstrFileContent->getCString());

#else

std::string path = CCFileUtils::sharedFileUtils()->fullPathFromRelativePath("hello.lua");

pEngine->addSearchPath(path.substr(0, path.find_last_of("/")).c_str());

pEngine->executeScriptFile(path.c_str());

#endif

return true;

我們要幹點壞事,好吧。我們嘗試着将其分别改為

CCEGLView::sharedOpenGLView()->setDesignResolutionSize(80, 320, kResolutionExactFit);

CCEGLView::sharedOpenGLView()->setDesignResolutionSize(80, 320, kResolutionNoBorder);

CCEGLView::sharedOpenGLView()->setDesignResolutionSize(80, 320, kResolutionShowAll);

并進行測試。下面是測試圖。

談一談Cocos2d-x中的某些“大小”

好好了解一下。

再回來看setDesignResolutionSize函數:

void CCEGLViewProtocol::setDesignResolutionSize(float width, float height, ResolutionPolicy resolutionPolicy)

//是否使用高清模式(視網膜螢幕),高清模式不讓設定分辨率。

CCAssert(m_bIsRetinaEnabled == false, "can not enable retina while set design resolution size!");

//確定分辨率顯示方式有效

CCAssert(resolutionPolicy != kResolutionUnKnown, "should set resolutionPolicy");

//如果參數無效,直接傳回。

if (width == 0.0f || height == 0.0f)

//在這裡對變量m_obDesignResolutionSize進行了設定。

m_obDesignResolutionSize.setSize(width, height);

//這裡計算出影幕大小與分辨率大小的比率。存放在變量m_fScaleX,m_fScaleY中。

m_fScaleX = (float)m_obScreenSize.width / m_obDesignResolutionSize.width;

m_fScaleY = (float)m_obScreenSize.height / m_obDesignResolutionSize.height;

//如果模式是kResolutionNoBorder,按照最大影幕方式,即保證像素不失真的情況下,影幕适應分辨率

//如果是低調整模式

if (resolutionPolicy == kResolutionNoBorder)

//縮放值按最大

m_fScaleX = m_fScaleY = MAX(m_fScaleX, m_fScaleY);

//如果是高調整模式

if (resolutionPolicy == kResolutionShowAll)

//縮放值按最小

m_fScaleX = m_fScaleY = MIN(m_fScaleX, m_fScaleY);

// 根據縮放值和分辨率計算視口的寬高

float viewPortW = m_obDesignResolutionSize.width * m_fScaleX;

float viewPortH = m_obDesignResolutionSize.height * m_fScaleY;

// 設定視口位置居螢幕中間

m_obViewPortRect.setRect((m_obScreenSize.width - viewPortW) / 2, (m_obScreenSize.height - viewPortH) / 2, viewPortW, viewPortH);

//儲存分辨率模式

m_eResolutionPolicy = resolutionPolicy;

//使用變量設定Opengl視口(此處屏蔽,在SetGLDefaultValues中會有設)

//setViewPortInPoints(0, 0,m_obScreenSize.width, m_obScreenSize.height);

// 建立FPS的文字标簽

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

//初始化邏輯點和像素值大小

CCDirector::sharedDirector()->m_obWinSizeInPoints = CCDirector::sharedDirector()->m_obWinSizeInPixels = getSize();

//對OpengGL用到的一些設定進行初始化,其中有重設投影函數,會再重置視口。

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

現在大家明白我為什麼将(2),(3),(4)并在一起說了。它們其實是有機結合的。相輔相成,缺一不可。

我們最後來看一下:(5),裁剪區域的大小:

裁剪區域:如果對Opengl顯示視窗設定裁剪區域,則裁剪區域外的像素将不會顯示。

我們仍然在HelloLua工程中進行說明:

在函數AppDelegate::applicationDidFinishLaunching()中我們在

CCEGLViewProtocol* tpCCEGLView = (CCEGLViewProtocol*) CCEGLView::sharedOpenGLView();

後面增加代碼:

//設定裁剪顯示區域

tpCCEGLView->setScissorInPoints(100,100,100,100);

//開啟裁剪檢測

glEnable(GL_SCISSOR_TEST);

運作測試:

談一談Cocos2d-x中的某些“大小”

可以看到,我們對畫面進行了裁剪。從螢幕100,100位置起的大小為寬100,高100的區域被設為了裁剪顯示區域,其它部分均被裁切掉了。

本文轉蓬萊仙羽51CTO部落格,原文連結:http://blog.51cto.com/dingxiaowei/1366387,如需轉載請自行聯系原作者

繼續閱讀