Created with <3 with dartpad.dev.
Last active
January 25, 2024 23:02
-
-
Save hardy716/9da3bb0b25a898b93fa1f80e4f1ef400 to your computer and use it in GitHub Desktop.
플러터챌린지 4일차 심화문제 - 신현호
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'dart:math'; | |
import 'package:flutter/material.dart'; | |
void main() { | |
runApp(const MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
const MyApp({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'CatchGreen', | |
debugShowCheckedModeBanner: false, | |
home: CatchGreenScreen(), | |
); | |
} | |
} | |
class CatchGreenScreen extends StatefulWidget { | |
@override | |
State<CatchGreenScreen> createState() => _CatchGreenScreenState(); | |
} | |
class _CatchGreenScreenState extends State<CatchGreenScreen> { | |
bool _isGameStarted = false; | |
void _startGame() { | |
setState(() { | |
_isGameStarted = true; | |
}); | |
} | |
void _stopGame() { | |
setState(() { | |
_isGameStarted = false; | |
}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
body: SafeArea( | |
child: Center( | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: <Widget>[ | |
_TimeBoard( | |
isGameStarted: _isGameStarted, | |
onStartGame: _startGame, | |
), | |
Expanded( | |
child: Container( | |
color: Colors.black, | |
child: _GameBoard( | |
isGameStarted: _isGameStarted, | |
onStopGame: _stopGame, | |
), | |
), | |
), | |
Container( | |
height: 100, | |
color: Colors.white, | |
), | |
], | |
), | |
), | |
), | |
); | |
} | |
} | |
class _TimeBoard extends StatefulWidget { | |
final bool isGameStarted; | |
final VoidCallback onStartGame; | |
const _TimeBoard({ | |
required this.isGameStarted, | |
required this.onStartGame, | |
}); | |
@override | |
State<_TimeBoard> createState() => _TimeBoardState(); | |
} | |
class _TimeBoardState extends State<_TimeBoard> { | |
late Timer _timer; | |
late DateTime _startDateTime; | |
String _timerToString = '0:0.0'; | |
@override | |
void didUpdateWidget(_TimeBoard oldWidget) { | |
super.didUpdateWidget(oldWidget); | |
if (widget.isGameStarted && !_timer.isActive) { | |
_startTimer(); | |
} else if (!widget.isGameStarted && _timer.isActive) { | |
_stopTimer(); | |
} | |
} | |
@override | |
void initState() { | |
super.initState(); | |
_startDateTime = DateTime.now(); | |
_timer = Timer.periodic(const Duration(milliseconds: 1), (timer) => _timer.cancel()); | |
} | |
void _startTimer() { | |
_startDateTime = DateTime.now(); | |
if (!_timer.isActive) { | |
_timer = Timer.periodic(const Duration(milliseconds: 1), (timer) => _updateTimer()); | |
} | |
setState(() => _timerToString = '0:0.0'); | |
} | |
void _stopTimer() { | |
_timer.cancel(); | |
_updateTimer(); | |
} | |
void _updateTimer() { | |
final diffTime = DateTime.now().difference(_startDateTime); | |
final m = diffTime.inMinutes.remainder(60); | |
final s = diffTime.inSeconds.remainder(60); | |
final ms = diffTime.inMilliseconds.remainder(1000).toString().padLeft(3, '0'); | |
setState(() => _timerToString = '$m:$s.$ms'); | |
} | |
void _buttonPressed() { | |
widget.onStartGame(); | |
_startTimer(); | |
} | |
@override | |
void dispose() { | |
if (_timer.isActive) { | |
_timer.cancel(); | |
} | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return SizedBox( | |
height: 140, | |
child: Column( | |
children: [ | |
const SizedBox(height: 10), | |
Text( | |
'Catch green game', | |
style: Theme.of(context).textTheme.titleLarge, | |
), | |
const SizedBox(height: 36), | |
Column( | |
mainAxisAlignment: MainAxisAlignment.end, | |
children: [ | |
Visibility( | |
visible: !widget.isGameStarted, | |
child: ElevatedButton( | |
onPressed: _buttonPressed, | |
child: const Text('Start!'), | |
), | |
), | |
const SizedBox(height: 10), | |
Text( | |
_timerToString, | |
style: Theme.of(context).textTheme.bodyMedium, | |
), | |
], | |
), | |
], | |
), | |
); | |
} | |
} | |
class _GameBoard extends StatefulWidget { | |
final bool isGameStarted; | |
final VoidCallback onStopGame; | |
const _GameBoard({ | |
required this.isGameStarted, | |
required this.onStopGame | |
}); | |
@override | |
State<_GameBoard> createState() => _GameBoardState(); | |
} | |
class _GameBoardState extends State<_GameBoard> { | |
bool _show = false; | |
final double greenSize = 50; | |
double screenWidth = 0; | |
double screenHeight = 0; | |
void showGreen() { | |
setState(() => _show = true); | |
} | |
@override | |
void didUpdateWidget(_GameBoard oldWidget) { | |
super.didUpdateWidget(oldWidget); | |
if (widget.isGameStarted && !_show) { | |
showGreen(); | |
} else if (!widget.isGameStarted && _show) { | |
setState(() => _show = false); | |
} | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
color: Colors.transparent, | |
child: LayoutBuilder( | |
builder: (context, constraint) { | |
screenWidth = constraint.maxWidth; | |
screenHeight = constraint.maxHeight; | |
return Stack( | |
children: [ | |
if (_show) | |
Positioned( | |
left: Random().nextDouble() * (screenWidth - greenSize), | |
top: Random().nextDouble() * (screenHeight - greenSize), | |
child: GestureDetector( | |
onTap: () => setState(() { | |
_show = false; | |
widget.onStopGame(); | |
}), | |
child: Container( | |
width: greenSize, | |
height: greenSize, | |
decoration: BoxDecoration( | |
borderRadius: BorderRadius.circular(greenSize / 2), | |
color: Colors.green, | |
), | |
), | |
), | |
), | |
], | |
); | |
}, | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment