Skip to content
Snippets Groups Projects
Commit c5bc3578 authored by Benoît Harrault's avatar Benoît Harrault
Browse files

Create minimal playable game

parent 5e18aa02
No related branches found
No related tags found
1 merge request!2Resolve "Create minimal playable game"
Pipeline #4802 passed
Showing
with 316 additions and 8 deletions
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
app.versionName=0.0.11 app.versionName=0.0.12
app.versionCode=11 app.versionCode=12
{ {
"app_name": "Twister", "app_name": "Twister",
"left_hand": "left hand",
"right_hand": "right hand",
"left_foot": "left foot",
"right_foot": "right foot",
"bottom_nav_game": "Game", "bottom_nav_game": "Game",
"bottom_nav_settings": "Settings", "bottom_nav_settings": "Settings",
......
{ {
"app_name": "Twister", "app_name": "Twister",
"left_hand": "main gauche",
"right_hand": "main droite",
"left_foot": "pied gauche",
"right_foot": "pied droit",
"bottom_nav_game": "Jeu", "bottom_nav_game": "Jeu",
"bottom_nav_settings": "Réglages", "bottom_nav_settings": "Réglages",
......
Add minimal playable game.
Création du jeu minimal mais jouable.
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:twister/models/move.dart';
part 'game_state.dart';
class GameCubit extends HydratedCubit<GameState> {
GameCubit() : super(const GameState());
Move getMove() {
return state.move ?? Move.createNull();
}
void setValues({
Move? move,
}) {
emit(GameState(
move: move ?? state.move,
));
}
@override
GameState? fromJson(Map<String, dynamic> json) {
Move move = json['move'] as Move;
return GameState(
move: move,
);
}
@override
Map<String, dynamic>? toJson(GameState state) {
return <String, dynamic>{
'move': state.move?.toJson(),
};
}
}
part of 'game_cubit.dart';
@immutable
class GameState extends Equatable {
const GameState({
this.move,
});
final Move? move;
@override
List<dynamic> get props => <dynamic>[
move,
];
Map<String, dynamic> get values => <String, dynamic>{
'move': move,
};
}
...@@ -14,6 +14,6 @@ class SettingsState extends Equatable { ...@@ -14,6 +14,6 @@ class SettingsState extends Equatable {
]; ];
Map<String, dynamic> get values => <String, dynamic>{ Map<String, dynamic> get values => <String, dynamic>{
'discoveriesDaysCount': timerValue, 'timerValue': timerValue,
}; };
} }
...@@ -9,6 +9,7 @@ import 'package:path_provider/path_provider.dart'; ...@@ -9,6 +9,7 @@ import 'package:path_provider/path_provider.dart';
import 'package:twister/config/theme.dart'; import 'package:twister/config/theme.dart';
import 'package:twister/cubit/bottom_nav_cubit.dart'; import 'package:twister/cubit/bottom_nav_cubit.dart';
import 'package:twister/cubit/game_cubit.dart';
import 'package:twister/cubit/settings_cubit.dart'; import 'package:twister/cubit/settings_cubit.dart';
import 'package:twister/ui/skeleton.dart'; import 'package:twister/ui/skeleton.dart';
...@@ -44,6 +45,7 @@ class MyApp extends StatelessWidget { ...@@ -44,6 +45,7 @@ class MyApp extends StatelessWidget {
return MultiBlocProvider( return MultiBlocProvider(
providers: [ providers: [
BlocProvider<BottomNavCubit>(create: (context) => BottomNavCubit()), BlocProvider<BottomNavCubit>(create: (context) => BottomNavCubit()),
BlocProvider<GameCubit>(create: (context) => GameCubit()),
BlocProvider<SettingsCubit>(create: (context) => SettingsCubit()), BlocProvider<SettingsCubit>(create: (context) => SettingsCubit()),
], ],
child: MaterialApp( child: MaterialApp(
......
import 'package:twister/models/twister_color.dart';
import 'package:twister/models/twister_member.dart';
class Move {
final TwisterColor? color;
final TwisterMember? member;
Move({
required this.color,
required this.member,
});
factory Move.createNull() {
return Move(
color: null,
member: null,
);
}
factory Move.pickRandom() {
return Move(
color: TwisterColor.pickRandom(),
member: TwisterMember.pickRandom(),
);
}
String toString() {
return 'Move(' + this.toJson().toString() + ')';
}
Map<String, dynamic>? toJson() {
return <String, dynamic>{
'color': this.color.toString(),
'member': this.member.toString(),
};
}
}
import 'dart:math';
enum TwisterAllowedColors {
blue,
green,
red,
yellow,
}
class TwisterColor {
final TwisterAllowedColors value;
TwisterColor({
required this.value,
});
factory TwisterColor.pickRandom() {
int random = Random().nextInt(TwisterAllowedColors.values.length);
return TwisterColor(value: TwisterAllowedColors.values[random]);
}
String toString() {
return this.value.toString();
}
}
import 'dart:math';
enum TwisterAllowedMembers {
leftHand,
rightHand,
leftFoot,
rightFoot,
}
class TwisterMember {
final TwisterAllowedMembers value;
TwisterMember({
required this.value,
});
factory TwisterMember.pickRandom() {
int random = Random().nextInt(TwisterAllowedMembers.values.length);
return TwisterMember(value: TwisterAllowedMembers.values[random]);
}
String toString() {
return this.value.toString();
}
}
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twister/ui/widgets/game.dart';
import 'package:unicons/unicons.dart'; import 'package:unicons/unicons.dart';
class ScreenHome extends StatelessWidget { class ScreenHome extends StatelessWidget {
...@@ -16,7 +17,7 @@ class ScreenHome extends StatelessWidget { ...@@ -16,7 +17,7 @@ class ScreenHome extends StatelessWidget {
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
children: <Widget>[ children: <Widget>[
const SizedBox(height: 8), const SizedBox(height: 8),
const Text('HOME'), const Game(),
const SizedBox(height: 36), const SizedBox(height: 36),
], ],
), ),
......
...@@ -18,7 +18,7 @@ class _SkeletonScreenState extends State<SkeletonScreen> { ...@@ -18,7 +18,7 @@ class _SkeletonScreenState extends State<SkeletonScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
List<Widget> pageNavigation = <Widget>[ List<Widget> pageNavigation = <Widget>[
const ScreenHome(), ScreenHome(),
const ScreenSettings(), const ScreenSettings(),
]; ];
...@@ -29,7 +29,8 @@ class _SkeletonScreenState extends State<SkeletonScreen> { ...@@ -29,7 +29,8 @@ class _SkeletonScreenState extends State<SkeletonScreen> {
builder: (BuildContext context, int state) { builder: (BuildContext context, int state) {
return AnimatedSwitcher( return AnimatedSwitcher(
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
child: pageNavigation.elementAt(state)); child: pageNavigation.elementAt(state),
);
}, },
), ),
backgroundColor: Theme.of(context).colorScheme.background, backgroundColor: Theme.of(context).colorScheme.background,
......
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:unicons/unicons.dart';
import 'package:twister/cubit/game_cubit.dart';
import 'package:twister/models/move.dart';
import 'package:twister/ui/widgets/show_move.dart';
class Game extends StatefulWidget {
const Game({super.key});
@override
State<Game> createState() => _GameState();
}
class _GameState extends State<Game> {
Move move = Move.createNull();
Widget pickNewMove() {
return BlocBuilder<GameCubit, GameState>(builder: (BuildContext context, GameState state) {
return TextButton(
onPressed: () {
BlocProvider.of<GameCubit>(context).setValues(
move: Move.pickRandom(),
);
},
child: Icon(UniconsSolid.refresh),
);
});
}
@override
Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>(
builder: (context, gameState) {
return Column(
children: [
ShowMove(move: gameState.move ?? Move.createNull()),
pickNewMove(),
],
);
},
);
}
}
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:twister/models/move.dart';
import 'package:twister/models/twister_color.dart';
import 'package:twister/models/twister_member.dart';
import 'package:twister/utils/color_extensions.dart';
class ShowMove extends StatelessWidget {
const ShowMove({super.key, required this.move});
final Move move;
Color getColor(Move move) {
switch (move.color?.value) {
case TwisterAllowedColors.blue:
return Colors.blue;
case TwisterAllowedColors.green:
return Colors.green;
case TwisterAllowedColors.red:
return Colors.red;
case TwisterAllowedColors.yellow:
return Colors.yellow;
default:
return Colors.grey;
}
}
Widget getWidget(Move move) {
TextStyle style = TextStyle(
color: Colors.black,
fontSize: 30,
fontWeight: FontWeight.bold,
);
switch (move.member?.value) {
case TwisterAllowedMembers.leftHand:
return Text(tr('left_hand'), style: style);
case TwisterAllowedMembers.rightHand:
return Text(tr('right_hand'), style: style);
case TwisterAllowedMembers.leftFoot:
return Text(tr('left_foot'), style: style);
case TwisterAllowedMembers.rightFoot:
return Text(tr('right_foot'), style: style);
default:
return Text('?', style: style);
}
}
@override
Widget build(BuildContext context) {
Color color = getColor(move);
return Container(
child: Padding(
padding: EdgeInsets.all(20),
child: getWidget(move),
),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.all(Radius.circular(50)),
border: Border.all(
color: color.darken(20),
width: 10,
),
),
);
}
}
import 'dart:ui';
extension ColorExtension on Color {
Color darken([int percent = 40]) {
assert(1 <= percent && percent <= 100);
final value = 1 - percent / 100;
return Color.fromARGB(
alpha,
(red * value).round(),
(green * value).round(),
(blue * value).round(),
);
}
Color lighten([int percent = 40]) {
assert(1 <= percent && percent <= 100);
final value = percent / 100;
return Color.fromARGB(
alpha,
(red + ((255 - red) * value)).round(),
(green + ((255 - green) * value)).round(),
(blue + ((255 - blue) * value)).round(),
);
}
Color avg(Color other) {
final red = (this.red + other.red) ~/ 2;
final green = (this.green + other.green) ~/ 2;
final blue = (this.blue + other.blue) ~/ 2;
final alpha = (this.alpha + other.alpha) ~/ 2;
return Color.fromARGB(alpha, red, green, blue);
}
}
...@@ -3,7 +3,7 @@ description: twister game companion ...@@ -3,7 +3,7 @@ description: twister game companion
publish_to: 'none' publish_to: 'none'
version: 0.0.11+11 version: 0.0.12+12
environment: environment:
sdk: '^3.0.0' sdk: '^3.0.0'
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment