Aplicacions amb Flutter, Dart i Flame

Tutorial Flutter Flame Projectes   Recursos CITCEA
Exemples Dart Dades pràctiques     Inici

Aplicació completa per a dos jugadors

Per completar l'aplicació per a dos jugadors, ens caldria alguna forma per tornar a començar un cop s'acaba la partida. Afegirem una filera sobre del text, on posarem un botó que permeti tornar a començar.

Definirem un botó genèric, que podrem personalitzar; així més endavant podrem afegir, si cal, algun botó més. El fitxer del botó anirà a la carpeta components. El botó tindrà tres paràmetres: el text que es mostra, un que controla si està en ús i la funció que s'executa quan es prem. El botó tindrà colors diferents segons si està en ús o no.

boto.dart
import 'package:flutter/material.dart';
import 'package:tres_linia/core/colors.dart';
import 'package:tres_linia/core/estils.dart';
class Boto extends StatefulWidget {
  final String textBoto;
  final bool enUs;
  final Function accio;
  const Boto({super.key, required this.textBoto, 
    required this.enUs, required this.accio});

  @override
  State<Boto> createState() => _BotoState();
}

class _BotoState extends State<Boto> {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        setState(() {
          widget.accio();
        });
      },
      child: Container(
        alignment: Alignment.center,
        decoration: BoxDecoration(
          color: widget.enUs ? ColorsApp.botoEnUs : ColorsApp.botoBlocat,
          borderRadius: BorderRadius.circular(12),
        ),
        child: Padding(
          padding: const EdgeInsets.all(10.0),
          child: Text(widget.textBoto, style: Estils.estilTextBotons),
        ),
      ),
    );
  }
}

Hem d'afegir els estils i colors que fem servir en el botó.

colors.dart
import 'dart:ui';
class ColorsApp {
  static const Color fons = Color(0xFF000000);
  static const Color primari = Color(0xFF444444);
  static const Color text = Color(0xFFFFFFFF);
  static const Color component = Color(0xFF531C00);
  static const Color botoEnUs = Color(0xFF008000);
  static const Color botoBlocat = Color(0xFF808080);
  static const List<Color> colsFitxes = [
    Color(0x00FFFFFF),  // transparent
    Color(0xFF00FFFF),  // cian
    Color(0xFFFFFF00),  // groc
  ];
}

estils.dart
import 'package:flutter/material.dart';
import 'package:tres_linia/core/colors.dart';
class Estils {
  static const TextStyle estilTextInfo = TextStyle(
    color: ColorsApp.text,
    fontSize: 30,
    fontWeight: FontWeight.bold,
  );
  static const TextStyle estilTextBotons = TextStyle(
    color: ColorsApp.text,
    fontSize: 20,
    fontWeight: FontWeight.bold,
  );
}

A la pantalla principal hi afegim la filera amb el botó.

pant_principal.dart
import 'package:flutter/material.dart';
import 'package:tres_linia/components/boto.dart';
import 'package:tres_linia/components/casella.dart';
import 'package:tres_linia/components/fitxa.dart';
import 'package:tres_linia/core/estils.dart';
class PantPral extends StatefulWidget {
  const PantPral({super.key});

  @override
  State<PantPral> createState() => _PantPralState();
}

class _PantPralState extends State<PantPral> {
  List<List<int>> estatCaselles = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
  int jugadorActual = 1;  // Comença el jugador 1
  int quiGuanya = 0;  // De moment, no hi ha guanyador
  String notificacio = "Tira:";
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        SizedBox(
          height: 20,
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Boto(textBoto: "Iniciar", enUs: quiGuanya > 0, accio: () {
              setState(() {
                if(quiGuanya > 0){
                  estatCaselles = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
                  jugadorActual = 1;  // Comença el jugador 1
                  quiGuanya = 0;  // De moment, no hi ha guanyador
                  notificacio = "Tira:";
                }
              });
            },)
          ],
        ),
        SizedBox(
          height: 20,
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Text(
              notificacio,
              style: Estils.estilTextInfo
            ),
            SizedBox(
              width: 20,
            ),
            Fitxa(estatAct: jugadorActual, mida: 25)
          ],
        ),
        for(int i = 0; i < 3; i++) filera(i),
        Expanded(child: Text(" "))
      ],
    );
  }

  Row filera(int pY) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      crossAxisAlignment: CrossAxisAlignment.end,
      children: [
        for(int i = 0; i < 3; i++) Casella(posX: i, posY: pY, estAct: estatCaselles[pY][i],
          posaFitxa: () {
            setState(() {
              // L'acció de picar la casella només es fa si la partida està en curs
              if(quiGuanya == 0){
                if(estatCaselles[pY][i] == 0) {
                  estatCaselles[pY][i] = jugadorActual;
                  if(jugadorActual == 1) {
                      jugadorActual = 2;
                  } else {
                    jugadorActual = 1;
                  }
                }
                // Després de cada tirada, mirem si hi ha guanyador
                quiGuanya = guanyador();
              }
            });
          },
        ),
      ],
    );
  }

  int comptaCaselles(int val){
    // Compta les caselles que tenen un determinat valor
    int total = 0;
    for(int i = 0; i < 3; i++){
      for(int j = 0; j < 3; j++){
        if(estatCaselles[i][j] == val){
          total++;
        }
      }
    }
    return total;
  }

  int guanyador(){
    int guanya = 0;
    // Atès que només s'afegeix una fitxa cada cop, només hi pot haver un guanyador
    // Primer mirem les diagonals
    if((estatCaselles[0][0] != 0) && (estatCaselles[0][0] == estatCaselles[1][1]) 
      && (estatCaselles[0][0] == estatCaselles[2][2])){
      guanya = estatCaselles[0][0];
    }
    if((estatCaselles[0][2] != 0) && (estatCaselles[0][2] == estatCaselles[1][1]) 
      && (estatCaselles[0][2] == estatCaselles[2][0])){
      guanya = estatCaselles[0][2];
    }
    // Mirem fileres i columnes
    for(int i = 0; i < 3; i++){
      if((estatCaselles[i][0] != 0) && (estatCaselles[i][0] == estatCaselles[i][1]) 
        && (estatCaselles[i][0] == estatCaselles[i][2])){
        guanya = estatCaselles[i][0];
      }
    }
    for(int i = 0; i < 3; i++){
      if((estatCaselles[0][i] != 0) && (estatCaselles[0][i] == estatCaselles[1][i]) 
        && (estatCaselles[0][i] == estatCaselles[2][i])){
        guanya = estatCaselles[0][i];
      }
    }
    // Si no hi ha guanyador, mirem si el taulell ja és ple
    // Si ho és, hi ha empat
    if((guanya == 0) && (comptaCaselles(0) == 0)){
      guanya = 3;
    }
    // S'acaba la partida si hi ha guanyador o no hi ha caselles
    // Es posa com a jugador al guanyador, per mostrar-lo
    // En cas d'empat, es deixa buit
    if(guanya > 0){
      if(guanya == 3){
        notificacio = "Empat!";
        jugadorActual = 0;
      } else {
        notificacio = "Guanya:";
        jugadorActual = guanya;
      }
    }
    return guanya;
  }
}

 

 

 

 

 

 

 

 

 

 

Llicència de Creative Commons
Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.