Flutter로 짝 맞추기 카드게임을 만들었습니다.
//main.dart (변경없음)
import 'package:flutter/material.dart';
import 'package:memory_matching_game/src/home.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: Home(),
);
}
}
ㄴ main.dart는 기존 코드에서 변경 없음
//home.dart
import 'package:flutter/material.dart';
import 'package:memory_matching_game/src/card_boards.dart';
import 'package:memory_matching_game/src/header.dart';
class Home extends StatefulWidget {
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
int tryCount = 0; // 추가
void updateTryCount() {
setState(() {
tryCount++;
});
}
//여기부터 추가(N)
int scoreCount = 0;
void updateScoreCount() {
setState(() {
scoreCount++;
});
} //여기까지
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xffECE7E4),
appBar: AppBar(
title: const Text('짝맞추기 게임'),
backgroundColor: const Color(0xff92CBFF),
),
body: Padding(
padding: EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Header(scoreCount: scoreCount, tryCount: tryCount),
SizedBox(height: 20),
Expanded(
child: CardBoards(
updateScoreCount: updateScoreCount, //코드 추가(N)
updateTryCount: updateTryCount,
),
),
],
),
),
);
}
}
//header.dart
import 'package:flutter/material.dart';
//여기부터 변경(N)
class Header extends StatelessWidget {
final int tryCount;
final int scoreCount;
Header({
super.key,
this.scoreCount = 0,
this.tryCount = 0,
}); //여기까지
@override
Widget build(BuildContext context) {
return SizedBox(
height: 60,
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Score',
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w200,
color: Colors.black,
letterSpacing: 0,
height: 0,
),
),
Text(scoreCount.toString(),
style: TextStyle(
height: 0,
fontSize: 30,
letterSpacing: -2,
fontWeight: FontWeight.bold,
color: Colors.black)),
],
)),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Try Count',
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w200,
color: Colors.black,
letterSpacing: 0,
height: 0,
),
),
Text(tryCount.toString(),
style: TextStyle(
height: 0,
fontSize: 30,
letterSpacing: -2,
fontWeight: FontWeight.bold,
color: Colors.black)),
],
)),
Expanded(
child: Container(
margin: EdgeInsets.only(top: 10, bottom: 10, left: 20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: Color(0xff94BEE5),
),
child: Center(child: Text('새 게임')),
),
),
],
),
);
}
}
//변경 전
class Header extends StatelessWidget {
final int tryCount;
Header({super.key, this.tryCount = 0});
int score = 100;
//변경 후
class Header extends StatelessWidget {
final int tryCount;
final int scoreCount;
Header({
super.key,
this.scoreCount = 0,
this.tryCount = 0,
});
//cart_boards.dart
import 'package:flutter/material.dart';
import 'package:memory_matching_game/src/card.dart';
import 'package:memory_matching_game/src/card_model.dart';
//여기부터 변경(N)
class CardBoards extends StatefulWidget {
final Function() updateTryCount;
final Function() updateScoreCount;
CardBoards(
{super.key,
required this.updateTryCount,
required this.updateScoreCount}); //여기까지
@override
State<CardBoards> createState() => _CardBoardsState();
}
class _CardBoardsState extends State<CardBoards> {
late List<CardModel> cards;
@override
void initState() {
super.initState();
List<int> cardsValue = [1, 5, 2, 6, 3, 4, 3, 2, 6, 1, 4, 5];
cardsValue.shuffle();
cards = List.generate(cardsValue.length, (index) {
return CardModel(index: index, cardValue: cardsValue[index]);
});
}
CardModel? instantFirstCard;
void onTapCard(int cardIndex) {
print('$cardIndex 번째 카드를 선택하셨습니다.');
if (instantFirstCard == null) {
instantFirstCard = cards[cardIndex];
} else {
// 두번째 카드가 선택되었을때 로직 추가
widget.updateTryCount();
var firstCard = instantFirstCard;
var secondCard = cards[cardIndex];
if (firstCard!.cardValue == secondCard.cardValue) {
print('짝이 맞았습니다.');
widget.updateScoreCount(); //추가(N) 점수 올리는 코드
instantFirstCard = null;
} else {
resetInstantCards(instantFirstCard!, secondCard);
}
}
setState(() {
cards[cardIndex].setFlipped(true);
});
}
void resetInstantCards(CardModel firstCard, CardModel secondCard) async {
await Future.delayed(Duration(seconds: 1));
setState(() {
firstCard.setFlipped(false);
secondCard.setFlipped(false);
});
instantFirstCard = null;
return;
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Wrap(
spacing: 4,
runSpacing: 4,
children: [
for (var i = 0; i < cards.length; i++)
CardWidget(
card: cards[i],
onTap: () {
onTapCard(i);
},
),
],
),
);
}
}
//변경 전
class CardBoards extends StatefulWidget {
final Function() updateTryCount;
CardBoards({super.key, required this.updateTryCount});
//변경 후
class CardBoards extends StatefulWidget {
final Function() updateTryCount;
final Function() updateScoreCount;
CardBoards(
{super.key,
required this.updateTryCount,
required this.updateScoreCount}); //여기까지
//card.dart
import 'package:flutter/material.dart';
import 'package:memory_matching_game/src/card_model.dart';
class CardWidget extends StatelessWidget {
final CardModel card;
final Function()? onTap;
const CardWidget({
super.key,
required this.card,
this.onTap,
});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
if (onTap != null && !card.isFlipped) {
// 수정
onTap!();
}
},
child: Container(
width: 115,
height: 150,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(51), //변경(N)전 withOpacity(0.2)권장되지 않아 수정
offset: Offset(0, 2),
blurRadius: 4,
),
],
),
child: card.isFlipped // 수정
? Center(
child: Image.asset('assets/images/${card.cardValue}.png'), // 수정
)
: Container(
margin: EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Color(0xffBBD0E3),
),
child: Center(child: Image.asset('assets/images/logo.png'))),
),
);
}
}
//card_model.dart (변경없음)
class CardModel {
final int index;
final int cardValue;
bool isFlipped;
CardModel({
required this.index,
required this.cardValue,
this.isFlipped = false,
});
void setFlipped(bool state) {
// 추가
isFlipped = state;
}
}
ㄴ card_model.dart 기존 코드에서 변경 없음
짝 맞추기 카드게임은 두 장의 카드를 뒤집어 같은 그림을 맞추면 점수가 올라가는 기억력 게임입니다.
짝이 맞으면 카드가 그대로 보이는 것에서 -> 점수 1점씩 올리는 것을 추가했고,
틀리면 다시 뒤집혀서 계속 도전하는 방식입니다.
'춘기IT > 춘기개발' 카테고리의 다른 글
위젯 트리 (Widget Tree): Flutter 앱의 뼈대 이해 (0) | 2025.06.18 |
---|---|
Flutter 카드게임 코드 (새 게임 버튼 추가) (0) | 2025.06.17 |
동기 / 비동기 / await / async (1) | 2025.06.17 |
Dart문법: 조건문 if/else문 / switch문 (2) | 2025.06.17 |
Dart 문법: Dart 함수 파라미터 정리 (Positional / Named / Optional) (0) | 2025.06.17 |