游戏制作之路(36)退出游戏循环返回开始菜单

在前面已经学习了从游戏开始菜单进入游戏主循环,当玩家玩累了,想退出游戏,或者想重新开始游戏,应该怎么样实现呢?下面就来解决这个问题。

 

首先要在游戏主循环的界面上创建一个退出的按钮,这样玩家才可以随时退出游戏。按前面方法,在StarGame.cs脚本里添加一个OnGUI()函数,如下:

    void OnGUI()

    {

 

}

然后在脚本里添加一个退出按钮的样式变量,如下:

public GUISkin skin;

再添加一个按钮的位置:

private Rect btnEndRect;

 

再按下面的代码来修改脚本,结果如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class StarGame : MonoBehaviour
{
    public GameObject starPrefab;
    public GUISkin skin;

    private Rect btnEndRect;

    // Use this for initialization
    void Start()
    {
        btnEndRect = new Rect();
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            //
            Vector3 pos = Input.mousePosition;
            pos.x /= Screen.width;
            pos.y /= Screen.height;

            //
            GameObject g = (GameObject)Instantiate(starPrefab, pos, Quaternion.identity);            
        }
    }

    void OnGUI()
    {
        btnEndRect.x = 0;
        btnEndRect.y = 0;
        btnEndRect.width = 100;
        btnEndRect.height = 45;
        //
        if (GUI.Button(btnEndRect, "结束", skin.button))
        {
           
        }

    }
}

接着下来要设置脚本里GUISkin skin变量,也就是把GameGUISkin拖到相应的变量里,如下图:

如果没有设置这个变量,就会运行出错,看不到显示的“结束”按钮,正确设置之后,运行如下图:

这时候可以看到结束按钮了,但点击之后并没有响应结束,因为我们还没有在点击响应的大括号里添加退出的代码,因此把这个响应代码修改如下:

        //

        if (GUI.Button(btnEndRect, "结束", skin.button))

        {

            StartMenu menu = gameObject.GetComponent<StartMenu>();

            menu.enabled = true;

            this.enabled = false;

        }

再接着运行之后,可以点击结束按钮:

上面是返回到开始菜单了,但是游戏里的内容并没有清空,还是看到在背景上显示很多星星,这显然不是我们希望的结果,那么怎么办呢?怎么样才可以恢复到游戏的初始化状态呢?好吧,得发挥思考能力了,其实问题就是要清空星星,如果我们可以把所有点击创建的星星都记录下来,在点击退出时,再把所有星星删除,不就是恢复到开始状态了吗?就按着这个思路来修改脚本代码,首先要添加一个容器来保存所有星星,但是我们使用什么容器来保存呢?使用数组可以吗?是不可以的,因为星星有多少个是不确定的,因此要使用动态变长的容器,那么最简单的容器就是列表了,如List<T>,最后可以游戏脚本代码修改如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class StarGame : MonoBehaviour
{
    public GameObject starPrefab;
    public GUISkin skin;

    private Rect btnEndRect;
    private List<GameObject> starList;

    // Use this for initialization
    void Start()
    {
        btnEndRect = new Rect();
        starList = new List<GameObject>();
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            //
            Vector3 pos = Input.mousePosition;
            pos.x /= Screen.width;
            pos.y /= Screen.height;

            //
            GameObject g = (GameObject)Instantiate(starPrefab, pos, Quaternion.identity);
            starList.Add(g);
        }
    }

    void OnGUI()
    {
        btnEndRect.x = 0;
        btnEndRect.y = 0;
        btnEndRect.width = 100;
        btnEndRect.height = 45;
        //
        if (GUI.Button(btnEndRect, "结束", skin.button))
        {
            foreach(GameObject g in starList)
            {
                Destroy(g);
            }
            starList.Clear();
            //
            StartMenu menu = gameObject.GetComponent<StartMenu>();
            menu.enabled = true;
            this.enabled = false;
        }

    }
}

经过上面的修改,结束游戏之后返回开始菜单,就可以看到跟开始的状态是一样的了,如下图:

到这里,就可以实现从游戏主循环里退出来,并恢复到游戏开始的状态。

https://blog.csdn.net/caimouse/article/details/51749579

<think>嗯,我现在需要解决用户关于创建游戏菜单系统的问题。用户已经提供了三个引用,分别涉及Godot引擎、C++的SFML以及Unity的学习路线。用户真正的需求是制作游戏菜单的教程或方法,特别是在游戏引擎中如何实现。首先,我应该分析每个引用中的相关信息。引用[1]提到Godot的场景和节点创建、UI处理等内容。引用[2]提到C++和SFML实现游戏循环和事件处理。引用[3]则指向Unity的入门学习路线。虽然用户提到这些引用可能不是直接需求,但其中包含的引擎特性对解决问题有帮助。接下来,我需要确定用户可能使用的游戏引擎。由于用户没有明确指定,应该覆盖主流引擎如Unity、Godot以及可能的自定义引擎(如C++/SFML)。针对不同引擎,提供具体步骤是关键。对于Unity,菜单创建通常涉及Canvas、UI元素(按钮、文本)、事件绑定和场景加载。需要强调UI组件的添加和OnClick事件的处理。引用[3]中的Unity学习路线可能相关,但用户需要的是具体步骤而非路线。对于Godot,引用[1]提到界面和UI处理,这里应详细说明Control节点、SceneTree管理、信号连接。Godot的步骤包括创建Control节点、按钮、脚本处理切换场景。至于C++/SFML,引用[2]提到的事件处理和渲染循环是关键。这里需要说明如何创建菜单类、处理事件(如鼠标点击按钮)和绘制元素。代码示例的部分应考虑sf::Text和sf::RectangleShape的使用,以及状态转换。用户的问题可能涉及多个方面:菜单结构、引擎工具使用、代码结构。需要分引擎解答,确保每个步骤清晰。同时要注意用户可能对引擎的选择不确定,因此比较不同引擎的方案会有帮助。最后,相关问题需要引导用户进一步细化需求,比如引擎选择、菜单类型(主菜单、暂停菜单)、是否需要动画等。这些问题有助于用户深入思考具体需求,也能提供更精准的帮助。需要检查是否遗漏关键点,比如音效管理(引用[1]提到)或性能优化,但用户主要聚焦在菜单创建,可能不需要深入这些方面。保持回答紧扣主题,同时提示可扩展的选项。</think> 在不同游戏引擎中创建菜单系统的方法有所差异,以下是主流引擎的实现指南: ### 🎮 通用菜单设计流程(引擎无关) 1. **菜单结构设计** - 主菜单(开始/设置/退出) - 暂停菜单(继续/重开/返回主菜单) - 设置菜单(音量/画质/控制) - 使用状态机管理菜单层级:$S = \{ \text{主菜单}, \text{游戏进行}, \text{暂停}, \text{设置} \}$ 2. **核心实现要素** ```mermaid graph TD A[UI框架] --> B(按钮组件) A --> C(文字渲染) A --> D(事件响应) D --> E(鼠标点击检测) D --> F(键盘导航) ``` --- ### ⚙️ 各引擎具体实现方案 #### **1. Unity引擎方案** ```csharp // 创建可交互按钮 public class MainMenu : MonoBehaviour { public GameObject settingsPanel; public void OnStartClick() { SceneManager.LoadScene("Level1"); // 场景加载 } public void OnSettingsClick() { settingsPanel.SetActive(true); // 显示设置面板 } public void OnExitClick() { Application.Quit(); // 退出游戏 } } ``` **实现步骤**: 1. 创建Canvas > Panel 作为菜单背景 2. 添加Button组件并绑定OnClick事件 3. 使用`SceneManager`管理场景切换 4. 通过`SetActive()`控制子菜单显隐 > 📚 参考:Unity官方UI教程中的 **"Creating In-Game Menus"** 章节[^3] #### **2. Godot引擎方案** ```gdscript extends Control func _ready(): $StartButton.connect("pressed", self, "_on_Start_pressed") $OptionsButton.connect("pressed", self, "_on_Options_pressed") func _on_Start_pressed(): get_tree().change_scene("res://Level1.tscn") # 场景切换 func _on_Options_pressed(): $SettingsPanel.visible = true # 显示设置面板 ``` **节点结构**: ``` MainMenu (Control) ├── VBoxContainer │ ├── StartButton (Button) │ ├── OptionsButton (Button) │ └── QuitButton (Button) └── SettingsPanel (Panel) ├── VolumeSlider (HSlider) └── BackButton (Button) ``` > 🔍 提示:使用Godot的**信号系统**实现按钮交互更高效[^1] #### **3. SFML(C++)方案** ```cpp class Menu { public: void update(sf::RenderWindow& window) { if (startButton.getGlobalBounds().contains(mousePos)) { if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) { currentState = GameState::PLAYING; // 切换游戏状态 } } } void draw(sf::RenderTarget& target) { target.draw(background); target.draw(startButton); } private: sf::RectangleShape startButton; sf::Sprite background; }; ``` **核心实现**: - 使用`sf::RectangleShape`创建按钮 - 通过`getGlobalBounds().contains()`检测点击 - 状态机控制菜单切换 --- ### ✨ 进阶功能实现 1. **菜单动画** Unity使用`DOTween`插件实现平滑过渡: ```csharp StartButton.transform.DOScale(1.2f, 0.3f).SetLoops(-1, LoopType.Yoyo); ``` 2. **控制器导航** Godot的输入映射方案: ```gdscript InputMap.add_action("ui_up") Input.action_press("ui_up") # 模拟按键 ``` 3. **本地化支持** 创建JSON语言文件: ```json { "start_button": { "en": "Start Game", "zh": "开始游戏" } } ``` --- ### 🔍 性能优化建议 1. **批量绘制** $$ \text{Draw Calls} \propto \frac{1}{\text{性能}} $$ - Unity:启用Canvas的 **"Batch"** 选项 - SFML:使用`VertexArray`合并渲染 2. **异步加载** ```csharp IEnumerator LoadSceneAsync(){ AsyncOperation asyncLoad = SceneManager.LoadSceneAsync("Level1"); while (!asyncLoad.isDone) { loadingBar.value = asyncLoad.progress; yield return null; } } ``` ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

caimouse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值