「Unity2D」使用Unity创建一个2D游戏系列-9

菜单选项 - 载入和重启游戏

本文由泰然教程组成员 betterdenger 翻译,原文请参阅「Menus - loading and restarting the game」

我们已经完成了我们游戏的第一个关卡,它具有基本的游戏性,一些声音,图像和粒子。

然后,当玩家死亡的时候,游戏会继续运行,不会重新开始。而且开始游戏得很突兀,直接就进入了游戏。很显然我们需要一些菜单按钮来控制游戏。

Damien: 我们直说: 菜单和GUI对游戏来说一点趣都没有。但是通常你还是得使用一套基础的GUI框架(或者直接不用)。这耽搁不少时间,效果仅仅是让玩家尽可能快的跳转。

Matthieu: 不像其他开发者,我不同意前面的观点。创造一个好的游戏GUI不是一个简单的任务,但是它却能带来回报,也会更有趣。当然,创建好的菜单要求好的工具和感性的设计(就像app的交互界面一样)。

但是一个好的菜单界面应该注意隐藏,甚至不应该在游戏中察觉它的存在。

不幸的是,除非你投入大量的时间或者使用第三方库,Unity没有一个真正强大的库来让你创建一个美妙的菜单。

我们本教程木有这个雄心壮志来创建一个复杂的GUI。本案例只使用内置工具套件,但是你会发现它们简直太有...局限性了。

我们先从基本的开始吧。

资源文件

背景

background

(右键保存图片)

Logo

logo

(右键保存图片)

导入这些文件到工程里去。你可以在"Textures"目录的创建一个子目录"Menu",再把他们放进去。否则"background"这个文件名会覆盖之前那个文件。

至于按钮的话,我们就忍忍用Unity(丑爆了的)自带标准按钮吧。

标题画面

几乎所有的游戏都有一个标题画面。玩家将在这个界面登陆和开始游戏。

Damien: 有些标题画面是非常棒让人印象深刻的, 比如《洛克人》、《合金弹头》...等等(我超喜欢游戏标题画面)。

我们要弄的就没那么棒了,但是...简洁!

场景

首先创建一个新的scene:

  1. "File" -> "New scene"。
  2. 命名为"Menu"保存到"Scenes"文件夹。

提示: 你也可以直接按cmd+N(OS X)或者 ctrl+N(Windows) 快捷键来新建scene。

我们的标题画面由以下元素构成:

  • 背景
  • logo
  • 显示按钮的脚本

对于背景:

  • 创建一个新的Sprite
  • 放到(0, 0, 1)
  • 设置尺寸大小为(2, 2, 1)

对于logo:

  • 创建一个新的Sprite
  • 放到(0, 2, 0)
  • 设置尺寸大小为(0.75, 0.75, 1)

这样的话,画面就变成这样了:

Result

当然你可以加上你的名字,一些介绍,小玩笑或者动画。菜单是一块儿无主之地,你可以随便开垦。但是一定要记住,一个玩家只是想要尽快开始游戏。

载入脚本

现在我们通过脚本添加一个按钮来开始游戏。

在"Script"文件夹下面创建一个新的脚本"MenuScript",把它和一个新的空游戏对象相关联(叫... "Scripts"? 我随便说说。):

    using UnityEngine;

    /// <summary>
    /// Title screen script
    /// </summary>
    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方法。

现在允许游戏,看看我们的菜单:

Button result

点击开始...我去,崩溃了!

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...

好吧,错误提示已经告诉我们需要干些什么了。

添加scene到build

打开"File" -> "Build Settings":

Build settings

现在把你想打包的所有scene都拖拽到包里。这里很简单就两个scene: "Menu" 和 "Stage1"。

Adding scenes

重新允许,点击开始...OK!

Start game

提示: 这个Application.LoadLevel()方法的任务是清除当前scene,同时实例化新scene里的游戏对象。有时候,你可能需要把上一个scene的对象运用于下一个scene(比如,在两个场景过渡中音乐不中断)。

Unity 提供了一个DontDestroyOnLoad(aGameObject)方法来处理这类事件。只需要在一个游戏对象上调用它,这个对象就不会在新场景过渡的时候被清除掉。实际上,它之后都不会被清理了。所以如果你想在之后的scene中移除它,你需要手动摧毁之。

死亡和重新开始

最后,我们要让玩家在死亡后能重新开始。如你所见,这涉及到很多(我们会在在接下来的章节里“简化”之)。

实际的过程是:

  1. 玩家被子弹击中。
  2. HealthScript.OnCollisionEnter被调用。
  3. 玩家失去一点生命值。
  4. 如果玩家生命少于1点,"HealthScript"摧毁玩家对象。

我们会添加两个新的步骤:

  1. PlayerScript.OnDestroy被调用。
  2. 一个"GameOverScript"被创建,然后被添加到scene里。

在"Scripts"文件夹里创建一个新的脚本"GameOverScript"。

只需这一点代码,会添加显示"Restart"按钮和"Back to Menu"按钮:

    using UnityEngine;

    /// <summary>
    /// Start or quit the game
    /// </summary>
    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<GameOverScript>();
    }

开始游戏然后去"找死":

Game Over

你可以在scene里发现这个脚本:

Game Over Script

当然,它可以做得更好,比如添加积分显示,动画显示等。

目前来说能运行就好! :)

"画面丑瞎我们的钛合金狗眼"

改改改,马上改!你先创建一个"GUI Skin":

  • "Assets" -> "Create" -> "Gui Skin":

GUISkin

在"Inspector"里, 调整UI控制让我们画风美妙起来。不过首先要确认皮肤(skin)已经被放入"Resources"文件夹了。

注意: "Resources"文件夹在Unity里是比较特殊的存在。凡在这个文件夹下的都会被游戏打包,然后可以使用Resources.Load()方法载入。

继续,皮肤需要在你在脚本里设置后才会生效。

在我们之前的GUI脚本里,我们得通过使用GUI.skin = Resources.Load("GUISkin");载入皮肤(一次就好,不需要每一帧都载入)。

这是"MenuScript"里的一个例子(注意Start()方法):

    using UnityEngine;

    /// <summary>
    /// Title screen script
    /// </summary>
    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插件,真心物超所值。

下一步

我们刚学了如何给我们游戏添加必不可少的按钮。

回想一下,目前你都做了什么:

  • 用三个背景层实现的视差滚动。
  • 很多的粒子效果!
  • 一个标题画面。
  • 图像和声音。
  • 一个shmup游戏,有一个玩家和多个敌人。

恭喜!但是遗憾的是,这只能在你电脑上运行。我们如果要卖这个游戏,需要分发安装包啊。

这就是我们最后一章要讨论的了——部署。

标签: unity2d, 教程

?>