トランプを表示してみよう
「ハートの2を探せゲーム」
※Scaffoldのbody引数に、Columnの代わりに「Wrap」を使用しています。これはRowと似ています(ウィジェットを横方向に並べます)が、画面の横幅の広さに応じてはみ出した場合にエラーとならず、次の段に移る特徴があります。
余力のある方は、RowとWrapを比較してみてください。
※Image.networkに新たな引数としてwidthを指定しています。widthは「横幅」を指定するもので、今回は各トランプカードの横幅を80に指定します。縦幅を指定するときは「height」を指定します。
・widthもheightも指定しない場合:元の画像の大きさがそのまま表示される
・横幅widthだけ指定した場合:縦幅は元の画像の縦横比を維持して、自動的に調整されます。
・縦幅heightだけ指定した場合:横幅は元の画像の縦横比を維持して、自動的に調整されます。
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
title: 'Flutter Demo',
//MaterialAppのhome引数にScaffoldウィジェットを指定する
home: Scaffold(
//Scaffoldの引数1、appBar(タイトル領域)
appBar: AppBar(title: Text("ハートの2を探せゲーム")),
//Scaffoldの引数2、body(本文領域)
body: Wrap(
children: [
GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_heart_01.png",
width: 80,
),
onTap: () {
print("ハートの1を押したよ!");
},
),
GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_heart_02.png",
width: 80,
),
onTap: () {
print("ハートの2を押したよ!");
print("正解!!!!");
},
),
GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_heart_03.png",
width: 80,
),
onTap: () {
print("ハートの3を押したよ!");
},
),
GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_spade_01.png",
width: 80,
),
onTap: () {
print("スペードの1を押したよ!");
},
),
GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_spade_02.png",
width: 80,
),
onTap: () {
print("スペードの2を押したよ!");
},
),
],
),
),
),
);
}
このプログラムにはいくつかの問題点があります。それは何でしょう?
〜シンキングタイム〜
GestureDetectorの部品化
トランプを13枚×4種類(スペード、クラブ、ハート、ダイヤ)=52枚を表示するために、GestureDetectorを52回コピー&ペーストするのは大変。。。
そこで、何度も似たような内容で登場するGestureDetectorのカタマリを部品化できないか?を検討します。
まずは、「それぞれのGestureDetectorで変わっている部分」を探します。
2つ目:URL内の2桁の連番がカードの数字を表している。1桁の場合は先頭に0がつく。
3つ目:onTapのprintの「〇〇の〜」の〇〇部分のマークがカードによって「ハート」、「スペード」など、異なる。
4つ目:onTapのprintの「○を押したよ!」の○にはカードの数字が入る。
5つ目:ハートの2の場合だけ、追加のprintが発生して「正解!!!!」と表示する。
これらを意識して、GestureDetectorを部品化します。
自分好みのカスタムWidgetを作る
GestureDetectorを自分好みのカスタムWidget化していきます。
void main(){ ~ }の外側に、以下のように記述します。
class 【新しく作るウィジェット名】 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return 【部品化するウィジェット】;
}
}
トランプカードを表す「PlayingCard」ウィジェットを作るためには、以下のように記述します。
//PlayingCardウィジェット
class PlayingCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
//繰り返し記述していたGestureDetectorウィジェットを部品化する
return GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_heart_01.png",
width: 80,
),
onTap: () {
print("ハートの1を押したよ!");
},
);
}
}
void main側からPlayingCardウィジェットを呼び出すためには、PlayingCard()と記述するだけです。
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
title: 'Flutter Demo',
//MaterialAppのhome引数にScaffoldウィジェットを指定する
home: Scaffold(
//Scaffoldの引数1、appBar(タイトル領域)
appBar: AppBar(title: Text("ハートの2を探せゲーム")),
//Scaffoldの引数2、body(本文領域)
body: Wrap(
children: [
PlayingCard(),
PlayingCard(),
PlayingCard(),
PlayingCard(),
PlayingCard(),
],
),
),
),
);
}
class PlayingCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_heart_01.png",
width: 80,
),
onTap: () {
print("ハートの1を押したよ!");
},
);
}
}
しかしこれでは問題があります。PlayingCard()ではハートの1しか作ることができません。他のカードも作れるようにしたいですね。
PlayingCardウィジェットであらゆるカードを作れるようにする
先ほどの図を思い出してみます。
変数とは?
よくプログラミングの入門書では、「変数とは、データを保管するための箱です」という表現をされますが、この場面でも変数という考え方が役立ちます。
まず、先ほどの赤い丸の部分を、「【変数X】」に書き換えてみます。(一旦ハートの2は置いておきます)
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
title: 'Flutter Demo',
//MaterialAppのhome引数にScaffoldウィジェットを指定する
home: Scaffold(
//Scaffoldの引数1、appBar(タイトル領域)
appBar: AppBar(title: Text("ハートの2を探せゲーム")),
//Scaffoldの引数2、body(本文領域)
body: Wrap(
children: [
PlayingCard(),
PlayingCard(),
PlayingCard(),
PlayingCard(),
PlayingCard(),
],
),
),
),
);
}
class PlayingCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_【変数1】_【変数2】.png",
width: 80,
),
onTap: () {
print("【変数3】の【変数4】を押したよ!");
},
);
}
}
これで、変数が4つ必要なことが分かりましたが、変数1は「heart」の英語表記で、変数3は「ハート」の日本語表記なので、変数3は変数1で代用することとします。
同様に、変数4は変数2で代用することとします。すると、以下のようになります。
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
title: 'Flutter Demo',
//MaterialAppのhome引数にScaffoldウィジェットを指定する
home: Scaffold(
//Scaffoldの引数1、appBar(タイトル領域)
appBar: AppBar(title: Text("ハートの2を探せゲーム")),
//Scaffoldの引数2、body(本文領域)
body: Wrap(
children: [
PlayingCard(),
PlayingCard(),
PlayingCard(),
PlayingCard(),
PlayingCard(),
],
),
),
),
);
}
class PlayingCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_【変数1】_【変数2】.png",
width: 80,
),
onTap: () {
print("【変数1】の【変数2】を押したよ!");
},
);
}
}
これで、必要な変数が2つに減りました。
次に、変数に名前をつけます。変数1がマークなので、英語で「mark」と名前を付けることにしましょう。同様に、変数2はカードの数字なので、英語で「number」と名前をつけることにしましょう。
これらは両方文字列中で使用されている「文字」なので、Dart言語では「String」という型(種類)の変数を使います。@overrideの前の行を開けて、「型名 変数名;」と変数の数だけ記述します。変数は好きなだけ作れます。
今回はすなわち、以下のようになります。
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
title: 'Flutter Demo',
//MaterialAppのhome引数にScaffoldウィジェットを指定する
home: Scaffold(
//Scaffoldの引数1、appBar(タイトル領域)
appBar: AppBar(title: Text("ハートの2を探せゲーム")),
//Scaffoldの引数2、body(本文領域)
body: Wrap(
children: [
PlayingCard(),
PlayingCard(),
PlayingCard(),
PlayingCard(),
PlayingCard(),
],
),
),
),
);
}
class PlayingCard extends StatelessWidget {
String mark; //変数mark(文字列String型)
String number; //変数number(文字列String型)
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_【変数1】_【変数2】.png",
width: 80,
),
onTap: () {
print("【変数1】の【変数2】を押したよ!");
},
);
}
}
Dart言語では、文字列中に変数を埋め込むためには「${変数名}」と書きます。すなわち、以下のようになります。
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
title: 'Flutter Demo',
//MaterialAppのhome引数にScaffoldウィジェットを指定する
home: Scaffold(
//Scaffoldの引数1、appBar(タイトル領域)
appBar: AppBar(title: Text("ハートの2を探せゲーム")),
//Scaffoldの引数2、body(本文領域)
body: Wrap(
children: [
PlayingCard(),
PlayingCard(),
PlayingCard(),
PlayingCard(),
PlayingCard(),
],
),
),
),
);
}
class PlayingCard extends StatelessWidget {
String mark; //変数mark(文字列String型)
String number; //変数number(文字列String型)
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_${mark}_${number}.png",
width: 80,
),
onTap: () {
print("${mark}の${number}を押したよ!");
},
);
}
}
コンストラクタとは
あと一歩で完成です!あとは、PlayingCardを生成する度にmarkとnumberを指定してもらう仕組みさえできれば解決です。そのためには、以下のように書きます。
ウィジェット名(this.引数名1, this.引数名2, ...);
また、呼び出し元(void main)に記載する時には、ウィジェット名(引数1, 引数2, ...)のように引数を指定します。
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
title: 'Flutter Demo',
//MaterialAppのhome引数にScaffoldウィジェットを指定する
home: Scaffold(
//Scaffoldの引数1、appBar(タイトル領域)
appBar: AppBar(title: Text("ハートの2を探せゲーム")),
//Scaffoldの引数2、body(本文領域)
body: Wrap(
children: [
//引数はコンストラクタに記載の順番、mark, numberの順に指定します
PlayingCard("heart", "01"),
PlayingCard("heart", "02"),
PlayingCard("heart", "03"),
PlayingCard("spade", "01"),
PlayingCard("spade", "02"),
],
),
),
),
);
}
class PlayingCard extends StatelessWidget {
String mark; //変数mark(文字列String型)
String number; //変数number(文字列String型)
//コンストラクタ
PlayingCard(this.mark, this.number);
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_${mark}_${number}.png",
width: 80,
),
onTap: () {
print("${mark}の${number}を押したよ!");
},
);
}
}
ハートの2を判定しよう
残るは、ハートの2の判定です。要は、markが"heart"でかつ、numberが"02"の時に「正解!!!!」と表示させたいわけですね。
聞いたことがある方もいるかもしれませんが、「〇〇の場合は××する」ということを条件分岐と呼び、if文という文法で記載します。
if文の使い方
if(条件式){
【条件式が真(true)の場合の処理(何行書いてもよい)】
}
今回は複合条件として、「markが"heart"でかつ、numberが"02"」であるかを調べます。
あるデータとあるデータが一致するかどうかを調べるには、「==」という記号を使用します。
また、ある条件とある条件が両方とも成立するかどうかを調べるには、「&&」という記号を使用します。
すなわち、以下のように書きます。
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
title: 'Flutter Demo',
//MaterialAppのhome引数にScaffoldウィジェットを指定する
home: Scaffold(
//Scaffoldの引数1、appBar(タイトル領域)
appBar: AppBar(title: Text("ハートの2を探せゲーム")),
//Scaffoldの引数2、body(本文領域)
body: Wrap(
children: [
//引数はコンストラクタに記載の順番、mark, numberの順に指定します
PlayingCard("heart", "01"),
PlayingCard("heart", "02"),
PlayingCard("heart", "03"),
PlayingCard("spade", "01"),
PlayingCard("spade", "02"),
],
),
),
),
);
}
class PlayingCard extends StatelessWidget {
String mark; //変数mark(文字列String型)
String number; //変数number(文字列String型)
//コンストラクタ
PlayingCard(this.mark, this.number);
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_${mark}_${number}.png",
width: 80,
),
onTap: () {
print("${mark}の${number}を押したよ!");
if(mark == "heart" && number == "02"){
print("正解!!!!");
}
},
);
}
}
PlayingCardがウィジェット化したことで、void main側からはマークと数字を指定するだけで、イラストもタップ時の操作も全てPlayingCard側に一任することができます。
void main側の記述がスッキリしたことがお分かりいただけるでしょう。これなら、何枚書いてもなんとかなりそうですね。
※今後も学習を継続する場合は、for文を用いた繰り返しを用いてPlayingCardウィジェットを効率よく作成することも可能ですので、是非チャレンジしてみてください。
応用編 カードの並び順をシャッフルしてみよう
毎回同じ順番にカードが並んでいても面白くありません。
mainではWrapウィジェットの子(children)として、PlayingCardのリストを作成しているのでしたね。
[
//引数はコンストラクタに記載の順番、mark, numberの順に指定します
PlayingCard("heart", "01"),
PlayingCard("heart", "02"),
PlayingCard("heart", "03"),
PlayingCard("spade", "01"),
PlayingCard("spade", "02"),
]
このリストも、丸ごと変数に格納することができます。
以下2通りの方法で書くことができます。
List<リスト化するウィジェット名> 変数名 = [データ1, データ2, ...];
var 変数名 = <リスト化するウィジェット名>[データ1, データ2, ...];
(varというキーワードは、リストだけでなくあらゆる型の変数を作ることができる汎用キーワードです。理解できなくてもOKです)
今回は、varを使用した書き方で書いてみます。void main(){の直後に、cardListという名前のリストを作成して、WrapのchildrenにはcardListを指定してみます。
import 'package:flutter/material.dart';
void main() {
//カードリスト
var cardList = <PlayingCard>[
//引数はコンストラクタに記載の順番、mark, numberの順に指定します
PlayingCard("heart", "01"),
PlayingCard("heart", "02"),
PlayingCard("heart", "03"),
PlayingCard("spade", "01"),
PlayingCard("spade", "02"),
];
runApp(
MaterialApp(
title: 'Flutter Demo',
//MaterialAppのhome引数にScaffoldウィジェットを指定する
home: Scaffold(
//Scaffoldの引数1、appBar(タイトル領域)
appBar: AppBar(title: Text("ハートの2を探せゲーム")),
//Scaffoldの引数2、body(本文領域)
body: Wrap(
children: cardList,
),
),
),
);
}
class PlayingCard extends StatelessWidget {
String mark; //変数mark(文字列String型)
String number; //変数number(文字列String型)
//コンストラクタ
PlayingCard(this.mark, this.number);
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_${mark}_${number}.png",
width: 80,
),
onTap: () {
print("${mark}の${number}を押したよ!");
if(mark == "heart" && number == "02"){
print("正解!!!!");
}
},
);
}
}
これで実行しても特にこれまでと変化がないのですが、変数にすることで便利な機能が使えるようになります。
【リストの変数】.shuffle();
たったこの1行を書くだけで、リストの並び順をシャッフルすることができます。
import 'package:flutter/material.dart';
void main() {
//カードリスト
var cardList = <PlayingCard>[
//引数はコンストラクタに記載の順番、mark, numberの順に指定します
PlayingCard("heart", "01"),
PlayingCard("heart", "02"),
PlayingCard("heart", "03"),
PlayingCard("spade", "01"),
PlayingCard("spade", "02"),
];
//シャッフル
cardList.shuffle();
runApp(
MaterialApp(
title: 'Flutter Demo',
//MaterialAppのhome引数にScaffoldウィジェットを指定する
home: Scaffold(
//Scaffoldの引数1、appBar(タイトル領域)
appBar: AppBar(title: Text("ハートの2を探せゲーム")),
//Scaffoldの引数2、body(本文領域)
body: Wrap(
children: cardList,
),
),
),
);
}
class PlayingCard extends StatelessWidget {
String mark; //変数mark(文字列String型)
String number; //変数number(文字列String型)
//コンストラクタ
PlayingCard(this.mark, this.number);
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_${mark}_${number}.png",
width: 80,
),
onTap: () {
print("${mark}の${number}を押したよ!");
if(mark == "heart" && number == "02"){
print("正解!!!!");
}
},
);
}
}
実行するたびに、並び順が変わるのが分かります。
例え並び順が変わったとしても、ひとつひとつはPlayingCardウィジェットなので、そこには絵柄に連動したmarkとnumberが内包されているので、クリックした時に想定通りに動作するわけです。(ハートの2がどの位置にあったとしても関係なく、ハートの2をタップしたら正解となる)
状態(State)を管理するStatefulWidget
次に、カードが「現在表である」「現在裏である」という状態を管理してみます。すなわち、「初期状態では裏となっていて、クリックすると表になる(めくれる)」ということを実現してみましょう。
これまでPlayingCardはStatelessWidget(State状態を、less管理しない、Widgetウィジェット)という分類で作っていたのですが、それをStatefulWidget(State状態を、ful管理する、Widgetウィジェット)に作り替える必要があります。
StatefulWidgetの使い方
StatefulWidgetは、次の2つをセットで使用します。
①StatefulWidget(ステートフルウィジェット)
②State(ステート)
書き方にはクセがありますが、ワンパターンなので「そういうもの」と認識すればOKです。
①StatefulWidgetを書く(StatelessWidgetと同様、void mainの外側に書きます)
class 【ステートフルウィジェット名】 extends StatefulWidget {
【必要であれば、コンストラクタで受け取る用の変数(StatelessWidgetの時と同様)】
【必要であれば、コンストラクタ(StatelessWidgetの時と同様)】
@override
【ステート名】 createState() => 【ステート名】();
}
②Stateを書く(同様に、void mainの外側に書きます)
class 【ステート名】 extends State<【ステートフルウィジェット名】> {
【状態管理用変数(複数書いてもOK)】
【状態管理用変数を変更する処理(複数書いてもOK)】
@override
Widget build(BuildContext context) {
return 【部品化するウィジェット】;
}
}
見るからに難しそうですが、順を追って解説します。
まず、StatelessWidgetの時はその内部にWidget build〜を書いていましたが、ステートフルのパターンではStatefulWidgetではなくState側にWidget buildを書きます。
PlayingCardをステートフル化する
今回は、PlayingCardをステートフルに書き換えてみましょう。
※今までのPlayingCardをPlayingCardStateに書き換えるとやりやすいです。
以下のように名前を名前を付けることにします。
①StatefulWidget:PlayingCard
②State:PlayingCardState
まずは、各所の名前を埋めます。
①StatefulWidgetの方は、こうなります。
外部から受け取る変数(下記例ではmark、number)とコンストラクタについては、こちら側に記載します。
class PlayingCard extends StatefulWidget {
String mark; //変数mark(文字列String型)
String number; //変数number(文字列String型)
//コンストラクタ
PlayingCard(this.mark, this.number);
@override
PlayingCardState createState() => PlayingCardState();
}
②Stateの方は、こうなります。
Widget buildはこちら側に記載します。
StatefulWidget側に記載している変数については、「widget.変数名」に書き換えることでアクセスできます。
「mark」→「widget.mark」
「number」→「widget.number」
class PlayingCardState extends State<PlayingCard> {
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_${widget.mark}_${widget.number}.png",
width: 80,
),
onTap: () {
print("${widget.mark}の${widget.number}を押したよ!");
if (widget.mark == "heart" && widget.number == "02") {
print("正解!!!!");
}
},
);
}
}
お疲れ様でした!これでひとまずStatelessWidgetからStatefulWidgetに書き換えることができました!(動作は特に変わっていません)
StatefulWidgetでカードの表・裏を状態管理してみよう
これで土台が整いました。いよいよ、カードの裏・表を管理してみましょう。
ここでは、bool(ブール)という型の変数を使ってみます。bool型というのは2択を表すことができる概念で、「Yes・No」や「表・裏」など2択のデータを管理するのに使われます。
bool型では真を「true」、偽を「false」と呼びます。
「カードが既にめくれたか?」という意味を込めて、変数名「isFlipped」を作ってみます。
状態管理を行う変数は、State側に記載します。(この場合はPlayingCardState)
初期状態はfalse(めくれていない)、クリックしたらtrue(めくれた)にすることにしましょう。
そしてカードをタップした時(onTap)、isFlippedをfalseからtrueにします。この時、onTapで状態変更を行う部分を「setState」という処理で囲みます。
setState(() { 【状態変更を行う処理】 });
class PlayingCard extends StatefulWidget {
String mark; //変数mark(文字列String型)
String number; //変数number(文字列String型)
//コンストラクタ
PlayingCard(this.mark, this.number);
//PlayingCardStateコンストラクタの引数としてmark, numberを指定
@override
PlayingCardState createState() => PlayingCardState(mark, number);
}
class PlayingCardState extends State<PlayingCard> {
//状態管理を行う変数isFlipped
bool isFlipped = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Image.network(
"https://2nd-step.net/wp-content/uploads/2022/10/card_${widget.mark}_${widget.number}.png",
width: 80,
),
onTap: () {
//タップ時に状態変更(isFlippedを変更)
setState(() {
isFlipped = true;
});
print("${widget.mark}の${widget.number}を押したよ!");
if (widget.mark == "heart" && widget.number == "02") {
print("正解!!!!");
}
},
);
}
}
この処理によって、タップ時にisFlippedが変更されるようになりました。
あとは、isFlippedの状況に応じて画像を変更するだけです。
色々な書き方がありますが、今回は三項演算子(〜?〜:〜)という方法を使って記述してみます。
三項演算子の書き方
【bool型の変数や式】?【trueの場合の値】:【falseの場合の値】
今回は、Image.networkで読み込むURLを、isFlippedがtrueの場合とfalseの場合で分けたいです。
そこで、このように記述を変更します。
import 'package:flutter/material.dart';
void main() {
//カードリスト
var cardList = <PlayingCard>[
//引数はコンストラクタに記載の順番、mark, numberの順に指定します
PlayingCard("heart", "01"),
PlayingCard("heart", "02"),
PlayingCard("heart", "03"),
PlayingCard("spade", "01"),
PlayingCard("spade", "02"),
];
//シャッフル
cardList.shuffle();
runApp(
MaterialApp(
title: 'Flutter Demo',
//MaterialAppのhome引数にScaffoldウィジェットを指定する
home: Scaffold(
//Scaffoldの引数1、appBar(タイトル領域)
appBar: AppBar(title: Text("ハートの2を探せゲーム")),
//Scaffoldの引数2、body(本文領域)
body: Wrap(
children: cardList,
),
),
),
);
}
class PlayingCard extends StatefulWidget {
String mark; //変数mark(文字列String型)
String number; //変数number(文字列String型)
//コンストラクタ
PlayingCard(this.mark, this.number);
@override
PlayingCardState createState() => PlayingCardState();
}
class PlayingCardState extends State<PlayingCard> {
//状態管理を行う変数isFlipped
bool isFlipped = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Image.network(
isFlipped
? "https://2nd-step.net/wp-content/uploads/2022/10/card_${widget.mark}_${widget.number}.png"
: "https://2nd-step.net/wp-content/uploads/2022/10/card_back.png",
width: 80,
),
onTap: () {
//タップ時に状態変更(isFlippedを変更)
setState(() {
isFlipped = true;
});
print("${widget.mark}の${widget.number}を押したよ!");
if (widget.mark == "heart" && widget.number == "02") {
print("正解!!!!");
}
},
);
}
}
おめでとうございます!これで裏面の状態、表面の状態を管理できるようになりました。だいぶゲームらしくなりましたね。
応用
・setState内、isFlipped = true; を isFlipped = !isFlipped;とすると、タップするたびに表と裏が入れ替わるようになります。
・慣れている方は、setStateをメソッドに切り出しても構いません。
・勝利条件を他のものに変更してみましょう。