• 实现僵尸跑酷游戏的 UGUI 实践


    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 设置为只动画一次, 不要循环 : 把 MainMenuFadeOutLoop 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. 实现时间倒计时功能 #

    也就是界面最上方中间的时间计数器的逻辑实现.

    随着时间的流逝, 上面的颜色池减少. (图片由右向左的长度的减少), 把 TimerFillImageImage 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.

  • 相关阅读:
    设计模式之装饰模式
    强化学习运行环境,atari 2600 游戏模拟器,atari-py库 —— 无法运行游戏,pacman,surround,报错: Segmentation fault (core dumped)
    【转载】 DQN玩Atari游戏安装atari环境bug指南
    【转载】 windows python3 安装 openai gym 的 atari_py
    【转载】 ubuntu18.04 cmake版本 更新方法
    强化学习baseline论文—— rainbow算法中给出实验结果的54个atari2600游戏名称列表
    UBUNTU18.04 SERVER 多显卡 服务器,为防止显卡计算任务出现不意外报错,设置显卡工作状态为:设定持久模式
    【转载】 nvidia-smi
    记录一次实验室显卡服务器崩溃事件(Ubuntu18.04 server系统,4块NVIDIA的特斯拉显卡)
    【转载】 Tensorboard:PermissionError: [Errno 13] Permission denied: ‘/tmp/.tensorboard-info/pid-46614.info‘
  • 原文地址:https://www.cnblogs.com/isayes/p/6380457.html
Copyright © 2020-2023  润新知