Unity自定义服务器:如何实现射击与子弹信息同步?
Hey there! Let's get to the bottom of why other players can't see your bullets. The main problem right now is that your code only spawns bullets locally on your machine—you never send any shoot-related data to your server, so it has no way to tell other clients that a bullet should be spawned.
Here's how to fix this step by step:
1. Merge Your Duplicate Start() Methods
First off, you have two Start() methods in your code—this will throw an error in Unity. Combine them into one so your connection setup and other initialization logic runs correctly.
2. Send Shoot Data to the Server
Add a method to package and send your bullet spawn details (like player ID, spawn position, and rotation) to the server whenever you shoot. Then call this method from your Shoot() function.
void Shoot() { if (Input.GetKeyDown(KeyCode.Mouse0)) { // Spawn bullet locally first (optional, you can wait for server confirmation too) SpawnLocalBullet(); // Send shoot data to server for other players SendShootData(); } } void SpawnLocalBullet() { var bullet = Instantiate(bulletObject, bulletSpawnPoint.position, bulletSpawnPoint.rotation); bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * bulletSpeed; Destroy(bullet, bulletDestroyTime); } void SendShootData() { if (sock == null || !sock.Connected) { Debug.Log("Can't send shoot data: Not connected to server"); return; } // Package shoot data with a clear command prefix (e.g., "SHOOT") string shootPayload = $"SHOOT|{ImPlayer}|{bulletSpawnPoint.position.x}|{bulletSpawnPoint.position.y}|{bulletSpawnPoint.position.z}|{bulletSpawnPoint.rotation.x}|{bulletSpawnPoint.rotation.y}|{bulletSpawnPoint.rotation.z}|{bulletSpawnPoint.rotation.w}"; byte[] data = System.Text.Encoding.ASCII.GetBytes(shootPayload); try { sock.Send(data); Debug.Log("Successfully sent shoot data to server"); } catch (System.Exception e) { Debug.LogError($"Failed to send shoot data: {e.Message}"); } }
3. Add Continuous Server Message Listening
Your original code only receives a single message from the server on startup. You need a background thread to listen for incoming messages non-stop—this is how you'll get shoot data from other players.
void Start() { anim = GetComponent<Animator>(); sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint IPaddress = new IPEndPoint(IPAddress.Parse("130.229.156.6"), 13000); try { sock.Connect(IPaddress); // Start a background thread to listen for server messages System.Threading.Thread receiveThread = new System.Threading.Thread(ListenForServerMessages); receiveThread.IsBackground = true; receiveThread.Start(); // Get your player ID from the server byte[] initialMsgBuffer = new byte[1024]; int initialMsgSize = sock.Receive(initialMsgBuffer); ImPlayer = System.Text.Encoding.ASCII.GetString(initialMsgBuffer, 0, initialMsgSize); Debug.Log($"Jag ar player {ImPlayer}"); } catch { Debug.Log("Unable to connect"); } InvokeRepeating("Send", 1.0f, 0.125f); } void ListenForServerMessages() { byte[] buffer = new byte[1024]; while (sock != null && sock.Connected) { try { int bytesReceived = sock.Receive(buffer); if (bytesReceived <= 0) break; string message = System.Text.Encoding.ASCII.GetString(buffer, 0, bytesReceived); Debug.Log($"Received from server: {message}"); // Parse the server message string[] messageParts = message.Split('|'); if (messageParts[0] == "SHOOT") { // Ignore if this is your own shoot message (to avoid duplicate bullets) if (messageParts[1] == ImPlayer) continue; // Parse spawn position and rotation Vector3 spawnPos = new Vector3( float.Parse(messageParts[2]), float.Parse(messageParts[3]), float.Parse(messageParts[4]) ); Quaternion spawnRot = new Quaternion( float.Parse(messageParts[5]), float.Parse(messageParts[6]), float.Parse(messageParts[7]), float.Parse(messageParts[8]) ); // Spawn the bullet on the main Unity thread (critical! Unity API isn't thread-safe) Invoke(nameof(SpawnRemoteBullet), 0, spawnPos, spawnRot); } // Add handling for other server messages (like player position updates) here } catch (System.Exception e) { Debug.LogError($"Error receiving server message: {e.Message}"); break; } } } void SpawnRemoteBullet(Vector3 spawnPos, Quaternion spawnRot) { var bullet = Instantiate(bulletObject, spawnPos, spawnRot); bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * bulletSpeed; Destroy(bullet, bulletDestroyTime); }
4. Server-Side Setup (Critical!)
Don't forget—your server needs to handle the "SHOOT" command when it receives it. When the server gets a shoot payload from a client, it should broadcast that exact message to all other connected clients. Without this step, other players will never get the shoot data.
Quick Notes
- Thread Safety: Always use
Invoke()or a main thread dispatcher when calling Unity API methods from background threads (likeInstantiate). Directly calling these from non-main threads will cause crashes. - Data Serialization: For more complex games, consider using a more robust serialization method (like JSON or Protobuf) instead of plain string splitting—this avoids issues with special characters and makes data parsing cleaner.
- Error Handling: Add more error checking for network operations (like disconnected sockets) to make your game more stable.
内容的提问来源于stack exchange,提问作者Stefi Zuzu

