1. 程式人生 > >unity網路實戰開發(叢林戰爭)-正式開發階段(015-遊戲場景及開始介面UI搭建)

unity網路實戰開發(叢林戰爭)-正式開發階段(015-遊戲場景及開始介面UI搭建)

使用工具:VS2017,unity3d

使用語言:c#

作者:Gemini_xujian

參考:siki老師-《叢林戰爭》視訊教程

上一篇文章中,我已經完成了遊戲客戶端與伺服器端的初步連線,接下來將開始進行遊戲場景與開始介面UI的搭建。

01-控制場景的視野漫遊動畫作為選單介面背景

首先,需要將資源包中的一個scene場景作為遊戲的主場景,這裡,提供一下資源的下載地址(https://download.csdn.net/download/gemini_xujian/10465872),如果有需要的同學可以下載一下去使用。

接下來開始製作漫遊動畫。選中主攝像機,點選Windows選單下面的animation選項,點選中間的create按鈕,將animation檔案儲存在新建的animations目錄下,命名為CameraWander,如圖所示:


然後在animation編輯器中新增需要變化的屬性,這裡我們只需要修改position和rotation即可,如圖:


新增完成之後是這樣子的:


然後按照自己的想法修改位置和旋轉,我在這裡讓攝像機圍繞場景旋轉一週回到起點,並調節幀率為4。如圖:


這樣就實現了開場動畫的製作,附畫面截圖:


02-開發登入按鈕

首先在Hierarchy檢視下右鍵UI->Image與Text,修改image名字為startpanel並將錨點設定為全屏四角,再建立好text,將text做為startpanel的子物體,調整字型大小以及位置,並將字型選擇為自己喜歡的一種字型,這裡我是用資源提供的方正胖娃字型,調整好後,為字型新增shadow元件,使字型看起來更有立體感,然後為字型新增一個button元件,並將元件下的Transition選擇為Animation,點選下面的Auto Generate Animation按鈕,會彈出animation檔案儲存位置,我放在了animations資料夾下,並改名為button,然後開啟animation編輯器,新增變化屬性rect transform裡面的scale,在中間位置將scale的x和y改為1.2,儲存並檢視效果,這樣就完成了登入按鈕的製作。如圖:



03-設計登入面板UI

右鍵canvas,選擇UI->image,作為登入面板的背景,然後將輸入框以及按鈕等元件做為其子物體,完成效果如圖所示:


目前的UI層級為:


04-開發註冊面板及提示資訊面板

直接複製loginpanel修改成registerpanel,然後再搭建一個提示面板,效果如圖:


UI面板層級結構如圖:


05-建立面板指令碼

將我們之前搭建好的UI框架中的base資料夾拖拽到scripts目錄下,改名為uipanel,然後我們給每一個面板都建立一個指令碼,命名方式與每個面板名稱相同,建立好後,將這些指令碼都繼承自basepanel這個類,實現效果如圖:


每個指令碼繼承自basepanel(以startpanel為例):


06-建立面板的prefab並修改json和paneltype

將所有的UI面板做成prefab並放入resources目錄的uipanel資料夾下,在UIFramework/UIPanel資料夾下找到UIPanelType,然後刪除原來的列舉值,新增上我們剛才建立的幾個面板的列舉值,分別是Start,Message,Login,Register,然後修改json檔案,json檔案位於UIFramework/Resources目錄下,按照原來的命名方式進行修改,修改後的程式碼如下:

UIPanelType.json:

{
"infoList":
[
{"panelTypeString":"Message",
"path":"UIPanel/MessagePanel"},

{"panelTypeString":"Start",
"path":"UIPanel/StartPanel"},

{"panelTypeString":"Login",
"path":"UIPanel/LoginPanel"},

{"panelTypeString":"Register",
"path":"UIPanel/RegisterPanel"}

]
}

UIPanelType.cs:

using UnityEngine;
using System.Collections;
using System;


public enum UIPanelType  {
   Message,
   Start,
   Login,
   Register,
}

07-開發提示資訊模組

先上程式碼:

MessagePanel.cs:

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

public class MessagePanel : BasePanel
{
    private Text text;
    private float showTime=1f;
    public override void OnEnter()
    {
        base.OnEnter();
        text = GetComponent<Text>();
        text.enabled = false;
        uiMng.InjectMsgPanel(this);
    }

    public override void OnExit()
    {
        base.OnExit();
    }

    public override void OnPause()
    {
        base.OnPause();
    }

    public override void OnResume()
    {
        base.OnResume();
    }

    public void ShowMessage(string msg)
    {
        text.CrossFadeAlpha(1,0.2f,true);
        text.text = msg;
        text.enabled = true;
        Invoke("Hide", showTime);
    }
    private void Hide()
    {
        text.CrossFadeAlpha(0, showTime, true);
    }
}

UIManager.cs:

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

public class UIManager:BaseManager {

    /// 
    /// 單例模式的核心
    /// 1,定義一個靜態的物件 在外界訪問 在內部構造
    /// 2,構造方法私有化

    //private static UIManager _instance;

    //public static UIManager Instance
    //{
    //    get
    //    {
    //        if (_instance == null)
    //        {
    //            _instance = new UIManager();
    //        }
    //        return _instance;
    //    }
    //}

    private Transform canvasTransform;
    private Transform CanvasTransform
    {
        get
        {
            if (canvasTransform == null)
            {
                canvasTransform = GameObject.Find("Canvas").transform;
            }
            return canvasTransform;
        }
    }
    private Dictionary<UIPanelType, string> panelPathDict;//儲存所有面板Prefab的路徑
    private Dictionary<UIPanelType, BasePanel> panelDict;//儲存所有例項化面板的遊戲物體身上的BasePanel元件
    private Stack<BasePanel> panelStack;
    private MessagePanel msgPanel;
    

    public UIManager(GameFacade facade) : base(facade)
    {
        ParseUIPanelTypeJson();
    }

    /// <summary>
    /// 把某個頁面入棧,  把某個頁面顯示在介面上
    /// </summary>
    public void PushPanel(UIPanelType panelType)
    {
        if (panelStack == null)
            panelStack = new Stack<BasePanel>();

        //判斷一下棧裡面是否有頁面
        if (panelStack.Count > 0)
        {
            BasePanel topPanel = panelStack.Peek();
            topPanel.OnPause();
        }

        BasePanel panel = GetPanel(panelType);
        panel.OnEnter();
        panelStack.Push(panel);
    }
    /// <summary>
    /// 出棧 ,把頁面從介面上移除
    /// </summary>
    public void PopPanel()
    {
        if (panelStack == null)
            panelStack = new Stack<BasePanel>();

        if (panelStack.Count <= 0) return;

        //關閉棧頂頁面的顯示
        BasePanel topPanel = panelStack.Pop();
        topPanel.OnExit();

        if (panelStack.Count <= 0) return;
        BasePanel topPanel2 = panelStack.Peek();
        topPanel2.OnResume();

    }

    /// <summary>
    /// 根據面板型別 得到例項化的面板
    /// </summary>
    /// <returns></returns>
    private BasePanel GetPanel(UIPanelType panelType)
    {
        if (panelDict == null)
        {
            panelDict = new Dictionary<UIPanelType, BasePanel>();
        }

        //BasePanel panel;
        //panelDict.TryGetValue(panelType, out panel);//TODO

        BasePanel panel = panelDict.TryGet(panelType);

        if (panel == null)
        {
            //如果找不到,那麼就找這個面板的prefab的路徑,然後去根據prefab去例項化面板
            //string path;
            //panelPathDict.TryGetValue(panelType, out path);
            string path = panelPathDict.TryGet(panelType);
            GameObject instPanel = GameObject.Instantiate(Resources.Load(path)) as GameObject;
            instPanel.transform.SetParent(CanvasTransform,false);
            instPanel.GetComponent<BasePanel>().UIMng = this;
            panelDict.Add(panelType, instPanel.GetComponent<BasePanel>());
            return instPanel.GetComponent<BasePanel>();
        }
        else
        {
            return panel;
        }

    }

    [Serializable]
    class UIPanelTypeJson
    {
        public List<UIPanelInfo> infoList;
    }
    private void ParseUIPanelTypeJson()
    {
        panelPathDict = new Dictionary<UIPanelType, string>();

        TextAsset ta = Resources.Load<TextAsset>("UIPanelType");

        UIPanelTypeJson jsonObject = JsonUtility.FromJson<UIPanelTypeJson>(ta.text);

        foreach (UIPanelInfo info in jsonObject.infoList) 
        {
            //Debug.Log(info.panelType);
            panelPathDict.Add(info.panelType, info.path);
        }
    }
    public void InjectMsgPanel(MessagePanel msgPanel)
    {
        this.msgPanel = msgPanel;
    }


    public void ShowMessage(string msg)
    {
        if (msg == null)
        {
            Debug.Log("無法顯示提示資訊,msgpanel為空");
            return;
        }
        msgPanel.ShowMessage(msg);
    }
    /// <summary>
    /// just for test
    /// </summary>
    //public void Test()
    //{
    //    string path ;
    //    panelPathDict.TryGetValue(UIPanelType.Knapsack,out path);
    //    Debug.Log(path);
    //}
}

BasePanel.cs:

using UnityEngine;
using System.Collections;

public class BasePanel : MonoBehaviour {
    protected UIManager uiMng;
    public UIManager UIMng
    {
        set
        {
            uiMng = value;
        }
    }
    /// <summary>
    /// 介面被顯示出來
    /// </summary>
    public virtual void OnEnter()
    {

    }

    /// <summary>
    /// 介面暫停
    /// </summary>
    public virtual void OnPause()
    {

    }

    /// <summary>
    /// 介面繼續
    /// </summary>
    public virtual void OnResume()
    {

    }

    /// <summary>
    /// 介面不顯示,退出這個介面,介面被關係
    /// </summary>
    public virtual void OnExit()
    {

    }
}

GameFacade.cs:

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

public class GameFacade : MonoBehaviour {

    private static GameFacade _instance;
    public static GameFacade Instance
    {
        get
        {
            return _instance;
        }
    }

    private UIManager uiMng;
    private AudioManager audioMng;
    private PlayerManager playerMng;
    private RequestManager requestMng;
    private CameraManager cameraMng;
    private ClientManager clientMng;

    private void Awake()
    {
        if (_instance != null)
        {
            Destroy(this.gameObject);
            return;
        }
        _instance = this;
    }
    // Use this for initialization
    void Start() {
        InitManager();
    }

    // Update is called once per frame
    void Update() {

    }

    private void InitManager()
    {
        uiMng = new UIManager(this);
        audioMng = new AudioManager(this);
        playerMng = new PlayerManager(this);
        requestMng = new RequestManager(this);
        cameraMng = new CameraManager(this);
        clientMng = new ClientManager(this);

        uiMng.OnInit();
        audioMng.OnInit();
        playerMng.OnInit();
        requestMng.OnInit();
        cameraMng.OnInit();
        clientMng.OnInit();
    }
    private void DestroyManager()
    {
        uiMng.OnDestory();
        audioMng.OnDestory();
        playerMng.OnDestory();
        requestMng.OnDestory();
        cameraMng.OnDestory();
        clientMng.OnDestory();

    }
    private void OnDestroy()
    {
        DestroyManager();
    }

    public void AddRequest(ActionCode actionCode, BaseRequest request)
    {
        requestMng.AddRequest(actionCode, request);
    }
    public void RemoveRequest(ActionCode actionCode)
    {
        requestMng.RemoveRequest(actionCode);
    }
    public void HandleResponse(ActionCode actionCode, string data)
    {
        requestMng.HandleResponse(actionCode, data);
    }
    public void ShowMessage(string msg)
    {
        uiMng.ShowMessage(msg);
    }
}

說明:首先,我們對messagepanel進行實現,通過showmessage方法來顯示提示資訊,在showmessage中呼叫invoke方法,來呼叫hide方法,invoke方法的兩個引數分別表示將要呼叫的方法名以及多長時間後呼叫,crossfadealpha的三個引數分別表示目標的透明度值,過渡完成的時間長短以及是否忽略時間的大小快慢。之後,我們想要讓其他面板可以呼叫showmsaage方法,那麼,我們可以在basepanel中得到uimanager,通過uimanager這個類來排程所有的UI面板對外的方法,我們在uimanager呼叫messagepanel中的方法之前,需要先得到messagepanel的例項,這裡通過messagepanel面板呼叫顯示資訊方法時將自身傳遞給uimanager,這樣我們就可以方便的得到messagepanel例項並使用他的方法,除了在UI面板中呼叫外,我們還想要在其他的模組中也可以呼叫顯示提示資訊的方法,那麼,我們就可以將gamefacade類作為中介,用它來完成對messagepanel中showmessage方法的呼叫。

08-開發開始介面和麵板進入的動畫

在使用dotween動畫之前,需要先進行初始化,初始化的方法可以通過使用dotween提供的視覺化介面進行初始化,在工具欄有會有一個tools選單欄選項,這個選項是在匯入dotween後出現的,我們點選Tools->demigiant->dotween utility panel選項,會彈出來一個面板,點選面板中的setup dotween按鈕。這樣就完成了dotween外掛初始化工作。

先上修改的程式碼:

StartPanel.cs:

using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class StartPanel : BasePanel {
    private Button loginbtn;
    private Animator btnAnimator;

    private void Start()
    {
        loginbtn = transform.Find("loginbtn").GetComponent<Button>();
        loginbtn.onClick.AddListener(OnLoginClick);
        btnAnimator = transform.Find("loginbtn").GetComponent<Animator>();
    }
    public override void OnEnter()
    {
        base.OnEnter();
        if (loginbtn == null)
        {
            loginbtn = transform.Find("loginbtn").GetComponent<Button>();
            loginbtn.onClick.AddListener(OnLoginClick);
        }
        if(btnAnimator==null)
        btnAnimator = transform.Find("loginbtn").GetComponent<Animator>();
    }

    public override void OnExit()
    {
        base.OnExit();
    }

    public override void OnPause()
    {
        base.OnPause();
        btnAnimator.enabled = false;
        loginbtn.transform.DOScale(0, 0.4f).OnComplete(() => loginbtn.gameObject.SetActive(false));
    }

    public override void OnResume()
    {
        base.OnResume();
        loginbtn.gameObject.SetActive(true);
        loginbtn.transform.DOScale(1, 0.4f).OnComplete(()=> btnAnimator.enabled = true);
    }
    public void OnLoginClick()
    {
        uiMng.PushPanel(UIPanelType.Login);
    }
}

LoginPanel.cs:

using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class LoginPanel : BasePanel
{
    private Button closebtn;
    private void Start()
    {
        closebtn = transform.Find("closebtn").GetComponent<Button>();
        closebtn.onClick.AddListener(OnCloseClick);
    }
    public override void OnEnter()
    {
        base.OnEnter();
        gameObject.SetActive(true);
        if (closebtn == null)
        {
            closebtn = transform.Find("closebtn").GetComponent<Button>();
            closebtn.onClick.AddListener(OnCloseClick);
        }
        transform.localScale = Vector3.zero;
        transform.localPosition = new Vector3(800,0,0);
        transform.DOScale(1, 0.4f);
        transform.DOLocalMove(Vector3.zero, 0.4f);
    }

    public override void OnExit()
    {
        base.OnExit();
        gameObject.SetActive(false);
    }

    public override void OnPause()
    {
        base.OnPause();
    }

    public override void OnResume()
    {
        base.OnResume();
    }
    public void OnCloseClick()
    {
        transform.DOScale(0, 0.4f);
        transform.DOLocalMove(new Vector3(800,0,0), 0.4f).OnComplete(()=> { uiMng.PopPanel(); });
    }
}
說明:當我們點選開始面板的登入按鈕的時候,需要顯示出來下一個面板並將當前的面板隱藏,因為我們繼承了basepanel,所以我們可以通過定義的四種面板狀態進行一些動畫的接入,動畫效果的實現是由dotween實現的,我們在得到一些物體或者元件時,需要同時在start方法以及enter方法中得到,要注意的是,在enter中得到物體或者元件時需要判斷是否已經得到了,尤其是對UI元件(例如按鈕)註冊事件時為了防止重複,防止重複的原因是多次重複可能會導致事件執行多次,例如點選按鈕時重複註冊事件會導致事件中的方法多次執行,可能會發生不可預料的錯誤。

相關推薦

unity網路實戰開發叢林戰爭-正式開發階段015-遊戲場景開始介面UI搭建

使用工具:VS2017,unity3d使用語言:c#作者:Gemini_xujian參考:siki老師-《叢林戰爭》視訊教程上一篇文章中,我已經完成了遊戲客戶端與伺服器端的初步連線,接下來將開始進行遊戲場景與開始介面UI的搭建。01-控制場景的視野漫遊動畫作為選單介面背景首先

unity網路實戰開發叢林戰爭-前期知識準備003-開發伺服器端的傳送資料和接收資料

使用工具:VS2015使用語言:c#作者:Gemini_xujian參考:siki老師-《叢林戰爭》視訊教程繼上一篇文章內容,這節課講解一下伺服器端的傳送資料和接收資料。上篇文章完成了ip和埠號的繫結,接下來,我們首先需要監聽埠並接收客戶端的連線serverSocket.Li

unity網路實戰開發叢林戰爭-前期知識準備011-c#連線資料庫並實現增刪改查以及sql注入問題

使用工具:VS2015,Mysql使用語言:c#作者:Gemini_xujian參考:siki老師-《叢林戰爭》視訊教程繼上一篇文章內容,這節課講解一下資料庫的前期連線準備以及通過c# 實現資料庫的增刪改擦操作。首先你需要自行安裝Mysql以及它的workbench元件。然後

unity網路實戰開發叢林戰爭-正式開發階段018-聲音管理器模組的完善

使用工具:VS2017,unity3d 使用語言:c# 作者:Gemini_xujian 參考:siki老師-《叢林戰爭》視訊教程 上一篇文章中,已經完成了註冊事件的處理,接下來將完善聲音管理器模組。 01-開發聲音管理器 為了使遊戲執行起來更加富有活力,接下來,

unity網路實戰開發叢林戰爭-正式開發階段016-資料庫設計以及登入處理

使用工具:VS2017,unity3d使用語言:c#作者:Gemini_xujian參考:siki老師-《叢林戰爭》視訊教程上一篇文章中,已經完成了遊戲場景與開始介面UI的搭建,接下來將對資料庫和登入請求響應等操作進行處理。01-設計資料庫表(使用者表和戰績表)首先,我們需要

unity網路實戰開發叢林戰爭-正式開發階段013-遊戲伺服器端框架搭建

使用工具:VS2015使用語言:c#作者:Gemini_xujian參考:siki老師-《叢林戰爭》視訊教程繼上一篇文章內容,這節課講解一下游戲伺服器端的開發。01-專案目錄結構建立:首先開啟VS並建立一個c#控制檯應用程式專案,起名為“遊戲伺服器端”,建立好後,右鍵專案-&

資料庫操作之增加資料叢林戰爭專案

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using MySql.Data.MyS

遊戲開發叢林戰爭3

34.訊息面板的顯示 首先的話,我們建立我們的MessagePanel指令碼,這裡我們提供了建立,顯示,隱藏三個方法,並且的話我們這個面板指令碼的控制是交給Uimanager進行管理的 publicclassMessagePanel : BasePanel { pr

Node教程——API介面開發(Node版的CRUD通用介面搭建MangoDB+Express_Version2

# 1. 概述 > 時間跨度有點大,之前就跟大家嘮嗑過一些知識點,也開啟了一個Node書寫一個後臺api專案的開始,出於各種原因,遲遲沒有更新博文。現在我把這個坑填上,如果你還有閱讀過我之前的文章,我建議你先閱讀一下 *博文地址https://www.cnblogs.com/BM-laoli/p/12708

負載均衡集群介紹,lvs介紹,LVS調度算法,NAT模式搭建

bottom table all lvs dr 有一個 gen 輪詢 chang 定向 一、負載均衡集群介紹負載均衡集群:簡單地說就是讓多臺服務器均衡地去承載壓力。實現負載均衡的開源軟件有:LVS,keepalived,haproxy,nginx等其中相對於(網絡OSI七層

CF1007D. Ants樹鏈剖分+線段樹+2-SAT字首優化建圖

題目連結 https://codeforces.com/problemset/problem/1007/D 題解 由於問題的本質是給定許多二元集合,判斷是否能從每一個二元集合中選出一個元素,使得所有選出的元素合法,因此考慮使用 2-SAT 解決該問題。 不難發現,使用 2-SAT 解決該問題的複雜度瓶

VS2010/MFC入門程式設計十七多執行緒的建立,包括工作執行緒和使用者介面執行緒

1.MFC多執行緒簡介 MFC對多執行緒進行了一層簡單的封裝,在Visual C++中每個執行緒都是從CWinThread類繼承而來的。每一個應用程式的執行都有一個主執行緒,這個主執行緒也是從CWinThread類繼承而來的。可以利用CWinThread物件建立應用程式執行的其它執行緒。 MFC用CW

Vue從入門到精通5--第四階段:Vue入門Vue-cli上手教程

第四階段 vue2.0語法 vue2.0+webpack搭建開發環境 官方腳手架vue-cli     Vue的作者尤雨溪大神寫了一篇《新手向:Vue 2.0 的建議學習順序》來介紹Vue及相關知識點的學習路線,主要列出了知識點概要,如果你覺得略

rabbitmq系列幾種常見模式的應用場景實現

一、簡單模式 原理:生產者將訊息交給預設的交換機,交換機獲取訊息後交給繫結這個生產者的佇列(投遞規則為佇列名稱和routing key 相同的佇列),監聽當前佇列的消費者獲取資訊並執行消費邏輯。 場景:有一個oa系統,使用者通過接收手機驗證碼進行註冊,頁面上點選獲取驗證碼後,將驗證碼放到訊息佇列,然後簡訊

【微信小遊戲實戰】零基礎製作《歡樂停車場》三、遊戲場景製作

1、遊戲立項 微信小遊戲中有一款《歡樂停車場Plus》的小遊戲,大家可以搜尋玩下。這是一款益智類的小遊戲,遊戲中有紅、黃、綠、藍、紫5輛豪車6個停車位,玩家通過可行走路線移動小車,最終讓各顏色的小車停到對應的顏色車位,則完成本關挑戰。接下來的日子,我將同大家一步一步的來實現這款小遊戲,從零基礎入門微信小遊戲

網路遊戲叢林戰爭開發與學習之:粘包分包現象以及服務端解析資料

1. 粘包和分包 粘包和分包是利用Socket在TCP協議下內部的優化機制。粘包指的是傳送資料比較頻繁,但資料量較少,此時客戶端不會直接將資料包傳送給伺服器,而是會與其它的資料包進行一個結合,例如遊戲中的位置資訊就是屬於頻繁傳送但資料量小的資訊,此時如果每條資料都S

網路遊戲叢林戰爭開發與學習之網路程式設計的基礎知識

《叢林戰爭》是一款完整的網路遊戲案例,運用U3D開發客戶端,Socket開發服務端,其中涉及到了網路程式設計、資料庫和Unity的功能實現,之前通過U3D開發了一個單機遊戲《黑暗之光》,並沒有涉及網路程式設計的知識,通過《叢林戰爭》這個完整的遊戲,系統性地學習網路程式設計,並

DDD實戰進階第一波(五):開發一般業務的大健康行業直銷系統實現產品上下文領域層

討論 clas 基本 ted ctc decimal nco protect pan 從這篇文章開始,我們根據前面的DDD理論與DDD框架的約束,正式進入直銷系統案例的開發。 本篇文章主要講產品上下文中的領域層的主要實現,先簡單講下業務方面的需求:產品SPU與產品SKU,產

Flask框架的學習與實戰開發環境搭建

進行 read 模型 clas tar pychar html itl .html Flask是一個使用 Python 編寫的輕量級 Web 應用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎則使用 Jinja2。很多功能的實現都參考了django框架。由於項

海康威視網路攝像機 SDK二次開發JAVA1-開發環境搭建

硬體環境 相關的硬體環境準備:攝像機型號:DS-2CD2T25FD-I3,按照說明書搭建好硬體環境 SDK下載 開發工具:IDEA20173.3 , JDK: 9 官網SDK地址:http://www.hikvision.com/cn/download_61.html