本文由泰然教程组成员 betterdenger 翻译,原文请参阅「Menus - loading and restarting the game」
我们已经完成了我们游戏的第一个关卡,它具有基本的游戏性,一些声音,图像和粒子。
然后,当玩家死亡的时候,游戏会继续运行,不会重新开始。而且开始游戏得很突兀,直接就进入了游戏。很显然我们需要一些菜单按钮来控制游戏。
Damien: 我们直说: 菜单和GUI对游戏来说一点趣都没有。但是通常你还是得使用一套基础的GUI框架(或者直接不用)。这耽搁不少时间,效果仅仅是让玩家尽可能快的跳转。
Matthieu: 不像其他开发者,我不同意前面的观点。创造一个好的游戏GUI不是一个简单的任务,但是它却能带来回报,也会更有趣。当然,创建好的菜单要求好的工具和感性的设计(就像app的交互界面一样)。
但是一个好的菜单界面应该注意隐藏,甚至不应该在游戏中察觉它的存在。
不幸的是,除非你投入大量的时间或者使用第三方库,Unity没有一个真正强大的库来让你创建一个美妙的菜单。
我们本教程木有这个雄心壮志来创建一个复杂的GUI。本案例只使用内置工具套件,但是你会发现它们简直太有...局限性了。
我们先从基本的开始吧。
(右键保存图片)
(右键保存图片)
导入这些文件到工程里去。你可以在"Textures"目录的创建一个子目录"Menu",再把他们放进去。否则"background"这个文件名会覆盖之前那个文件。
至于按钮的话,我们就忍忍用Unity(丑爆了的)自带标准按钮吧。
几乎所有的游戏都有一个标题画面。玩家将在这个界面登陆和开始游戏。
Damien: 有些标题画面是非常棒让人印象深刻的, 比如《洛克人》、《合金弹头》...等等(我超喜欢游戏标题画面)。
我们要弄的就没那么棒了,但是...简洁!
首先创建一个新的scene:
提示: 你也可以直接按
cmd+N
(OS X)或者ctrl+N
(Windows) 快捷键来新建scene。
我们的标题画面由以下元素构成:
对于背景:
(0, 0, 1)
(2, 2, 1)
对于logo:
(0, 2, 0)
(0.75, 0.75, 1)
这样的话,画面就变成这样了:
当然你可以加上你的名字,一些介绍,小玩笑或者动画。菜单是一块儿无主之地,你可以随便开垦。但是一定要记住,一个玩家只是想要尽快开始游戏。
现在我们通过脚本添加一个按钮来开始游戏。
在"Script"文件夹下面创建一个新的脚本"MenuScript",把它和一个新的空游戏对象相关联(叫... "Scripts"? 我随便说说。):
using UnityEngine;
///
/// Title screen script
///
public class MenuScript : MonoBehaviour
{
void OnGUI()
{
const int buttonWidth = 84;
const int buttonHeight = 60;
// Determine the button's place on screen
// Center in X, 2/3 of the height in Y
Rect buttonRect = new Rect(
Screen.width / 2 - (buttonWidth / 2),
(2 * Screen.height / 3) - (buttonHeight / 2),
buttonWidth,
buttonHeight
);
// Draw a button to start the game
if(GUI.Button(buttonRect,"Start!"))
{
// On Click, load the first level.
// "Stage1" is the name of the first scene we created.
Application.LoadLevel("Stage1");
}
}
}
关于语法:语法是对的,虽然是有一点诡异。
我们要绘制一个按钮,玩家一点它,"Stage1"就会被载入。
Note:
OnGUI
方法会在每一帧都被调用,所有代码都会被嵌入到显示一个GUI元素的代码里: 血条,菜单,界面等等。
GUI
对象允许你快速从代码里创建GUI组件。就像一个按钮拥有GUI.Button
方法。
现在允许游戏,看看我们的菜单:
点击开始...我去,崩溃了!
Level 'Stage1' (-1) couldn not be loaded because it has not been added to the build settings. To add a level to the build settings use the menu File->Build Settings...
好吧,错误提示已经告诉我们需要干些什么了。
打开"File" -> "Build Settings":
现在把你想打包的所有scene都拖拽到包里。这里很简单就两个scene: "Menu" 和 "Stage1"。
重新允许,点击开始...OK!
提示: 这个
Application.LoadLevel()
方法的任务是清除当前scene,同时实例化新scene里的游戏对象。有时候,你可能需要把上一个scene的对象运用于下一个scene(比如,在两个场景过渡中音乐不中断)。Unity 提供了一个
DontDestroyOnLoad(aGameObject)
方法来处理这类事件。只需要在一个游戏对象上调用它,这个对象就不会在新场景过渡的时候被清除掉。实际上,它之后都不会被清理了。所以如果你想在之后的scene中移除它,你需要手动摧毁之。
死亡和重新开始
最后,我们要让玩家在死亡后能重新开始。如你所见,这涉及到很多(我们会在在接下来的章节里“简化”之)。
实际的过程是:
HealthScript.OnCollisionEnter
被调用。我们会添加两个新的步骤:
PlayerScript.OnDestroy
被调用。在"Scripts"文件夹里创建一个新的脚本"GameOverScript"。
只需这一点代码,会添加显示"Restart"按钮和"Back to Menu"按钮:
using UnityEngine;
///
/// Start or quit the game
///
public class GameOverScript : MonoBehaviour
{
void OnGUI()
{
const int buttonWidth = 120;
const int buttonHeight = 60;
if (
GUI.Button(
// Center in X, 1/3 of the height in Y
new Rect(Screen.width / 2 - (buttonWidth / 2),
(1 * Screen.height / 3) - (buttonHeight / 2),
buttonWidth,
buttonHeight),
"Retry!"
)
)
{
// Reload the level
Application.LoadLevel("Stage1");
}
if (
GUI.Button(
// Center in X, 2/3 of the height in Y
new Rect(Screen.width / 2 - (buttonWidth / 2),
(2 * Screen.height / 3) - (buttonHeight / 2),
buttonWidth,
buttonHeight),
"Back to menu")
)
{
// Reload the level
Application.LoadLevel("Menu");
}
}
}
跟我们上一个脚本差不多,不过多了一个按钮而已。
在新脚本"PlayerScript"中, 我们必须在死亡的时候实例化这个新脚本:
void OnDestroy()
{
// Game Over.
// Add the script to the parent because the current game
// object is likely going to be destroyed immediately.
transform.parent.gameObject.AddComponent();
}
开始游戏然后去"找死":
你可以在scene里发现这个脚本:
当然,它可以做得更好,比如添加积分显示,动画显示等。
目前来说能运行就好! :)
改改改,马上改!你先创建一个"GUI Skin":
在"Inspector"里, 调整UI控制让我们画风美妙起来。不过首先要确认皮肤(skin)已经被放入"Resources"文件夹了。
注意: "Resources"文件夹在Unity里是比较特殊的存在。凡在这个文件夹下的都会被游戏打包,然后可以使用
Resources.Load()
方法载入。
继续,皮肤需要在你在脚本里设置后才会生效。
在我们之前的GUI脚本里,我们得通过使用GUI.skin = Resources.Load("GUISkin");
载入皮肤(一次就好,不需要每一帧都载入)。
这是"MenuScript"里的一个例子(注意Start()方法
):
using UnityEngine;
///
/// Title screen script
///
public class MenuScript : MonoBehaviour
{
private GUISkin skin;
void Start()
{
// Load a skin for the buttons
skin = Resources.Load("GUISkin") as GUISkin;
}
void OnGUI()
{
const int buttonWidth = 128;
const int buttonHeight = 60;
// Set the skin to use
GUI.skin = skin;
// Draw a button to start the game
if (GUI.Button(
// Center in X, 2/3 of the height in Y
new Rect(Screen.width / 2 - (buttonWidth / 2), (2 * Screen.height / 3) - (buttonHeight / 2), buttonWidth, buttonHeight),
"START"))
{
// On Click, load the first level.
Application.LoadLevel("Stage1"); // "Stage1" is the scene name
}
}
}
如你所见,仅仅是简单添加该死的按钮是多么的无趣。
注意: 如果你经济能够支持而且你需要添加一堆菜单和文本在你的游戏里。你可以考虑购买NGUI插件,真心物超所值。
我们刚学了如何给我们游戏添加必不可少的按钮。
回想一下,目前你都做了什么:
恭喜!但是遗憾的是,这只能在你电脑上运行。我们如果要卖这个游戏,需要分发安装包啊。
这就是我们最后一章要讨论的了——部署。