diff --git a/android/gradle.properties b/android/gradle.properties index db7a1ee2908d6e94aeb319e1c1b548a8bb245891..14eed3944b547f02179b1b42f4b601f91b7957c0 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true android.enableJetifier=true -app.versionName=0.0.3 -app.versionCode=3 +app.versionName=0.0.4 +app.versionCode=4 diff --git a/fastlane/metadata/android/en-US/changelogs/4.txt b/fastlane/metadata/android/en-US/changelogs/4.txt new file mode 100644 index 0000000000000000000000000000000000000000..eb726b1f48dfe469dc907c23ecee30457f9565bd --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/4.txt @@ -0,0 +1 @@ +Count points on each player turn diff --git a/fastlane/metadata/android/fr-FR/changelogs/4.txt b/fastlane/metadata/android/fr-FR/changelogs/4.txt new file mode 100644 index 0000000000000000000000000000000000000000..cdcce1cd77c6a052cf396321601ad36042fd8307 --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/4.txt @@ -0,0 +1 @@ +Compte les points à chaque tour de jeu diff --git a/lib/entity/counter.dart b/lib/entity/counter.dart new file mode 100644 index 0000000000000000000000000000000000000000..e1be46dc747ed51a38a2be0578e925080c77bd83 --- /dev/null +++ b/lib/entity/counter.dart @@ -0,0 +1,184 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:tetrisdual/provider/data.dart'; + +class Counter { + // Current counter + bool _match = false; // Does this new tetrimino touch an other tetrimino of same player + int _lines = 0; // Count lines fully filled by this new tetrimino + int _holes = 0; // Count hole non fillable caused by this new tetrimino + + // Points definitions + int _base = 50; + int _pointsIfMatch = 50; + int _pointsPerLine = 60; + int _pointsPerHole = -10; + + Color categoryIconColor = Colors.green; + Color buttonIconColor = Colors.blue; + double iconSize = 30.0; + double textSize = 25.0; + + Widget buildCounterWidget(Data myProvider) { + return Container( + child: Table( + children: [ + buildMatchWidget(myProvider), + buildLinesWidget(myProvider), + buildHolesWidget(myProvider), + ], + ), + ); + } + + TableRow buildMatchWidget(Data myProvider) { + return TableRow( + children: [ + Icon( + Icons.join_full, + color: categoryIconColor, + size: iconSize, + ), + IconButton( + padding: EdgeInsets.zero, + constraints: BoxConstraints(), + icon: Icon( + Icons.remove, + color: buttonIconColor, + size: iconSize, + ), + onPressed: () { + _match = false; + myProvider.redraw(); + }, + ), + Center( + child: Icon( + _match ? Icons.radio_button_checked : Icons.radio_button_unchecked, + color: categoryIconColor, + size: iconSize, + ), + ), + IconButton( + padding: EdgeInsets.zero, + constraints: BoxConstraints(), + icon: Icon( + Icons.add, + color: buttonIconColor, + size: iconSize, + ), + onPressed: () { + _match = true; + myProvider.redraw(); + }, + ), + ], + ); + } + + TableRow buildLinesWidget(Data myProvider) { + return TableRow( + children: [ + Icon( + Icons.table_rows, + color: categoryIconColor, + size: iconSize, + ), + IconButton( + padding: EdgeInsets.zero, + constraints: BoxConstraints(), + icon: Icon( + Icons.remove, + color: buttonIconColor, + size: iconSize, + ), + onPressed: () { + _lines = max(_lines - 1, 0); + myProvider.redraw(); + }, + ), + Center( + child: Text( + _lines.toString(), + style: TextStyle( + fontSize: textSize, + ), + ), + ), + IconButton( + padding: EdgeInsets.zero, + constraints: BoxConstraints(), + icon: Icon( + Icons.add, + color: buttonIconColor, + size: iconSize, + ), + onPressed: () { + _lines = min(_lines + 1, 4); + myProvider.redraw(); + }, + ), + ], + ); + } + + TableRow buildHolesWidget(Data myProvider) { + return TableRow( + children: [ + Icon( + Icons.check_box_outline_blank, + color: categoryIconColor, + size: iconSize, + ), + IconButton( + padding: EdgeInsets.zero, + constraints: BoxConstraints(), + icon: Icon( + Icons.remove, + color: buttonIconColor, + size: iconSize, + ), + onPressed: () { + _holes = max(_holes - 1, 0); + myProvider.redraw(); + }, + ), + Center( + child: Text( + _holes.toString(), + style: TextStyle( + fontSize: textSize, + ), + ), + ), + IconButton( + padding: EdgeInsets.zero, + constraints: BoxConstraints(), + icon: Icon( + Icons.add, + color: buttonIconColor, + size: iconSize, + ), + onPressed: () { + _holes = min(_holes + 1, 4); + myProvider.redraw(); + }, + ), + ], + ); + } + + int computePoints() { + return _base + + (_match ? _pointsIfMatch : 0) + + _lines * _pointsPerLine + + _holes * _pointsPerHole; + } + + void reset() { + _match = false; + _lines = 0; + _holes = 0; + } +} diff --git a/lib/entity/player.dart b/lib/entity/player.dart index 227ab9f9b1b9a10afae27aef719fbb22f499699a..addfc90e3118a1e51760e2df987f3a10f605d1a6 100644 --- a/lib/entity/player.dart +++ b/lib/entity/player.dart @@ -1,11 +1,17 @@ import 'dart:math'; -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:tetrisdual/entity/counter.dart'; import 'package:tetrisdual/layout/board_painter.dart'; import 'package:tetrisdual/provider/data.dart'; class Player { + Player(this.playerId); + int playerId; + + int _score = 0; int _currentTetrimino = 0; + Counter _counter = new Counter(); Widget buildTetriminoWidget(Data myProvider, double width) { return Container( @@ -27,24 +33,79 @@ class Player { ); } - Widget buildManagerWidget() { - return Container( - margin: EdgeInsets.all(5), - child: Column( - children: [ - Text(''), - ], + Widget buildManagerWidget(Data myProvider) { + List<Widget> items = [ + Text( + _score.toString(), + style: TextStyle( + fontSize: 40, + fontWeight: FontWeight.bold, + ), ), + ]; + + if (myProvider.currentPlayer == playerId) { + items.add(_counter.buildCounterWidget(myProvider)); + items.add(buildSubmitWidget(myProvider)); + } + + return Expanded( + child: Container( + margin: EdgeInsets.all(5), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: items, + ), + ), + ); + } + + Widget buildSubmitWidget(Data myProvider) { + return Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + '+' + _counter.computePoints().toString(), + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + width: 10, + ), + IconButton( + padding: EdgeInsets.zero, + constraints: BoxConstraints(), + icon: Icon( + Icons.done_all, + color: Colors.amber, + size: 25, + ), + onPressed: () { + _score = _score + _counter.computePoints(); + _counter.reset(); + myProvider.toggleCurrentPlayer(); + }, + ), + SizedBox( + width: 10, + ), + ], ); } - Widget buildPlayerBoard(Data myProvider, double boardWidth) { - double tetriminoBlockWidth = boardWidth / 2; + Widget buildPlayerBoard(Data myProvider, double screenWidth) { + double tetriminoBlockWidth = screenWidth / 2; return Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, children: [ buildTetriminoWidget(myProvider, tetriminoBlockWidth), - buildManagerWidget(), + buildManagerWidget(myProvider), ], ); } @@ -62,4 +123,9 @@ class Player { void resetTetrimino() { _currentTetrimino = 0; } + + void submitPoints() { + _score = _score + _counter.computePoints(); + _counter.reset(); + } } diff --git a/lib/layout/board.dart b/lib/layout/board.dart index 06686669b7dd5a6467703196b6c54307ac664282..8ee110186d129102c3ac6c334bf0c985fc46695b 100644 --- a/lib/layout/board.dart +++ b/lib/layout/board.dart @@ -16,17 +16,16 @@ class Board { ); } - static Container buildGameBoard(Data myProvider, double boardWidth) { + static Container buildGameBoard(Data myProvider, double screenWidth) { Widget player1 = new RotatedBox( quarterTurns: 2, - child: myProvider.getPlayer(1).buildPlayerBoard(myProvider, boardWidth), + child: myProvider.getPlayer(1).buildPlayerBoard(myProvider, screenWidth), ); - Widget player2 = myProvider.getPlayer(2).buildPlayerBoard(myProvider, boardWidth); + Widget player2 = myProvider.getPlayer(2).buildPlayerBoard(myProvider, screenWidth); Widget togglePlayerWidget = GestureDetector( onTapUp: (details) { myProvider.toggleCurrentPlayer(); - myProvider.getPlayer(myProvider.currentPlayer).pickRandomTetrimino(); }, child: Text( '🔄', diff --git a/lib/layout/game.dart b/lib/layout/game.dart index a12eddeb986da596402a86d4988e38a3e260a562..4d44d2dcde0bbafe9763eca9673c285d22538b1c 100644 --- a/lib/layout/game.dart +++ b/lib/layout/game.dart @@ -4,10 +4,10 @@ import 'package:tetrisdual/provider/data.dart'; import 'package:tetrisdual/utils/game_utils.dart'; class Game { - static Container buildGameWidget(Data myProvider, double boardWidth) { + static Container buildGameWidget(Data myProvider, double screenWidth) { return Container( child: !myProvider.isGameFinished - ? Board.buildGameBoard(myProvider, boardWidth) + ? Board.buildGameBoard(myProvider, screenWidth) : Game.buildEndGameMessage(myProvider), ); } diff --git a/lib/provider/data.dart b/lib/provider/data.dart index 63c76e329b5ff22c9fe7255a0017e447e2abc428..061baf17929c050ac48f182ec5c8041889cef5b2 100644 --- a/lib/provider/data.dart +++ b/lib/provider/data.dart @@ -62,11 +62,16 @@ class Data extends ChangeNotifier { // 1 -> 2 ; 2 -> 1 _currentPlayer = 3 - _currentPlayer; } + + // Pick new tetrimino + getCurrentPlayer().pickRandomTetrimino(); + notifyListeners(); } void enableRandomPlayer() { _currentPlayer = Random().nextInt(2) + 1; + toggleCurrentPlayer(); } Player getPlayer(int playerId) { @@ -75,7 +80,7 @@ class Data extends ChangeNotifier { // Create new player if none if (null == player) { - player = new Player(); + player = new Player(playerId); _players[playerIndex] = player; } @@ -93,7 +98,7 @@ class Data extends ChangeNotifier { void resetGame() { _gameIsRunning = false; _gameIsFinished = false; - _players = [new Player(), new Player()]; + _players = [new Player(1), new Player(2)]; notifyListeners(); } } diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 952fb7ca99c5cc0a9e2458dca70b9c561030f4ad..5b8ee82f10c9b18fdcaf0aaccb32a9b69e3b44bd 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -22,7 +22,7 @@ class _HomeState extends State<Home> { @override Widget build(BuildContext context) { Data myProvider = Provider.of<Data>(context); - double boardWidth = MediaQuery.of(context).size.width; + double screenWidth = MediaQuery.of(context).size.width; List<Widget> menuActions = []; @@ -54,7 +54,7 @@ class _HomeState extends State<Home> { ), body: SafeArea( child: myProvider.isGameRunning - ? Game.buildGameWidget(myProvider, boardWidth) + ? Game.buildGameWidget(myProvider, screenWidth) : Parameters.buildParametersSelector(myProvider), ), );