춘기IT/춘기개발
Flutter 카드게임 코드 (새 게임 버튼 추가)
화춘기
2025. 6. 17. 21:07
Flutter로 짝 맞추기 카드게임을 만들었습니다.
짝이 맞으면 카드가 그대로 보이면서 1점씩 점수가 추가하는 것에서
-> 새 게임 버튼을 추가하여
새 게임 버튼을 누르게 되면 모든 카드를 초기화하고 점수와 시도 횟수를 0으로 변경시켜 줍니다.
//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 {
const Home({super.key}); // 여기 추가(N)
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
int tryCount = 0;
void updateTryCount() {
setState(() {
tryCount++;
});
}
int scoreCount = 0;
void updateScoreCount() {
setState(() {
scoreCount++;
});
}
//여기부터 추가(N)
int gameid = 0;
void resetGame() {
setState(() {
tryCount = 0;
scoreCount = 0;
// 게임 ID를 증가시켜 새로운 게임을 시작할 수 있도록 합니다.
// 이 ID는 게임의 상태를 관리하는 데 사용될 수 있습니다.
// 예를 들어, 게임이 끝나고 새로운 게임을 시작할 때마다 ID를 증가시켜
// 이전 게임과의 상태를 구분할 수 있습니다.
// gameid는 게임의 고유 식별자로 사용될 수 있습니다
gameid++;
});
} //여기까지
@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, onReset: resetGame), //수정(N) 변경전 (tryCount: tryCount)
SizedBox(height: 20),
Expanded(
child: CardBoards(
key: ValueKey(gameid), //추가(N) 게임 ID를 키로 사용하여 상태를 관리
updateScoreCount: updateScoreCount,
updateTryCount: updateTryCount,
),
),
],
),
),
);
}
}
//header.dart
import 'package:flutter/material.dart';
class Header extends StatelessWidget {
final int tryCount;
final int scoreCount;
final VoidCallback onReset; // 추가(N)
const Header({ //변경(N) 전 Header
super.key,
this.scoreCount = 0,
this.tryCount = 0,
required this.onReset, // 생성자에도 추가(N)
});
@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: const EdgeInsets.only(top: 10, bottom: 10, left: 20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: const Color(0xff94BEE5), //const 추가(N)
),
//여기 변경(N)
child: TextButton(
// 수정: TextButton으로 변경
onPressed: onReset,
child: const Center(
child: Text(
'새 게임',
style: TextStyle(color: Colors.white),//여기까지
),
),
),
),
),
],
),
);
}
}
//변경 전
child: Center(child: Text('새 게임'))
//변경 후
child: TextButton(
// 수정: TextButton으로 변경
onPressed: onReset,
child: const Center(
child: Text(
'새 게임',
style: TextStyle(color: Colors.white),
),
//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 기존 코드에서 변경 없음
//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),
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.dart는 기존 코드에서 변경 없음
//card_boards.dart
import 'package:flutter/material.dart';
import 'package:memory_matching_game/src/card.dart';
import 'package:memory_matching_game/src/card_model.dart';
import 'dart:developer';//추가(N)
class CardBoards extends StatefulWidget {
final Function() updateTryCount;
final Function() updateScoreCount;
const CardBoards( //const 추가(N), 변경 전 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) {
log('$cardIndex 번째 카드를 선택하셨습니다.'); //변경(N) 전 print
if (instantFirstCard == null) {
instantFirstCard = cards[cardIndex];
} else {
// 두번째 카드가 선택되었을때 로직 추가
widget.updateTryCount();
var firstCard = instantFirstCard;
var secondCard = cards[cardIndex];
if (firstCard!.cardValue == secondCard.cardValue) {
log('짝이 맞았습니다.'); //변경(N) 전 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);
},
),
],
),
);
}
}
이렇게 해서 짝 맞추기 카드 게임을 완성했습니다.