가위바위보 앱 만들기
main.dart
import 'package:flutter/material.dart';
import 'package:rsp_game/game/game_body.dart';
void main() {
runApp(const RSPAPP());
}
class RSPAPP extends StatelessWidget {
const RSPAPP({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('가위 바위 보 게임'), backgroundColor: Colors.blue, titleTextStyle: const TextStyle(color: Colors.white, fontSize: 20), ),
body: const GameBody(),
),
);
}
}
game_body.dart
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:rsp_game/game/enum.dart';
import 'package:rsp_game/game/widget/cpu_input.dart';
import 'package:rsp_game/game/widget/game_result.dart';
import 'package:rsp_game/game/widget/user_input.dart';
class GameBody extends StatefulWidget {
const GameBody({super.key});
@override
State<GameBody> createState() => _GameBodyState();
}
class _GameBodyState extends State<GameBody> {
late bool isDone;
InputType? _userInput;
late InputType _cpuInput;
@override
void initState() {
super.initState();
isDone = false;
setCpuInput();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(child: CpuInput(isDone: isDone, cpuInput: _cpuInput)),
Expanded(
child: GameResult(
isDone: isDone,
result: getResult(),
callback: reset,
)),
Expanded(
child: UserInput(
isDone: isDone, callback: setUserInput, userInput: _userInput)),
],
);
}
void setUserInput(InputType userInput) {
setState(() {
isDone = true;
_userInput = userInput;
});
}
void setCpuInput() {
final random = Random();
_cpuInput = InputType.values[random.nextInt(3)];
}
void reset() {
setState(() {
isDone = false;
setCpuInput();
});
}
Result? getResult() {
if (_userInput == null) return null;
switch (_userInput!) {
case InputType.rock:
switch (_cpuInput) {
case InputType.rock:
return Result.draw;
case InputType.scissors:
return Result.playerWin;
case InputType.paper:
return Result.cpuWin;
}
case InputType.scissors:
switch (_cpuInput) {
case InputType.rock:
return Result.cpuWin;
case InputType.scissors:
return Result.draw;
case InputType.paper:
return Result.playerWin;
}
case InputType.paper:
switch (_cpuInput) {
case InputType.rock:
return Result.playerWin;
case InputType.scissors:
return Result.cpuWin;
case InputType.paper:
return Result.draw;
}
}
}
}
enum.dart
const assetPath = 'assets/images';
enum InputType {
rock,
scissors,
paper;
String get path => '$assetPath/$name.png';
}
enum Result {
playerWin('Player 승리'),
draw('무승부'),
cpuWin('Player 패배');
const Result(this.displayString);
final String displayString;
}
user_input.dart
import 'package:flutter/material.dart';
import 'package:rsp_game/game/enum.dart';
import 'package:rsp_game/game/widget/input_card.dart';
class UserInput extends StatelessWidget {
final bool isDone;
final InputType? userInput;
final Function(InputType) callback;
const UserInput(
{this.userInput,
required this.isDone,
required this.callback,
super.key});
@override
Widget build(BuildContext context) {
if (isDone) {
return Row(
children: [
const Expanded(child: SizedBox.shrink()),
Expanded(child: InputCard(child: Image.asset(userInput!.path))),
const Expanded(child: SizedBox.shrink()),
],
);
}
return Row(
children: _getInputs(callback),
);
}
List<Widget> _getInputs(Function(InputType) callback) {
return InputType.values
.map(
(type) => Expanded(
child: InkWell(
onTap: () => callback.call(type),
child: InputCard(
child: Image.asset(type.path),
),
),
),
)
.toList();
}
}
cpu_input.dart
import 'package:flutter/material.dart';
import 'package:rsp_game/game/enum.dart';
import 'package:rsp_game/game/widget/input_card.dart';
class CpuInput extends StatelessWidget {
final bool isDone;
final InputType cpuInput;
const CpuInput({required this.isDone, required this.cpuInput, super.key});
@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(child: SizedBox.shrink()),
Expanded(
child: InputCard(
child: getCpuInput(),
),
),
Expanded(child: SizedBox.shrink()),
],
);
}
Widget getCpuInput() {
if (isDone) {
return Image.asset(cpuInput.path);
}
return const SizedBox(
height: 80,
child: Center(
child: Text(
'?',
style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold),
),
),
);
}
}
input_card.dart
import 'package:flutter/material.dart';
class InputCard extends StatelessWidget {
final Widget child;
const InputCard({
super.key,
required this.child,
});
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
border: Border.all(color: Colors.grey, width: 8),
),
child: child,
);
}
}
game_result.dart
import 'package:flutter/material.dart';
import 'package:rsp_game/game/enum.dart';
class GameResult extends StatelessWidget {
final bool isDone;
final Result? result;
final VoidCallback callback;
const GameResult({required this.isDone, required this.callback, this.result, super.key});
@override
Widget build(BuildContext context) {
if (isDone) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(result!.displayString, style: const TextStyle(fontSize: 32,fontWeight: FontWeight.bold),),
SizedBox(height: 8,),
TextButton(onPressed: () => callback.call(), child: const Text('다시 하기', style: TextStyle(fontSize: 24))),]
);
}
return Center(
child: Text('가위, 바위, 보 중 하나를 선택해주세요.', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),),
);
}
}