如何使用带有脚本的 godot fbx 导入器
Posted
技术标签:
【中文标题】如何使用带有脚本的 godot fbx 导入器【英文标题】:how to use godot fbx importer with script 【发布时间】:2021-10-14 21:51:32 【问题描述】:我正在尝试制作一款在线游戏,我想从服务器导入一些 3d 文件,但我不知道如何使用脚本将它们导入到游戏中。
是否可以在服务器端将 fbx 转换为 PoolByteArray
并在客户端再次将其转换为 fbx?
【问题讨论】:
【参考方案1】:网络代码
基本服务器设置
由于我们想要客户端-服务器并且我们想要发送PoolByteArray
,我假设我们正在使用 Godot(而不是其他技术)制作权威服务器。特别是我们将使用MultiplayerAPI
。
我们可以从NetworkedMultiplayerEnet
类的对象开始。我们将选择一个端口来监听(理想情况下,您可以使其可配置,但这里是硬编码的):
服务器 Server.gd:
extends Node
var network := NetworkedMultiplayerENet.new()
var port:int = 1024
func _ready():
# start server
var error: = network.create_server(port)
if error != OK:
print ("Error Creating Server: ", error)
return
get_tree().multiplayer.set_network_peer(network)
基本客户端设置
客户端代码非常相似。除了我们需要提供服务器的地址和端口(这里我硬编码了“127.0.0.1”)。
客户server.gd:
extends Node
var network := NetworkedMultiplayerENet.new()
var server_port:int = 1024
var server_address:String = "127.0.0.1"
func _ready():
# start server
var error: = network.create_client(server_address, server_port)
if error != OK:
print ("Error Connecting to the Server: ", error)
return
get_tree().multiplayer.set_network_peer(network)
客户端-服务器连接
我们可以连接MultiplayerAPI
的"network_peer_connected"
和"network_peer_disconnected"
信号:
客户端和服务器Server.gd:
get_tree().multiplayer.connect("network_peer_connected", self, "_on_peer_connected")
get_tree().multiplayer.connect("network_peer_disconnected", self, "_on_peer_disconnected")
我们可以在SceneTree
和NetworkedMultiplayerEnet
上找到类似的信号。他们都工作。我使用MultiplayerAPI
只是为了保持一致。
无论我们连接的是哪个版本的这些信号,处理程序的外观和行为都相同:
func _on_peer_connected(player_id:int) -> void:
print("Player Connected with id: ", player_id)
func _on_peer_disconnected(player_id:int) -> void:
print("Player Disconnected with id: ", player_id)
在客户端上,您应该与player_id
的1
建立对等连接。那总是服务器。在服务器上,您将获得一个对等连接的信号,该信号带有一个大的player_id
数字,用于标识客户端。如果有多个客户端,它们会相互获取对等连接信号。
同样,当客户端离线时,您将收到对等断开信号。但是,当服务器离线时,客户端不会收到对等断开信号。相反,您会收到 "server_disconnected"
信号。在MultiplayerAPI
(和SceneTree
)上还有一个"connected_to_server"
信号可用。
通过网络发送PoolByteArray
在服务器上,让我们发送我们的PoolByteArray
。例如成功连接:
func _on_peer_connected(player_id:int) -> void:
print("Player Connected with id: ", player_id)
get_tree().multiplayer.send_bytes(PoolByteArray([125, 30, 50]), player_id)
您当然会跟踪已连接玩家的 id,并在适当的时候将PoolByteArray
发送给适当的客户端。出于解释的目的,我这样做是这样的。
通过网络接收PoolByteArray
在客户端,我们将连接"network_peer_packet"
信号:
get_tree().multiplayer.connect("network_peer_packet", self, "_on_network_packet")
我们将PoolByteArray
作为处理程序的参数:
func _on_network_packet(player_id:int, packet:PoolByteArray) -> void:
print("Packet from ", player_id)
以PoolByteArray
读写文件
阅读PoolByteArray
我们将使用File
类的对象和get_buffer
函数。
func read_file_to_pool_byte_array(path:String) -> PoolByteArray:
var file = File.new()
var error = file.open("user://path/to/file", File.READ)
if error == OK:
var result:PoolByteArray = file.get_buffer(file.get_len())
file.close()
return result
else:
print("Error opening the file.")
写信PoolByteArray
func write_file_from_pool_byte_array(path:String, data:PoolByteArray) -> void:
var file = File.new()
var error = file.open("user://path/to/file", File.WRITE)
if error == OK:
file.store_buffer(data)
file.close()
else:
print("Error opening the file.")
资源序列化
如您所知,您可以使用load
、preload
、ResourceLoader.load
或ResourceLoader.load_interactive
加载资源(请参阅Background loading)。
对应的是ResourceSaver
。您可以使用ResourceSaver.save
将资源保存到文件中。
FBX?
没有。
导入 FBX 所需的功能只能由编辑器实例化。它不适用于游戏构建。 好的,至少默认情况下它不可用,但启用它需要自定义构建 Godot。除非您想从源代码构建 Godot 以启用它们……那是“否”。
把所有东西放在一起
在 Godot 项目中导入您的 FBX。它作为场景导入。打开它并将其另存为资源格式。那是您要发送的文件,而不是 FBX。
在服务器上:
将资源文件读入PoolByteArray
。
将PoolByteArray
发送给客户端。
在客户端:
从服务器接收PoolByteArray
。
将PoolByteArray
保存到文件中。
使用ResourceLoader.load
或ResourceLoader.load_interactive
加载文件,因此您将获得PackedScene
然后您可以在必要时通过调用instance
来实例化PackedScene
。
因为您将在客户端上存储资源文件。您可以更多地参与解决方案,并让客户端仅在服务器没有资源时才从服务器请求资源。
您甚至可以让服务器告诉客户端文件的哈希值...然后,对于每个文件,客户端可以检查它是否有它,以及哈希值是否匹配(请参阅HashingContext
)。如果没有,或者哈希不匹配,则客户端可以向服务器请求文件。
您可以根据需要执行此操作……或者让服务器发送包含所有文件及其哈希值的清单,并在前面执行此操作,并带有进度条。
您也可以考虑使用二进制差异解决方案,但这超出了本文的范围。
【讨论】:
非常感谢,您的回答解决了我的问题【参考方案2】:感谢 theraot 解决了我的问题 我这样做。并且此代码适用于任何项目只需复制和粘贴只需更改端口号
`### clint side
# main clint server code
var network
var port = 9166
var ip = "127.0.0.1"
# create clint server
func _ready():
network = NetworkedMultiplayerENet.new()
network.create_client(ip,port)
get_tree().set_network_peer(network)
print("server start")
network.connect("connection_failed",self,"_Network_connection_failed")
network.connect("connection_succeeded",self,"_Network_connection_succeeded")
# sinal shot when you connect to server
func _Network_connection_succeeded():
print("connect")
# sinal shot when you disconnect to server
func _Network_connection_failed():
print("disconnect")
# must be called in the game for file that you want
func send_object_requast(object):
rpc_id(1,"send_back_object", object)
# server response to your requast
remote func received_object(informatoin):
# i dont know have to create new file so i copy existing file
# if you know help me
var file = Directory.new()
file.copy("res://sourse/2d material/white.png","res://sourse/2d material/123.png")
# store file in flie you create
var object = File.new()
object.open("res://sourse/2d material/123.png", File.WRITE)
object.store_buffer(informatoin)
object.close()
print("done")`
你应该做服务器项目
`## server side
# main ENet code
var network = NetworkedMultiplayerENet.new()
var port = 9166
var max_player = 100
# create server
func _ready():
network.create_server(port,max_player)
get_tree().set_network_peer(network)
print("main server start")
network.connect("peer_connected", self,"peer_connected_")
network.connect("peer_disconnected", self, "peer_disconnected_")
# signal shot when any clint connect
func peer_connected_(player_id):
print("user " + str(player_id) + "connect")
# signal shot when any clint diconnect
func peer_disconnected_(player_id):
print("user" + str(player_id)+ "disconnect")
# received and response back to clint
remote func send_back_object(object):
var plyer_id = get_tree().get_rpc_sender_id()
var file = File.new()
# you can choise any file for testing i choise godot icon
file.open("res://icon.png", File.READ)
var bytes : PoolByteArray = file.get_buffer(file.get_len())
file.close()
rpc_id(plyer_id, "received_object", bytes)`
【讨论】:
我不会说英语,很好,请原谅我 要创建一个新文件,你可以用File.WRITE
打开它。如果它不存在,Godot 将创建它。编辑:顺便说一句,您将要写入user://
路径。顺便说一句,我在MultiplayerAPI
周围写下了我的答案,以便能够使用send_bytes
,因为您想发送PoolByteArray
。如果您使用 rpc,则不限于发送PoolByteArray
。我相信您应该能够load
资源并发送它。否则,您可以使用var2bytes
和bytes2var
或类似的(例如var2str
和str2var
)。以上是关于如何使用带有脚本的 godot fbx 导入器的主要内容,如果未能解决你的问题,请参考以下文章
如何将搅拌机文件导出到 fbx 并将其导入统一,使其外观和工作方式相同?