Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Carregamento e salvamento de arquivos durante a execução
Ver também
Consulte Salvando jogos (save) para informações sobre salvar e carregar progresso de jogo.
Às vezes, exportar pacotes, patches e mods não é o ideal quando você deseja que os jogadores possam carregar conteúdo gerado por usuários em seu projeto. Isso exige que os usuários gerem um arquivo PCK ou ZIP através do editor do Godot, o qual contém recursos importados pelo Godot.
Exemplos de casos de uso para carregamento e salvamento de arquivos em tempo de execução incluem:
Carregando pacotes de texturas projetados para o jogo.
Carregar faixas de áudio fornecidas pelo usuário e reproduzi-las em uma estação de rádio do jogo.
Usar fontes fornecidas pelo usuário para menus e HUD.
Salvar/carregar um formato de arquivo que possa conter múltiplos arquivos, mas que ainda possa ser lido facilmente por outros aplicativos (ZIP).
Carregar arquivos criados por outro jogo ou programa, ou até mesmo arquivos de dados de outro jogo não feito com o Godot.
Carregar arquivos criados por outro jogo ou programa, ou até mesmo arquivos de dados de outro jogo não feito com o Godot.
O carregamento de arquivos em tempo de execução pode ser combinado com HTTP requests para carregar recursos da Internet diretamente.
Aviso
Não use esta abordagem de carregamento em tempo de execução para carregar recursos que fazem parte do projeto, pois é menos eficiente e não permite se beneficiar das funcionalidades de manipulação de recursos do Godot (como remapeamentos de tradução). Veja Processo de importação para detalhes.
Ver também
Você pode ver como salvar e carregar funciona na prática usando o projeto de demonstração Run-time File Saving and Loading (Serialization).
Arquivos de texto simples e binários
A classe FileAccess do Godot fornece métodos para acessar arquivos no sistema de arquivos para leitura e escrita:
func save_file(content):
var file = FileAccess.open("/path/to/file.txt", FileAccess.WRITE)
file.store_string(content)
func load_file():
var file = FileAccess.open("/path/to/file.txt", FileAccess.READ)
var content = file.get_as_text()
return content
private void SaveFile(string content)
{
using var file = FileAccess.Open("/Path/To/File.txt", FileAccess.ModeFlags.Write);
file.StoreString(content);
}
private string LoadFile()
{
using var file = FileAccess.Open("/Path/To/File.txt", FileAccess.ModeFlags.Read);
string content = file.GetAsText();
return content;
}
Para lidar com formatos binários personalizados (como carregar formatos de arquivo não suportados pelo Godot), FileAccess fornece vários métodos para ler/escrever inteiros, floats, strings e mais. Esses métodos FileAccess têm nomes que começam com get_ e store_.
Se você precisar de mais controle sobre a leitura de arquivos binários ou precisar ler fluxos binários que não fazem parte de um arquivo, PackedByteArray fornece vários métodos auxiliares para decodificar/codificar séries de bytes em inteiros, floats, strings e mais. Esses métodos PackedByteArray têm nomes que começam com decode_ e encode_. Veja também API de serialização binária.
Imagens
O método estático Image.load_from_file da Image cuida de tudo, desde a detecção do formato com base na extensão do arquivo até a leitura do arquivo do disco.
Se precisar de tratamento de erros ou mais controle (como alterar a escala em que um SVG é carregado), use um dos seguintes métodos, dependendo do formato do arquivo:
Vários formatos de imagem também podem ser salvos pelo Godot em tempo de execução usando os seguintes métodos:
Os métodos com o sufixo to_buffer salvam a imagem em um PackedByteArray em vez do sistema de arquivos. Isso é útil para enviar a imagem pela rede ou para dentro de um arquivo ZIP sem ter que gravá-la no sistema de arquivos. Isso pode aumentar o desempenho reduzindo a utilização de E/S (I/O).
Nota
Se for exibir a imagem carregada em uma superfície 3D, certifique-se de chamar Image.generate_mipmaps para que a textura não pareça granulada quando vista à distância. Isso também é útil em 2D ao seguir as instruções sobre reduzir o aliasing ao reduzir a resolução (downsampling).
Exemplo de carregamento de uma imagem e exibição dela em um nó TextureRect (o que requer conversão para ImageTexture):
# Load an image of any format supported by Godot from the filesystem.
var image = Image.load_from_file(path)
# Optionally, generate mipmaps if displaying the texture on a 3D surface
# so that the texture doesn't look grainy when viewed at a distance.
#image.generate_mipmaps()
$TextureRect.texture = ImageTexture.create_from_image(image)
# Save the loaded Image to a PNG image.
image.save_png("/path/to/file.png")
# Save the converted ImageTexture to a PNG image.
$TextureRect.texture.get_image().save_png("/path/to/file.png")
// Load an image of any format supported by Godot from the filesystem.
var image = Image.LoadFromFile(path);
// Optionally, generate mipmaps if displaying the texture on a 3D surface
// so that the texture doesn't look grainy when viewed at a distance.
// image.GenerateMipmaps();
GetNode<TextureRect>("TextureRect").Texture = ImageTexture.CreateFromImage(image);
// Save the loaded Image to a PNG image.
image.SavePng("/Path/To/File.png");
// Save the converted ImageTexture to a PNG image.
GetNode<TextureRect>("TextureRect").Texture.GetImage().SavePng("/Path/To/File.png");
Arquivos de áudio/vídeo
O Godot suporta o carregamento de áudio Ogg Vorbis, MP3 e WAV em tempo de execução. Note que nem todos os arquivos com a extensão .ogg são arquivos Ogg Vorbis. Alguns podem ser vídeos Ogg Theora ou conter áudio Opus dentro de um contêiner Ogg. Esses arquivos não serão carregados corretamente como arquivos de áudio no Godot.
Exemplo de carregamento de um arquivo de áudio Ogg Vorbis em um nó AudioStreamPlayer:
$AudioStreamPlayer.stream = AudioStreamOggVorbis.load_from_file(path)
GetNode<AudioStreamPlayer>("AudioStreamPlayer").Stream = AudioStreamOggVorbis.LoadFromFile(path);
Exemplo de carregar um arquivo de vídeo Ogg Theora em um nó VideoStreamPlayer:
var video_stream_theora = VideoStreamTheora.new()
# File extension is ignored, so it is possible to load Ogg Theora videos
# that have a `.ogg` extension this way.
video_stream_theora.file = "/path/to/file.ogv"
$VideoStreamPlayer.stream = video_stream_theora
# VideoStreamPlayer's Autoplay property won't work if the stream is empty
# before this property is set, so call `play()` after setting `stream`.
$VideoStreamPlayer.play()
var videoStreamTheora = new VideoStreamTheora();
// File extension is ignored, so it is possible to load Ogg Theora videos
// that have a `.ogg` extension this way.
videoStreamTheora.File = "/Path/To/File.ogv";
GetNode<VideoStreamPlayer>("VideoStreamPlayer").Stream = videoStreamTheora;
// VideoStreamPlayer's Autoplay property won't work if the stream is empty
// before this property is set, so call `Play()` after setting `Stream`.
GetNode<VideoStreamPlayer>("VideoStreamPlayer").Play();
Cenas 3D
O Godot possui suporte nativo de primeira classe para glTF 2.0, tanto no editor quanto em projetos exportados. Usando GLTFDocument e GLTFState juntos, o Godot pode carregar e salvar arquivos glTF em projetos exportados, tanto em formatos de texto (.gltf) quanto binários (.glb). O formato binário deve ser o preferido, pois é mais rápido de gravar e menor, mas o formato de texto é mais fácil de depurar.
Desde o Godot 4.3, cenas em FBX também podem ser carregadas (mas não salvas) em tempo de execução usando as classes FBXDocument e FBXState. O código para fazer isso é o mesmo do glTF, mas você precisará substituir todas as instâncias de GLTFDocument e GLTFState por FBXDocument e FBXState nos exemplos de código abaixo.
Exemplo de carregamento de uma cena glTF e anexação do seu nó raiz à cena:
# Load an existing glTF scene.
# GLTFState is used by GLTFDocument to store the loaded scene's state.
# GLTFDocument is the class that handles actually loading glTF data into a Godot node tree,
# which means it supports glTF features such as lights and cameras.
var gltf_document_load = GLTFDocument.new()
var gltf_state_load = GLTFState.new()
var error = gltf_document_load.append_from_file("/path/to/file.gltf", gltf_state_load)
if error == OK:
var gltf_scene_root_node = gltf_document_load.generate_scene(gltf_state_load)
add_child(gltf_scene_root_node)
else:
show_error("Couldn't load glTF scene (error code: %s)." % error_string(error))
# Save a new glTF scene.
var gltf_document_save := GLTFDocument.new()
var gltf_state_save := GLTFState.new()
gltf_document_save.append_from_scene(gltf_scene_root_node, gltf_state_save)
# The file extension in the output `path` (`.gltf` or `.glb`) determines
# whether the output uses text or binary format.
# `GLTFDocument.generate_buffer()` is also available for saving to memory.
gltf_document_save.write_to_filesystem(gltf_state_save, path)
// Load an existing glTF scene.
// GLTFState is used by GLTFDocument to store the loaded scene's state.
// GLTFDocument is the class that handles actually loading glTF data into a Godot node tree,
// which means it supports glTF features such as lights and cameras.
var gltfDocumentLoad = new GltfDocument();
var gltfStateLoad = new GltfState();
var error = gltfDocumentLoad.AppendFromFile("/Path/To/File.gltf", gltfStateLoad);
if (error == Error.Ok)
{
var gltfSceneRootNode = gltfDocumentLoad.GenerateScene(gltfStateLoad);
AddChild(gltfSceneRootNode);
}
else
{
GD.PrintErr($"Couldn't load glTF scene (error code: {error}).");
}
// Save a new glTF scene.
var gltfDocumentSave = new GltfDocument();
var gltfStateSave = new GltfState();
gltfDocumentSave.AppendFromScene(gltfSceneRootNode, gltfStateSave);
// The file extension in the output `path` (`.gltf` or `.glb`) determines
// whether the output uses text or binary format.
// `GltfDocument.GenerateBuffer()` is also available for saving to memory.
gltfDocumentSave.WriteToFilesystem(gltfStateSave, path);
Nota
Ao carregar uma cena glTF, um caminho base deve ser definido para que recursos externos, como texturas, possam ser carregados corretamente. Ao carregar a partir de um arquivo, o caminho base é definido automaticamente para a pasta que contém o arquivo. Ao carregar a partir de um buffer, este caminho base deve ser definido manualmente, pois não há como o Godot inferir esse caminho.
Para definir o caminho base, configure GLTFState.base_path na sua instância de GLTFState antes de chamar GLTFDocument.append_from_buffer ou GLTFDocument.append_from_file.
Fontes
O método FontFile.load_dynamic_font suporta os seguintes formatos de arquivo de fonte: TTF, OTF, WOFF, WOFF2, PFB, PFM
Por outro lado, o método FontFile.load_bitmap_font suporta o formato BMFont (.fnt ou .font).
Adicionalmente, é possível carregar qualquer fonte instalada no sistema usando o suporte do Godot para Fontes do sistema.
Exemplo de carregamento automático de um arquivo de fonte de acordo com sua extensão de arquivo e, em seguida, sua adição como uma sobreposição de tema (theme override) em um nó Label:
var path = "/path/to/font.ttf"
var path_lower = path.to_lower()
var font_file = FontFile.new()
if (
path_lower.ends_with(".ttf")
or path_lower.ends_with(".otf")
or path_lower.ends_with(".woff")
or path_lower.ends_with(".woff2")
or path_lower.ends_with(".pfb")
or path_lower.ends_with(".pfm")
):
font_file.load_dynamic_font(path)
elif path_lower.ends_with(".fnt") or path_lower.ends_with(".font"):
font_file.load_bitmap_font(path)
else:
push_error("Invalid font file format.")
if not font_file.data.is_empty():
# If font was loaded successfully, add it as a theme override.
$Label.add_theme_font_override("font", font_file)
string path = "/Path/To/Font.ttf";
var fontFile = new FontFile();
if (
path.EndsWith(".ttf", StringComparison.OrdinalIgnoreCase)
|| path.EndsWith(".otf", StringComparison.OrdinalIgnoreCase)
|| path.EndsWith(".woff", StringComparison.OrdinalIgnoreCase)
|| path.EndsWith(".woff2", StringComparison.OrdinalIgnoreCase)
|| path.EndsWith(".pfb", StringComparison.OrdinalIgnoreCase)
|| path.EndsWith(".pfm", StringComparison.OrdinalIgnoreCase)
)
{
fontFile.LoadDynamicFont(path);
}
else if (path.EndsWith(".fnt", StringComparison.OrdinalIgnoreCase) || path.EndsWith(".font", StringComparison.OrdinalIgnoreCase))
{
fontFile.LoadBitmapFont(path);
}
else
{
GD.PrintErr("Invalid font file format.");
}
if (!fontFile.Data.IsEmpty())
{
// If font was loaded successfully, add it as a theme override.
GetNode<Label>("Label").AddThemeFontOverride("font", fontFile);
}
Arquivos ZIP
O Godot suporta a leitura e escrita de arquivos ZIP usando as classes ZIPReader e ZIPPacker. Isso suporta qualquer arquivo ZIP, incluindo arquivos gerados pela funcionalidade "Exportar PCK/ZIP" do Godot (embora estes contenham recursos importados do Godot em vez dos arquivos originais do projeto).
Nota
Use ProjectSettings.load_resource_pack para carregar arquivos PCK ou ZIP exportados pelo Godot como pacotes de dados adicionais. Essa abordagem é preferida para DLCs, pois torna a interação com pacotes de dados adicionais contínua (sistema de arquivos virtual).
Este suporte a arquivos ZIP pode ser combinado com o carregamento em tempo de execução de imagens, cenas 3D e áudio para fornecer uma experiência de modding contínua, sem exigir que os usuários usem o editor do Godot para gerar arquivos PCK/ZIP.
Exemplo que lista os arquivos em um arquivo ZIP em um nó ItemList e, em seguida, grava o conteúdo lido dele em um novo arquivo ZIP (essencialmente duplicando o arquivo):
# Load an existing ZIP archive.
var zip_reader = ZIPReader.new()
zip_reader.open(path)
var files = zip_reader.get_files()
# The list of files isn't sorted by default. Sort it for more consistent processing.
files.sort()
for file in files:
$ItemList.add_item(file, null)
# Make folders disabled in the list.
$ItemList.set_item_disabled(-1, file.ends_with("/"))
# Save a new ZIP archive.
var zip_packer = ZIPPacker.new()
var error = zip_packer.open(path)
if error != OK:
push_error("Couldn't open path for saving ZIP archive (error code: %s)." % error_string(error))
return
# Reuse the above ZIPReader instance to read files from an existing ZIP archive.
for file in zip_reader.get_files():
zip_packer.start_file(file)
zip_packer.write_file(zip_reader.read_file(file))
zip_packer.close_file()
zip_packer.close()
// Load an existing ZIP archive.
var zipReader = new ZipReader();
zipReader.Open(path);
string[] files = zipReader.GetFiles();
// The list of files isn't sorted by default. Sort it for more consistent processing.
Array.Sort(files);
foreach (string file in files)
{
GetNode<ItemList>("ItemList").AddItem(file);
// Make folders disabled in the list.
GetNode<ItemList>("ItemList").SetItemDisabled(-1, file.EndsWith('/'));
}
// Save a new ZIP archive.
var zipPacker = new ZipPacker();
var error = zipPacker.Open(path);
if (error != Error.Ok)
{
GD.PrintErr($"Couldn't open path for saving ZIP archive (error code: {error}).");
return;
}
// Reuse the above ZIPReader instance to read files from an existing ZIP archive.
foreach (string file in zipReader.GetFiles())
{
zipPacker.StartFile(file);
zipPacker.WriteFile(zipReader.ReadFile(file));
zipPacker.CloseFile();
}
zipPacker.Close();