【Unity3d】手机游戏关卡制作

时间:2022-02-18 18:59:23

很多手机游戏的关卡都是采用激活和未激活的状态

当某一关通过以后 则再次进入关卡选择界面时 相应的图标显示激活状态 否则为未激活状态

如愤怒的小鸟

【Unity3d】手机游戏关卡制作

 

这里使用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的自适应缩放可以查看另一篇文章