3D Computer Game Programming-Note 9UI 效果制作 —— Quest Log 公告牌效果展示制作过程 3D Computer Game Programming-Note 9 UI 效果制作 —— Quest Log 公告牌 效果展示 制作过程 点击菜单 GameObject -> UI -> Scroll View 新建一个滚动视图,在 Content 下创建几个的 Button 对象和 Text 对象,根据需要修改文本及位置等参数信息Scroll ViewContentButton/TextText 为 Content 添加 VerticalLayoutGroup 组件,便于调整其子对象的布局粗略排版如下: 为 Canvas 和 Scroll View 对象添加 Image 组件,并设置对应的 Source Image 分别作为主视图和滚动视图的背景使用 Menu Chalk Board 中的 Texture 素材,先将其转化为 Sprite 类型:CanvasScroll View 根据素材效果重新调整部分子对象的颜色、位置、大小等Button 调整滚动条样式,具体为隐藏水平滚动条的 Image 组件,并修改垂直滚动条的背景/颜色Scroll VerticalScroll Vertical/Sliding Area/Handle现在界面如下: 接下来为 Button 添加点击处理事件,使菜单可折叠展开新建脚本 ButtonHandler.cs,首先为 Button 组件添加点击事件,使用协程实现菜单折叠和展开的过程: ```csharp private Button button; void Start() { button = this.gameObject.GetComponent(); button.onClick.AddListener(Click); } void Click() { if (text.gameObject.activeSelf) { StartCoroutine(fold()); } else { StartCoroutine(unfold()); } } - 菜单折叠/展开时 Text 的文字以绕 x 轴旋转的方式被隐藏/出现,利用协程可逐帧修改 Text 的旋转角和高度,实现动态地隐藏/显示文字:```csharppublic Text text;private float timer = 50.0f;private float oriHeight;void Start() { /* ... */ oriHeight = text.rectTransform.sizeDelta.y;}IEnumerator fold() { float rx = 0; float curHeight = oriHeight; for (int i = 0; i < timer; ++i) { rx += 90.0f / timer; curHeight -= oriHeight / timer; text.rectTransform.sizeDelta = new Vector2(text.rectTransform.sizeDelta.x, curHeight); text.transform.rotation = Quaternion.Euler(rx, 0, 0); yield return null; } text.gameObject.SetActive(false);}IEnumerator unfold() { text.gameObject.SetActive(true); float rx = 90; float curHeight = 0; for (int i = 0; i < timer; ++i) { rx -= 90.0f / timer; curHeight += oriHeight / timer; text.rectTransform.sizeDelta = new Vector2(text.rectTransform.sizeDelta.x, curHeight); text.transform.rotation = Quaternion.Euler(rx, 0, 0); yield return null; }} 此时运行会发现虽然实现了菜单的折叠与展开,但滚动条不能随着折叠/展开的进行而自适应地伸缩,那么我们需要在fold和unfold过程中同样地调整Content的高度: ```csharp IEnumerator fold() { / … / float curContHeight = content.sizeDelta.y; for (int i = 0; i < timer; ++i) { /* ... */ curContHeight -= oriHeight / timer; /* ... */ content.sizeDelta = new Vector2(content.sizeDelta.x, curContHeight); yield return null; } / … / } IEnumerator unfold() { / … / float curContHeight = content.sizeDelta.y; for (int i = 0; i < timer; ++i) { /* ... */ curContHeight += oriHeight / timer; /* ... */ content.sizeDelta = new Vector2(content.sizeDelta.x, curContHeight); yield return null;}} - 取消点击 Button 时的过渡效果:<br />![](https://cdn.nlark.com/yuque/0/2020/png/2589459/1609041953032-47004277-2f46-4bb0-96b3-96556b745c3e.png#align=left&display=inline&height=153&margin=%5Bobject%20Object%5D&originHeight=153&originWidth=583&size=0&status=done&style=none&width=583)- 将脚本拖放到所有 Button 上,并拖放对应的 Text,运行:<br />![](https://cdn.nlark.com/yuque/0/2020/gif/2589459/1609041953035-75809769-7585-4b5d-8033-cd6fcc36c5e4.gif#align=left&display=inline&height=451&margin=%5Bobject%20Object%5D&originHeight=451&originWidth=818&size=0&status=done&style=none&width=818)- 接下来增加一个切换按钮并实现远近景的切换:<br />在 `Canvas` 下添加 `Button` 对象,调整合适的样式和位置,挂载脚本`SwitchHanler.cs`:```csharpusing System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;using UnityEngine.SceneManagement;public class SwitchHandler : MonoBehaviour { private Button button; void Start() { button = this.gameObject.GetComponent<Button>(); button.onClick.AddListener(Click); } void Click() { SceneManager.LoadScene("Scenes/Main"); }} 原场景命名为Detail,新建场景Main,使用素材中的预制并实例化为对象Quest Log,实现一个粗糙的远景: 为Quest Log添加触发事件,使点击公告牌时能够切换到近景查看详细信息,具体操作参考Unity中3D物体添加点击事件,挂载的脚本为EventClick.cs,如下: using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;using UnityEngine.SceneManagement;public class EventClick : MonoBehaviour { public void OnPointerClick() { SceneManager.LoadScene("Scenes/Detail"); }} 最后的关键一步是将所要加载的所有场景添加到 Build Settings 中,点击 File->Build Settings: 在 Main 场景下点击运行:成功!