序文
ついに登場しました。これまで多くの人が、マルチプレイヤー ゲームの実装方法を知りたいと私にプライベート メッセージを送ってきました。それがここにあります。
実は、私は長い間 Mirror プラグインに注目していましたが、最近になってようやくそれを整理する時間ができました。
Mirror は、シンプルで効率的なオープン ソースの Unity マルチプレイヤー ゲーム ネットワーク フレームワークであり、Unity ストアで無料で入手できます。
公式 API アドレス: https://mirror-networking.gitbook.io/docs
ミラープラグインのインポート
https://assetstore.unity.com/packages/tools/network/mirror-129321
簡単な紹介
1.RPC呼び出し
関数の変更に 3 つのキーワードが使用されている場合、関数はローカルではなくリモートで呼び出されます。[コマンド]、[ClientRpc]、[TargetRpc]。
- コマンドはクライアントで呼び出され、サーバーで実行されます。メソッド名は「Cmd」で始まります。
- ClientRpc はサーバー上で呼び出され、サーバーに接続されているすべてのクライアント上で実行されます。メソッド名は「Rpc」で始まります。
- TargetRpc はサーバー上で呼び出され、サーバーに接続されている指定されたクライアント上で実行されます。このメソッドには、どのクライアントで実行されるかを決定するために使用される NetworkConnection の仮パラメータが少なくとも 1 つあり、メソッド名は「Target」で始まります。
- ServerCallback: サーバーによってのみ呼び出され、サーバー上で実行できます。そしてメソッド名は「Server」で始まります。使い方はTargetRpcと似ています
使用
using Mirror;
using UnityEngine;
public class MyNetworkBehaviour : NetworkBehaviour
{
[Command]
void CmdFire()
{
// 在服务器上调用
}
[ClientRpc]
void RpcGetHit()
{
// 在客户端上调用
}
}
たとえば、特定のクライアント キャラクターが追加のポイントを獲得します。
# TargetRpc
NetworkIdentity netIdentity = GetComponent<NetworkIdentity();
TargetShowMessage(netIdentity.connectionToClient,1);
[TargetRpc]
private void TargetShowMessage(NetworkConnection target, int count)
{
sumCount += count;//加分
}
# ServerCallback
[ServerCallback]
private void ServerPlayerReady(NetworkConnection connection)
{
// 将指定客户端标记为已准备状态的逻辑
}
2. エラーに関する注意事項
-
1. コードにリンクされているシーン内のすべてのオブジェクトは、デフォルトでネットワーク ID とともに追加されますが、ネットワーク マネージャー コンポーネントとネットワーク ID コンポーネントが同じオブジェクトに配置されている場合、エラーが報告されます。
-
2. オブジェクト内にネットワーク マネージャー コンポーネントはあるが Kcp トランスポート コンポーネントがない場合、エラーが報告されます。
-
3. シーン内に複数のネットワーク マネージャー コンポーネントがある場合、エラーが報告されます。
-
4. キャラクター プレハブをプレーヤー プレハブ列にロードできない場合、ネットワーク ID コンポーネントでハングしない可能性があります。
-
5. ロール コードには、if (!isLocalPlayer) return; それ以外の場合を含める必要があります。。。あなたはその結果を知っています。
基本的な使い方
1.シーンネットワークマネージャーを作成する
ネットワーク マネージャーは、マルチプレイヤー ゲームの中核となる制御コンポーネントです。ネットワーク マネージャーは、マルチプレイヤー ゲームの中核となる制御コンポーネントです。
開始シーンに空のゲーム オブジェクトを作成し、新しく作成したネットワーク マネージャー コンポーネント (networkManager、Kcp Transport、networkManagerHUD コンポーネント) を追加します。
kcp トランスポート コンポーネントは、networkManager のトランスポートにマウントされ
、シーン シーンを構成します。オフラインとオンラインは、オフライン インターフェイスとゲーム インターフェイスです。たとえば、新しいオフライン シーンを作成し、その中にネットワーク マネージャーのネットワーク マネージャー HUD を配置し、新しいオンライン シーン。オフラインを一番上にして、ビルド設定のビルドのシーン バーにすべて登録 (ドラッグ イン)。次に、オフライン シーンに入り、実行し、ホストをクリックすると、オンライン シーンに入ります。
2. プレーヤーを作成する
プレーヤー オブジェクト Player を作成し、ネットワーク同期用の一意の識別子として networkIdentity をプレーヤーに追加します。一般に、除了
ネットワーク マネージャー コンポーネントを含むゲーム内のすべてのオブジェクト (これからハッチングされるオブジェクトも含めて) をこのコンポーネント内でハングする必要があります。これには 2 つのオプションしかありません。1 つのチェック ボックスは [サーバーのみ] で、これはサーバーのみが操作できることを意味します。必要に応じてチェックできます。2 つ目は表示されており、Default、Force Hidden、ForceShown の 3 つのオプションがありますが、個人的には役に立たないと感じているので、誰もがデフォルトで構いません。
networkIdentity がマウントされている場合にのみ、ネットワーク ハブはこのオブジェクトを認識して同期できます。次に、预制体
プレーヤーをプレーヤーとして保存し、シーン内で削除し、プレハブをネットワーク ハブ (networkManager) のプレーヤー プレハブ スロットにドラッグします。将来の世代は、ネットワーク ハブに完全に依存して、接続後に自動的に生成されます。ザ・ホスト。
Auto Create Player: デフォルトでチェックされており、チェックされている場合、サーバーに接続するときに上記の「プレーヤー プレハブ」が自動的に生成されます。
注: キャラクター プレハブをプレーヤー プレハブ列にロードできない場合、ネットワーク ID コンポーネントでハングしない可能性があります。
プレーヤーの Network Transform を追加し、ネットワーク内のネットワーク化されたゲーム オブジェクトの位置、回転、スケーリングを同期し、networkTransport の Client Authority 属性を確認します。
Mirror は現在 2 種類のネットワーク変換を提供しています。
Reliable:低带宽,与Rpcs/Cmds/等相同的延迟。
Unreliable:高带宽,极低延迟
使用Reliable,除非需要超低延迟。
注: プレーヤー本体のスケールを使用して、後で反転します。ここでは、本体にネットワーク変換コードも追加します。同期スケールをオンにすることを忘れないでください。
3. プレイヤーの初期スポーン位置を追加します
プレーヤーの初期スポーン位置としていくつかの空のオブジェクトを作成し、ネットワーク開始位置スクリプトを追加して、オブジェクトを適切な場所にドラッグします。
そして、NetworkManager でランダム (Random) またはラウンドロビン (Round Robin) のスポーンポイント選択方法を選択します。
1.Random:生成为随机(可能相同的生成位置将被两个或更多玩家使用)
2.Round Robin:循环(使用每个可用位置,直到客户端数超过生成点数)。
効果
4. プレーヤーのコントロール
ネットワーク同期については次の点に注意してください。
1. ネットワーク関数を使用する必要があるスクリプトは、対応する API を使用するために Mirror を追加し、MonoBehaviour の代わりに NetworkBehaviour を継承する必要があります。
2. プレーヤー入力に関しては、まず isLocalPlayer を判断し、islocalplayer を使用して現在のオブジェクトの権限があるかどうかを判断する必要があります。
ゲーム オブジェクトを制御するには、NetworkBehaviour を継承する単純なキャラクター制御スクリプトを PlayerControl.cs に追加します。
using UnityEngine;
using Mirror;
public class PlayerControl : NetworkBehaviour //MonoBehaviour --> NetworkBehaviour
{
private Rigidbody2D rb; // 刚体组件
void Start()
{
rb = GetComponent<Rigidbody2D>(); // 获取刚体组件
}
//速度:每秒移动5个单位长度
public float moveSpeed = 5;
void Update()
{
if (!isLocalPlayer) return; //不应操作非本地玩家
Move();
}
void Move()
{
//通过键盘获取水平轴的值,范围在-1到1
float horizontal = Input.GetAxisRaw("Horizontal");
rb.velocity = new Vector2(horizontal * moveSpeed, rb.velocity.y); // 设置刚体速度
if (horizontal != 0)
{
transform.GetChild(0).localScale = new Vector3(-horizontal, 1, 1); // 翻转角色
}
}
}
効果
5. カメラを同期する
各クライアントで独立して生成されたオブジェクト (ここでは、各プレーヤーのカメラを例として取り上げます) の場合、開始メソッドを OnStartLocalPlayer() に変更する必要があります。これにより、複数のクライアントのカメラが同じカメラに変更されるのを防ぐことができます。
OnStartLocalPlayer: クライアントでのみ実行され、スクリプトが配置されているオブジェクトがプレイヤー キャラクターの場合に呼び出され、追跡カメラの設定、キャラクターの初期化などに使用されます。
public override void OnStartLocalPlayer()
{
rb = GetComponent<Rigidbody2D>(); // 获取刚体组件
//摄像机与角色绑定
Camera.main.transform.SetParent(transform);
Camera.main.transform.localPosition = new Vector3(0, 0, Camera.main.transform.position.z);
}
効果
6. 異なるキャラクターの名前と色の変更を同期する
同期変数は、同期変数でマークする必要があります[SyncVar(hook=nameof(FunctionExecOnClient))]
。同期変数が変更されると、後続の FunctionExecOnClient メソッドが呼び出されます。
サーバー シーンの SyncVar の値が変更されると、他のすべてのクライアントと同期されます。
同期変数の変更には[Command]
タグ(メソッドのマーク、メソッド名が で始まるCmd
)を使用します。
using TMPro;
public TMP_Text nameText;
//需要把name和颜色同步给其他玩家,添加同步变量的标记[SyncVar(hook=nameof(FunctionExecOnClient))]
[SyncVar(hook = nameof(OnPlayerNameChanged))]
public string playerName;
[SyncVar(hook = nameof(OnPlayerColorChanged))]
private Color playerColor;
//申明OnPlayerNameChanged和OnPlayerColorChanged这两个方法
//第一个变量(oldstr)是同步变量修改前的值,第二个(newstr)是同步变量修改后的值
private void OnPlayerNameChanged(string oldstr, string newstr)
{
nameText.text = newstr;
}
private void OnPlayerColorChanged(Color oldCor, Color newCor)
{
nameText.color = newCor;
}
void Update()
{
if (!isLocalPlayer) return; //不应操作非本地玩家
Move();
if (Input.GetKeyDown(KeyCode.Space))
{
//随机生成颜色和名字
ChangedColorAndName();
}
}
public override void OnStartLocalPlayer()
{
//。。。
//开始就随机生成颜色和名字
ChangedColorAndName();
}
//player 的随机名称和颜色
private void ChangedColorAndName()
{
//随机名称和颜色
var tempName = $"Player{
Random.Range(1, 999)}";
var tempColor = new Color(Random.Range(0, 1f), Random.Range(0, 1f), Random.Range(0, 1f), 1);
//同步变量进行修改
CmdSetupPlayer(tempName, tempColor);
}
//对于同步变量的修改,使用[Command]标记(针对方法的标记,方法名以Cmd开头)
//通过这个方法同时对name和颜色进行修改
[Command]
private void CmdSetupPlayer(string name, Color color)
{
playerName = name;
playerColor = color;
}
効果
7. 同期アニメーション
Network Animator コンポーネントをマウントする
private Animator anim; // 动画组件
anim = gameObject.GetComponentInChildren<Animator>(); // 获取动画组件
public override void OnStartLocalPlayer()
{
//。。。
anim = gameObject.GetComponentInChildren<Animator>(); // 获取动画组件
}
void Update()
{
if (!isLocalPlayer) return; //不应操作非本地玩家
//。。。
//攻击动画控制
if (Input.GetMouseButtonDown(0))
{
anim.SetTrigger("isAttack");
anim.SetBool("isIdle", false);
}else{
anim.SetBool("isIdle", true);
}
}
8. シンクロ弾丸
爆弾は通常の爆弾の組立式本体です
方法 1
[ClientRpc] キーワードでは、サーバーは接続されているすべてのクライアントに同期指示を送信できます。メソッド名も Rpc で始まる必要があります。
public GameObject bomb;//炸弹预制体
void Update()
{
if (!isLocalPlayer) return; //不应操作非本地玩家
//。。。
//生成炸弹
if (Input.GetMouseButtonDown(1))
{
Cmdshoot();
}
}
[Command]
private void Cmdshoot()
{
RpcWeaponFire();
}
[ClientRpc]
private void RpcWeaponFire()
{
GameObject b = Instantiate(bomb, transform.position, Quaternion.identity);
b.transform.Translate(1, 0, 0);//防止子弹撞到角色
b.GetComponent<Rigidbody2D>().AddForce(Vector2.up * 500f);
}
効果
方法 2
NetworkManager
一番下にリスト(登録済みスポーン可能プレハブ)があり、敵や弾などゲーム内で孵化させる必要があるオブジェクトを配置するために使用されますので、それらをドラッグしてください
。そうでないと、ドラッグすることができません。
public GameObject bomb;//炸弹预制体
void Update()
{
if (!isLocalPlayer) return; //不应操作非本地玩家
//。。。
//生成炸弹
if (Input.GetMouseButtonDown(1))
{
Cmdshoot();
}
}
[Command]
private void Cmdshoot()
{
GameObject b = Instantiate(bomb, transform.position, Quaternion.identity);
b.transform.Translate(1, 0, 0);//防止子弹撞到角色
b.GetComponent<Rigidbody2D>().AddForce(Vector2.up * 500f);
Destroy(b, 2.0f);//两秒后删除
NetworkServer.Spawn(b);//服务器孵化,同步客户端
}
効果の
問題
クライアントによって爆弾に適用された AddForce フォースが効果がないことがわかります。その理由は、同期された剛体コンポーネントを追加せず、ネットワーク Rigidbody 2D コンポーネントを爆弾に追加したためです。
効果
9.チャット機能
ChatControllerスクリプトを追加しました
using UnityEngine;
using Mirror;
using TMPro;
using UnityEngine.UI;
public class ChatController : NetworkBehaviour
{
public TMP_InputField chatText;//输入框
public Button chatBtn;//发送按钮
public GameObject chatInfo;//聊天框内容预制体
public GameObject chatFrame;//聊天框
public PlayerController playerController ;
[SyncVar(hook = nameof(OnChatTextStringChanged))]
public string chatTextString;
private void OnChatTextStringChanged(string oldstr, string newstr)
{
//添加聊天内容
GameObject ci = Instantiate(chatInfo);
ci.GetComponent<TMP_Text>().text = newstr;
ci.transform.SetParent(chatFrame.transform);
}
void Awake()
{
chatBtn.onClick.AddListener(SendBtn);
}
public void SendBtn()
{
if (player != null)
{
playerController.CmdSendPLayerMessage(chatText.text);
}
}
}
PlayerControllerを変更し、転送キャラクター名を呼び出します
private ChatController chatController;
void Awake()
{
chatController = FindObjectOfType<ChatController>();
}
public override void OnStartLocalPlayer()
{
//。。。
chatController.playerController = this;
}
[Command]
public void CmdSendPLayerMessage(string message)
{
if (chatController != null)
{
chatController.chatTextString = playerName + "说:" + message;
}
}
UI ページを描画するときは、ネットワーク ID コンポーネントを追加することを忘れずに、
ネットワーク ID スクリプトをチャット UI キャンバスにマウントすることを忘れないでください。
効果
10. 同期シーン切り替え
3 つの新しいシーン NetworkManager オブジェクトを作成し
、NetworkManagerHUD の可視性を制御するために SceneController コードを追加します。
using UnityEngine;
using UnityEngine.UI;
using Mirror;
using UnityEngine.SceneManagement;
public class ScenceController : MonoBehaviour
{
private void Update()
{
Scene scene = SceneManager.GetActiveScene();
//控制NetworkManagerHUD的显隐
if(scene.name == "Main"){
GetComponent<NetworkManagerHUD>().enabled = false;
}else{
GetComponent<NetworkManagerHUD>().enabled = true;
}
}
//开始游戏,场景切换
public void ButtonLoadScene()
{
SceneManager.LoadScene("SampleScene1");
}
}
Main シーンはゲームのスタート ページです。デフォルトでは、ボタンが配置されます。ボタンは ButtonLoadScene メソッドを呼び出します。Network Manager は最初のシーン (および Main シーン) にのみマウントする必要があります。前のコードは可視性を制御しました。エラーが報告されたときに HUD ビューにいない場合、メイン シーンには
マウントに対応するシーンが表示されます。
SampleScene1 シーンと SampleScene2 シーンに基本的な違いはありません。前のゲーム ページと同じです。メイン インターフェイスの Main シーンとの競合を防ぐために、元の NetworkManager オブジェクトを削除します。シーンの切り替えを制御する ButtonChangeScene メソッドを追加します。ゲームのSampleScene1シーンとSampleScene2シーンにメソッドが実装されており、シーン切り替えボタン上にあります。
//同步切换场景
public void ButtonChangeScene()
{
if (isServer)
{
var scene = SceneManager.GetActiveScene();
NetworkManager.singleton.ServerChangeScene
(
scene.name == "SampleScene1" ? "SampleScene2" : "SampleScene1"
);
}
else
{
Debug.Log("你不是host");
}
}
効果
11. HUD インターフェースを再描画する
NetworkManagerHUD (Network Manager コンポーネントと連携する必要があります)、GUI を自動的に描画します。
Host (ホスト): サーバーとクライアントに相当します。
クライアント: サーバーに接続し、サーバーの IP アドレスを続けます。localhost はローカル ポートであり、自分自身で接続するのと同じです。
サーバーのみ: サーバーとしてのみ機能します。
ただし、この UI インターフェイスはあまり見栄えがよくないため、通常はこのコンポーネントを使用せず、独自の GUI を作成します。
シーンに 3 つの新しいボタンを追加します
ゲームページにマウントされた MyNetworkManagerHUD コードを追加、サンプルコード
using UnityEngine;
using UnityEngine.UI;
using Mirror;
public class MyNetworkManagerHUD : MonoBehaviour
{
private NetworkManager networkManager; // 创建 NetworkManager 对象
public GameObject btn;
public GUISkin mySkin;
private GameObject startHost;//启动网络主机按钮
private GameObject startClient;//启动网络客户端按钮
private GameObject stopHost;//停止网络主机或客户端按钮
void Awake()
{
networkManager = FindObjectOfType<NetworkManager>();
startHost = GameObject.Find("StartHost");
startClient = GameObject.Find("StartClient");
stopHost = GameObject.Find("StopHost");
startHost.GetComponent<Button>().onClick.AddListener(OnStartHost);
startClient.GetComponent<Button>().onClick.AddListener(StartClient);
stopHost.GetComponent<Button>().onClick.AddListener(StopHost);
}
private void Update()
{
// GetComponent<NetworkManagerHUD>().enabled = true;
if (!NetworkClient.isConnected && !NetworkServer.active) // 检查客户端和服务器的连接状态
{
startHost.SetActive(true);
startClient.SetActive(true);
stopHost.SetActive(false);
}
else
{
startHost.SetActive(false);
startClient.SetActive(false);
stopHost.SetActive(true);
}
}
private void OnStartHost()
{
networkManager.StartHost(); // 启动网络主机
}
private void StartClient()
{
networkManager.StartClient(); // 启动网络客户端
}
private void StopHost()
{
networkManager.StopHost(); // 停止网络主机或客户端
}
}
もちろん、元の NetworkManagerHUD コンポーネントは役に立たないので削除しても構いませんが、NetworkManagerHUD の表示と非表示を制御する以前のコードも同時に削除することを忘れないでください。
実行結果
12. サーバーを見つける
ネットワークディスカバリーHUD+ネットワークディスカバリーコンポーネントを使用して、元のNetworkManagerHUDを置き換えます。
このネットワーク検出コンポーネントは、ネットワーク マネージャーでも使用する必要があります。LAN 内のすべてのサーバーを一覧表示できます。トランスポート列があります。ネットワーク マネージャー コンポーネントと一緒に Kcp トランスポート コンポーネントをそこにドラッグする必要があります。そうしないと実行されません。
network DiscoveryHUD は networkmanagerHUD に似ていますが、クライアントが 1 つ少なく、検索サーバーが 1 つ多い点が異なります。
この機能は、「サーバーの検索」をクリックすると、LAN 内のすべての競技 (サーバー) がリストされますが、LAN 内のみが表示されます。
実行結果
14. キャラクターの死と復活
// 角色是否死亡的标志
[SyncVar(hook = nameof(OnIsDeadChanged))]
public bool isDead = false;
// 当角色死亡状态改变时的回调方法
void OnIsDeadChanged(bool oldValue, bool newValue)
{
if (newValue)
{
// 执行死亡逻辑,例如播放死亡动画、禁用角色控制等
Debug.Log("Player has died.");
Destroy(gameObject, 2f); // 延迟2秒后销毁角色对象
}
}
void Update()
{
if (Input.GetKeyDown(KeyCode.T))
{
CmdDestroyPlayerServer();
// 创建一个新的Camera对象
GameObject cameraObject = new GameObject("Main Camera");
// 添加Camera组件到对象上
Camera cameraComponent = cameraObject.AddComponent<Camera>();
// 设置摄像机的位置和旋转
cameraComponent.transform.position = new Vector3(0, 0, -10f);
cameraComponent.transform.rotation = Quaternion.identity;
}
}
[Command]
private void CmdDestroyPlayerServer()
{
isDead = true;
}
復活方法(キャラの再生成)は別の場所に書いてください
public class GameManager : MonoBehaviour
{
void Update()
{
if (Input.GetKeyDown(KeyCode.R))
{
//让当前客户端复活角色
NetworkClient.AddPlayer();
}
}
}
効果
13. 自分でネットワーク管理者を立てる
ロールを作成する簡単な関数は次のとおりです。
using Mirror;
using UnityEngine;
using UnityEngine.UI;
public class MyNetworkManager : NetworkManager//继承network manager类
{
public InputField myname; // 输入玩家名称的InputField
// 在服务器启动时调用
public override void OnStartServer()
{
Debug.Log("启动服务器");
// 启动服务器
base.OnStartServer();
// 注册CreateMMOCharacterMessage消息的处理方法
NetworkServer.RegisterHandler<CreateMMOCharacterMessage>(OnCreateCharacter);
}
public override void OnStopServer()
{
Debug.Log("关闭服务器");
// 关闭服务器
base.OnStopServer();
}
public override void OnServerConnect(NetworkConnectionToClient conn)
{
Debug.Log("处理连接事件");
// 处理连接事件
base.OnServerConnect(conn);
}
public override void OnServerDisconnect(NetworkConnectionToClient conn)
{
Debug.Log("处理断开事件");
// 处理断开事件
base.OnServerDisconnect(conn);
}
// CreateMMOCharacterMessage消息结构体
public struct CreateMMOCharacterMessage : NetworkMessage
{
public string playername; // 玩家名称
}
// 在客户端连接到服务器时调用
public override void OnClientConnect()
{
base.OnClientConnect();
// 在这里发送消息,或者您想要的任何其他地方
CreateMMOCharacterMessage characterMessage = new CreateMMOCharacterMessage
{
// playername = myname.text // 设置玩家名称为InputField中的文本
playername = "测试" // 设置玩家名称为InputField中的文本
};
NetworkClient.Send(characterMessage); // 发送消息给服务器
}
// 创建角色的方法,在收到CreateMMOCharacterMessage消息时调用
// 参数conn:与服务器的连接;参数message:接收到的消息
void OnCreateCharacter(NetworkConnectionToClient conn, CreateMMOCharacterMessage message)
{
//PlayerPrefab是在Network Manager的Inspector中指定的,
//但您可以在每个比赛中使用不同的预制体,例如:
GameObject gameobject = Instantiate(playerPrefab); // 实例化玩家预制体
//根据游戏的需要,应用消息中的数据
Player player = gameobject.GetComponent<Player>();
player.playerName = message.playername; // 将玩家名称赋值给Playercode组件中的playername变量
//将此游戏对象添加为连接上的玩家的控制对象
NetworkServer.AddPlayerForConnection(conn, gameobject);
}
}
元の NetworkManager を削除し、作成したコードをマウントし、ロールを自動的に作成するためのチェック ボックスを削除します。そうしないと、最初に 2 人の主人公が作成されます。
実行効果は正常です。
AOIフォグエフェクトの実装
空間ハッシュ関心管理コンポーネントをネットワーク管理者と同じオブジェクトに配置します。
パラメータ:
可視距離、
表示にかかる時間、
3D 2D 切り替え、
デバッグ スライダー
近づいたときのみアイテムを表示
ルームオープン機能
実際には、Mirror/Examples/MultipleMatches/Scenes/Main に公式デモがあり、最初にエフェクトを確認することができます。
オンラインサーバーへの接続(つづき)
Linuxサーバー
オンライン サーバーの IP とポート番号を変更します。
サーバーにアクセスして、対応するポートのセキュリティ グループのホワイトリストを忘れずに追加してください。
HUD スクリプト コンポーネントを削除します
。サーバーかクライアントかを制御するコードを作成します。
最初にサーバーをパッケージ化するため、最初にサーバーを確認してください。
次に、Linux サーバー側プログラムをパッケージ化します
ps: お持ちでない場合は、最初に Unity モジュールをインストールすることを忘れないでください。
すべてのサーバー側プログラムをサーバーにアップロードします。
最初に、実行可能ファイルにアクセス許可を追加し
、実行可能プログラムを実行します。
その後、クライアントを通常どおりパッケージ化し、サーバーに接続して再生できます。
パッケージ化するときは、AppIsServer のチェック ボックスを削除し、ターゲット プラットフォームを Windows に変更することを忘れないでください。
接続に成功しました
ソースコード
整理できたら載せます。
終わり
バラの贈り物、香りを贈ろう!点赞评论和关注
記事の内容が参考になった場合は、できるだけ早くフィードバックを受け取ることができるよう、ケチらずにフィードバック支持
をいただければ、私が創作を続ける最大のモチベーションとなります。「いいね!」が増えると更新が早くなります!もちろん、記事内で存在错误
何かを見つけた場合は更好的解决方法
、お気軽にコメントしてプライベートメッセージを送ってください。
はい、私向宇
はhttps://xiangyu.blog.csdn.net
小さな会社で黙々と働いていた開発者が、最近興味本位でUnityを独学で勉強し始めました。何か問題が発生した場合は、コメントやプライベート メッセージを送っていただければ幸いです。私が必ずしも問題を知っているわけではないかもしれませんが、すべての関係者からの情報を確認し、最善の提案を提供できるよう努めます。プログラミングを学びたい人が増えますよ、みんなで励まし合いましょう〜