Como você salva o estado do jogo?

27

Qual é o procedimento seguido pelos programadores de jogos para salvar e retomar o estado do jogo? como arquivos / mapeamentos. Quero salvá-lo para o jogo de defesa e uso o mecanismo de jogo unity3D.

Syed
fonte

Respostas:

16

Geralmente, não penso em termos de um instantâneo de memória, mas apenas faço uma lista de quais valores precisam ser salvos entre as sessões e salve esses valores em um arquivo externo.

Isso depende, é claro, das necessidades do seu jogo específico, mas geralmente eu simplesmente salvo o estado do nível atual (ou seja, onde estão todos os inimigos, qual é a saúde deles, etc.) e, em seguida, coisas de nível superior, como o nível do jogador já foi concluído.

jhocking
fonte
3
+1 É assim que eu faço. Eu escrevo o que preciso em um arquivo binário. E, se precisar adicionar algo novo, adiciono-o ao final para não quebrar os arquivos salvos antigos.
chaosTechnician
Essa é uma boa dica para não quebrar arquivos salvos antigos, embora adicionar dados ao final seja irrelevante para a maneira como eu salvo os dados. Eu faço isso serializando / desserializando um Dicionário, e a ordem é irrelevante nessa estrutura de dados.
jhocking
(basicamente, o código na resposta dos Jonas, com o meu objeto ser um dicionário)
jhocking
10

Esta resposta é específica do Unity3d .
No Unity, a maioria das classes é serializável, ou seja, você pode transmitir objetos completos do Unity para o disco. O código UnityScript a seguir é uma maneira de serializar um objeto, salve-o em disco e carregue-o novamente (após o carregamento, você deve converter o objeto):

import System;
import System.IO;
import System.IO.Stream;
import System.Runtime.Serialization;
import System.Runtime.Serialization.Formatters.Binary;

class SaveLoad {
        public static function SaveFile(filename:String, obj:Object):void {
                try {
                        Debug.Log("Writing Stream to Disk.", SaveLoad);
                        var fileStream:Stream = File.Open(filename, FileMode.Create);
                        var formatter:BinaryFormatter = new BinaryFormatter();
                        formatter.Serialize(fileStream, obj);
                        fileStream.Close();
                } catch(e:Exception) {
                        Debug.LogWarning("Save.SaveFile(): Failed to serialize object to a file " + filename + " (Reason: " + e.ToString() + ")");
                }
        }

        public static function LoadFile(filename:String):Object {
                try {
                        Debug.Log("Reading Stream from Disk.", SaveLoad);
                        var fileStream:Stream = File.Open(filename, FileMode.Open, FileAccess.Read);
                        var formatter:BinaryFormatter = new BinaryFormatter();
                        var obj:Object= formatter.Deserialize(fileStream);
                        fileStream.Close();
                        return obj;
                } catch(e:Exception) {
                        Debug.LogWarning("SaveLoad.LoadFile(): Failed to deserialize a file " + filename + " (Reason: " + e.ToString() + ")");
                        return null;
                }       
        }
}
jonas
fonte
2
Além de usar C #, você também desejaria usar PlayerPrefs. Eles são multiplataforma, você não pode fazer IO na Web / iOS / Android. unity3d.com/support/documentation/ScriptReference/... (amostra agradável embora!)
TJHeuvel
As PlayerPrefs são bem menos flexíveis, elas são realmente multiplataforma e são perfeitas para armazenar valores únicos ou não relacionados. Mas no Windows PlayerPrefs são armazenados no registro, em texto sem formatação.
Jonas
7
Se você já está serializando, por que não serializá-lo em uma String e armazená-lo no PlayerPrefs. Claro que é menos flexível, mas é praticamente a única solução para um jogo de plataforma cruzada.
TJHeuvel 18/04
2
O PlayerPrefs é ótimo para armazenar pequenos dados, como configurações, mas para jogos de
jhocking
2
@TJHeuvel: "você não pode fazer IO na Web / iOS / Android" Você definitivamente pode fazer IO no celular
Przemysław Wrzesiński
2

Para um TD, provavelmente salvaria exclusivamente entre ondas. Dessa forma, tudo o que você precisa pensar são as torres. Coloque alguns pontos de salvamento automáticos nos níveis, não mais do que 10 minutos entre, mas menos provavelmente é preferível.

Obviamente, se seus níveis forem curtos o suficiente, você poderá salvar apenas o status da campanha.

aaaaaaaaaaaa
fonte
1

Quando me refiro ao estado atual do jogo, estou me referindo ao instantâneo da memória no momento da gravação. Você precisa recriar isso a partir dos dados que deseja armazenar no seu HDD.

É mais fácil apenas serializar todas as classes que possuem dados que precisam ser persistentes e despejá-las no HDD, executando essencialmente um despejo de memória. O problema é que alterar as classes alterará o número / tipos de valores serializados e interromperá os salvamentos antigos. Também porque você está salvando tudo, aumenta o tempo de carregamento. É mais eficiente marcar campos individuais que são realmente necessários para reconstruir o "instantâneo da memória" atual com qualquer sistema de atributos usado pelo serializador / IDE. Em seguida, recrie o "instantâneo da memória" a partir dos dados salvos.

Também nunca usei o Unity antes, por isso pode ter algo embutido. No entanto, essa é a abordagem típica.

ClassicThunder
fonte
quer dizer que tenho que armazenar meus estados em um arquivo?
Syed
11
@Syed sim, no final do dia, ele deve ser gravado em algum arquivo, pois o estado do aplicativo não será salvo na memória. Com o Unity especificamente, você pode usar a classe PlayerPrefs (que, na verdade, acho que armazena coisas no registro no Windows), se você quiser evitar a leitura / gravação de todo o arquivo.
Tétrada