🏗️ Cap 12: Arquitetura de Jogo (MVVM)

🎯 Objetivo da Aula: Ao final desta aula, você entenderá o padrão MVVM (Model-View-ViewModel). Você aprenderá a separar o “Cérebro” do seu jogo (a lógica de pontos e vida) do “Corpo” (a interface visual), usando as pastas padrão do curso.


🏢 O Cenário Prático (Seu Desafio): Até agora, você colocou toda a lógica (contas, variáveis) dentro da mesma função da tela. Isso funciona para apps pequenos, mas em um jogo grande vira uma bagunça impossível de consertar! Seu desafio é criar o Motor do Jogo (ViewModel): um local separado onde a vida do personagem é calculada, deixando a tela apenas com a função de mostrar o desenho.


🧠 Fundamentos: A Teoria Traduzida

📖 Dicionário do Programador

🎨 O Mapa das Pastas (Revisão)

Crie estas pastas no seu projeto br.com.curso.pokedex (o mesmo AppPokedexMestre_SeuNome desde o Cap 07):

  1. ui/screens/ -> Coloque suas funções @Composable aqui.
  2. ui/viewmodel/ -> Coloque suas classes ViewModel aqui.
graph TD
    A["View: Tela do Game"] <-->|Observa o Estado| B["ViewModel: Garçom da Lógica"]
    B <-->|Gerencia| C["Model: Dados do Personagem"]

📦 Dependência Gradle

Para usar viewModel() dentro de uma função @Composable, adicione no build.gradle (Module: app), dentro de dependencies { }:

implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0'

📦 Imports Necessários

Antes de copiar os códigos abaixo, adicione estes imports no topo do seu arquivo .kt:

import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewmodel.compose.viewModel

📖 Exemplo Passo a Passo: O Garçom de Pontos

  1. Crie o arquivo JogoViewModel.kt na pasta ui/viewmodel.
  2. Use o prefixo _ para o estado privado (ninguém de fora mexe) e uma variável pública para a tela ler.
package br.com.curso.pokedex.ui.viewmodel

import androidx.lifecycle.ViewModel
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.State

class JogoViewModel : ViewModel() {
    // 1. O dado secreto (Só o Garçom mexe)
    private val _pontos = mutableStateOf(0)
    
    // 2. O dado que a tela pode ver
    val pontos: State<Int> = _pontos

    // 3. A ação que muda o dado
    fun ganharPonto() {
        _pontos.value += 10
    }
}

🛠️ Prática Obrigatória 1: Crie uma classe PersonagemViewModel. Ela deve ter um estado privado para vida (começando em 100) e uma função receberDano(). A função deve tirar 10 de vida, mas nunca deixar ficar menor que 0.


🛠️ Prática Obrigatória 2: Crie a tela @Composable chamada ArenaScreen na pasta ui/screens. Ela deve usar o seu PersonagemViewModel para mostrar a vida atual e ter um botão “Receber Golpe”.


🔑 Gabarito Passo a Passo:

ViewModel:

class PersonagemViewModel : ViewModel() {
    private var _vida = mutableStateOf(100)
    val vida: State<Int> = _vida

    fun receberDano() {
        if (_vida.value > 0) _vida.value -= 10
    }
}

Screen:

@Composable
fun ArenaScreen(vm: PersonagemViewModel = viewModel()) {
    Column {
        Text("Vida: ${vm.vida.value}")
        Button(onClick = { vm.receberDano() }) { Text("Receber Golpe") }
    }
}

📤 Instruções de Entrega (Microsoft Teams):

  1. Envie o código do seu ViewModel e da sua Screen.
  2. Submeta no canal de tarefas.

⬅️ Voltar para a Home