Untiy 3 Dネットワークプラグイン-Photonのカスタムオブジェクトプールの使用方法
この文章はcartzhangによって作成され、転載は出典を明記してください.すべての権利は保持されます.記事リンク:http://blog.csdn.net/cartzhang/article/details/68068178 作者:cartzhang
一、前に書く
最初にPhotonに触れたとき、コードをあまり理解していなかったので、自分たちの書いたオブジェクトプールとPhotonを組み合わせて使うのはとても不便でした.毎回プールからオブジェクトを取り、手動でView IDを設定するのは煩わしいですが、感覚的にはphotonの開き方が間違っています.ある日再び辛抱強くPhotonのコードを読んでやっと発見することができて、感じは正しいで、人が池の使い方を考慮していないほどではありませんて、使うことができるだけではなくて、その上任意に自分のクラスを使うことができて、以下はどのように使うことを紹介して、しかも後でPhotoNetworkの最適化と改善を提供しました.本編の主な内容は、1つは、photonがカスタムメモリプールにアクセスし、一部の最適化を行ったこと、2つは、photonのインスタンス化方法を拡張し、使いやすいことです.
二、Photonの中の池の使用
PhotonNetwork.Instantiateの関数呼び出しプロセスを検索すると、主なインスタンス化コードがNetworkingPeer.csでDoInstantiate関数クラスのコードを表示していることがわかります.
三、カスタムオブジェクトプールの使用
PhotonClasses.csにはIpunPrefabPoolというインタフェースがあり、上のコードの
http://blog.csdn.net/cartzhang/article/details/54096845 http://blog.csdn.net/cartzhang/article/details/55051570 必要な学生は参考にすることができます.カスタムプールへのアクセスを実現するには、まずインタフェースクラスを実現し、そこで書き込みコードの最適化を行います.
さらに最適化の部分は、Photonを使用する前に、すべてのプリセットPrefabをResourcesフォルダの下のルートディレクトリの下に置く必要があります.他のサブフォルダを探すことができず、直接名前を呼び出すことができないからです.コードを見てください:
四、PhotonNetworkの拡張最適化
PhotonNetwork.Instantiate()を呼び出してインスタンス化する過程で、stringタイプのプリセットの名前を入力する必要があり、使用するたびにプリセットまたはオブジェクトの名前を入力パラメータとして取得する必要があるので、これは人間的ではないでしょう.
この記事を通じて、自分のオブジェクトプールにネットワーク機能を追加してほしいです.もし問題があれば、いつでも連絡してください!!
五、その他の関連
【1】http://blog.csdn.net/cartzhang/article/details/54096845 【2】http://blog.csdn.net/cartzhang/article/details/55051570 ラベル:Photon、オブジェクトプール、カスタム.もし問題があれば、いつでも連絡してください.
一、前に書く
最初にPhotonに触れたとき、コードをあまり理解していなかったので、自分たちの書いたオブジェクトプールとPhotonを組み合わせて使うのはとても不便でした.毎回プールからオブジェクトを取り、手動でView IDを設定するのは煩わしいですが、感覚的にはphotonの開き方が間違っています.ある日再び辛抱強くPhotonのコードを読んでやっと発見することができて、感じは正しいで、人が池の使い方を考慮していないほどではありませんて、使うことができるだけではなくて、その上任意に自分のクラスを使うことができて、以下はどのように使うことを紹介して、しかも後でPhotoNetworkの最適化と改善を提供しました.本編の主な内容は、1つは、photonがカスタムメモリプールにアクセスし、一部の最適化を行ったこと、2つは、photonのインスタンス化方法を拡張し、使いやすいことです.
二、Photonの中の池の使用
PhotonNetwork.Instantiateの関数呼び出しプロセスを検索すると、主なインスタンス化コードがNetworkingPeer.csでDoInstantiate関数クラスのコードを表示していることがわかります.
if (ObjectPool != null)
{
GameObject go = ObjectPool.Instantiate(prefabName, position, rotation);
PhotonView[] photonViews = go.GetPhotonViewsInChildren();
if (photonViews.Length != viewsIDs.Length)
{
throw new Exception("Error in Instantiation! The resource's PhotonView count is not the same as in incoming data.");
}
for (int i = 0; i < photonViews.Length; i++)
{
photonViews[i].didAwake = false;
photonViews[i].viewID = 0;
photonViews[i].prefix = objLevelPrefix;
photonViews[i].instantiationId = instantiationId;
photonViews[i].isRuntimeInstantiated = true;
photonViews[i].instantiationDataField = incomingInstantiationData;
photonViews[i].didAwake = true;
photonViews[i].viewID = viewsIDs[i]; // with didAwake true and viewID == 0, this will also register the view
}
// Send OnPhotonInstantiate callback to newly created GO.
// GO will be enabled when instantiated from Prefab and it does not matter if the script is enabled or disabled.
go.SendMessage(OnPhotonInstantiateString, new PhotonMessageInfo(photonPlayer, serverTime, null), SendMessageOptions.DontRequireReceiver);
return go;
}
オブジェクトプールがある場合は、オブジェクトプールを使用してネットワークオブジェクトを作成します.おおらかなのか、ここで使われている対象プールです.では、カスタムオブジェクトプールにどのようにアクセスしますか?三、カスタムオブジェクトプールの使用
PhotonClasses.csにはIpunPrefabPoolというインタフェースがあり、上のコードの
internal IPunPrefabPool ObjectPool;
このインタフェースタイプのオブジェクトです.public interface IPunPrefabPool
{
/// <summary>
/// This is called when PUN wants to create a new instance of an entity prefab. Must return valid GameObject with PhotonView.
/// </summary>
/// <param name="prefabId">The id of this prefab.</param>
/// <param name="position">The position we want the instance instantiated at.</param>
/// <param name="rotation">The rotation we want the instance to take.</param>
/// <returns>The newly instantiated object, or null if a prefab with <paramref name="prefabId"/> was not found.</returns>
GameObject Instantiate(string prefabId, Vector3 position, Quaternion rotation);
/// <summary>
/// This is called when PUN wants to destroy the instance of an entity prefab.
/// </summary>
/// <remarks>
/// A pool needs some way to find out which type of GameObject got returned via Destroy().
/// It could be a tag or name or anything similar.
/// </remarks>
/// <param name="gameObject">The instance to destroy.</param>
void Destroy(GameObject gameObject);
}
カスタムプールにアクセスするために私たちが使用するのを待っている場所であることは明らかです.説明すると、ここではカスタムオブジェクトプールを使用していますが、他のブログでも紹介されています.http://blog.csdn.net/cartzhang/article/details/54096845 http://blog.csdn.net/cartzhang/article/details/55051570 必要な学生は参考にすることができます.カスタムプールへのアクセスを実現するには、まずインタフェースクラスを実現し、そこで書き込みコードの最適化を行います.
public class NetPoolManager : PoolManager, IPunPrefabPool
{
public static Dictionary<string, GameObject> prefabResoucePrefabCache = new Dictionary<string, GameObject>();
private bool bOnce = false;
public void Awake()
{
PhotonNetwork.PrefabPool = this;
InitailResoucesCache();
}
public GameObject Instantiate(string prefabId, Vector3 position, Quaternion rotation)
{
Debug.Log("net instantiate " + prefabId);
GameObject gameObj = GetGameObjFromCache(prefabId);
return gameObject.InstantiateFromPool(gameObj, position, rotation).gameObject;
}
public void Destroy(GameObject gameObject)
{
gameObject.DestroyToPool(gameObject);
}
private void InitailResoucesCache()
{
string prefabTmpName = string.Empty;
if (!bOnce)
{
bOnce = true;
UnityEngine.Object[] all_resources = Resources.LoadAll("", typeof(GameObject));
for (int i = 0; i < all_resources.Length; i++)
{
GameObject Go = all_resources[i] as GameObject;
prefabTmpName = Go.name;
if (null != Go && !string.IsNullOrEmpty(prefabTmpName))
{
if (!prefabResoucePrefabCache.ContainsKey(prefabTmpName))
{
prefabResoucePrefabCache.Add(prefabTmpName, Go);
}
else
{
Debug.LogError(prefabTmpName + " have more than one prefab have the same name ,check all resoures folder.");
}
}
}
}
}
private GameObject GetGameObjFromCache(string prefabName)
{
GameObject resourceGObj = null;
if (!prefabResoucePrefabCache.TryGetValue(prefabName, out resourceGObj))
{
Debug.LogError("please check ,if current " + prefabName + "not in resouce folder");
}
if (resourceGObj == null)
{
Debug.LogError("Could not Instantiate the prefab [" + prefabName + "]. Please verify this gameobject in a Resources folder.");
}
return resourceGObj;
}
}
ただし、Awakeでは、このポインタをPhotonNetwork.PrefabPoolに割り当てる必要があります.これにより、ObjectPoolを呼び出すときにnullにはなりません.さらに最適化の部分は、Photonを使用する前に、すべてのプリセットPrefabをResourcesフォルダの下のルートディレクトリの下に置く必要があります.他のサブフォルダを探すことができず、直接名前を呼び出すことができないからです.コードを見てください:
resourceGameObject = (GameObject)Resources.Load(prefabName, typeof (GameObject));
NetPoolManagerクラスでは、Resourcesでサブフォルダを作成し、呼び出しをスムーズにインスタンス化できます.最適化は2つのステップに分けられます.まず、サブフォルダ内のプリセットを含むすべてのresourcesフォルダを収集し、テーブルを保存します.第二に,必要に応じてGameObjectオブジェクトを直接取り出し,インスタンス化することができる.次の利点と欠点:利点は、resourceから毎回ロードする必要がなく、本番プール内のオブジェクトをすぐに取得できることです.欠点として、現在、サブフォルダ内のプリセットには名前を変更することはできません.また、多すぎると、ロードに時間がかかる可能性があり、ゲームが閉じられないため、メモリに保存されているため、メモリが増加します.四、PhotonNetworkの拡張最適化
PhotonNetwork.Instantiate()を呼び出してインスタンス化する過程で、stringタイプのプリセットの名前を入力する必要があり、使用するたびにプリセットまたはオブジェクトの名前を入力パラメータとして取得する必要があるので、これは人間的ではないでしょう.
public static GameObject Instantiate(string prefabName, Vector3 position, Quaternion rotation, int group)
{
return Instantiate(prefabName, position, rotation, group, null);
}
直接拡張するつもりでしたが、静的クラスでサポートされていません.public static partial class PhotonNetworkを考えてPhotonNetworkExtent.csファイルを作成し、直接船体Transformを実現する方法です.もちろん、自分の必要に応じて他のものを変更したり実現したりすることができます.ここはレンガを投げて玉を引くだけです.//////////////////////////////////////////////////////////////////////////
using UnityEngine;
using ExitGames.Client.Photon;
using System.Collections.Generic;
/// Author: cartzhang
/// Time: 2017-03-22
/// extent photonNetWork.
/// this can instantiate by transform,what is more,can auto get prefab from
/// subfold in resources.
public static partial class PhotonNetwork
{
private static bool bInitialOnce = false;
private static Dictionary<string, GameObject> PrefabResoucePaths = new Dictionary<string, GameObject>();
/// <summary>
/// @cartzhang use prefab to load.
/// </summary>
/// <param name="prefabTransform"></param>
/// <param name="position"></param>
/// <param name="rotation"></param>
/// <param name="group"></param>
/// <returns></returns>
public static GameObject Instantiate(Transform prefabTransform, Vector3 position, Quaternion rotation, int group)
{
return Instantiate(prefabTransform, position, rotation, group, null);
}
/// <summary>
/// @ TODO
/// </summary>
/// <param name="prefabTransform"></param>
/// <param name="position"></param>
/// <param name="rotation"></param>
/// <param name="group"></param>
/// <param name="data"></param>
/// <returns></returns>
public static GameObject Instantiate(Transform prefabTransform, Vector3 position, Quaternion rotation, int group, object[] data)
{
#if USE_SELF_CACHE
// whether use himself cache.
if (!bInitialOnce)
{
bInitialOnce = true;
GetAllResourceFileGameObjectFullPath();
}
#endif
string prefabName = prefabTransform.name;
if (prefabName.Length < 1)
{
Debug.LogError("Failed to Instance prefab: " + prefabTransform.name + " input is not a prefab");
}
if (!connected || (InstantiateInRoomOnly && !inRoom))
{
Debug.LogError("Failed to Instantiate prefab: " + prefabName + ". Client should be in a room. Current connectionStateDetailed: " + PhotonNetwork.connectionStateDetailed);
return null;
}
GameObject prefabGo = null;
if (!UsePrefabCache || !SLQJ.NetPoolManager.prefabResoucePrefabCache.TryGetValue(prefabName, out prefabGo))
{
//prefabGo = (GameObject)Resources.Load(prefabName, typeof(GameObject));
//if (UsePrefabCache)
//{
// PrefabResoucePaths.Add(prefabName, prefabGo);
//}
}
if (prefabGo == null)
{
Debug.LogError("Failed to Instantiate prefab: " + prefabName + ". Verify the Prefab is in a Resources folder (and not in a subfolder)");
return null;
}
// a scene object instantiated with network visibility has to contain a PhotonView
if (prefabGo.GetComponent<PhotonView>() == null)
{
Debug.LogError("Failed to Instantiate prefab:" + prefabName + ". Prefab must have a PhotonView component.");
return null;
}
Component[] views = (Component[])prefabGo.GetPhotonViewsInChildren();
int[] viewIDs = new int[views.Length];
for (int i = 0; i < viewIDs.Length; i++)
{
//Debug.Log("Instantiate prefabName: " + prefabName + " player.ID: " + player.ID);
viewIDs[i] = AllocateViewID(player.ID);
}
// Send to others, create info
Hashtable instantiateEvent = networkingPeer.SendInstantiate(prefabName, position, rotation, group, viewIDs, data, false);
// Instantiate the GO locally (but the same way as if it was done via event). This will also cache the instantiationId
return networkingPeer.DoInstantiate(instantiateEvent, networkingPeer.LocalPlayer, prefabGo);
}
}
これで本編は終わりです.主にphotonがカスタムメモリプールにアクセスすることを話し、一部の最適化とPhotonのインスタンス化方法を拡張し、使いやすいようにしました.この記事を通じて、自分のオブジェクトプールにネットワーク機能を追加してほしいです.もし問題があれば、いつでも連絡してください!!
五、その他の関連
【1】http://blog.csdn.net/cartzhang/article/details/54096845 【2】http://blog.csdn.net/cartzhang/article/details/55051570 ラベル:Photon、オブジェクトプール、カスタム.もし問題があれば、いつでも連絡してください.