ENetMultiplayerPeer
2026/4/14大约 5 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — ENetMultiplayerPeer
ENetMultiplayerPeer
定义
ENetMultiplayerPeer 是 Godot 提供的网络传输层——它负责在多个玩家之间建立网络连接、发送和接收数据。基于 ENet 库实现,支持可靠和不可靠两种传输模式。
打个比方:如果多人游戏是一场电话会议,ENetMultiplayerPeer 就是电话线路——它负责把所有人的电话连在一起,保证通话畅通。你在电话里说的内容(游戏数据)通过这条线路传给其他人。
在实际游戏开发中,你不需要直接操作 ENet 的大部分底层功能,Godot 的 MultiplayerAPI 会在上层帮你处理。但你需要用它来创建服务器(监听端口等待连接)或创建客户端(连接到服务器)。
常用方法
| 方法 | 返回值 | 说明 |
|---|---|---|
CreateServer(port, maxClients) | Error | 创建服务器,在指定端口监听 |
CreateClient(address, port) | Error | 作为客户端连接到指定地址和端口的服务器 |
Close() | void | 关闭连接 |
GetConnectionStatus() | ConnectionStatus | 获取当前连接状态 |
Poll() | void | 处理网络事件(需在循环中调用) |
SetTargetPeer(id) | void | 设置下次 RPC 发送给哪个玩家 |
常用信号(通过 MultiplayerAPI)
| 信号 | 说明 |
|---|---|
peer_connected(id) | 有新玩家连接时触发 |
peer_disconnected(id) | 有玩家断开时触发 |
代码示例
基础用法:创建服务器和客户端
C#
using Godot;
public partial class NetworkManager : Node
{
private ENetMultiplayerPeer _peer;
public void HostGame(int port = 7777, int maxClients = 4)
{
_peer = new ENetMultiplayerPeer();
Error err = _peer.CreateServer(port, maxClients);
if (err == Error.Ok)
{
Multiplayer.MultiplayerPeer = _peer;
GD.Print($"服务器已启动,端口:{port}");
// 运行结果: 服务器在端口 7777 上监听,最多允许 4 个客户端连接
}
else
{
GD.Print($"服务器启动失败:{err}");
}
}
public void JoinGame(string address = "127.0.0.1", int port = 7777)
{
_peer = new ENetMultiplayerPeer();
Error err = _peer.CreateClient(address, port);
if (err == Error.Ok)
{
Multiplayer.MultiplayerPeer = _peer;
GD.Print($"正在连接到 {address}:{port}...");
// 运行结果: 客户端尝试连接到指定服务器
}
}
}GDScript
extends Node
var _peer: ENetMultiplayerPeer
func host_game(port: int = 7777, max_clients: int = 4):
_peer = ENetMultiplayerPeer.new()
var err = _peer.create_server(port, max_clients)
if err == OK:
multiplayer.multiplayer_peer = _peer
print("服务器已启动,端口:%d" % port)
# 运行结果: 服务器在端口 7777 上监听,最多允许 4 个客户端连接
else:
print("服务器启动失败:%s" % err)
func join_game(address: String = "127.0.0.1", port: int = 7777):
_peer = ENetMultiplayerPeer.new()
var err = _peer.create_client(address, port)
if err == OK:
multiplayer.multiplayer_peer = _peer
print("正在连接到 %s:%d..." % [address, port])
# 运行结果: 客户端尝试连接到指定服务器实际场景:带连接状态检测的网络管理器
C#
using Godot;
public partial class GameNetworkManager : Node
{
private ENetMultiplayerPeer _peer;
public override void _Ready()
{
Multiplayer.PeerConnected += OnPeerConnected;
Multiplayer.PeerDisconnected += OnPeerDisconnected;
Multiplayer.ConnectedToServer += OnConnectedToServer;
Multiplayer.ConnectionFailed += OnConnectionFailed;
}
public void HostGame(int port = 7777)
{
_peer = new ENetMultiplayerPeer();
_peer.CreateServer(port);
Multiplayer.MultiplayerPeer = _peer;
GD.Print("服务器已创建,等待玩家加入...");
// 运行结果: 服务器开始监听
}
public void JoinGame(string host, int port = 7777)
{
_peer = new ENetMultiplayerPeer();
_peer.CreateClient(host, port);
Multiplayer.MultiplayerPeer = _peer;
// 运行结果: 客户端尝试连接
}
private void OnPeerConnected(long id)
{
GD.Print($"玩家 {id} 已加入游戏");
// 运行结果: 有新玩家连接时打印提示
}
private void OnPeerDisconnected(long id)
{
GD.Print($"玩家 {id} 已离开游戏");
// 运行结果: 有玩家断开时打印提示
}
private void OnConnectedToServer()
{
GD.Print("成功连接到服务器!");
// 运行结果: 客户端成功连接后打印提示
}
private void OnConnectionFailed()
{
GD.Print("连接服务器失败!");
// 运行结果: 连接失败时打印提示
}
}GDScript
extends Node
var _peer: ENetMultiplayerPeer
func _ready():
multiplayer.peer_connected.connect(_on_peer_connected)
multiplayer.peer_disconnected.connect(_on_peer_disconnected)
multiplayer.connected_to_server.connect(_on_connected_to_server)
multiplayer.connection_failed.connect(_on_connection_failed)
func host_game(port: int = 7777):
_peer = ENetMultiplayerPeer.new()
_peer.create_server(port)
multiplayer.multiplayer_peer = _peer
print("服务器已创建,等待玩家加入...")
# 运行结果: 服务器开始监听
func join_game(host: String, port: int = 7777):
_peer = ENetMultiplayerPeer.new()
_peer.create_client(host, port)
multiplayer.multiplayer_peer = _peer
# 运行结果: 客户端尝试连接
func _on_peer_connected(id):
print("玩家 %d 已加入游戏" % id)
# 运行结果: 有新玩家连接时打印提示
func _on_peer_disconnected(id):
print("玩家 %d 已离开游戏" % id)
# 运行结果: 有玩家断开时打印提示
func _on_connected_to_server():
print("成功连接到服务器!")
# 运行结果: 客户端成功连接后打印提示
func _on_connection_failed():
print("连接服务器失败!")
# 运行结果: 连接失败时打印提示进阶用法:带房间号的多人游戏连接
C#
using Godot;
public partial class RoomManager : Node
{
private ENetMultiplayerPeer _peer;
[Export] public int ExDefaultPort = 7777;
[Export] public int ExMaxPlayers = 8;
public void CreateRoom()
{
_peer = new ENetMultiplayerPeer();
Error err = _peer.CreateServer(ExDefaultPort, ExMaxPlayers);
if (err != Error.Ok)
{
GD.PrintErr($"创建房间失败:{err}");
return;
}
Multiplayer.MultiplayerPeer = _peer;
GD.Print($"房间已创建!端口:{ExDefaultPort},最大人数:{ExMaxPlayers}");
// 运行结果: 服务器创建成功,等待其他玩家连接
// 服务器也是玩家之一,生成自己的角色
SpawnPlayer(1); // 服务器玩家 ID 为 1
}
public void JoinRoom(string serverIp)
{
_peer = new ENetMultiplayerPeer();
Error err = _peer.CreateClient(serverIp, ExDefaultPort);
if (err != Error.Ok)
{
GD.PrintErr($"连接失败:{err}");
return;
}
Multiplayer.MultiplayerPeer = _peer;
// 运行结果: 正在连接到服务器
}
private void SpawnPlayer(long id)
{
GD.Print($"生成玩家 {id} 的角色");
// 运行结果: 为指定 ID 的玩家创建角色节点
}
}GDScript
extends Node
var _peer: ENetMultiplayerPeer
@export var default_port: int = 7777
@export var max_players: int = 8
func create_room():
_peer = ENetMultiplayerPeer.new()
var err = _peer.create_server(default_port, max_players)
if err != OK:
push_error("创建房间失败:%s" % err)
return
multiplayer.multiplayer_peer = _peer
print("房间已创建!端口:%d,最大人数:%d" % [default_port, max_players])
# 运行结果: 服务器创建成功
# 服务器也是玩家之一
spawn_player(1)
func join_room(server_ip: String):
_peer = ENetMultiplayerPeer.new()
var err = _peer.create_client(server_ip, default_port)
if err != OK:
push_error("连接失败:%s" % err)
return
multiplayer.multiplayer_peer = _peer
# 运行结果: 正在连接到服务器
func spawn_player(id: int):
print("生成玩家 %d 的角色" % id)
# 运行结果: 为指定 ID 的玩家创建角色节点注意事项
- 服务器和客户端使用同一个类:
ENetMultiplayerPeer既可以创建服务器也可以创建客户端,通过CreateServer和CreateClient区分。 - 需要设置
Multiplayer.MultiplayerPeer:创建完 ENetMultiplayerPeer 后,必须赋值给Multiplayer.MultiplayerPeer,Godot 的 RPC 系统才能工作。 - 端口冲突:确保使用的端口没有被其他程序占用。同一台机器上不能同时启动两个使用相同端口的服务器。
- NAT 穿透:互联网上的客户端连接服务器时可能受路由器 NAT 影响。Godot 4.x 支持
ENetConnection的 NAT 穿透功能,但需要额外配置。 - 断线重连:ENet 本身支持一定程度的断线重连,但复杂的重连逻辑需要你自己实现。
