bytes_to_var
最后同步日期:2026-04-15 | Godot 官方原文 — bytes_to_var
bytes_to_var
定义
bytes_to_var() 是 var_to_bytes() 的逆操作——它把一段之前打包好的字节数据还原回原来的值。
继续用快递的比喻:你朋友收到了你寄出去的包裹(字节数组),现在需要拆开它还原成原始的物品(变量)。bytes_to_var() 就是这个"拆包"的过程,它把二进制数据重新变回数字、字符串、数组、字典等 Godot 数据类型。
简单来说:var_to_bytes() 负责"打包",bytes_to_var() 负责"拆包",它们必须成对使用。
函数签名
// C# 中使用 GD.BytesToVar
Variant restored = GD.BytesToVar(byte[] bytes);
// 也可通过字节数组包装
Variant restored = GD.BytesToVar(Variant.From(bytes));func bytes_to_var(bytes: PackedByteArray) -> Variant参数说明
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
bytes | PackedByteArray | 是 | 由 var_to_bytes() 生成的字节数组。不能混用 var_to_bytes_with_objects() 生成的数据 |
返回值
Variant —— 反序列化后的值。数据结构和原始值完全一致。
代码示例
基础用法:还原字节数据
using Godot;
public partial class BytesToVarExample : Node
{
public override void _Ready()
{
// 原始数据
int score = 42;
string name = "Godot";
// 打包成字节
byte[] scoreBytes = GD.VarToBytes(Variant.From(score));
byte[] nameBytes = GD.VarToBytes(Variant.From(name));
// 从字节还原
var restoredScore = GD.BytesToVar(scoreBytes);
var restoredName = GD.BytesToVar(nameBytes);
GD.Print($"还原的分数: {restoredScore}"); // 运行结果: 还原的分数: 42
GD.Print($"还原的名字: {restoredName}"); // 运行结果: 还原的名字: Godot
}
}extends Node
func _ready():
# 原始数据
var score = 42
var name = "Godot"
# 打包成字节
var score_bytes = var_to_bytes(score)
var name_bytes = var_to_bytes(name)
# 从字节还原
var restored_score = bytes_to_var(score_bytes)
var restored_name = bytes_to_var(name_bytes)
print("还原的分数: ", restored_score) # 运行结果: 还原的分数: 42
print("还原的名字: ", restored_name) # 运行结果: 还原的名字: Godot实际场景:存档读取系统
using Godot;
public partial class SaveManager : Node
{
private string SavePath => "user://save_game.dat";
public void SaveGame()
{
var saveData = new Godot.Collections.Dictionary
{
["player_name"] = "勇者",
["level"] = 5,
["hp"] = 100,
["items"] = new Godot.Collections.Array { "剑", "盾", "药水" }
};
byte[] data = GD.VarToBytes(Variant.From(saveData));
using var file = FileAccess.Open(SavePath, FileAccess.ModeFlags.Write);
if (file != null)
{
file.StoreBuffer(data);
GD.Print("存档保存成功");
}
}
public void LoadGame()
{
if (!FileAccess.FileExists(SavePath))
{
GD.PrintErr("存档文件不存在");
return;
}
using var file = FileAccess.Open(SavePath, FileAccess.ModeFlags.Read);
if (file != null)
{
byte[] data = file.GetBuffer((long)file.GetLength());
var restored = (Godot.Collections.Dictionary)GD.BytesToVar(data);
GD.Print($"读取存档: {restored["player_name"]}, 等级: {restored["level"]}, HP: {restored["hp"]}");
// 运行结果: 读取存档: 勇者, 等级: 5, HP: 100
}
}
public override void _Ready()
{
SaveGame();
LoadGame();
}
}extends Node
var _save_path := "user://save_game.dat"
func save_game() -> void:
var save_data = {
"player_name": "勇者",
"level": 5,
"hp": 100,
"items": ["剑", "盾", "药水"]
}
var data = var_to_bytes(save_data)
var file = FileAccess.open(_save_path, FileAccess.WRITE)
if file:
file.store_buffer(data)
file.close()
print("存档保存成功")
func load_game() -> void:
if not FileAccess.file_exists(_save_path):
push_error("存档文件不存在")
return
var file = FileAccess.open(_save_path, FileAccess.READ)
if file:
var data = file.get_buffer(file.get_length())
file.close()
var restored = bytes_to_var(data)
print("读取存档: %s, 等级: %s, HP: %s" % [restored["player_name"], restored["level"], restored["hp"]])
# 运行结果: 读取存档: 勇者, 等级: 5, HP: 100
func _ready():
save_game()
load_game()进阶用法:网络数据传输
using Godot;
public partial class NetworkSync : Node
{
// 将游戏状态打包为字节数组,用于网络传输
public byte[] PackGameState(Vector2 playerPos, int score, bool alive)
{
var state = new Godot.Collections.Dictionary
{
["pos_x"] = playerPos.X,
["pos_y"] = playerPos.Y,
["score"] = score,
["alive"] = alive
};
return GD.VarToBytes(Variant.From(state));
}
// 从接收到的字节数组还原游戏状态
public void UnpackGameState(byte[] data)
{
var state = (Godot.Collections.Dictionary)GD.BytesToVar(data);
float posX = (float)state["pos_x"];
float posY = (float)state["pos_y"];
int score = (int)state["score"];
bool alive = (bool)state["alive"];
GD.Print($"玩家位置: ({posX:F1}, {posY:F1}), 分数: {score}, 存活: {alive}");
}
public override void _Ready()
{
// 模拟网络传输:打包 -> 传输 -> 拆包
byte[] packed = PackGameState(new Vector2(100, 200), 999, true);
GD.Print($"打包后字节长度: {packed.Length}");
UnpackGameState(packed);
}
}extends Node
# 将游戏状态打包为字节数组,用于网络传输
func pack_game_state(player_pos: Vector2, score: int, alive: bool) -> PackedByteArray:
var state = {
"pos_x": player_pos.x,
"pos_y": player_pos.y,
"score": score,
"alive": alive
}
return var_to_bytes(state)
# 从接收到的字节数组还原游戏状态
func unpack_game_state(data: PackedByteArray) -> void:
var state = bytes_to_var(data)
var pos_x = float(state["pos_x"])
var pos_y = float(state["pos_y"])
var score = int(state["score"])
var alive = bool(state["alive"])
print("玩家位置: (%.1f, %.1f), 分数: %d, 存活: %s" % [pos_x, pos_y, score, alive])
func _ready():
# 模拟网络传输:打包 -> 传输 -> 拆包
var packed = pack_game_state(Vector2(100, 200), 999, true)
print("打包后字节长度: ", packed.size())
unpack_game_state(packed)注意事项
必须与
var_to_bytes()配对使用:用var_to_bytes()打包的数据,必须用bytes_to_var()来还原。用var_to_bytes_with_objects()打包的数据,必须用bytes_to_var_with_objects()来还原。两对函数不能交叉使用。不能还原包含对象引用的数据:如果原始数据中包含对象引用(如节点实例),
bytes_to_var()无法还原这些引用(会变成null)。需要使用bytes_to_var_with_objects()来还原包含对象引用的数据。C# 中的类型转换:
GD.BytesToVar()返回Variant类型,需要根据实际数据结构进行类型转换(如转换为Godot.Collections.Dictionary或Godot.Collections.Array)。安全的反序列化:
bytes_to_var()不会执行任意代码,因此即使字节数据来自不可信来源(如网络),也是安全的。
