网络相关

TCP 可靠有序速度缓慢
UDP 不可靠无序速度快(Godot提供的高级api是用的UDP,支持IPv6)
在避免不需要的部分(拥塞/流量控制特性、Nagle算法等)的同时,重新构建游戏所需的TCP部分(可选的可靠性和包顺序)一般来说还是有道理的。
正因如此,大多数游戏引擎都带有这样的实现,Godot 也不例外。

可以使用低级网络API来实现最大限度的控制,并在完全裸露的网络协议之上实现所有功能
也可以使用基于 SceneTree 的高级网络API,该API通常以一种比较优化的方式在后台完成大部分繁重工作。

每个节点都有一个multiplayer属性,它是对场景树为其配置的MultiplayerAPI实例的引用
可以对节点单独设置MultiplayerAPI,同时覆盖所有子节点
可以实现在一个Godot示例中运行多个服务端和客户端

结束联网
multiplayer.multiplayer_peer = null
导出Android需要勾选INTERNET权限,否则不能联网

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
## 代码
extends Node2D

var ip_list = IP.get_local_addresses()
@onready var players: Node = $Players
@onready var http_request = $HTTPRequest
const PLAYER = preload("res://play/player.tscn")
var peer = ENetMultiplayerPeer.new()
var target_ip: String = "www.weiguang.fun"

## 创建服务器
func _on_create_button_down() -> void:
#创建监听的服务器,即创建了一个地址为 127.0.0.1:7788 的服务器
var error = peer.create_server(7788)
if error != OK:
printerr("创建服务器失败, 错误码", error)
return
multiplayer.multiplayer_peer = peer
# 作为服务端,需要监听是否有别的客户端进行连接
multiplayer.peer_connected.connect(_on_peer_connected)
# 客户端创建成功后,在当前场景添加玩家
# multiplayer.get_unique_id()用于获取当前客户端的唯一id
# 作为服务器的客户端,一般id均为1
add_player(multiplayer.get_unique_id())

func add_player(id: int) -> void:
var player = PLAYER.instantiate()
player.name = str(id)
players.add_child(player)

## 当有新的客户端连接时,该方法会被触发, 该方法只有主机端会被触发!
func _on_peer_connected(id: int) -> void:
print("有玩家连接,ID为",id)
# 添加新玩家
add_player(id)
pass

## 创建客户端并连接服务器
func _on_join_button_down() -> void:
if target_ip.is_empty():
printerr("IP地址不能为空!")
return
# 创建客户端并连接ip为target_ip:7788的服务器
var error = peer.create_client(target_ip, 7788)
if error != OK:
printerr("无法连接到指定服务器")
return
multiplayer.multiplayer_peer = peer

## 获取IP
func is_ipv4(ip: String) -> bool:
var parts = ip.split(".")
if parts.size() != 4:
return false
for part in parts:
if not part.is_valid_int():
return false
var num = int(part)
if num < 0 or num > 255:
return false
return true

# 判断是否是私有地址
func is_private_ipv4(ip: String) -> bool:
var parts = ip.split(".")
var first_octet = int(parts[0])
var second_octet = int(parts[1])

# 判断是否属于私有地址范围
if first_octet == 10:
return true
if first_octet == 172 and second_octet >= 16 and second_octet <= 31:
return true
if first_octet == 192 and second_octet == 168:
return true
return false

# 主函数:筛选无线局域网适配器的 IPv4 地址
func find_wireless_lan_ipv4() -> String:
var private_ipv4_list = []

for ip in ip_list:
if is_ipv4(ip):
if is_private_ipv4(ip):
private_ipv4_list.append(ip)

# 返回第一个符合条件的私有 IPv4 地址
if private_ipv4_list.size() > 0:
return private_ipv4_list[0]
else:
return "未找到符合条件的无线局域网适配器 IPv4 地址"

func _ready():
var button = Button.new()
button.pressed.connect(_on_ip_get_button_up)
var result = find_wireless_lan_ipv4()
print("无线局域网适配器的 IPv4 地址:", result)


func _on_ip_get_button_up() -> void:
var label1 = get_node("UI/Label1")
label1.text = "您的局域网IP地址是:"+find_wireless_lan_ipv4()
# 发起GET请求
var url = "http://inip.in/ip.json"
http_request.request(url)

func _on_ip_input_text_changed(new_text: String) -> void:
target_ip = new_text.strip_edges()
print("输入的IP:", target_ip)


func http_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void:
if result == OK:
if response_code == 200: # 检查是否成功获取数据
# 将body转换为字符串,并解析json
var json = body.get_string_from_utf8()
# 创建JSON对象
var json_parser = JSON.new()
# 解析JSON字符串
var _jx = json_parser.parse(json)
# 获取数据
var data = json_parser.get_data()
print("公网IP地址: ",data.ip)
var pip = str(data.ip)
_on_ip_received(pip)
else:
print("未能正确获取公网IP地址,状态码:", response_code)
else:
print("请求失败")

func _on_ip_received(ip_address: String):
var label2 = get_node("UI/Label2") # 确保Label节点存在并且路径正确
label2.text = "您的公网IP地址是: " + ip_address