ãããã¯ãŒã¯ãªããžã§ã¯ãã¯ãªããžã§ã¯ãåæïŒObject SynchronizationïŒã«ãã£ãŠã宿çã«ããŒã¿ã®éåä¿¡ãè¡ã£ãŠãèªç±ãªå€ãåæããããšãã§ããŸãã
ãªããžã§ã¯ãåæã®åºç€
ãããã¯ãŒã¯ãªããžã§ã¯ãã«IPunObservable
ã€ã³ã¿ãŒãã§ãŒã¹ãå®è£
ããã¹ã¯ãªããã远å ãããšããã®ã¹ã¯ãªããã¯PhotonView
ã®ç£èŠå¯Ÿè±¡ã³ã³ããŒãã³ãïŒObserved ComponentsïŒãšãªã£ãŠãIPunObservable.OnPhotonSerializeView()
ã宿çã«åŒã°ããããã«ãªããŸãã
IPunObservable.OnPhotonSerializeView()
ã§ã¯ãã¹ããªãŒã ïŒPhotonStream
ïŒããPhotonã§éä¿¡ã§ããããŒã¿åã®å€ãèªã¿æžãããŠãããŸããèªèº«ã管çãããããã¯ãŒã¯ãªããžã§ã¯ããªãããŒã¿ãã¹ããªãŒã ã«æžã蟌ãã§éä¿¡ããåŠçãä»ãã¬ã€ã€ãŒã管çãããããã¯ãŒã¯ãªããžã§ã¯ããªãåä¿¡ããã¹ããªãŒã ãèªã¿èŸŒãã§åæããåŠçãè¡ããŸããã©ã¡ãã®åŠçãè¡ãã¹ããã¯stream.IsWriting
ã§å€å®ã§ããŸãã
using Photon.Pun;
using UnityEngine;
// IPunObservableã€ã³ã¿ãŒãã§ãŒã¹ãå®è£
ããŠãPhotonViewã®ç£èŠå¯Ÿè±¡ã³ã³ããŒãã³ãã«ãã
public class SampleTransformView : MonoBehaviourPunCallbacks, IPunObservable
{
void IPunObservable.OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
if (stream.IsWriting) {
// Transformã®å€ãã¹ããªãŒã ã«æžã蟌ãã§éä¿¡ãã
stream.SendNext(transform.localPosition);
stream.SendNext(transform.localRotation);
stream.SendNext(transform.localScale);
} else {
// åä¿¡ããã¹ããªãŒã ãèªã¿èŸŒãã§Transformã®å€ãæŽæ°ãã
transform.localPosition = (Vector3)stream.ReceiveNext();
transform.localRotation = (Quaternion)stream.ReceiveNext();
transform.localScale = (Vector3)stream.ReceiveNext();
}
}
}
æ¢è£œã³ã³ããŒãã³ã
PUN2ã§ã¯ããªããžã§ã¯ãã®åº§æšãã¢ãã¡ãŒã·ã§ã³ãªã©ã®åæãç°¡åã«è¡ããããã«ããããã®ããªããžã§ã¯ãåæãå©çšããŠäœæãããã³ã³ããŒãã³ãããããããçšæãããŠããŸããããã䜿çšããããšã§ããªããžã§ã¯ãåæãè¡ãã¹ã¯ãªãããªã©ãç¬èªã«å®è£ ããã«åæåŠçãæžãŸããããšãã§ããŸãã
PhotonTransformView
PhotonTransformView
ã³ã³ããŒãã³ãã¯Transform
ã®å€ïŒåº§æšã»å転ã»ã¹ã±ãŒã«ïŒã®åæãè¡ãã¹ã¯ãªããã§ãããã®ã³ã³ããŒãã³ãããããã¯ãŒã¯ãªããžã§ã¯ãã«è¿œå ããã ãã§ãTransform
ã®å€ãåæãããããšãã§ããŸãã
PhotonTransformViewClassic
PhotonTransformViewClassic
ã³ã³ããŒãã³ãã¯ãå€ãããŒãžã§ã³ã®PhotonTransformView
ãç§»æ€ãããã®ã§ããPhotonTransformView
ã¯çްãã調æŽãªãã§ããæãã«åº§æšãåæã§ããããã«äœãããŠããŸãããéã«çްãã調æŽãã§ããªããšããäžæºç¹ãäžãã£ãŠããŸãããPhotonTransformView
ã®æåã«æºè¶³ããããããã现ãã調æŽãããå Žåã«äœ¿ã£ãŠã¿ããšè¯ãã§ãããã
PhotonRigidbodyViewïŒPhotonRigidbody2DViewïŒ
PhotonRigidbodyView
ã³ã³ããŒãã³ãã§Rigidbody
ã®åæãè¡ãããšãã§ããŸãããã®ã³ã³ããŒãã³ãã远å ãããšãRigidbody
ã®å€ïŒåº§æšã»å転ïŒãåæãããããã«ãªããŸããPhotonTransformView
ãšäœµçšããå Žåã¯ã座æšãå転ã®å€ãäºéã«åæããªãããã«ããŠãããªããšãåããã«ã¯ã€ãããç¡é§ãªéä¿¡è² è·ãçºçããŠããŸãå¯èœæ§ãããã®ã§æ³šæããŸãããã
ãŸããRigidbody2D
ã®åæãè¡ãPhotonRigidbody2DView
ã³ã³ããŒãã³ããçšæãããŠããŸãã
PhotonAnimatorView
PhotonAnimatorView
ã³ã³ããŒãã³ãã§Animator
ã®ã¢ãã¡ãŒã·ã§ã³ãã©ã¡ãŒã¿ãŒãåæã§ããŸããã€ã³ã¹ãã¯ã¿ãŒã«ã¯ã察å¿ããAnimator
ã®ã¢ãã¡ãŒã·ã§ã³ãã©ã¡ãŒã¿ãŒã®ãªã¹ããèªåçã«è¡šç€ºãããŸãã
ð® ã¢ãã¿ãŒã®ã¹ã¿ããã²ãŒãžã衚瀺ããã
ãã¥ãŒããªã¢ã«ã§äœæãããµã³ãã«ãããžã§ã¯ãã®ã¢ãã¿ãŒã«ãã¹ã¿ããã®ãã©ã¡ãŒã¿ãŒãæãããŠããªããžã§ã¯ãåæã§ã¹ã¿ããã²ãŒãžã®è¡šç€ºãåæããŠã¿ãŸããããã¹ã¿ããã¯ãç§»åäžã¯æžå°ããŠããã鿢ãããšå埩ããŠãããã®ãšããŸãã
ã¹ã¿ããã²ãŒãžã®UIãäœæããã
æåã«ãã¢ãã¿ãŒã®ã²ãŒã ãªããžã§ã¯ãã®åèŠçŽ ãšããŠãã¹ã¿ããã²ãŒãžã®UIãäœæããŸãããã
ã¹ã¿ããã²ãŒãžãåæããã
ã¢ãã¿ãŒãæäœããã¹ã¯ãªããã«ã¹ã¿ããã®ãã©ã¡ãŒã¿ãŒïŒcurrentStamina
ïŒã远å ããŠãå
¥åã®æç¡ã§å¢æžãããåŠçãå®è£
ããŸãããã®åŸã«ãã¹ã¯ãªããã®ã¯ã©ã¹ã«IPunObservable
ã€ã³ã¿ãŒãã§ãŒã¹ãå®è£
ããŠãã¹ã¿ããã®å€ãIPunObservable.OnPhotonSerializeView()
ã§éåä¿¡ããŠåæãããŸãããã
using Photon.Pun;
using UnityEngine;
using UnityEngine.UI;
public class AvatarController : MonoBehaviourPunCallbacks, IPunObservable
{
private const float MaxStamina = 6f;
[SerializeField]
private Image staminaBar = default;
private float currentStamina = MaxStamina;
private void Update() {
if (photonView.IsMine) {
var input = new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"), 0f);
if (input.sqrMagnitude > 0f) {
// å
¥åããã£ãããã¹ã¿ãããæžå°ããã
currentStamina = Mathf.Max(0f, currentStamina - Time.deltaTime);
transform.Translate(6f * Time.deltaTime * input.normalized);
} else {
// å
¥åããªãã£ãããã¹ã¿ãããå埩ããã
currentStamina = Mathf.Min(currentStamina + Time.deltaTime * 2, MaxStamina);
}
}
// ã¹ã¿ãããã²ãŒãžã«åæ ãã
staminaBar.fillAmount = currentStamina / MaxStamina;
}
void IPunObservable.OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
if (stream.IsWriting) {
// èªèº«ã®ã¢ãã¿ãŒã®ã¹ã¿ãããéä¿¡ãã
stream.SendNext(currentStamina);
} else {
// ä»ãã¬ã€ã€ãŒã®ã¢ãã¿ãŒã®ã¹ã¿ãããåä¿¡ãã
currentStamina = (float)stream.ReceiveNext();
}
}
}
ã€ã³ã¹ãã¯ã¿ãŒãããå
ã»ã©äœæããUIã®åç
§ãstaminaBar
ã«ã¢ã¿ããããã®ãå¿ããªãããã«ããŸãããã
ãããžã§ã¯ãããã«ãããŠãã¹ã¿ããã²ãŒãžã®è¡šç€ºãåæãããŠããã°æåã§ãã
ð¶ ãªããžã§ã¯ãåæã®é »åºŠã調æŽãã
ãªããžã§ã¯ãåæã¯ããŒã¿ã宿çã«éä¿¡ããŸããããã®é »åºŠã«ãã£ãŠãåæã®ç²ŸåºŠãåŠçã³ã¹ããéä¿¡éããã®è² è·ãªã©ã倧ããå€ãã£ãŠããŸããPUN2ã§ã¯PhotonNetwork
ããç°¡åã«éä¿¡é »åºŠã調æŽããããšãã§ããŸãã
PhotonNetwork.SendRate = 20; // 1ç§éã«ã¡ãã»ãŒãžéä¿¡ãè¡ãåæ°
PhotonNetwork.SerializationRate = 10; // 1ç§éã«ãªããžã§ã¯ãåæãè¡ãåæ°
æ¬æžã§ã¯äŸ¿å®äžãIPunObservable.OnPhotonSerializeView()
ã§PhotonStream
ã«å€ãæžã蟌ãããšããããŒã¿ãéä¿¡ããããšæžããŠããŸãããå³å¯ã«ã¯ãéä¿¡ããŒã¿ãäœæããããæ£ããã§ããPhotonã«ã¯ãè€æ°ã®éä¿¡ããŒã¿ãå¯èœãªéããŸãšããŠéä¿¡ããããšã§ãéä¿¡ãæé©åããä»çµã¿ãåãã£ãŠããŸããSerializationRate
ã®ééã§äœæãããéä¿¡ããŒã¿ã¯ãSendRate
ã®ééã§ãŸãšããŠéä¿¡ãããŸããã€ãŸããããŒã¿ãäœæãããŠããéä¿¡ããããŸã§ã«ã¯è¥å¹²ã®é
å»¶ããããšããããšã§ããSendRate
ãäžããããšã§ããã®é
å»¶ãæå°ã«æããããšãã§ããŸãããè€æ°ã®éä¿¡ããŒã¿ããã©ãã©ã«éãããããã«ãªãéä¿¡éãå¢ããå¯èœæ§ããããŸãã
ð¶ ãªããžã§ã¯ãåæã®äžæåæ¢
ãªããžã§ã¯ãåæã§äžèŠãªããŒã¿ãéä¿¡ããªãããã«ããããšã§ãéä¿¡éãåæžã§ããŸãã
PhotonStreamã«æžã蟌ãŸãªã
空ã®PhotonStream
ã¯éä¿¡ãããŸãããäŸãã°ããã©ã°ã䜿ã£ãŠæžã蟌ã¿ãè¡ããªãããã«ããã ãã§ããªããžã§ã¯ãåæã®ããŒã¿éä¿¡ãäžæåæ¢ããããšãå¯èœã§ãã
private bool isSyncing = true; // åæãã©ã°
void IPunObservable.OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
if (stream.IsWriting) {
// åæãã©ã°ãç«ã£ãŠããå Žåã®ã¿éä¿¡ãè¡ã
if (isSyncing) {
stream.SendNext(transform.position);
}
} else {
transform.position = (Vector3)stream.ReceiveNext();
}
}
PhotonViewã®ç£èŠãªãã·ã§ã³ãèšå®ãã
PhotonView
ã®ç£èŠãªãã·ã§ã³ããReliable Delta CompressedãããUnreliable On Changeãã«èšå®ãããšãç£èŠå¯Ÿè±¡ã®å€ãæŽæ°ãããå Žåã«ã®ã¿ããŒã¿ãéä¿¡ããããã«ãªããŸãã
å€ãæŽæ°ããããšã¿ãªãéŸå€ã調æŽãã
PhotonView
ã®ç£èŠå¯Ÿè±¡ã®å€ãæŽæ°ããããšã¿ãªãéŸå€ã¯ãPhotonNetwork
ãã調æŽã§ããŸãã
PhotonNetwork.PrecisionForVectorSynchronization = 0.00001f;
PhotonNetwork.PrecisionForQuaternionSynchronization = 1f;
PhotonNetwork.PrecisionForFloatSynchronization = 0.01f;
ããããããã¯ããŒã¿åã®åäœã§ããèšå®ããããšãã§ããªãã®ã§ãæ£çŽäœ¿ãã¥ããæããããŸããåããããªåŠçãç¬èªã§å®è£ ããŠããŸãæ¹ã楜ãªããšãå€ãã§ãã
private Vector3 lastPosition = transform.position;
void IPunObservable.OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
if (stream.IsWriting) {
// ååã«éä¿¡ãã座æšãããäžå®ã®è·é¢ä»¥äžç§»åããå Žåã®ã¿çŸåšã®åº§æšãéä¿¡ãã
if (Vector3.Distance(transform.position, lastPosition) > 0.01f) {
stream.SendNext(transform.position);
lastPosition = transform.position;
}
} else {
transform.position = (Vector3)stream.ReceiveNext();
}
}