Menu

Tutorial de Unity 2D #13 – Save e Load

Olá meus queridos futuros donos de jogos indie, estamos finalmente no nosso ultimo tutorial. Hoje vamos aprender a como salvar e carregar o nosso jogo.

Semana passada eu peguei bem pesado com vocês não é mesmo? Mas relaxem, que hoje sendo a ultima aula, aquela que o povo não quer saber mais de nada além de comemorar, a aula será bem curtinha. Para vocês terem ideia, só vamos ter 4, isso mesmo 4 novas linhas de script para usar no nosso jogo ! Mas relaxem ai que também não vou deixar vocês tão largados assim não.

Embora no nosso script só vou usar 4, vou ensinar algumas coisas a mais que vocês podem precisar no futuro e abrir a mente de vocês para outras possibilidades. ^^

Bom, como a aula de hoje será bem curta, então vamos logo inicia-la. Aqui a ideia é bem simples. No nosso jogo existirá apenas um auto-save toda vez que mudamos de fase. Ou seja, se mudamos de fase, ele irá salvar a fase atual e quando clicarmos em continuar no menu principal, já iniciamos da ultima fase que chegamos. A única diferença é ao concluir o jogo (Chegar aos créditos), pois o antigo save será deletado, só a nível de aprendizagem.

Eu disse que iriamos aprender apenas 4 novas linhas de código. Essas linhas são:

PlayerPrefs.SetInt();
PlayerPrefs.GetInt();
PlayerPrefs.DeleteKey();
PlayerPrefs.HasKey();

Eu creio que no tutorial de programação eu expliquei o que é set e get, mas caso eu não tenha (ou vocês não lembrem): Set é usado para atribuir um valor, ou seja, “setar” valor. Get é utilizado para recuperar esse valor.

Então olhando as linhas acimas vamos usar o SetInt para salvar e dizer qual é a fase atual. O GetInt para recuperar essa fase no load. O HasKey verifica se tem algo salvo e o DeleteKey serve para deletar esse save.

Os métodos da classe PlayerPrefs são:

SetInt – Salva um atributo do tipo integer/int (inteiro)
SetFloat – salva um atributo do tipo float (decimal)
SetString – Salva um atributo do tipo String (Texto)
GetInt – Recupera um valor do tipo integer/int (Inteiro)
GetFloat – Recupera um valor do tipo float (decimal)
GetString – Recupera um valor do tipo String (Texto)
DeleteKey – Deleta um conteúdo salvo (Deve informar qual é)
DeleteAll – Deleta tudo que tem salvo
HasKey – Verifica se existe ou não algo salvo com o nome do conteúdo;
Save – Salva o conteúdo no disco (Vou explicar melhor mais na frente).

Bom, basicamente só vamos usar 4 desses ai, porem vou explicar todos ao longo do tutorial. Mas primeiro bora terminar o nosso jogo!

Voltando ao nosso projeto no nosso script Bandeira, que é responsável por passar de fase, apenas precisamos adicionar uma linha antes de mudar de fase:

	void OnTriggerEnter2D(Collider2D colisor) {
		if (colisor.gameObject.tag == "Player") {
			PlayerPrefs.SetInt("faseSalva", proximaFase);
			Application.LoadLevel(proximaFase);
		}
	}

Ao adicionar o PlayerPrefs.SetInt(proximaFase), JÁ salvamos informando a fase que o nosso personagem está. Sim, só isso e já salvamos. Salvamos a fase do jogo que o jogador está com o nome faseSalva.

Simples, né?

E pra carregar? Agora vamos para o Script MenuPrincipal, onde tínhamos aquele botão continuar, vamos fazer a seguinte alteração:

void OnGUI() {
		GUI.DrawTexture (new Rect (0, 0, Screen.width, Screen.height), background);
		GUI.DrawTexture (new Rect (225, 50, 150, 40), titulo);

		GUI.BeginGroup (new Rect(240,150, 120, 120));
		GUI.Box(new Rect(0, 0, 120, 120), "Menu");
		if (GUI.Button (new Rect (20, 30, 50, 20), "Iniciar")) {
			Application.LoadLevel("fase01");
		}
		if (GUI.Button (new Rect (20, 60, 70, 20), "Continuar")) {
			if (PlayerPrefs.HasKey("faseSalva")) {
				Application.LoadLevel(PlayerPrefs.GetInt ("faseSalva"));
			}
		}
		if (GUI.Button (new Rect (20, 90, 50, 20), "Sair")) {
			Application.Quit();
		}
		GUI.EndGroup();
	}

Dentro do if do botão continuar, adicionei um novo if:

if (PlayerPrefs.HasKey(“faseSalva”)) {
     Application.LoadLevel(PlayerPrefs.GetInt (“faseSalva”));
}
Esse if (PlayerPrefs.HasKey(“faseSalva”)), apenas verifica se tem alguma coisa salva em “faseSalva”. Caso tenha ele entra na condição e carrega a fase que estiver salva. Com isso o seu jogo já salva e já carrega.

Para finalizar esse tutorial, vamos adicionar apenas uma linha no método Start do script Creditos, para que quando o jogar complete o jogo, o save seja deletado:

void Start () {
		fonte = new GUIStyle();
		fonte.fontSize = 20;
		fonte.normal.textColor = Color.gray;

		PlayerPrefs.DeleteKey ("faseSalva");
	}

Pronto, com o PlayerPrefs.DeleteKey (“faseSalva”), o save é deletado. Como prometido o tutorial de hoje foi bem simples e curto!
Mas antes do fim bora explicar os demais conteúdos do PlayerPrefs. Se vocês repararam, eu em momento algum usei o método Save. Então para que ele serve?

Bom, o save do seu jogo só vai salvar no disco quando o jogador fechar o jogo. Logo se o jogo crashar, faltar energia ou fechar de outra forma inesperada pelo jogo, o save estará perdido. Agora se você quiser garantir que o save não se perca, você utiliza o método PlayerPrefs.Save(), logo após salvar os seus dados, que neste momento ele já salva os conteúdos em disco, logo pode faltar energia ou o que for, os dados já vão estar em segurança. O problema disso é que normalmente ao utilizar o Save, o jogo dá aquelas travadas de leve (Sabe quando chega em Checkpoint e o jogo trava por 1 ou 2 segundos? Ou você vai na opção Save e ele dá aquela travadinha? Isso acontece porque o jogo está salvando os dados da memoria ram para o disco). Por isso você deve analisar se quer usar ou save ou não. Se o seu jogo tiver uma tela de Save, pode usar tranquilo, agora se for de auto-save fica a sua escolha.

Carlos, eu quero um save point no meu cenário, como faço?

1 – Crie um objeto com um Collider 2D e a opção Is Trigger marcada.
2 – Crie um script para esse objeto e adicione uma propriedade podeSalvar do tipo booleana.
3 – Crie um OnTriggerEnter2D que torne podeSalvar = true
4 – Crie um OnTriggerExit2D que torne podeSalvar = false
5 – Se o jogador clicar no botão de interação e podeSalvar for igual a true, então salva o jogo!

Carlos, eu gostaria de salvar dados como nome do personagem, experiência, level, HP, habilidades, armas… Neste caso você pode usar os demais Set e Get:

//Salva
	PlayerPrefs.SetString ("nome", nomeJogador);
	PlayerPrefs.SetInt ("nivel", nivelJogador);
	PlayerPrefs.SetInt ("experiencia", expJogador);
	PlayerPrefs.SetInt ("hp", hpJogador);
	if (habilidade1Liberada) {
		PlayerPrefs.SetInt ("habilidade1Liberada", 1);
	}

	//Carrega
	nomeJogador = PlayerPrefs.GetString ("nome");
	nivelJogador = PlayerPrefs.GetInt ("nivel");
	expJogador = PlayerPrefs.GetInt ("experiencia");
	hpJogador = PlayerPrefs.GetInt ("hp");
	if (PlayerPrefs.HasKey ("habilidade1Liberada")) {
		habilidade1Liberada = true;
	} else {
		habilidade1Liberada = false;
	}

Carlos, quero ter mais de uma opção de Save como faço? Crie nomes diferentes para cada save:

//Salvar
	if (GUI.Button (new Rect(100, 100, 100, 100), "Save 1")) {
		PlayerPrefs.SetInt("save1_ProximaFase", proximaFase);
	}

	if (GUI.Button (new Rect(100, 100, 100, 100), "Save 2")) {
		PlayerPrefs.SetInt("save2_ProximaFase", proximaFase);
	}

	if (GUI.Button (new Rect(100, 100, 100, 100), "Save 3")) {
		PlayerPrefs.SetInt("save3_ProximaFase", proximaFase);
	}

	//Carregar
	if ((GUI.Button (new Rect(100, 100, 100, 100), "Save 1")) && PlayerPrefs.HasKey("save1_ProximaFase")) {
		Application.LoadLevel(PlayerPrefs.GetInt("save1_ProximaFase"));
	}
		
	if ((GUI.Button (new Rect(100, 100, 100, 100), "Save 2")) && PlayerPrefs.HasKey("save2_ProximaFase")) {
		Application.LoadLevel(PlayerPrefs.GetInt("save2_ProximaFase"));
	}
		
	if ((GUI.Button (new Rect(100, 100, 100, 100), "Save 3")) && PlayerPrefs.HasKey("save3_ProximaFase")) {
		Application.LoadLevel(PlayerPrefs.GetInt("save3_ProximaFase"));
	}

Com isso vocês já conseguem montar bastante coisa.

E agora sim terminamos de vez o tutorial que começou em 16/05/2014 (Praticamente 7 meses!!). Sinceramente foi uma experiência nova e interessante para mim. De fato gostei e também aprendi bastante. Gostaria de saber quem conseguiu completar o jogo? Quem era aquele cara que não sabia absolutamente nada de programação e hoje terminou um jogo com 18 Scritps!!!

Também gostaria de agradecer a vocês pelo feedback. Se não fosse por isso, provavelmente eu nem teria terminado esse tutorial. Valeu mesmo pessoal!

E não, esse não será o fim da minha relação com vocês. Pode ter certeza que muitos outros tutoriais estão por vir. No final da página tem a chamada para um  post Projetos Futuros, onde vocês vão escolher quais serão nossos próximos projetos!!

Dúvidas, criticas ou sugestões deixem nos comentários!

Bandeira.cs

using UnityEngine;
using System.Collections;

public class Bandeira : MonoBehaviour {
	public int proximaFase;

	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
	
	}

	void OnTriggerEnter2D(Collider2D colisor) {
		if (colisor.gameObject.tag == "Player") {
			PlayerPrefs.SetInt("faseSalva", proximaFase);
			Application.LoadLevel(proximaFase);
		}
	}
}

MenuPrincipal.cs

using UnityEngine;
using System.Collections;

public class MenuPrincipal : MonoBehaviour {

	public Texture2D background;
	public Texture2D titulo;


	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
	
	}

	void OnGUI() {

		GUI.DrawTexture (new Rect (0, 0, Screen.width, Screen.height), background);
		GUI.DrawTexture (new Rect (225, 50, 150, 40), titulo);

		GUI.BeginGroup (new Rect(240,150, 120, 120));
		GUI.Box(new Rect(0, 0, 120, 120), "Menu");
		if (GUI.Button (new Rect (20, 30, 50, 20), "Iniciar")) {
			Application.LoadLevel("fase01");
		}
		if (GUI.Button (new Rect (20, 60, 70, 20), "Continuar")) {
			if (PlayerPrefs.HasKey("faseSalva")) {
				Application.LoadLevel(PlayerPrefs.GetInt ("faseSalva"));
			}
		}
		if (GUI.Button (new Rect (20, 90, 50, 20), "Sair")) {
			Application.Quit();
		}
		GUI.EndGroup();
	}
}

Creditos.cs

using UnityEngine;
using System.Collections;

public class Creditos : MonoBehaviour {

	public Texture2D titulo;
	public float duracao;
	private float contagem;
	private GUIStyle fonte;	
	// Use this for initialization
	void Start () {
		fonte = new GUIStyle();
		fonte.fontSize = 20;
		fonte.normal.textColor = Color.gray;

		PlayerPrefs.DeleteKey ("faseSalva");
	}
	
	// Update is called once per frame
	void Update () {
		contagem += Time.deltaTime;
		if (contagem >= duracao) {
			Application.LoadLevel(0);
		}
	}

	void OnGUI() {
		GUI.DrawTexture (new Rect (225, 150, 150, 40), titulo);
		
		GUI.BeginGroup (new Rect(175,200, 250, 150));
		GUI.Label(new Rect(0, 0, 150, 20), "Tutorial de Unity 2D", fonte);
		GUI.Label(new Rect(0, 30, 150, 20), "Criador: Carlos W. Gama", fonte);
		GUI.Label(new Rect(0, 60, 150, 20), "Jogos Indie", fonte);
		GUI.EndGroup();
	}
}

Parte 12 – Fase e GUI

Índice

Projetos Futuros

Criador do Jogos Indie, amante de jogos, terror, música, anime e programação. Estudante de mestrado com foco em jogos na educação. Louco por Resident Evil e... sei lá, acho que é isso O.o

25 comments

  1. Lucas disse:

    Muito Obrigado!
    Seus tutoriais sempre foram muito bons!
    Há algum tempo eu nem sabia fazer o jogador andar nem como usar o Debug.Log .Hoje completo meu jogo, e tem algumas diferenças do seu.

    • É justamente isso que eu falei, a maioria de vocês começaram do zero sem saber nada e hoje já sabem iniciar um jogo.

      Muitos de vocês me mandaram seus projetos com dúvidas para eu ver como solucionava coisa X ou Y, e neles eu pude ver o potêncial d e vocês.

      Os jogos possuíam uma outra coisa diferente, ou até bem diferentes. Vocês podem até achar o jogos de vocês meio fraca, mas eu digo que já é um grande avanço, para quem não sabia fazer nada. Agora o que vocês precisam mais é determinação, pois o básico vocês já sabem.

      Fico muito feliz por vocês ^^

      • Lucas disse:

        Até o da vida fiz exatamente igual ao seu,ai foi quando seus tutoriais tinham parado(até chegar a próxima semana).
        Mas ai comecei tudo do zero, com outro personagem , animações, inimigos, objetos.Deu mais trabalho pois tive que fazer todos os sprites, animações, e algumas modificações em alguns scripts, mas ficou legal e só tenho a agradecer.

        Espero o próximo tutorial(espero que o vencedor da votação seja o Unity 2D Intermediário) .

  2. Antonio disse:

    Carlos, estou tentando fazer um “Save point” usando a bandeira que você disponibilizou.

    Mas estou com um problema, como usar o OnTriggerExit2D;

    Neste momento o meu script esta assim:

    public class bandeira : MonoBehaviour {

    private bool podeSalvar;

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }

    void OnTriggerEnter2D(Collider2D colisor) {
    if (colisor.gameObject.tag == “Player”) {

    podeSalvar = true;
    }

    }

    Obrigado Carlos!

    • E aê Antônio o/

      Então, você só esqueceu de dizer qual é o problema =P

      Mas vou imaginar que é pra fazer o save point. Bom o OnTriggerEnter2D está beleza, agora tem que fazer o OnTriggerExit2D:

      void OnTriggerExit2D(Collider2D colisor) {
      if (colisor.gameObject.tag == “Player”) {
      podeSalvar = false;
      }
      }

      e no update pode colocar que se tiver on e a pessoa apertar o botão E (Qualquer botão que você quiser), ele salva

      void Update() {
      if (podeSalvar && Input.GetKeyDown(“e”)) {
      PlayerPrefs.SetInt(“faseAtual”, Application.loadedLevel);
      Debug.Log(“Fase salva”);
      }
      }

  3. Faça um mini tutorial de inventario por favor.

  4. Boa Carlos.

    Tudo de boa,estou implementando algumas coisas no jogo com base no conhecimentos que você passou, o menu principal já conseguir fazer pela Unity 4.6. Também implementei um coletor de moedas e vou colocar mais dois coletores .

    Minha duvida que to quebrando a cabeça, quero que para passar de fase ele tenha que ter recolhido todas as moedas , fragmentos e filetes .

    Outra coisa que quero implementar é um sistema de mensagem que aparece no canto da tela dizendo , “você coletou 1 moeda ” e por ai vai.

    Se puder me ajudar , agradeço

    Abraços

    • O sistema de Mensagem pode ser apenas um guiText. Onde terá alguns parametros. Primeiro ele verifica se tem algum texto escrito. Se tiver ele inicia uma contagem (Igual fizemos com os ataques) para limpar o campo. Se tiver dificuldade é só falar que eu implemento isso ai.

      Agora quanto a pontuação existe inúmeras formas de fazer. Uma é baseado nesse tutorial ai de save e load. Ou seja toda vez que você ganhar pontos você salva usando um script Score e toda vez que mudar de fase (dentro do método Start) você recupera esse valor.

      Outra forma de fazer isso é usando o método DontDestroyOnLoad, desta forma ao passar de fase o seu Score irá continuar lá mesmo sem você precisar adiciona-lo novamente a scene:

      using UnityEngine;
      using System.Collections;

      public class Score : MonoBehaviour {

      public int pontuacao;

      // Use this for initialization
      void Start () {
      pontuacao = 0;
      }

      void Awake () {
      DontDestroyOnLoad(transform.gameObject);
      }

      // Update is called once per frame
      void Update () {
      transform.guiText.text = “Score: ” + pontuacao;
      }

      public void AdicionarPontos(int pontos) {
      pontuacao += pontos;
      }
      }

      Existe outras formas ainda de fazer, porém ainda considero essas duas as mais fáceis. Se quiser explico outros modos ^^

  5. Blz ja me ajudou muito, tomara que os proximos tutos sejam 2d intermediario continuando esse projeto
    vou fazer os testes aqui e depois posto os resultados

    abs

  6. Carlos, gostei muito do seu modo de ensinar, está de parabéns!
    Vejo que algumas pessoas como eu, também gostariam de implementar as pontuações, e se você fizesse mais um tópico mostrando isso?
    Tipo diferentes valores de pontuação, tipo: matou um inimigo tem x pontos, coletou um item recebe Y pontos, acumulo de pontos de cena para cena, se morrer perde z pontos etc.
    Acho que assim ficar muito bom.

    Aprendi muita coisa com seus tutorias, vou aplica-lo lá no FootBox também, corrigir muita que fiz de errado.

    Obrigado

    • Opa valeu Marcos, provavelmente terá isso no novo tutorial ^^

      • Ah, vou explorar um pouco mais, lá no owpoga.com, como você deve ter visto eu faço um ranking com os pontos dos jogos, assim como também carrego outras informações, tipo tempo decorrido, nível alcançado etc São valores interessantes para salvar não acha? Fiz o seu tutorial completo, agora quero adaptá-lo para colocar no site e fazer parte do rank, acredito que ficará muito bom. Qual versão do Unity está usando, parece que existem algumas diferenças com o meu (4.5)

  7. Alvaro disse:

    Eae Carlos tudo bem. Fiz seu tutorial só falta esta ultima parte e gravei um video do jogo.Porém tentei tentei fazer um efeito quando a bola de fogo batia no personagem, mas aconteceu um bug que aparece na segunda fase do jogo ao pular no cogumelo, mas já o corrigi.Sitei vc nos creditos em agradecimento. Segue o link:

    https://www.youtube.com/watch?v=ZDA9uNMpFBQ

    Caso vc não goste da ideia. É só dizer tiro ele do ar.

  8. Kulyk disse:

    Carlos parabéns pelo tutorial! muito bem explicado, de fácil entendimento!
    Muito obrigado!

  9. LouiZ disse:

    Tem como exportar o jogo depois de criado para mobile??

  10. carloswgama disse:

    tem sim Louiz.

    Vá em File >> Build Settings e na parte de Plataform você escolhe Android ou IOS.

    Agora esse jogo provavelmente não vai funcionar, pois precisaríamos criar botões para esquerda/direita/pular e atacar ao invés de usar os botões do teclado.

  11. Carlos, valeu mesmo pelo tutorial, foi o melhor que achei e que explica de forma simples e direta tudo que precisamos!

  12. carloswgama disse:

    Valeu cara, uma pena é que foi terminando esse tutorial e o Unity mudando de versão

    E valeu pelo apoio tirando a dúvida da galera ^^

  13. Muito bom parabéns 😉

  14. Renato Ramos disse:

    Oi! Muito Bom esse tutorial, você poderia liberar o projeto no git?

  15. Olá Carlos.
    Gostaria de agradecer pelo seu ótimo tutorial, não sabia nada sobre programação em unity, já havia testado fazer uns 3 tipos de tutorial mas nos scripts sempre dava erro. Aqui quase tudo funcionou perfeitamente, isso foi muito bom pra mim e eu realmente acredito que graças a suas aulas eu vou conseguir fazer algum tipo de jogo maneiro. Vou continuar a buscar tutoriais, sei que tem alguns mais avançado aqui no site mesmo, já vou começar a segui-los após criar mais fazes para o meu jogo e desenvolve-lo um pouco mais.
    Eu ainda não entendo muito de programação, mas é como se eu tivesse acesso ao mar de informação e assim que eu quiser me aprofundar em algum assunto eu só preciso voltar aqui. Obrigado de novo por criar isso e nos ajudar com nossos problemas.

Deixe uma resposta

Parceiros

Steam Brasil LoboLimão Centro RPG Lab Indie
Mundo Gamer PodTerror

Anunciantes

Aglomerando - Agregador de conteúdo
Uêba - Os Melhores Links GeraLinks - Agregador de links Piadas Idiotas - São idiotas mas o faz rir Tedioso: Os melhores links LinkLog MeusLinks.com - Informação e conteúdo todos os dias para você! Agregador de Links - Madruga Links 4Blogs - Agregador de conteúdo Está no seu momento de descanso né? Entao clique aqui!