很多手機游戲的關卡都是采用激活和未激活的狀態
當某一關通過以后 則再次進入關卡選擇界面時 相應的圖標顯示激活狀態 否則為未激活狀態
如憤怒的小鳥
這里使用unity3d內置GUI系統
繪制按鈕之前我們需要知道哪些關卡是已經通過了的
在unity3d中可以使用PlayerPrefs來保存關卡信息 詳見PlayerPrefs
我們使用一個boolean數組來標識關卡的激活狀態
var m_bActive : boolean[];
在初始化過程中讀取PlayerPrefs保存的關卡信息
如果已經通過則為true 否則為false 關卡通過條件取決於具體的游戲規則 例如每關所用時間小於3分鍾為通過等等
m_bActive = new boolean[m_iLevelTotals];
for (idx = 1; idx < m_iLevelTotals; ++idx)
(關卡通過條件) ? m_bActive[idx] = true : m_bActive = false;
m_bActive[0] = true;
這里將第一關默認為激活狀態 不然所有關卡全鎖定 則現場直憋了
通過初始化 已經知道了關卡的通過信息
繪制關卡圖標之前 我們知道unity3d的GUI有GUISkin和GUIStyle
GUISkin可以指定多個GUI的風格
而GUIStyle只是針對一個GUI風格
因此我們要為關卡的按鈕定義一個GUIStyle
var m_GuiStageBtn : GUIStyle;
並有一個激活狀態的圖片和未激活狀態的圖片
var m_texLocked : Texture2D;
var m_texActive : Texture2D;
下面開始繪制關卡圖標 這里假設當前頁有16關 則要繪制16個圖標 4行4列
// col_1
for ( i = 0; i < 13; i += 4)
{
if (!m_bEasyActive[i])
m_GuiStageBtn.normal.background = m_texLocked;
else
m_GuiStageBtn.normal.background = m_texActive;
if (GUI.Button(Rect(81, 29 * i + 220 , 57, 52), "", m_GuiStageBtn))
{
if (!m_bEasyActive[i])
return;
if (m_bEffectActive)
audio.PlayOneShot(g_ButtonDownClip);
g_iCurrentLevel = i + 1;
LoadSelectLevel(g_iCurrentLevel);
}
}
// col_2
for ( i = 1; i < 14; i += 4)
{
if (!m_bEasyActive[i])
m_GuiStageBtn.normal.background = m_texLocked;
else
m_GuiStageBtn.normal.background = m_texActive;
if (GUI.Button(Rect(165, 29 * (i - 1) + 220, 57, 52), "", m_GuiStageBtn))
{
if (!m_bEasyActive[i])
return;
if (m_bEffectActive)
audio.PlayOneShot(g_ButtonDownClip);
g_iCurrentLevel = i + 1;
LoadSelectLevel(g_iCurrentLevel);
}
}
// col_3
for (i = 2; i < 15; i += 4)
{
if (!m_bEasyActive[i])
m_GuiStageBtn.normal.background = m_texLocked;
else
m_GuiStageBtn.normal.background = m_texActive;
if (GUI.Button(Rect(250, 29 * (i - 2)+ 220, 57, 52), "", m_GuiStageBtn))
{
if (!m_bEasyActive[i])
return;
if (m_bEffectActive)
audio.PlayOneShot(g_ButtonDownClip);
g_iCurrentLevel = i + 1;
LoadSelectLevel(g_iCurrentLevel);
}
}
// col_4
for ( i = 3; i < 16; i += 4)
{
if (!m_bEasyActive[i])
m_GuiStageBtn.normal.background = m_texLocked;
else
m_GuiStageBtn.normal.background = m_texActive;
if (GUI.Button(Rect(345, 29 * (i - 3) + 220, 57, 52 ), "", m_GuiStageBtn))
{
if (!m_bEasyActive[i])
return;
if (m_bEffectActive)
audio.PlayOneShot(g_ButtonDownClip);
g_iCurrentLevel = i + 1;
LoadSelectLevel(g_iCurrentLevel);
}
}
當然 可以在繪制之前 也就是 if (GUI.Button(...)) 之前 直接根據當前關卡的激活狀態來處理按鈕的激活狀態 加上GUI.enabled = m_bActive[i];
很簡單 但是在循環繪制時候要細心 設想這只是繪制16個圖標 若是繪制很多 再加上Easy模式 Hard模式 Expert模式等等 則很容易出錯
但是原理基本上不變
使用Unity3d的內置GUI 則繪制GUI時的位置是很頭疼的 而且GUI的繪制函數OnGUI是消耗比較大的 再加上drawcall帶來的渲染效率
在手機游戲的應用中都是不容忽視的問題 另外Unity3d中GUI的自適應縮放可以查看另一篇文章