unity网络游戏开发

【千锋合集】史上最全Unity3D全套教程|匠心之作_哔哩哔哩_bilibili

  toggle group的添加

 自己搭建UI和预设体

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

public class LobbyFacade : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        UIManager.Instance.ShowUI("MainPanel");
        UIManager.Instance.ShowUI("TopPanel");
        
    }

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

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

public class MainPanelController : UIControllerBase
{
    protected override void ControllerStart()
    {
        base.ControllerStart();
        Debug.Log("MainPanel Start!");
        BindEvent();
    }
    protected void BindEvent()
    {

    }
}
 

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

public class MainPanelModule : UIModuleBase
{
    public override void Awake()
    {
        base.Awake();
        //创建控制器
        var controller = new MainPanelController();
        //绑定控制
        BindController(controller);
    }
}
 

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

public class TopPanelController : UIControllerBase
{
    protected override void ControllerStart()
    {
        base.ControllerStart();
        Debug.Log("TopPanel Start!");
        BindEvent();
    }
    protected void BindEvent() {

    }
}
 

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

public class TopPanelModule : UIModuleBase
{
    public override void Awake()
    {
        base.Awake();
        //创建控制器
        var controller = new TopPanelController();
        //绑定控制
        BindController(controller);
    } 
}
 

--------------------------------------------------------------------------------------------------------------------------------

json文件

{
"AllData":[
{
  "SceneName":"LobbyScene",
  "Data": [
    { "PanelName":"TopPanel",
    "PanelPath":"LobbyUIPanels/TopPanel" },
    { "PanelName":"MainPanel",
    "PanelPath": "LobbyUIPanels/MainPanel" },
    {"PanelName": "RoomPanel",
    "PanelPath": "LobbyUIPanels/RoomPanel" },
    { "PanelName":"RoomListPanel",
    "PanelPath": "LobbyUIPanels/RoomListPanel" }
    ]
    }
  ] 
}

所有代码汇总:

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

public class TopPanelModule : UIModuleBase

{

    public override void Awake()

    {

        base.Awake();

        //创建控制器

        var controller = new TopPanelController();

        //绑定控制

        BindController(controller);

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class CameraFollow : MonoBehaviour

{

    [Header("跟随速度")]

    public float moveSpeed = 3f;

    // Start is called before the first frame update

    void Start()

    {

       

    }

    // Update is called once per frame

    void Update()

    {

        if (HumanGameManager.Instance.currentHero == null) {

            return;

        }

        float Instance_x = HumanGameManager.Instance.currentHero.position.x;

        float Instance_y = 15f;

        float Instance_z = HumanGameManager.Instance.currentHero.position.z;

       

        Vector3 followPosition = new Vector3(Instance_x, Instance_y, Instance_z);

        transform.position = Vector3.Lerp(transform.position, followPosition,Time.deltaTime*moveSpeed);

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using Photon.Pun;

using Photon.Realtime;

using UIFrame;

using Hashtable = ExitGames.Client.Photon.Hashtable;

using ExitGames.Client.Photon;

using System;

public class GameController : MonoBehaviourPunCallbacks

{

    public bool hasInit = false;

    // Start is called before the first frame update

    void Start()

    {

        //设置每秒发送包数

        PhotonNetwork.SendRate = 30;

        //PhotonNetwork.Instantiate(JsonDataManager.Instance.FindHeroPath(HumanGameManager.Instance.selectedHeroIndex),Vector3.zero,Quaternion.identity);

        //设置玩家加载成功属性

        SetPlayerLoaded();

        //房主检测是否所有玩家都加载成功

        //CheckAllPlayerLoaded();

        //Test();

    }

    private void Test() {

        if (!PhotonNetwork.IsMasterClient)

            return;

        //生产场景网络对象

        PhotonNetwork.InstantiateSceneObject(JsonDataManager.Instance.FindHeroPath(0),Vector3.back,Quaternion.identity);      

    }

    // Update is called once per frame

    void Update()

    {

       

    }

    /// <summary>

    /// 设置当前玩家已经加载场景成功

    /// </summary>

    private void SetPlayerLoaded() {

        Hashtable hashtable = new Hashtable();

        //添加属性

        hashtable.Add(GameConst.LOADED_PROPERTY,true);

        //设置属性

        PhotonNetwork.LocalPlayer.SetCustomProperties(hashtable);

    }

    /// <summary>

    /// 检测所有玩家是否都已经加载场景成功

    /// </summary>

    private bool CheckAllPlayerLoaded() {

        if (!PhotonNetwork.IsMasterClient)

            return false;

        for (int i = 0; i < PhotonNetwork.PlayerList.Length; i++) {

            //是否加载

            object isLoaded = false;

            //尝试加载属性

            PhotonNetwork.PlayerList[i].CustomProperties.TryGetValue(GameConst.LOADED_PROPERTY, out isLoaded);

            //如果没有加载到或加载到了,值还为未加载场景成功

            if (isLoaded == null || !(bool)isLoaded) {

                return false;

            }

        }

        Hashtable hashtable = new Hashtable();

        //添加房间属性

        hashtable.Add(GameConst.INITHERO_PROPERTY, true);

        //设置房间属性

        PhotonNetwork.CurrentRoom.SetCustomProperties(hashtable);

        //表示所有玩家都已经加载场景成功

        return true;

    }

    #region Photon Callbacks

    public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)

    {

        object canInit = false;

        //尝试获取属性

        propertiesThatChanged.TryGetValue(GameConst.INITHERO_PROPERTY,out canInit);

        if (canInit == null) {

            canInit = false;

        }

        //属性获取到,且值为True

        if ((bool)canInit&&!hasInit) {

            //每个玩家生成各自的英雄

            InitHero();

        }

    }

    private void InitHero()

    {

        //标记已经创建好了英雄

        hasInit = true;

        PhotonNetwork.Instantiate(JsonDataManager.Instance.FindHeroPath(HumanGameManager.Instance.selectedHeroIndex),new Vector3(PhotonNetwork.LocalPlayer.ActorNumber*3-3,0,0),Quaternion.identity);

    }

    public override void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)

    {

        //房主检测是否所有玩家都加载成功

        CheckAllPlayerLoaded();

    }

    #endregion

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using Photon.Pun;

using UIFrame;

using UnityEngine.AI;

using System;

public class HeroController : MonoBehaviourPunCallbacks,IPunObservable

{

    [Header("攻击范围")]

    public float attackRange = 2f;

    [Header("移动速度")]

    public float moveSpeed = 3f;

    [Header("转身速度")]

    public float turnSpeed;

    //射线碰撞检测器

    private RaycastHit hit;

    private NavMeshAgent nav;

    private Animator ani;

    private PhotonAnimatorView aniView;

    //导航去找英雄

    private bool gotoHero = false;

    //目标英雄

    private PhotonView targetHero;

    //攻击特效脚本

    private TriggerProjectile _triggerProjectile;

    private void Awake()

    {

        nav = GetComponent<NavMeshAgent>();

        ani = GetComponent<Animator>();

        aniView = GetComponent<PhotonAnimatorView>();

        _triggerProjectile = GetComponent<TriggerProjectile>();

    }

    private void Start() {

        //设置制动距离

        nav.stoppingDistance = 0;

        //设置移动速度

        nav.speed = moveSpeed;

        if (photonView.IsMine) {

            //标记当前英雄

            HumanGameManager.Instance.currentHero = transform;

        }

    }

    private void Update()

    {

        if (!photonView.IsMine)

            return;

        //if (photonView.Owner == null)

            //return;

        CheckArrive();

        HeroInput();

        CheckTargetHeroInRange();

    }

    /// <summary>

    /// 检测目标英雄是否脱离攻击范围

    /// </summary>

    private void CheckTargetHeroInRange() {

        if (targetHero == null)

            return;

        //如果对方已经走远

        if (Vector3.Distance(targetHero.transform.position, transform.position) > attackRange) {

            //停止攻击

            ani.SetBool(GameConst.PLAYERATTACK_PARA, false);

            //导航去目标角色

            SetHeroDestination(targetHero.transform.position);

        }

    }

    /// <summary>

    /// 检测当前英雄是否到达导航目标

    /// </summary>

    private void CheckArrive() {

        //到达目标

        if (nav.remainingDistance - nav.stoppingDistance <= 0.05f) {

            ani.SetFloat(GameConst.SPEED_PARA, 0);

            if (targetHero!=null)

            {

                //转向目标

                RotateTo(targetHero.transform.position);

                //攻击

                ani.SetBool(GameConst.PLAYERATTACK_PARA, true);

            }

            else

            {

                //停止攻击

                ani.SetBool(GameConst.PLAYERATTACK_PARA, false);

            }

        }

    }

    /// <summary>

    /// 转向目标

    /// </summary>

    /// <param name="target"></param>

    private void RotateTo(Vector3 target) {

        //方向向量

        Vector3 dir = target - transform.position;

        //转成四元数

        Quaternion targetQua = Quaternion.LookRotation(dir);

        //Lerp

        

        transform.rotation = Quaternion.Lerp(transform.rotation, targetQua, Time.deltaTime * turnSpeed);

    }

    /// <summary>

    /// 英雄操作输入检测

    /// </summary>

    private void HeroInput() {

        if (Input.GetButtonDown("HeroMove"))

        {

            //将鼠标位置转换为物理射线

            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            if (Physics.Raycast(ray, out hit, 100, 1 << 8 | 1 << 9))

            {

                //如果点击的是当前英雄

                if (hit.collider.gameObject == gameObject)

                    return;

                //设置位置

                //如果点击的是地面

                if (hit.collider.gameObject.layer == LayerMask.NameToLayer("Ground"))

                {

                    nav.stoppingDistance = 0;

                    //标记目标丢失

                    targetHero = null;

                    //生成对象

                    GameObject tempParticle = Instantiate(AssetsManager.Instance.GetAsset(SystemDefine.ClickParticlePath)) as GameObject;

                    //设置位置

                    tempParticle.transform.position = hit.point;

                    //定时销毁

                    Destroy(tempParticle, 2);

                }

                else {

                    nav.stoppingDistance = attackRange;

                    //获取目标英雄

                    targetHero = hit.collider.GetComponent<PhotonView>();

                    //同步给其他玩家

                    photonView.RPC("SendTarget",RpcTarget.All,targetHero.ViewID);

                }

                //设置导航目标

                nav.SetDestination(hit.point);

                nav.velocity = Vector3.zero;

                //设置导航目标

                SetHeroDestination(hit.point);

               

               

            }

        }

    }

    [PunRPC]

    public void SendTarget(int viewID) {

        _triggerProjectile.targetPoint=PhotonView.Find(viewID).transform;

    }

    private void SetHeroDestination(Vector3 target) {

        //设置动画参数

        ani.SetFloat(GameConst.SPEED_PARA, 1.5f);

        //当前玩家指向目标的方向向量

        Vector3 dir=target - transform.position;

        //计算夹角

        float angle=Vector3.Angle(dir, transform.forward);

        if (angle > 80) {

            nav.velocity = Vector3.zero;

        }

        nav.velocity = Vector3.zero;

        //设置导航目标

        nav.SetDestination(target);

    }

    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)

    {

        return;

        if (stream.IsWriting)

        {

            if (targetHero != null)

            {

                //写入ViewID

                stream.SendNext(targetHero.ViewID);

                //设置特效目标

                _triggerProjectile.targetPoint = targetHero.transform;

            }          

        }

        else if(stream.IsReading)

        {

            try {

                //读取ViewID

                int viewID = (int)stream.ReceiveNext();

                //通过ViewID拿到PhotonView

                _triggerProjectile.targetPoint = PhotonView.Find(viewID).transform;

            }

            catch (Exception e)

            {

                Debug.LogWarning(e);

            }          

        }

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class HumanGameManager : MonoBehaviour

{

    public static HumanGameManager Instance;

    /// <summary>

    /// 选择英雄编号

    /// </summary>

    public byte selectedHeroIndex = 1;

    /// <summary>

    /// 当前英雄

    /// </summary>

    public Transform currentHero;

    private void Awake()

    {

        Instance = this;

        //过渡场景时,不要销毁

        DontDestroyOnLoad(gameObject);

    }

    // Start is called before the first frame update

    void Start()

    {

       

    }

    // Update is called once per frame

    void Update()

    {

       

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class TriggerProjectile : MonoBehaviour

{

    public GameObject projectile;

    public Transform shootPoint;

    public Transform targetPoint;

    private GameObject magicMissile;

    public float attackCostTime=1;

    public float attackHeight = 12;

    public GameObject hitEffect;

    public void shoot() {

        magicMissile = Instantiate(projectile, shootPoint.position,transform.rotation);

        StartCoroutine(lerpyLoop(magicMissile));

    }

    //shoot loop

    public IEnumerator lerpyLoop(GameObject projectileInstance) {

        float progress = 0;

        float timeScale = 1.0f / attackCostTime;

        Vector3 origin = projectileInstance.transform.position;

        if (targetPoint == null)

            yield break;

        while (progress < 1) {

            if (projectileInstance && targetPoint) {

                progress += timeScale * Time.deltaTime;

                float ypos = (progress-Mathf.Pow(progress,2)) * attackHeight;

                float ypos_b = ((progress+0.1f)-Mathf.Pow(progress+0.1f,2))*attackHeight;

                projectileInstance.transform.position = Vector3.Lerp(origin,targetPoint.position,progress);

                if (progress < 0.9f) {

                    projectileInstance.transform.LookAt(Vector3.Lerp(origin,targetPoint.position,progress+0.1f)+new Vector3(0,ypos_b,0));

                }

                yield return null;

            }

        }

    }

    public void clearProjectiles() {

        if (magicMissile)

            Destroy(magicMissile);

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

using Photon.Pun;

using Photon.Realtime;

using Photon;

public class RoomPanelModule:UIModuleBase

{

    //创建控制器

    RoomPanelController controller;

    public override void Awake()

    {

        base.Awake();

        //创建控制器

        controller = new RoomPanelController();

        //绑定控制

        BindController(controller);

    }

    /// <summary>

    /// 更新玩家UI的显示

    /// </summary>

    public void UpdatePlayerUIMsg() {

        controller.UpdatePlayerMsg();

    }

    //【新】

    public void SetPlayerReadyStateHash(int playerID, bool isReady) {

        controller.SetPlayerReadyStateHash(playerID, isReady);

    }

    /// <summary>

    /// 设置玩家准备状态

    /// </summary>

    /// <param name="playerID"></param>

    /// <param name="isReady"></param>

   

    public void SetPlayerReadyState(int playerID, bool isReady) {

        controller.SetPlayerReadyState(playerID,isReady);

    }

    public void ShowStartGameBtn() {

        controller.ShowStartGameBtn();

    }

    public override void OnEnter()

    {

        base.OnEnter();

        _canvasGroup.alpha = 1;

        UpdatePlayerUIMsg();

    }

    public override void OnPause()

    {

        base.OnPause();

        _canvasGroup.alpha = 0;

    }

    public override void OnResume()

    {

        base.OnResume();

        _canvasGroup.alpha = 1;

    }

    public override void OnExit()

    {

        base.OnExit();

        _canvasGroup.alpha = 0;

        controller.ClearPlayerUIList();

        //离开房间时,取消当前玩家的准备状态(新)

        SetPlayerReadyState(PhotonNetwork.LocalPlayer.ActorNumber, false);

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

using Photon.Pun;

using Photon.Realtime;

public class RoomListPanelModule : UIModuleBase

{

    //对应的控制器

    private RoomListPanelController controller;

    public override void Awake()

    {

        base.Awake();

        //创建控制器

        controller = new RoomListPanelController();

        //绑定控制

        BindController(controller);

    }

    /// <summary>

    /// 设置房间信息列表

    /// </summary>

    /// <param name="roomInfos"></param>

    public void SetRoomInfos(List<RoomInfo> roomInfos) {

        //设置房间信息列表

        controller.UpdateRoomList(roomInfos);

    }

    public override void OnEnter()

    {

        base.OnEnter();

        _canvasGroup.alpha = 1;

        controller.UpdateRoomListUI();

       

    }

    public override void OnPause()

    {

        base.OnPause();

        _canvasGroup.alpha = 0;

    }

    public override void OnResume()

    {

        base.OnResume();

        _canvasGroup.alpha = 1;

        if (!PhotonNetwork.InLobby) {

            PhotonNetwork.JoinLobby();

        }

        controller.UpdateRoomListUI();

    }

    public override void OnExit()

    {

        base.OnExit();

        _canvasGroup.alpha = 0;

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

public class InfoPanelModule : UIModuleBase

{

    //创建控制器

    private InfoPanelController controller;

    public override void Awake()

    {

        base.Awake();

        //创建控制器

        controller = new InfoPanelController();

        //绑定控制

        BindController(controller);

    }

    public override void OnEnter()

    {

        base.OnEnter();

        _canvasGroup.alpha = 1;

        controller.SetInfoText(LobbyManager.Instance.infoMessage);

    }

    public override void OnPause()

    {

        base.OnPause();

        _canvasGroup.alpha = 0;

    }

    public override void OnResume()

    {

        base.OnResume();

        _canvasGroup.alpha = 1;

    }

    public override void OnExit()

    {

        base.OnExit();

        _canvasGroup.alpha = 0;

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.Events;

using UnityEngine.UI;

using UIInterface;

using TMPro;

namespace UIInterface

{

    public class UIMono : MonoBehaviour, IRectTransform, IText, IImage, IRawImage, IButton, IInputField, ItmpTextPro, ITMP_InputFIeld,IGameObject

    {

        #region Component

        private RectTransform _rectTransform;

        private Text _text;

        private Image _image;

        private RawImage _rawImage;

        private Button _button;

        private InputField _inputField;

        private TMP_Text _textmesh;

        private TMP_InputField _tmpinputField;

        #endregion

        #region Mono Callback

        protected virtual void Awake() {

            _rectTransform = GetComponent<RectTransform>();

            _text = GetComponent<Text>();

            _image = GetComponent<Image>();

            _rawImage = GetComponent<RawImage>();

            _button = GetComponent<Button>();

            _inputField = GetComponent<InputField>();

            _textmesh=GetComponent<TMP_Text>();

            _tmpinputField = GetComponent<TMP_InputField>();

        }

        #endregion

        public virtual void AddOnClickListener(UnityAction action)

        {

            _button.onClick.AddListener(action);

        }

        public virtual void AddOnValueChangeListener(UnityAction<string> action)

        {

            _inputField.onValueChanged.AddListener(action);

        }

        public virtual Color GetImageColor()

        {

            return _image.color;

        }

        public virtual string GetInputFieldText()

        {

            return _inputField.text;

        }

        public virtual Sprite GetSprite()

        {

            return _image.sprite;

        }

      

        public virtual void SetImageColor(Color color)

        {

            _image.color = color;

        }

        public virtual void SetInputFieldText(string text)

        {

            _inputField.text = text;

        }

        public virtual void SetSprite(Sprite sprite)

        {

            _image.sprite = sprite;

        }

        public virtual void SetTextColor(Color color)

        {

            _text.color = color;

        }

        public virtual void SetTextText(string text)

        {

            _text.text = text;

        }

        public virtual string GetTextText()

        {

            return _text.text;

        }

        public void SetParent(Transform parent)

        {

            transform.SetParent(parent);

        }

        public void SetParent(Transform parent, bool stayWorldPos)

        {

            transform.SetParent(parent,stayWorldPos);

        }

        public void tmpSetTextText(string text)

        {

            _textmesh.text = text;

        }

        public string tmpGetText()

        {

            return _textmesh.text;

        }

        public void tmpSetColor(Color color)

        {

            _textmesh.color = color;

        }

        public void tmpAddOnValueChangeListener(UnityAction<string> action)

        {

            _tmpinputField.onValueChanged.AddListener(action);

        }

        public string tmpGetInputFieldText()

        {

            return _tmpinputField.text;

        }

        public void tmpSetInputFieldText(string text)

        {

            _tmpinputField.text = text;

        }

        public void SetGameObjectActive(bool active)

        {

            gameObject.SetActive(active);

        }

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

namespace UIInterface {

public interface ItmpTextPro {

        void tmpSetTextText(string text);

        string tmpGetText();

        void tmpSetColor(Color color);

        

}

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using TMPro;

using UnityEngine.Events;

namespace UIInterface {

public interface ITMP_InputFIeld {

        void tmpAddOnValueChangeListener(UnityAction<string> action);

        string tmpGetInputFieldText();

        void tmpSetInputFieldText(string text);

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

namespace UIInterface {

public interface IText {

        void SetTextText(string text);

        string GetTextText();

        void SetTextColor(Color color);

        

}

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

namespace UIInterface

{

    public interface IRectTransform

    {

        void SetParent(Transform parent);

        void SetParent(Transform parent,bool stayWorldPos);

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

public class MainPanelModule : UIModuleBase

{

    public override void Awake()

    {

        base.Awake();

        //创建控制器

        var controller = new MainPanelController();

        //绑定控制

        BindController(controller);

    }

    public override void OnEnter()

    {

        base.OnEnter();

        _canvasGroup.interactable = false;

    }

    public void ResumePanelInteractable() {

        _canvasGroup.interactable = true;

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.Events;

namespace UIInterface

{

    public interface IInputField

    {

        void AddOnValueChangeListener(UnityAction<string> action);

        string GetInputFieldText();

        void SetInputFieldText(string text);

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

namespace UIInterface

{

    public interface IImage

    {

        void SetSprite(Sprite sprite);

        Sprite GetSprite();

        void SetImageColor(Color color);

        Color GetImageColor();      

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

namespace UIInterface {

    public interface IGameObject {

        void SetGameObjectActive(bool active);

    }  

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.Events;

namespace UIInterface

{

    public interface IButton

    {

        void AddOnClickListener(UnityAction action);     

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using System.Reflection;

using System;

namespace UIFrame {

public class Singleton<T> where T:class {

    //单例对象

    private static T _singleton;

    //获取单例

         public static T Instance {

        get {

            if (_singleton == null) {

                //如果这样写,那么该类型T必有一个public的构造函数

                //_singleton = new T();

                //通过反射的方式,去实例化一个对象出来

                //派生的单例类中必须要有一个私有的无参构造

                _singleton=(T)Activator.CreateInstance(typeof(T), nonPublic: true);

            }

            return _singleton;

        }

    }

}

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

using System;

namespace UIFrame {

    public class JsonDataManager : Singleton<JsonDataManager>

    {

        private JsonDataManager()

        {

            //Json解析【Json文件orJsonString

            //private void JsonUtilityTest<T>(string json) {

            //T result=JsonUtility.FromJson<T>("json");

            panelDataDic = new Dictionary<int, Dictionary<string, string>>();

            widgetDataDic = new Dictionary<int, Dictionary<string, string>>();

            widgetData = new JsonWidgetsModel();

            heroDataDic = new Dictionary<int, Dictionary<int, string>>();

            ParsePanelData();

            ParseWidgetData();

            ParseHeroData();

        }

        /// <summary>

        /// 解吸英雄数据

        /// </summary>

        private void ParseHeroData()

        {

            //获取配置文本资源

            TextAsset heroConfig = AssetsManager.Instance.GetAsset(SystemDefine.HeroConfigPath) as TextAsset;

            //widget的配置文件进行解析

            heroData = JsonUtility.FromJson<JsonHeroModel>(heroConfig.text);

            //Widget转换为方便检索的字典

            for (int i = 0; i < heroData.AllData.Length; i++)

            {

                //创建一个字典

                Dictionary<int, string> crtDic = new Dictionary<int, string>();

                //添加一个场景ID和一个字典

                heroDataDic.Add(i, crtDic);

                //遍历当前场景内所有Panel路径资源

                for (int j = 0; j < heroData.AllData[i].Data.Length; j++)

                {

                    //PanelNameKey,以PanelPathvalue进行存储

                    crtDic.Add(heroData.AllData[i].Data[j].HeroIndex, heroData.AllData[i].Data[j].HeroPath);

                }

            }

        }

        #region Json Parse

        /// <summary>

        /// 解析动态元件数据

        /// </summary>

        private void ParseWidgetData()

        {

            //获取配置文本资源

            TextAsset widgetConfig = AssetsManager.Instance.GetAsset(SystemDefine.WidgetConfigPath) as TextAsset;

            //widget的配置文件进行解析

            widgetData = JsonUtility.FromJson<JsonWidgetsModel>(widgetConfig.text);

            //Widget转换为方便检索的字典

            for (int i = 0; i < widgetData.AllData.Length; i++)

            {

                //创建一个字典

                Dictionary<string, string> crtDic = new Dictionary<string, string>();

                //添加一个场景ID和一个字典

                widgetDataDic.Add(i, crtDic);

                //遍历当前场景内所有Panel路径资源

                for (int j = 0; j < widgetData.AllData[i].Data.Length; j++)

                {

                    //PanelNameKey,以PanelPathvalue进行存储

                    crtDic.Add(widgetData.AllData[i].Data[j].WidgetName, widgetData.AllData[i].Data[j].WidgetPath);

                }

            }

        }

        #endregion

        #region Saved Structure

        //Panel解析后的数据

        JsonPanelsModel panelData;

        //Panel解析后的数据【字典版】

        private Dictionary<int,Dictionary<string, string>> panelDataDic;

        //Widget解析后的数据

        JsonWidgetsModel widgetData;

        //Widget解析后的数据【字典版】

        private Dictionary<int, Dictionary<string, string>> widgetDataDic;

        //Hero解析后的数据

        JsonHeroModel heroData;

        //Hero解析后的数据【字典版】

        private Dictionary<int, Dictionary<int, string>>heroDataDic;

        #endregion

        #region DataFind

        //Json解析【Json文件orJsonString

        private void ParsePanelData() {

            //获取配置文本资源

            TextAsset panelConfig = AssetsManager.Instance.GetAsset(SystemDefine.PanelConfigPath) as TextAsset;

            //Panel的配置文件进行解析

            panelData= JsonUtility.FromJson<JsonPanelsModel>(panelConfig.text);

            //PanelData转换为方便检索的字典

            for (int i=0;i<panelData.AllData.Length;i++) {

                //创建一个字典

                Dictionary<string, string> crtDic = new Dictionary<string, string>();

                //添加一个场景ID和一个字典

                panelDataDic.Add(i,crtDic);

                //遍历当前场景内所有Panel路径资源

                for (int j=0;j<panelData.AllData[i].Data.Length;j++) {

                    //PanelNameKey,以PanelPathvalue进行存储

                    crtDic.Add(panelData.AllData[i].Data[j].PanelName, panelData.AllData[i].Data[j].PanelPath);

                }

            }

        }

      

        /// <summary>

        /// 通过Panel名称返回Panel的资源路径

        /// </summary>

        /// <param name="panelName"></param>

        /// <returns></returns>

        public string FindPanelPath(string panelName, int sceneID = (int)SystemDefine.SceneID.MainScene) {

            if (!panelDataDic.ContainsKey(sceneID))

                return null;

            if (!panelDataDic[sceneID].ContainsKey(panelName))

                return null;

            //如果IDPanel在字典中都存在,则直接返回

            return panelDataDic[sceneID][panelName];          

        }

        /// <summary>

        /// 通过元件名称找到其对应的路径

        /// </summary>

        /// <param name="panelName"></param>

        /// <returns></returns>

        public string FindWidgetPath(string widgetName, int sceneID = (int)SystemDefine.SceneID.MainScene)

        {

            if (!widgetDataDic.ContainsKey(sceneID))

                return null;

            if (!widgetDataDic[sceneID].ContainsKey(widgetName))

                return null;

            //如果IDWidget在字典中都存在,则直接返回

            return widgetDataDic[sceneID][widgetName];

        }

/// <summary>

/// 通过英雄ID获取资源路径

/// </summary>

/// <param name="heroIndex"></param>

/// <param name="sceneID"></param>

/// <returns></returns>

        public string FindHeroPath(int heroIndex, int sceneID = (int)SystemDefine.SceneID.MainScene)

        {

            if (!heroDataDic.ContainsKey(sceneID))

                return null;

            if (!heroDataDic[sceneID].ContainsKey(heroIndex))

                return null;

            //如果IDWidget在字典中都存在,则直接返回

            return heroDataDic[sceneID][heroIndex];

        }

        #endregion

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

namespace UIFrame

{

    public class AssetsManager : Singleton<AssetsManager>

    {

        //私有构造

        private AssetsManager() {

            assetsCache = new Dictionary<string, Object>();

        }

       

        /// <summary>

        /// 资源缓存

        /// </summary>

        private Dictionary<string, Object> assetsCache;

        /// <summary>

        /// 获取资源

        /// </summary>

        /// <typeparam name="T"></typeparam>

        /// <param name="path">资源路径</param>

        /// <returns></returns>

     

        public Object OldGetAsset<T>(string path)

        {

            //要返回的资源

            Object assetObj = null;

            //如果缓存中没有该资源

            if (!assetsCache.ContainsKey(path))

            {

                //通过resources加载资源

                assetObj = Resources.Load(path);

                //将资源存进缓存

                assetsCache.Add(path, assetObj);

            }

            else {

                //如果缓存中有,则直接从缓存中拿

                assetObj = assetsCache[path];

            }

           return assetObj;

        }

        ///新方法---获取资源

        public Object GetAsset(string path) {

            //要返回的资源

            Object assetObj = null;

            //尝试从字典中获取该路径所对应的资源

            if (!assetsCache.TryGetValue(path,out assetObj))

            {

                //通过resources加载资源

                assetObj = Resources.Load(path);

                //将资源存进缓存

                assetsCache.Add(path, assetObj);

            }          

            return assetObj;

        }

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

using UIInterface;

namespace UIFrame

{

    public class UIWidgetBase : UIMono

    {

        //当前元件所处的模块

        private UIModuleBase currentModule;

        //临时参数

        private ArrayList tempParameters;

        /// <summary>

        /// 设置临时参数

        /// </summary>

        /// <param name="para"></param>

        public void SetTemParamters(object para) {

            if (tempParameters == null) {

                tempParameters = new ArrayList();

            }

            if (!tempParameters.Contains(para)) {

                tempParameters.Add(para);

            }

        }

        /// <summary>

        /// 获取临时参数

        /// </summary>

        /// <param name="index"></param>

        /// <returns></returns>

        public object GetTempParamter(int index) {

            return tempParameters[index];

        }

        public void UIWidgetInit(UIModuleBase uiModuleBase) {

            //设置当前所属模块

            currentModule = uiModuleBase;

            //将当前元件,添加到UIManager的字典中

            UIManager.Instance.addUIWidget(currentModule.name, widgetName: name, uiWidget: this);

        }

     

        protected virtual void OnDestroy()

        {

            将当前元件,从UIManager的字典中移除

            UIManager.Instance.RemoveUIWidget(currentModule.name, widgetName: name);

        }

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class UIType {

    public string Name { get; set; }

         public string Path { get; set; }

    public UIType(string path) {

        Path = path;

        //eg.Panels/MainScene/MainPanel

        //MainPanel

        //Substring(17,3) 17以后的3个字母

        //通过Path的字符串拿到其中名字

        //最后一个斜杠后面的就是Path所对应的名字

        Name = path.Substring(path.LastIndexOf("/")+1);

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

namespace UIFrame

{

    public static class SystemDefine

    {

        #region Configuration Path

        public const string PanelConfigPath = "Configuration/UIPanelConfig";

        public const string WidgetConfigPath = "Configuration/UIWidgetConfig";

        public const string HeroConfigPath = "Configuration/HeroConfig";

        public const string ClickParticlePath = "Particles/Fire";

        #endregion

        #region Scene ID

        public enum SceneID {

            MainScene=0,

            FightScene=1

        }

        #endregion

        #region Widget Token

        public static string[] WIDGET_TOKENS = new string[] { "_F","_S","_T"};

        #endregion

        #region PlayerColors

        public static Color[] PLAYER_COLORS;

        #endregion

        #region Static Constructor

        static SystemDefine() {

            PLAYER_COLORS = new[] {

                Color.red,

                Color.blue,

                Color.gray,

                Color.green,

                Color.cyan

            };

        }

        #endregion

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

namespace UIFrame {

    /// <summary>

    /// 子类挂载在每一个Panel模块上

    /// </summary>

    /// 当前模块组件依赖于CanvasGroup

    [RequireComponent(typeof(CanvasGroup))]

    public class UIModuleBase : MonoBehaviour

    {

        protected CanvasGroup _canvasGroup;

        /// <summary>

        /// 所有的子对象

        /// </summary>

        private Transform[] allChild;

        public virtual void Awake() {

            _canvasGroup = GetComponent<CanvasGroup>();

            //获取当前模块的所有子对象

            allChild = GetComponentsInChildren<Transform>();

            //修改当前模块的名称[去掉Clone]

            gameObject.name = gameObject.name.Remove(gameObject.name.Length-"(Clone)".Length);

            //给所有可用的UI元件添加行为

            AddWidgetBehaviour();

        }

        #region Controller Bind

        protected void BindController(UIControllerBase controllerBase) {

            controllerBase.ControllerInit(this);

        }

        #endregion

        #region Set Widgets

        private void AddWidgetBehaviour() {

            //遍历所有的子对象

            for (int i=0;i<allChild.Length;i++) {

                //遍历所有标记Token

                for (int j = 0; j < SystemDefine.WIDGET_TOKENS.Length; j++) {

                    //判断当前元件对象是否以该标记作为名称结尾的

                    if (allChild[i].name.EndsWith(SystemDefine.WIDGET_TOKENS[j])) {

                        //添加组件

                        AddComponentForWidget(i);

                    }

                }              

            }

        }

        protected virtual void AddComponentForWidget(int index) {

            //给该元件添加UIWidgetBase组件

            UIWidgetBase uiWidgetBase=allChild[index].gameObject.AddComponent<UIWidgetBase>();

            //设置该元件的模块是this

            uiWidgetBase.UIWidgetInit(uiModuleBase:this);

        }

        #endregion

        #region Find Widget

        public UIWidgetBase FindCurrentModuleWidget(string widgetName) {

            return UIManager.Instance.FindWidget(moduleName:name,widgetName:widgetName);

        }

        #endregion

        /// <summary>

        /// 进入当前模块执行该函数

        /// </summary>

        public virtual void OnEnter() {

            _canvasGroup.blocksRaycasts = true;

            //当前窗口在Canvas中的最后一个位置,保证显示最前面

            transform.SetSiblingIndex(transform.parent.childCount-1);          

        }

        /// <summary>

        /// 离开当前模块执行该函数

        /// </summary>

        public virtual void OnExit() {          

            _canvasGroup.blocksRaycasts = false;

        }

        /// <summary>

        /// 暂离当前模块执行该函数

        /// </summary>

        public virtual void OnPause() {

            _canvasGroup.blocksRaycasts = false;

        }

        /// <summary>

        /// 恢复当前模块执行该函数

        /// </summary>

        public virtual void OnResume() {

            _canvasGroup.blocksRaycasts = true;

        }

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

namespace UIFrame

{

    /// <summary>

    /// 专注于写UI中的业务逻辑

    /// </summary>

    public class UIControllerBase

    {

        //当前所处模块

        public UIModuleBase crtModule;

        public void ControllerInit(UIModuleBase moduleBase) {

            crtModule = moduleBase;

            //启动

            ControllerStart();

        }

        protected virtual void ControllerStart() {

        }

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

namespace UIFrame {

    [System.Serializable]

    public class JsonWidgetsModel{      

        public SceneWidgetDataModel[] AllData;   

    }

    [System.Serializable]

    public class SceneWidgetDataModel {

        public string SceneName;

        public WidgetDataModel[] Data;

    }

    [System.Serializable]

    public class WidgetDataModel {

        public string WidgetName;

        public string WidgetPath;

    }

}

using System;

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

namespace UIFrame {

    [System.Serializable]

    public class JsonPanelsModel{

        public SceneDataModel[] AllData;

        public static implicit operator JsonPanelsModel(JsonWidgetsModel v)

        {

            throw new NotImplementedException();

        }

    }

    [System.Serializable]

    public class SceneDataModel {

        public string SceneName;

        public PanelDataModel[] Data;

    }

    [System.Serializable]

    public class PanelDataModel {

        public string PanelName;

        public string PanelPath;

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

namespace UIFrame

{

    [System.Serializable]

    public class JsonHeroModel

    {

        public SceneHeroDataModel[] AllData;

    }

    [System.Serializable]

    public class SceneHeroDataModel

    {

        public string SceneName;

        public HeroDataModel[] Data;

    }

    [System.Serializable]

    public class HeroDataModel

    {

        public int HeroIndex;

        public string HeroPath;

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

namespace UIFrame

{

    public class UITypeManager : Singleton<UITypeManager>

    {

        private UITypeManager() {

            _uiTypes = new Dictionary<string, UIType>();

        }

        //UIType的缓冲池

        private Dictionary<string, UIType> _uiTypes;

        /// <summary>

        /// 通过UIPanelName名称,获取其UIType

        /// </summary>

        /// <param name="uiPanelName"></param>

        public UIType GetUIType(string uiPanelName) {

            //要返回的UITYPE

            UIType uiType = null;

            //如果缓存池内没有该Key

            if (!_uiTypes.TryGetValue(uiPanelName, out uiType)) {

                //实例化一个新的UIType

                uiType = new UIType(

                   JsonDataManager.Instance.FindPanelPath(uiPanelName)

                    );

                //添加到字典

                _uiTypes.Add(uiPanelName,uiType);

            }

            return uiType;

        }

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

namespace UIFrame {

    public class UIManager:Singleton<UIManager> {

        private UIManager() {

            uiModuleList = new List<UIModuleBase>();

            uiModules = new Dictionary<UIType, UIModuleBase>();

            _canvas = GameObject.Find("Canvas").transform;

            uiModuleStack = new Stack<UIModuleBase>();

            uiWidgets=new Dictionary<string, Dictionary<string, UIWidgetBase>>();

        }

        //UI模块的栈存储

        private Stack<UIModuleBase> uiModuleStack;

        //UIType.Path--->GameObject里的UIModule组件

        //管理当前场景的所有UI模块

        private Dictionary<UIType, UIModuleBase> uiModules;

      

        //管理当前场景的所有UI元件

        private Dictionary<string,Dictionary<string,UIWidgetBase>> uiWidgets;

        //当前场景中的画布

        private Transform _canvas;

        //UI模块的列表存储

        private List<UIModuleBase> uiModuleList;

        #region UI Module GameObject

        /// <summary>

        /// 通过名字去获取模块

        /// </summary>

        /// <param name="uiPanelName"></param>

        /// <returns></returns>

        public UIModuleBase GetUIModuleByName(string uiPanelName) {

            //获取UIType

            UIType _uiType = UITypeManager.Instance.GetUIType(uiPanelName);

            //获取UIModuleBase

            return GetUIModule(_uiType);

        }

        /// <summary>

        /// 通过UIType获取该Type所对应的模块游戏对象身上的UIModuleBase

        /// </summary>

        /// <param name="uiType"></param>

        /// <returns></returns>

        private UIModuleBase GetUIModule(UIType uiType) {

            //当前要返回的模块

            UIModuleBase crtModule = null;

            //如果字典中没有该模块

            if (!uiModules.TryGetValue(uiType, out crtModule))

            {

                //Instantiate生成该模块

                crtModule= InstantiateUIModule(prefab: AssetsManager.Instance.GetAsset(uiType.Path) as GameObject);

                //将该模块添加到字典中

                uiModules.Add(uiType,crtModule);

            }

            else if(uiModules[uiType]==null) {

                //Instantiate生成该模块

                crtModule = InstantiateUIModule(prefab: AssetsManager.Instance.GetAsset(uiType.Path) as GameObject);

                //将该模块更新到字典中

                uiModules[uiType]=crtModule;

            }

            return crtModule;

        }

        private UIModuleBase InstantiateUIModule(GameObject prefab) {

            //生成当前模块

            GameObject crtModuleObj=GameObject.Instantiate(prefab);          

            //设置父物体为画布

            crtModuleObj.transform.SetParent(_canvas, worldPositionStays: false);

            //等价于crtModuleObj.transform.localPosition = Vector3.zero;

            //返回组件

            return crtModuleObj.GetComponent<UIModuleBase>();

        }

        #endregion

        /// <summary>

        /// 通过PanelName获取模块对象并压栈

        /// </summary>

        /// <param name="uiPanelName"></param>

        #region UI Module Stack

        public void PushUI(string uiPanelName) {

            //获取UIType

            UIType _uiType=UITypeManager.Instance.GetUIType(uiPanelName);

            //获取UIModuleBase

            UIModuleBase crtModuleBase=GetUIModule(_uiType);

            //如果栈里面有元素

            if (uiModuleStack.Count!=0) {

                //此时栈顶的窗口进入暂停状态

                uiModuleStack.Peek().OnPause();

            }

            //进入窗口压栈

            uiModuleStack.Push(crtModuleBase);

            //新窗口执行Enter

            crtModuleBase.OnEnter();

        }

        /// <summary>

        /// 栈顶元素出栈

        /// </summary>

        public void PopUI() {

            if (uiModuleStack.Count != 0)

            {

                //当前栈顶元素出栈,并执行离开的回调方法

                uiModuleStack.Pop().OnExit();

            }

            else {

                Debug.LogWarning(message:"UI栈中没有元素,无法出栈!");

            }

            //栈顶元素出栈后,栈内还有没有元素

            if (uiModuleStack.Count!=0) {

                uiModuleStack.Peek().OnResume();

            }

        }

        #endregion

        #region UI Module list

        public void ShowUI(string uiPanelName)

        {

            //获取UIType

            UIType _uiType = UITypeManager.Instance.GetUIType(uiPanelName);

            //获取UIModuleBase

            UIModuleBase crtModuleBase = GetUIModule(_uiType);

            if (!uiModuleList.Contains(crtModuleBase)) {

                //添加到列表

                uiModuleList.Add(crtModuleBase);

            }

            //新窗口执行Enter

            crtModuleBase.OnEnter();

        }

       

        #endregion

        /// <summary>

        /// 注册UI模块

        /// </summary>

        /// <param name="moduleName">模块名称</param>

        #region UI Widgets->Module (Un)Register

        private void RegisterUIModuleToUIWidgets(string moduleName) {

            if (!uiWidgets.ContainsKey(moduleName))

            {

                //向字典添加元素

                uiWidgets.Add(moduleName, new Dictionary<string, UIWidgetBase>());

            }

            else {

                //Debug.Log(message:"该模块已经存在!");

            }

        }

        /// <summary>

        /// 取消注册UI模块

        /// </summary>

        /// <param name="moduleName"></param>

        public void UnRegisterUiModuleFromUIWidgets(string moduleName) {

            if (uiWidgets.ContainsKey(moduleName))

            {

                //从字典中移除该元素

                uiWidgets.Remove(moduleName);

            }

            else {

                Debug.LogWarning(message:"无法取消注册该模块,因为无该模块。");

            }

        }

        #endregion

        #region UI Widgets Add/Remove

        /// <summary>

        /// 添加元件

        /// </summary>

        /// <param name="moduleName">模块名称</param>

        /// <param name="widgetName">元件名称</param>

        /// <param name="uiWidgetBase">元件对象</param>

        public void addUIWidget(string moduleName,string widgetName,UIWidgetBase uiWidget) {

            //如果模块不存在,添加模块

            RegisterUIModuleToUIWidgets(moduleName);

            //如果字典中已经存在该元件

            if (uiWidgets[moduleName].ContainsKey(widgetName))

            {

                Debug.LogWarning(message: "该元件已经再字典中存在,无需再添加...");

            }

            else {

                uiWidgets[moduleName].Add(widgetName,uiWidget);

            }

        }

        /// <summary>

        /// 移除元件

        /// </summary>

        /// <param name="moduleName">模块名称</param>

        /// <param name="widgetName">元件名称</param>

        public void RemoveUIWidget(string moduleName,string widgetName) {

            if (uiWidgets[moduleName].ContainsKey(widgetName))

            {

                //移除该元件

                uiWidgets[moduleName].Remove(widgetName);

            }

            else {

                Debug.LogWarning(message:"该元件在字典中不存在...");

            }

            }

        #endregion

        /// <summary>

        /// 获取某个模块的某个元件

        /// </summary>

        /// <param name="moduleName">模块</param>

        /// <param name="widgetName">元件</param>

        /// <returns></returns>

        #region Find Widget

        public UIWidgetBase FindWidget(string moduleName,string widgetName) {

            //如果模块不存在,注册模块

            RegisterUIModuleToUIWidgets(moduleName);

            //要返回的UIModle

            UIWidgetBase uiWidget =null;

            //尝试获取该元件,如果没有获取到,返回Null

            uiWidgets[moduleName].TryGetValue(widgetName, out uiWidget);          

            return uiWidget;

        }

        #endregion

        #region Dynamic Widget Instantiate

        public GameObject CreateDynamicWidget(string widgetName) {

            //获取元件的资源路径

            string widgetPath=JsonDataManager.Instance.FindWidgetPath(widgetName);

            //获取预设体

            GameObject prefab=AssetsManager.Instance.GetAsset(widgetPath) as GameObject;

         

            //创建对象

            return GameObject.Instantiate(prefab);

        }

        /// <summary>

        /// 创建动态元件,并设置父物体

        /// </summary>

        /// <param name="widgetName"></param>

        /// <param name="parent"></param>

        /// <param name="worldPosStays"></param>

        /// <returns></returns>

        public GameObject CreateDynamicWidget(string widgetName,Transform parent, bool worldPosStays) {

            //创建对象

            GameObject obj=CreateDynamicWidget(widgetName);

            //Debug.Log("CreateDynamicWidget"+obj);

            //设置父物体

            obj.transform.SetParent(parent,worldPosStays);

            return obj;

        }

        #endregion

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

public class GameFacade : MonoBehaviour {

    private void Start()

    {

        //启动游戏

        UIManager.Instance.PushUI("MainPanel");

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

using Photon.Pun;

using Photon.Realtime;

using UnityEngine.UI;

public class TopPanelController : UIControllerBase

{

    protected override void ControllerStart()

    {

        base.ControllerStart();

        Debug.Log("TopPanel Start!");

        BindEvent();

    }

    protected void BindEvent() {

        //crtModule

        crtModule.FindCurrentModuleWidget("BackButton_F").AddOnClickListener(()=> {

            //离开房间和大厅

            if (PhotonNetwork.InLobby)

            {

                PhotonNetwork.LeaveLobby();

            }

            else if (PhotonNetwork.InRoom) {

                PhotonNetwork.LeaveRoom();

            }

                //暂时

                UIManager.Instance.PopUI();

                UIManager.Instance.PopUI();

        });      

        Debug.Log(PhotonNetwork.NetworkClientState);

     

        MonoHelper.Instance.InvokeRepeat(method:()=> { crtModule.FindCurrentModuleWidget("StatusInfo_F").SetTextText("Status: " + PhotonNetwork.NetworkClientState); },0,()=> { return false; });       

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

using Photon.Pun;

using Photon.Realtime;

public class RoomPanelController : UIControllerBase

{

    /// <summary>

    /// 当前房间的所有玩家

    /// </summary>

    Dictionary<int, GameObject> roomPlayers;

    protected override void ControllerStart()

    {

        base.ControllerStart();

        roomPlayers = new Dictionary<int, GameObject>();

        crtModule.FindCurrentModuleWidget("StartGameButton_F").AddOnClickListener(() =>

        {

            //加载进入游戏场景

            PhotonNetwork.LoadLevel("CompleteMainScene");

        }

        );

    }

    private void BindEvent() {

    }

    /// <summary>

    /// 清空玩家列表

    /// </summary>

    public void ClearPlayerUIList() {

        foreach (var item in roomPlayers) {

            //销毁游戏对象

            GameObject.Destroy(item.Value);

        }

        //清理

        roomPlayers.Clear();

    }

    private void GeneratePlayerUIList() {

        Transform parent = crtModule.FindCurrentModuleWidget("PlayerList_F").transform;

        for (int i = 0; i < PhotonNetwork.PlayerList.Length; i++) {

            //生成一个玩家

            GameObject tempPlayer=UIManager.Instance.CreateDynamicWidget("PlayerInfo",parent,false);

            //执行玩家初始化

            tempPlayer.GetComponent<PlayerBehaviour>().PlayerInit(PhotonNetwork.PlayerList[i]);

            //添加到字典

            roomPlayers.Add(PhotonNetwork.PlayerList[i].ActorNumber, tempPlayer);

        }

    }

    //更新玩家信息

    public void UpdatePlayerMsg() {

        ClearPlayerUIList();

        GeneratePlayerUIList();

    }

    /// <summary>

    /// 设置玩家准备状态

    /// </summary>

    /// <param name="playerID"></param>

    /// <param name="isReady"></param>

    public void SetPlayerReadyState(int playerID,bool isReady) {

        if (!roomPlayers.ContainsKey(playerID))

            return;

        roomPlayers[playerID].GetComponent<PlayerBehaviour>().SetReadyStateUI(isReady);

       

    }

    //

    public void SetPlayerReadyStateHash(int playerID, bool isReady) {

        if (!roomPlayers.ContainsKey(playerID))

            return;

        roomPlayers[playerID].GetComponent<PlayerBehaviour>().SetPlayerReadyState(isReady);

    }

    /// <summary>

    /// 显示游戏开始按钮

    /// </summary>

    public void ShowStartGameBtn() {

        //1.当前玩家是主客户端

        //2:房间里的所有玩家都已经准备

        crtModule.FindCurrentModuleWidget("StartGameButton_F").SetGameObjectActive(PhotonNetwork.IsMasterClient&&AllPlayerHasReady());    

    }

    /// <summary>

    /// 是否所有玩家都已经准备

    /// </summary>

    /// <returns></returns>

    private bool AllPlayerHasReady() {

        foreach (var item in roomPlayers) {

            //如果遍历到任意一个玩家没有准备,则不能开始游戏

            if (!item.Value.GetComponent<PlayerBehaviour>().isReady) {

                return false;

            }        

        }

        //能运行到此处,说明所有玩家都已经准备

        return true;

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using Photon.Pun;

using UIFrame;

using Photon.Realtime;

public class RoomListPanelController : UIControllerBase

{

    //房间信息

    public List<RoomInfo> roomInfos;

    //所有的房间

    Dictionary<string, RoomBehaviour> rooms;

   

    protected override void ControllerStart()

    {

        base.ControllerStart();

        roomInfos = new List<RoomInfo>();

        rooms = new Dictionary<string, RoomBehaviour>();     

    }

    public void UpdateRoomList(List<RoomInfo> roomInfos) {

        this.roomInfos = roomInfos;

        UpdateRoomListUI();

    }

    void ClearRoomListUI() {

        foreach (var item in rooms) {

            //销毁房间信息的游戏对象

            GameObject.Destroy(item.Value.gameObject);

        }

        //清除

        rooms.Clear();

    }

    private void ShowRoomListUI() {

        //找到父对象

        Transform parent = crtModule.FindCurrentModuleWidget("RoomList_F").transform;

        //遍历RoomInfos

        foreach (var item in roomInfos) {

            if (!item.IsOpen)

                continue;

            if (!item.IsVisible)

                continue;

            if (item.MaxPlayers == 0)

                continue;

            //生成一个房间

            GameObject tempRoom = UIManager.Instance.CreateDynamicWidget("RoomInfo", parent, false);

            //执行房间初始化

            tempRoom.GetComponent<RoomBehaviour>().RoomInit(item);

            //添加到字典

            rooms.Add(item.Name, tempRoom.GetComponent<RoomBehaviour>());

        }

    }

    public void UpdateRoomListUI() {

        ClearRoomListUI();

        ShowRoomListUI();

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

public class InfoPanelController : UIControllerBase

{

    protected override void ControllerStart()

    {

        base.ControllerStart();

        crtModule.FindCurrentModuleWidget("CancelButton_F").AddOnClickListener(()=> { UIManager.Instance.PopUI(); });

        BindEvent();

    }

    private void BindEvent()

    {

    }

    public void SetInfoText(string text) {

        crtModule.FindCurrentModuleWidget("Text _F").tmpSetTextText(text);

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using Photon.Pun;

using Photon.Realtime;

using TMPro;

using UnityEngine.UI;

public class RoomBehaviour : MonoBehaviour

{

    private RoomInfo _roomInfo;

    #region UI Field

    private TMP_Text roomNameText;

    private TMP_Text slotsText;

    private Button joinButton;

    #endregion

    private void Awake()

    {

        roomNameText = transform.GetChild(0).GetComponent<TMP_Text>();

        slotsText = transform.GetChild(1).GetComponent<TMP_Text>();

        joinButton = transform.GetChild(2).GetComponent<Button>();

    }

    public void RoomInit(RoomInfo roomInfo)

    {

        _roomInfo = roomInfo;

        roomNameText.text = roomInfo.Name;

        joinButton.onClick.AddListener(

            () => {

                //离开大厅

                PhotonNetwork.LeaveLobby();

                //进入房间

                PhotonNetwork.JoinRoom(roomInfo.Name);

            }

            );

    }

   

  

    private void Update()

    {

        slotsText.text = _roomInfo.PlayerCount + "/" + _roomInfo.MaxPlayers;

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using Photon.Pun;

using Photon.Realtime;

using UnityEngine.UI;

using UIFrame;

using TMPro;

using UIInterface;

using UnityEngine.Events;

using ExitGames.Client.Photon;

namespace UIFrame

{

    public class PlayerBehaviour : MonoBehaviour, IButton

    {

        //当前玩家

        private Player _player;

        #region UI Field

        private Image color;

        private TMP_Text playerName;

        private Button readyButton;

        private Button notReadyButton;

        private GameObject hasReadySign;

        #endregion

        //当前玩家是否准备

        public bool isReady = false;

        private void Awake()

        {

            color = transform.Find("Color").GetComponent<Image>();

            playerName = transform.Find("PlayerName").GetComponent<TMP_Text>();

            readyButton = transform.Find("ReadyButton").GetComponent<Button>();

            //标记玩家是否已经准备

            hasReadySign = readyButton.transform.Find("isReadySign").gameObject;

            notReadyButton = transform.Find("NonReadyButton").GetComponent<Button>();

            //绑定点击事件

            readyButton.onClick.AddListener(OnReadyButtonClick);

        }

        private void OnReadyButtonClick()

        {

            if (!_player.IsLocal)

                return;

            bool crtReadyState = GetPlayerReadyState();

            //设置当前玩家准备状态【新】

            SetPlayerReadyState(!crtReadyState);

        }

        /// <summary>

        /// 设置当前玩家准备状态【新】

        /// </summary>

        /// <param name="isReady"></param>

        public void SetPlayerReadyState(bool isReady)

        {

            ExitGames.Client.Photon.Hashtable hashtable = new ExitGames.Client.Photon.Hashtable();

            hashtable.Add(GameConst.READY_PROPERTY, isReady);

            //设置

            _player.SetCustomProperties(hashtable);

            //触发自己的UI变化

            SetReadyStateUI(isReady);

            //readyButton.gameObject.SetActive(!isReady);

           // notReadyButton.gameObject.SetActive(isReady);

        }

        /// <summary>

        /// 玩家初始化

        /// </summary>

        /// <param name="player"></param>

        public void PlayerInit(Player player)

        {

            _player = player;

            playerName.text = player.NickName;

            //设置玩家编号所对应的颜色显示

            color.color = GameConst.PLAYER_COLORS[(player.ActorNumber - 1) % GameConst.PLAYER_COLORS.Length];

           

            if (player.IsLocal)

            {

                readyButton.gameObject.SetActive(true);

                notReadyButton.gameObject.SetActive(false);

            }

            else

            {

                readyButton.gameObject.SetActive(false);

               notReadyButton.gameObject.SetActive(true);

            }

            //关于准备状态

            SetReadyStateUI((GetPlayerReadyState()));

        }

        public void AddOnClickListener(UnityAction action)

        {

            throw new System.NotImplementedException();

        }

        /// <summary>

        /// 获取玩家的准备状态

        /// </summary>

        /// <returns></returns>

        private bool GetPlayerReadyState()

        {

            //结果

            object result = null;

            //尝试获取准备属性

            _player.CustomProperties.TryGetValue(GameConst.READY_PROPERTY, out result);

            if (result == null)

                return false;

            return (bool)result;

        }

        /// <summary>

        /// 设置当前玩家的准备状态UI

        /// </summary>

        public void SetReadyStateUI(bool isReady)

        {

            this.isReady = isReady;

           

            hasReadySign.SetActive(isReady);

            //如果玩家不是自己,准备按钮要看准备的状态

            if (!_player.IsLocal)

            {

                readyButton.gameObject.SetActive(isReady);

                readyButton.interactable = false;

                notReadyButton.gameObject.SetActive(!isReady);

            }

        }

    }

}

using System;

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using Photon.Pun;

public class MonoHelper : MonoBehaviour

{

    public static MonoHelper Instance;

    private void Awake()

    {

        Instance = this;

    }

    /// <summary>

    /// 持续执行某个函数

    /// </summary>

    /// <param name="method"></param>

    /// <param name="interval"></param>

    /// <param name="endCondition"></param>

    public void InvokeRepeat(Action method,float interval,Func<bool> endCondition) {

        StartCoroutine(RepeatCRT(method, interval, endCondition));

    }

    IEnumerator RepeatCRT(Action method, float interval, Func<bool> endCondition) {

        while (true) {

            if (interval <= 0) { yield return 0; }

            else { yield return new WaitForSeconds(interval); }

            //执行事件

            method();

            //判断结束条件是否达成

            if (endCondition())

                yield break;

        }            

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using Photon.Pun;

using UIFrame;

using Photon.Realtime;

using ExitGames.Client.Photon;

public class LobbyManager : MonoBehaviourPunCallbacks

{

    public static LobbyManager Instance;

    public string infoMessage="";

   

    //获取房间模块

    //private RoomPanelModule roomPanel;

    //获取大厅模块

    private RoomListPanelModule roomListPannel;

    private void Awake()

    {

        Instance = this;

        //设置为当前对象在过渡场景时不要销毁

        //DontDestroyOnLoad(gameObject);

        //支持后台运行

        Application.runInBackground = true;

        //机制网络场景同步

        PhotonNetwork.AutomaticallySyncScene = true;

        //实例化房间列表

        //rooms = new List<RoomInfo>();

    }

    // Start is called before the first frame update

    void Start()

    {

        //连接云服务器

        PhotonNetwork.ConnectUsingSettings();

        //roomPanel = UIManager.Instance.GetUIModuleByName("RoomPanel") as RoomPanelModule;

        //roomListPannel = UIManager.Instance.GetUIModuleByName("RoomListPanel") as RoomListPanelModule;

    }

    public override void OnConnectedToMaster()

    {

        base.OnConnectedToMaster();

        //恢复主模块的可交互性

        MainPanelModule mainPanel =UIManager.Instance.GetUIModuleByName("MainPanel") as MainPanelModule;

        mainPanel.ResumePanelInteractable();

    }

    public override void OnJoinedRoom()

    {   

        //进入房间界面

        UIManager.Instance.PushUI("RoomPanel");

        //roomPanel.SetPlayerReadyState(PhotonNetwork.LocalPlayer.ActorNumber, false);【旧】

        //更新房间时,取消当前玩家的准备状态[]

        RoomPanelModule roomPanel = UIManager.Instance.GetUIModuleByName("RoomPanel") as RoomPanelModule;

        roomPanel.SetPlayerReadyStateHash(PhotonNetwork.LocalPlayer.ActorNumber, false);

    }

    public override void OnJoinRandomFailed(short returnCode, string message)

    {

        //储存失败原因信息

        infoMessage =message;

        //显示提示框

        UIManager.Instance.PushUI("InfoPanel");

    }

    public override void OnJoinedLobby()

    {

        base.OnJoinedLobby();

        //进入大厅界面

        UIManager.Instance.PushUI("RoomListPanel");

    }

    public override void OnPlayerEnteredRoom(Player newPlayer)

    {

        base.OnPlayerEnteredRoom(newPlayer);

        RoomPanelModule roomPanel = UIManager.Instance.GetUIModuleByName("RoomPanel") as RoomPanelModule;

        //更新玩家列表

        roomPanel.UpdatePlayerUIMsg();

        //设置是否显示启动游戏按钮

        roomPanel.ShowStartGameBtn();

    }

    public override void OnPlayerLeftRoom(Player otherPlayer)

    {

        base.OnPlayerLeftRoom(otherPlayer);

        RoomPanelModule roomPanel = UIManager.Instance.GetUIModuleByName("RoomPanel") as RoomPanelModule;

        //更新玩家列表

        roomPanel.UpdatePlayerUIMsg();

        //设置是否显示启动游戏按钮

        roomPanel.ShowStartGameBtn();

    }

   

    public override void OnCreateRoomFailed(short returnCode, string message)

    {

        //储存失败原因信息

        infoMessage = message;

        //显示提示框

        UIManager.Instance.PushUI("InfoPanel");

    }

    public override void OnPlayerPropertiesUpdate(Player targetPlayer, ExitGames.Client.Photon.Hashtable changedProps)

    {

        object result = null;

        //获取准备状态

        changedProps.TryGetValue(GameConst.READY_PROPERTY, out result);

        if (result == null) {

            result = false;

        }

        RoomPanelModule roomPanel = UIManager.Instance.GetUIModuleByName("RoomPanel") as RoomPanelModule;

        //调用房间模块方法

        roomPanel.SetPlayerReadyState(targetPlayer.ActorNumber,(bool)result);

        //设置是否显示启动游戏按钮

        roomPanel.ShowStartGameBtn();

    }

    public override void OnRoomListUpdate(List<RoomInfo> roomList)

    {

        base.OnRoomListUpdate(roomList);

        roomListPannel = UIManager.Instance.GetUIModuleByName("RoomListPanel") as RoomListPanelModule;

        //临时存储当前的所有房间信息

        roomListPannel.SetRoomInfos(roomList);

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

using Photon.Pun;

using Photon.Realtime;

using Photon;

using UnityEngine.Events;

using Hashtable = ExitGames.Client.Photon.Hashtable;

public class MainPanelController : UIControllerBase

{

    protected override void ControllerStart()

    {

        base.ControllerStart();

        Debug.Log("MainPanel Start!");

       

        BindEvent();

        BaseMsgInit();

    }

    private void BaseMsgInit() {

        //随机玩家昵称

        crtModule.FindCurrentModuleWidget("PlayerNameInputField_F").tmpSetInputFieldText("Player"+Random.Range(101,999));

        //随机房间名称

        crtModule.FindCurrentModuleWidget("RoomNameInputField_F").tmpSetInputFieldText("Room" + Random.Range(101, 999));

        //设置默认的最大人数

        crtModule.FindCurrentModuleWidget("RoomMaxCountInputFIeld_F").tmpSetInputFieldText("5");

    }

    protected void BindEvent()

    {

        //Hero点击事件绑定

       

        crtModule.FindCurrentModuleWidget("Hero01Button_F").AddOnClickListener(()=> {

             //父物体

             Transform parent = crtModule.FindCurrentModuleWidget("Hero01Button_F").transform;

                //设置选择框到当前模块

             crtModule.FindCurrentModuleWidget("Select_F").SetParent(parent, false);

            //标记当前选择英雄的编号

            HumanGameManager.Instance.selectedHeroIndex = 1;

        });

        //Hero点击事件绑定

        crtModule.FindCurrentModuleWidget("Hero02Button_F").AddOnClickListener(() => {

            //父物体

            Transform parent = crtModule.FindCurrentModuleWidget("Hero02Button_F").transform;

            //设置选择框到当前模块

            crtModule.FindCurrentModuleWidget("Select_F").SetParent(parent, false);

            //标记当前选择英雄的编号

            HumanGameManager.Instance.selectedHeroIndex = 2;

        });

        //Hero点击事件绑定

        crtModule.FindCurrentModuleWidget("Hero03Button_F").AddOnClickListener(() => {

            //父物体

            Transform parent = crtModule.FindCurrentModuleWidget("Hero03Button_F").transform;

            //设置选择框到当前模块

            crtModule.FindCurrentModuleWidget("Select_F").SetParent(parent, false);

            //标记当前选择英雄的编号

            HumanGameManager.Instance.selectedHeroIndex = 3;

        });

        //绑定创建房间按钮事件CreateButton_F

        crtModule.FindCurrentModuleWidget("CreateButton_F").AddOnClickListener(CreateRoomBtnClick);

        //crtModule.FindCurrentModuleWidget("CreateButton_F").AddOnClickListener(test);

        //随机加入房间按钮事件CreateButton_F

        crtModule.FindCurrentModuleWidget("RandomRoomButton_F").AddOnClickListener(JoinRandomRoom);

        //绑定进入游戏大厅按钮事件CreateButton_F

        crtModule.FindCurrentModuleWidget("ListServerButton_F").AddOnClickListener(JoinLobby);

       

    }

    private void test() {     

        string playerName = crtModule.FindCurrentModuleWidget("PlayerNameInputField_F").tmpGetInputFieldText();

        Debug.Log("Player" + Random.Range(101, 999));

    }

    private void CreateRoomBtnClick() {

        //已经进入房间,不能再创建房间

        if (PhotonNetwork.NetworkClientState == ClientState.Joined)

            return;

        string playerName= crtModule.FindCurrentModuleWidget("PlayerNameInputField_F").tmpGetInputFieldText();

        string roomName = crtModule.FindCurrentModuleWidget("RoomNameInputField_F").tmpGetInputFieldText();

        string roomPwd = crtModule.FindCurrentModuleWidget("RoomPasswordInputField_F").tmpGetInputFieldText();

        string roomMaxCount = crtModule.FindCurrentModuleWidget("RoomMaxCountInputFIeld_F").tmpGetInputFieldText();

        if (playerName == "") {

            playerName = "Player" + Random.Range(101, 999);

        }

        if (roomName == "")

        {

            roomName = "Room" + Random.Range(101, 999);

        }

        if (roomMaxCount == "")

        {

            roomMaxCount = "5";

        }

        //设置玩家昵称

        PhotonNetwork.NickName = playerName;

        //Debug.Log(PhotonNetwork.NickName);

        //创建房间选项对象

        RoomOptions roomOptions = new RoomOptions();

        //设置最大人数

        roomOptions.MaxPlayers = byte.Parse(roomMaxCount);

        if (roomPwd != "") {

            //添加房间密码

            //如果hashtable为空

            if (roomOptions.CustomRoomProperties == null) {

                //实例化

                roomOptions.CustomRoomProperties = new Hashtable();

            }

            roomOptions.CustomRoomProperties.Add("Password", roomPwd);         

        }       

        //创建房间

        PhotonNetwork.CreateRoom(roomName, roomOptions);

    }

    private void JoinRandomRoom() {

        //已经进入房间,不能再创建房间

        if (PhotonNetwork.NetworkClientState == ClientState.Joined)

            return;

        string playerName = crtModule.FindCurrentModuleWidget("PlayerNameInputField_F").tmpGetInputFieldText();

       

        if (playerName == "")

        {

            playerName = "Player" + Random.Range(101, 999);

        }

        //设置玩家昵称

        PhotonNetwork.NickName = playerName;

        //随机加入房间

        PhotonNetwork.JoinRandomRoom();

    }

    private void JoinLobby() {

      

        string playerName = crtModule.FindCurrentModuleWidget("PlayerNameInputField_F").tmpGetInputFieldText();

        if (playerName == "")

        {

            playerName = "Player" + Random.Range(101, 999);

        }

        PhotonNetwork.NickName = playerName;

        if (!PhotonNetwork.InLobby)

            //加入大厅

            PhotonNetwork.JoinLobby();

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UIFrame;

public class LobbyFacade : MonoBehaviour

{

    // Start is called before the first frame update

    void Start()

    {

        UIManager.Instance.ShowUI("TopPanel");

        UIManager.Instance.ShowUI("MainPanel");

   

       

    }

    // Update is called once per frame

    void Update()

    {

       

    }

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public static class GameConst

{

    #region Player Custom Properties

    public const string READY_PROPERTY = "Ready";

    public const string LOADED_PROPERTY = "Loaded";

    #endregion

    #region Room Custom Properties

    public const string INITHERO_PROPERTY = "InitHero";

    #endregion

    #region PlayerColors

    public static Color[] PLAYER_COLORS;

    #endregion

    #region Virtual Axis & Button

    public const string HEROMOVE = "HeroMove";

    #endregion

    #region Animator Paramters

    public static int SPEED_PARA;

    public static int PLAYERATTACK_PARA;

    #endregion

    #region Custom Properties

    static GameConst()

    {

        PLAYER_COLORS = new[] {

                Color.red,

                Color.blue,

                Color.gray,

                Color.green,

                Color.cyan

            };

        SPEED_PARA = Animator.StringToHash("Speed");

        PLAYERATTACK_PARA = Animator.StringToHash("PlayerAttack");

    }

    #endregion

}

{

"AllData":[

{

  "SceneName":"HeroScene",

  "Data": [

    { "HeroIndex":1,

         "HeroPath":"PlayerPrefabs/char_ethan" },

    { "HeroIndex":2,

         "HeroPath": "PlayerPrefabs/char_robotGuard" },

         { "HeroIndex":3,

         "HeroPath": "PlayerPrefabs/dragon" }

         ]

         }

  ]

}

{

"AllData":[

{

  "SceneName":"LobbyScene",

  "Data": [

    { "PanelName":"TopPanel",

         "PanelPath":"LobbyUIPanels/TopPanel" },

    { "PanelName":"MainPanel",

         "PanelPath": "LobbyUIPanels/MainPanel" },

    {"PanelName": "RoomPanel",

         "PanelPath": "LobbyUIPanels/RoomPanel" },

    { "PanelName":"RoomListPanel",

         "PanelPath": "LobbyUIPanels/RoomListPanel" },

         { "PanelName":"InfoPanel",

         "PanelPath": "LobbyUIPanels/InfoPanel" }

         ]

         }

  ]

}

{

"AllData":[

{

  "SceneName":"LobbyScene",

  "Data": [

    { "WidgetName":"RoomInfo",

         "WidgetPath":"LobbyPrefabs/RoomInfo" },

    { "WidgetName":"PlayerInfo",

         "WidgetPath": "LobbyPrefabs/PlayerInfo" }   

         ]

         }

  ]

}

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很高兴听到你对转行到Unity游戏开发的兴趣!转行是一个挑战,但也是一个机会来学习新的技能和追求自己的兴趣。下面是一些步骤和资源,可以帮助你开始转行到Unity游戏开发: 1. 学习Unity引擎:Unity是一款流行的游戏开发引擎,它提供了丰富的工具和功能来创建游戏。你可以通过官方网站(https://unity.com/)下载并安装Unity引擎。同时,Unity还提供了大量的教程和文档,可以帮助你入门和深入学习。 2. 学习C#编程语言:Unity使用C#作为主要的编程语言。如果你已经有Java开发的经验,学习C#将会相对容易,因为两者在语法上有很多相似之处。你可以通过在线教程、书籍或者参加培训课程来学习C#。 3. 完成Unity游戏开发教程:为了熟悉Unity的工作流程和开发过程,你可以完成一些基础的Unity游戏开发教程。这些教程将帮助你了解如何创建场景、添加角色、实现游戏逻辑等。 4. 参与游戏开发项目:参与实际的游戏开发项目是提高技能和经验的最佳方式。你可以加入游戏开发社区,寻找志同道合的人一起合作开发游戏项目。这样可以帮助你建立自己的作品集,并且学习到更多实际的开发经验。 5. 持续学习和提升:游戏开发是一个不断进步和学习的领域。除了掌握Unity和C#的基础知识外,你还可以学习其他相关的技术,如游戏设计、图形学、物理模拟等。参加游戏开发相关的培训、研讨会和会议也是不错的选择。 希望以上的步骤和资源对你转行到Unity游戏开发有所帮助!祝你好运!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值