На самом деле это довольно сложно и зависит от вашего случая.
В лучшем случае вы должны заранее знать, какие спрайты доступны, и сохранить их, например, в List<Sprite>
.. тогда вы можете просто сказатьклиенты, которые используют спрайт, устанавливая, например, [SyncVar]
для порожденного объекта.Что-то вроде
// on the spawned object
public class SpriteController : NetworkBehaviour
{
// Also good if you reference this already in the Inspector
[SerializeField] private SpriteRenderer spriteRenderer;
// Configured via the Inspector befrorehand
public List<Sprite> Sprites;
// Whenever this is changed on the Server
// the change is automatically submitted to all clients
// by using the "hook" it calls the OnSpriteIndexChanged and passes
// the new value in as parameter
[SyncVar(hook = nameof(OnSpriteIndexChanged))] public int SpriteIndex;
// Will be called everytime the index is changed on the server
[ClientCallback]
private void OnSpriteIndexChanged(int newIndex)
{
// First when using a hook you have to explicitly apply the changed value at some point
SpriteIndex = newIndex;
if (!spriteRenderer) spriteRenderer = GetComponent<SpriteRenderer>();
spriteRenderer.sprite = Sprites[SpriteIndex];
}
}
и затем, например, сделать
// If you make this of type SpriteController the Inspector automatically
// references the correct component and you can get rid of the GetComponent call later
public SpriteController testingCardCOntainerGameObject;
var testingCardObjectInstance = Instantiate(testingCardCOntainerGameObject, testingContainerCoords, Quaternion.identity);
// for testing use 1 since 0 is the default for int ;)
testingCardObjectInstance.SpriteIndex = 1;
NetworkServer.Spawn(testingCardObjectInstance);
Теперь целевой объект-спрайт инициализируется с правильным спрайтом.
Кроме того, используя hook
, теперь онфактически изменяется каждый раз, когда изменяется индекс на сервере .Так что теперь вы даже можете динамически переключать Sprite во время выполнения, просто назначив новый индекс:
private void Update()
{
if(!isServer || !Input.GetKeyDown(KeyCode.ArrowUp)) return;
SpriteIndex = (SpriteIndex + 1) % Sprites.Count;
}
Альтернативой может бытьпри передаче фактических Texture2D
данных.Это немного сложно, поскольку разрешенные параметры / типы данных, передаваемые через UNet, очень ограничены
// the sprite we will transfer
public Sprite targetSprite;
// the prefab to spawn
// directly use the component type here so we get rid of one GetComponent call
public SpriteRenderer examplePRefab;
[Command]
public void Cmd_Spawn()
{
// ON SERVER
var obj = Instantiate(examplePRefab);
// on the server set the sprite right away
obj.sprite = targetSprite;
// spawn (sprite will not be set yet)
NetworkServer.Spawn(obj.gameObject);
// tell clients to set the sprite and pass required data
Rpc_AfterSpawn(obj.gameObject, targetSprite.texture.EncodeToPNG(), new SpriteInfo(targetSprite));
}
[Serializable]
private struct SpriteInfo
{
public Rect rect;
public Vector2 pivot;
public SpriteInfo(Sprite sprite)
{
rect = sprite.rect;
pivot = sprite.pivot;
}
}
[ClientRpc]
private void Rpc_AfterSpawn(GameObject targetObject, byte[] textureData, SpriteInfo spriteInfo)
{
// ON CLIENTS
// the initial width and height don't matter
// they will be overwritten by load
// also the texture format will automatically be RGB24 for jpg data
// and RGBA32 for png
var texture = new Texture2D(1, 1);
// load the byte[] into the texture
texture.LoadImage(textureData);
var newSprite = Sprite.Create(texture, spriteInfo.rect, spriteInfo.pivot);
// finally set the sprite on all clients
targetObject.GetComponent<SpriteRenderer>().sprite = newSprite;
}
Обратите внимание, однако :
Это также очень ограничено, так как UNet допускает только сетевой буфер размером 64 кбайт, поэтому любое большее изображение / текстуру (+ остальные данные!) Будет невозможно передать таким способом.и это станет более сложным.
Также обратите внимание, что EncideToXY
часто приводит к большему размеру данных, чем исходное изображение.
Я также не уверен прямо сейчас, будет ли порядок выполнения Spawn
и Rpc_AfterSpawn
надежным в сети.Может случиться, что Rpc_AfterSpawn
достигнет клиентов до того, как Spawn
будет фактически выполнен.