0. 对本次实践的介绍 #
学习 Unity 5.x 原生态 UGUI 的开发实践, 学习参考自 58 开发网, 这是一个跑酷类游戏的 UI 界面, 包含了游戏开始的 主界面|主角的 UI 设置|时间 UI 设置以及所获得的金币 UI 设置等. 通过此次实践可以了解到以下内容, 对 UGUI 有一个深入的认识 :
- Sprite 资源导入及切割
- 制作主界面欢迎文字
- 制作主界面开始|退出按钮
- 制作人物 HUD 和金币 HUD 和时间 HUD
- CanvasGroup 的使用
- UI 动画制作及显示
- 实现金币 UI 数量显示功能
- 实现生命数量 UI 更新功能
- 实现时间倒计时功能
- UI 自适应调整
想要实现的效果
1. Sprite 资源导入及切割 #
UISprites.psd
把准备好的素材 UISprites.psd 导入项目, 检查 Texture Type
的类型是 Sprite(2D and UI)
模式, Sprite Mode
改成 Multiple
, 进而 Apply
一下.
点击进入 Sprite Editor
精灵的编辑器.
在 Sprite Editor 左键圈住内容选择切割区域, Apply
一下便切割开了.
切割之前与切割之后的项目目录对比 :
和
2. 制作主界面欢迎文字 #
新建一个 Canvas>Image
, 把切好的 UISprites 的 Title 作为 Source Image
给它. 调整大小和位置.
修改文字锚点的位置, 保持四个角的相对位置, 使之自适应屏幕大小的改变.
改成
在 Image
Title 下添加文字 Text
, 修改内容和字体等格式, 选中 Best Fit
, 同样, 也需要修改其锚点.
欢迎界面就做好了.
3. 制作主界面开始|退出按钮 #
Canvas
下面创建3个 Button
, 分别对应为 Start
| Options
| Exit
, 关联 Source Image
以及修改背景颜色和文字
界面效果
4. 制作人物 HUD 和金币 HUD 和时间 HUD#
添加一个新的 Canvas 里面有一个 Image 和两个 Text, 如下图所示
为了适应屏幕, 将 Image 的 Rect Transform 设置为 left + top
Coin 的图标同理, 锚点设为 right + top
.
新建 Create Empty
添加时间轴图片, 操作同上, 最终效果
5. CanvasGroup 的使用 #
在 MainMenuCanvas
里新建一个 Create Empty
作为其他对象的父物体, 即 Title StartBtn OptionsBtn ExitBtn
都属于同一个 GameObject 命名为 MainMenu
, 这个 MainMenu 的锚点设为 Stretch - Stretch
.
为 MainMenu
Add Component 添加 CanvasGroup 组件, 可以通过控制他的 Alpha 通道来显示或者隐藏界面
同理, 把原先的 MainMenuCanvas 重命名为 Canvas, 给其增加一个 HUD 用于放置原先的 Canvas 的子物体.增加 CanvasGroup, 可以通过控制他的 Alpha 通道来显示或者隐藏界面
上述描述的结果如下图所示
MainMenu 的 CanvasGroup>Alpha
初始化为 1, HUD 的 CanvasGroup>Alpha
初始化为 0.
给 StartBtn 按钮的 On Click()
添加事件通知 MainMenu 上面的 Alpha 属性值置为 0, 再添加一个事件通知 HUD 的 Alpha 属性值置为 1.
动图效果
6. UI 动画制作及显示 #
但是界面的切换有点生硬, 最好使用一下 UI 的动画制作, 使显示的更自然.
打开 Window>Animation
编辑器, 为 MainMenu 创建一个 Animator 和 一个 Animation Clip
. Add Property MainMenu : Canvas Group.Alpha
范围设为动画的0~1
对应其1~0
默认的 Animator
设置为只动画一次, 不要循环 : 把 MainMenuFadeOut
的 Loop Time
的勾选去掉.
实现 HUD 的动画操作类似.
为了有更好的衔接效果, 最好给 Animator 里做个过渡, 即可以添加一个 Create Empty New State
作为默认的 Default State
再由它 Make Transition
到原有的 MainMenuFadeOut
. HUD 操作同理
触发相关 Trigger 的过程如下, 点击 Start 按钮触发 MainMenu 的 FadeOut
使之淡出, 紧接着也触发 HUD 的 FadeIn
使之淡入, 这样就做好了. 对 Trigger 的控制需要脚本. 脚本内容如下
脚本 MainMenuController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MainMenuController : MonoBehaviour {
private Animator mainMenuAnim;
void Awake(){
mainMenuAnim = GetComponent<Animator> ();
}
public void MenuFade(){
mainMenuAnim.SetTrigger ("FadeOut");
}
}
脚本 HudController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HudController : MonoBehaviour {
private Animator hudAnim;
void Awake(){
hudAnim = GetComponent<Animator> ();
}
public void HudFade(){
hudAnim.SetTrigger ("FadeIn");
}
}
让 StartBtn
删除原来的事件, 换成与上述脚本绑定的 OnClick()
事件
至此, 渐出渐入的动画效果就做好了. 效果如下所示 :
7. 实现金币 UI 数量显示功能 #
实现界面右上角金币的数量逻辑.
找到 HUD>CoinsUI>TexCoinsCount
添加一个 CoinCounter.cs 脚本.
僵尸吃硬币就是僵尸与金币进行碰撞, 每吃一个硬币就使右上角加1. 硬币 Coin 脚本 :
using UnityEngine;
using System.Collections;
public class Coin : MonoBehaviour
{
private CoinCounter coinCounter;
void Awake()
{
coinCounter = GameObject.FindGameObjectWithTag ("TextCoinsCount").GetComponent<CoinCounter> ();
}
void OnTriggerEnter2D(Collider2D other)
{
if(other.gameObject.tag == "Player")
print ("You picked up a coin!");
coinCounter.coinCount++;
gameObject.SetActive(false);
}
}
脚本 CoinCounter
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CoinCounter : MonoBehaviour {
public int coinCount = 0;
void Start () {
}
void Update () {
GetComponent<Text>().text = coinCount.ToString ();
}
}
效果如图所示
8. 实现生命数量 UI 更新功能 #
硬币收集到一定数量就增加一个生命值的数量, 当收满 24 个金币的时候就会增加一条命.
脚本 LivesCounter
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
[ExecuteInEditMode]
public class LivesCounter : MonoBehaviour
{
public int initialLives = 3; // 游戏刚开始的时候的生命数量
public int extraLives = 0; // 游戏进行时额外增加的生命数量
public int totalLives; // 主角生命数量的总数
void Start()
{
GetLives();
}
// Update is called once per frame
void Update ()
{
totalLives = initialLives + extraLives;
GetComponent<Text> ().text = totalLives.ToString ();
}
void GetLives()
{
totalLives = initialLives + extraLives;
}
}
脚本 GameState
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class GameState : MonoBehaviour
{
private GameObject[] coins;
public int totalCoins; // 所有的金币总数
public bool gameRunning = false;
private CoinCounter coinCounter;
private LivesCounter liveCounter;
void Awake ()
{
coinCounter = GameObject.FindGameObjectWithTag ("TextCoinsCount").GetComponent<CoinCounter> ();
liveCounter = GameObject.FindGameObjectWithTag ("TextLiveCount").GetComponent<LivesCounter> ();
coins = GameObject.FindGameObjectsWithTag("Coin");
totalCoins = coins.Length;
}
void Update ()
{
int collectedCoins;
collectedCoins = coinCounter.coinCount; // 当前收集到的金币数量
liveCounter.extraLives = collectedCoins / totalCoins;
if (liveCounter.totalLives < 0) {
print ("Game Over!");
}
}
public void StartGame()
{
gameRunning = true;
}
public void GameOver()
{
gameRunning = false;
print ("Game Over!");
}
}
9. 实现时间倒计时功能 #
也就是界面最上方中间的时间计数器的逻辑实现.
随着时间的流逝, 上面的颜色池减少. (图片由右向左的长度的减少), 把 TimerFillImage
的 Image Type
换成 Filled, 并且将 Fill Method
设置为 Horizontal, 那么 Fill Amount
就可以用来做计时了.
为 Canvas>HUD>Timer>TimerFillImage
新建脚本 Timer.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Timer : MonoBehaviour {
public float currentTimer;
public float startTimer = 10f;
public float timerPercent;
private Image image;
void Awake () {
currentTimer = startTimer;
image = GetComponent<Image> ();
}
void Update () {
// 计时
currentTimer -= Time.deltaTime;
timerPercent = currentTimer / startTimer;
image.fillAmount = timerPercent;
}
}
效果如图所示
但是有一点需要注意, 那就是只有当 StartBtn 被点击出现新界面之后才应该开始计时. 需要利用在 GameState.cs 里的 gameRunning 状态, 在 Timer.cs 中把 gameRunning 读取过来, 是否开始进行一下控制. 当然,还不能忘记了, 还需要给 StartBtn 再增加一个 点击事件的反馈, 即去调用 GameState.cs 里的 StartGame() 方法.
看看 Timer.cs 脚本的改进
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Timer : MonoBehaviour {
public float currentTimer;
public float startTimer = 10f;
public float timerPercent;
private Image image;
private GameState gameState;
void Awake () {
currentTimer = startTimer;
image = GetComponent<Image> ();
gameState = GameObject.Find ("GameState").GetComponent<GameState> ();
}
void Update () {
// 游戏的确开始在运行的时候才开始进行倒计时
if(gameState.gameRunning){
// 计时
currentTimer -= Time.deltaTime;
timerPercent = currentTimer / startTimer;
image.fillAmount = timerPercent;
}
}
}
目前为止的效果
10. UI 自适应调整 #
即需要调整锚点的地方就调整一下.
学习自 58 开发网视频教程 : http://www.58kaifa.com/course/35
End.