Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
Tags
- 앱번들
- Flutter #플러터 #프로젝트 #파이어베이스 #파이어스토어 #Firebase #FireStore
- 플러터 #Flutter #파이어베이스 #firebase #firestore #파이어스토어
- 유니티게임 #상점만들기 #뽑기구현 #케이디리듬게임
- 플레이스토어 앱등록
- AAB
- 복권번호예측 #Flutter #플러터 #Provider
- 초성게임앱 #플러터앱 #플러터카운트다운
- GetX #CustomScrollView #Flutter
- flutter #android #androidstudio
- Flutter #플러터 #모바일앱만들기 #GetX
- 복권번호예측기 #Flutter #adMob #광고배너 #리워드형광고
Archives
- Today
- Total
이코노딩
Flutter Project : 오프라인 게임 지원앱 만들기 -3 본문
▶ Game2(폭탄게임)
옵션 페이지
Game1과는 다르게 플레이어수는 필요없고 타이머 랜덤 지정과 가리기 보이기를 정할 수 있게 하였다.
●필수기능
1. 스위치로 타이머 가림막모드 지정
2. 스위치로 타이머 short(10 ~ 60), Long(50 ~110) 랜덤 생성
3. 바텀시트로 How to play 지원
▶코드
class Game2 extends StatelessWidget{
const Game2({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp,DeviceOrientation.portraitDown]);
return MaterialApp(
title: "폭탄 게임",
debugShowCheckedModeBanner: false,
home: Game2Option(),
);
}
}
//가리기모드 체크
bool _timevis = false;
class Game2OptionMenu extends State<Game2Option>{
bool _timeLen = false;
final List<String> _conList = ['직업','노래','영화','연예인','배우','아이돌','나라','드라마',
'도시','무기','음식','디저트','전자기기','게임','식물','동물','브랜드','운동','운동선수','걸그룹','보이그룹'];
void checkTime(){
if(!_timeLen){
_currentTimer = 10 + Random().nextInt(50);
}else{
_currentTimer = 50 + Random().nextInt(60);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.fromLTRB(20, 40, 20, 0),
child: Column(
children: [
Image.asset("assets/images/logo.png"),
Divider(
height: 30,
color: Colors.lightGreenAccent[400],
),
Stack(children: [
Image.asset("assets/images/bomb.png" ,width: 400, height: 250,),
Positioned(
top: 150,
left: 45,
child: Text("폭탄게임",
style: TextStyle(
fontSize: 72,
color: Colors.tealAccent[700],
fontWeight: FontWeight.bold,
),)
),
//howtoplay
Positioned(
top: 60,
left: 140,
child: IconButton(
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 500,
color: Colors.amber,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('1. 타이머 가림막 모드와 타미머를 지정해주세요. \n\n '
'2. Short는 10~60초 Long은 50 ~ 110초 사이로 랜덤하게 지정됩니다. \n\n'
'3. 게임시작 시 랜덤하게 주제가 중앙에 뜹니다.\n\n'
'4. 돌아가며 주제와 연관된 단어를 말해주세요.\n\n'
'5. 타이머가 종료되어 폭탄이 터지면 들고있던 기기를 들고있던 사람이 탈락!\n\n'
'Tip 게임 진행 중 멈추고 싶다면 상단 중앙 일시정지 버튼을 눌러주세요.',style: TextStyle(fontSize: 20), textAlign: TextAlign.center,),
ElevatedButton(
child: const Text('닫기'),
onPressed: () => Navigator.pop(context),
)
],
),
),
);
},
);
},
icon: ImageIcon(AssetImage('assets/images/q_mark.png'), size: 80),
iconSize: 80,
color: Colors.lightGreenAccent[400],
),
)
],
),
Container(
padding: EdgeInsets.all(40),
child: Column(
children: [
Row(
children: [
Text("모드 "
, style: TextStyle(
fontSize: 30,
),),
Text(
"타이머ON ",
style: TextStyle(
fontSize: 15,
)
),
Container(
width: 50,
padding: EdgeInsets.only(left: 20),
child:
Switch(
value: _timevis,
onChanged: (value) {
setState(() {
_timevis = value;
});
},
activeColor: Colors.greenAccent[400],
)
),
Text(" 타이머OFF"
, style: TextStyle(
fontSize: 15,
),),
],
),
Row(
children: [
Text("타이머 "
, style: TextStyle(
fontSize: 30,
),),
Text(
"Short ",
style: TextStyle(
fontSize: 15,
)
),
Container(
width: 50,
padding: EdgeInsets.only(left: 20),
child:
Switch(
value: _timeLen,
onChanged: (value) {
setState(() {
_timeLen = value;
});
},
activeColor: Colors.greenAccent[400],
)
),
Text(" Long"
, style: TextStyle(
fontSize: 15,
),),
],
),
Container(
padding: EdgeInsets.all(40),
child: TextButton(onPressed: () {
checkTime(); //스위치 상태 계산
currentCon = _conList[Random().nextInt(_conList.length-1)]; //주제선정
Navigator.push(
context, MaterialPageRoute(builder: (context) => new PlayInGame2()),
);
print('game2');
},
child: Text("게임시작",
style: TextStyle(
fontSize: 30.0,
color: Colors.black,
),
),
style: ElevatedButton.styleFrom(
minimumSize: Size(200, 50),
elevation: 10,
primary: Colors.lightGreenAccent[400],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)
)
),
),
),
Container(
padding: EdgeInsets.only(top: 20),
child:
TextButton(onPressed: () {
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (context) => SelectMenu()));
},
child: Text("뒤로가기",
style: TextStyle(
fontSize: 30.0,
color: Colors.black,
),
),
style: ElevatedButton.styleFrom(
minimumSize: Size(200, 50),
elevation: 10,
primary: Colors.lightGreenAccent[400],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)
)
),
),)
],
)
),
]),
)
);
}
}
class Game2Option extends StatefulWidget{
const Game2Option({Key? key}) : super(key: key);
@override
Game2OptionMenu createState() => Game2OptionMenu();
}
Game1 옵션과 코드가 유사하다.
인게임 페이지
●필수기능
1. 랜덤 타이머 표시 및 시작/일시정지 기능
2. 타이머 가림막 모드 식별 후 모드에 맞게 타이머 가림 여부
3. 주제 랜덤 띄우기
4. 타이머 종료 시, 진동 넣기 (대체 이미지 전환)
5. 뒤로가기 Game1과 동일
▶코드
//폭탄게임실제동작
class PlayInGame2 extends StatelessWidget {
const PlayInGame2({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: InGame2(),
);
}
}
class InGame2 extends StatefulWidget{
const InGame2({Key? key}) : super(key: key);
@override
InGame2View createState() => InGame2View();
}
//폭탄 게임 뷰
class InGame2View extends State<InGame2>{
//주제 글자크기
double _chkConLen(){
if(currentCon!.length <= 3)
return 90;
else
return 65;
}
//주제 글자 포지션
double _chkConpos(){
if(currentCon!.length == 2){
return 100;
}else if(currentCon!.length == 4) {
return 60;
}else{
return 55;
}
}
double _chkConposTop(){
if(currentCon!.length == 4){
return 70;
}else
return 55;
}
//뒤로가기 경고창
void back(){
pause();
setState((){
isPlaying = false;
_playIcon =Icons.play_arrow;
_playCol = Colors.grey;
_currentState = '다시시작';
});
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext ctx){
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
title: Column(
children: [
new Text('Warning'),
],
),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text('게임진행을 멈추고 나가시겠습니까?')
],
),
actions: [
new FlatButton(
child: new Text("나가기"),
onPressed:(){
Navigator.of(context).pop();
Navigator.pop(ctx);
Navigator.push(
context, MaterialPageRoute(builder: (context) => Game2()),
);
},
),
new FlatButton(
child: new Text("계속하기"),
onPressed:(){
Navigator.pop(ctx);
},
),
],
);
});
}
//백버튼을 눌렀을 때
Future<bool> _onBackKey() async{
return await showDialog(context: context, builder: (BuildContext context){
return AlertDialog(backgroundColor: Colors.amber,
title: Text(
"진행중이던 게임을 멈추고 나가시겠습니까?.",
) ,
actions: [
TextButton(onPressed: (){
Navigator.pop(context, 1);
}, child: Text('종료')),
TextButton(onPressed: (){
Navigator.pop(context, 0);
}, child: Text('취소')),
],
);
});
}
//일시정지 버튼
var _playIcon = Icons.play_arrow;
var _playCol = Colors.grey;
var _currentState = '시작';
// 타이머 구성
var time = _currentTimer;
Timer? timer;
var isPlaying = false;
@override
void dispose(){
timer?.cancel();
super.dispose();
}
Widget TimerTxt() {
if (time == -100) {
return Text(' ',
style: TextStyle(
fontSize: 25,
color: Colors.black,
)
);
}
else {
if (_timevis) {
return Text(' ',
style: TextStyle(
fontSize: 25,
color: Colors.black,
)
);
} else {
return Text('$time',
style: TextStyle(
fontSize: 25,
color: Colors.black,
)
);
}
}
}
bool _isOver = false;
//이미지 변환부분
@override
Widget changeImg(){
if(!_isOver){
return
CircleAvatar(
backgroundImage: AssetImage('assets/images/bombdeco.gif'),
radius: 200);
}else {
return
Padding(
padding: EdgeInsets.only(top: 50),
child: Image.asset('assets/images/bombdeco2.gif', width: 250, height: 250,)
);
}
}
//타이머 함수
void start() {
timer = Timer.periodic(Duration(milliseconds: 1000), (timer) {
setState(() {
isPlaying = true;
if(time > 0) {
time--;
if (time == 1) _isOver = true;
}
else if(time == 0){
gameover();
}
});
});
}
void pause(){
timer?.cancel();
setState((){
isPlaying = false;
});
}
//게임오버
void gameover(){
timer?.cancel();
time = -100;
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context){
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
title: Column(
children: [
new Text('Result'),
],
),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text('GameOver!')
],
),
actions: [
new FlatButton(
child: new Text("다시하기"),
onPressed:(){
Navigator.pop(context);
Navigator.push(
context, MaterialPageRoute(builder: (context) => Game2()),
);
},
),
],
);
});
}
//게임내 필요요소
void _clickTimer(){
setState(() {
if(_playIcon == Icons.play_arrow){
_playIcon = Icons.pause;
_playCol = Colors.amber;
_currentState = '일시정지';
start();
}else{
_playIcon =Icons.play_arrow;
_playCol = Colors.grey;
_currentState = '다시시작';
pause();
}}
);
}
//UI
@override
Widget build(BuildContext context){
return WillPopScope(onWillPop: (){
return _onBackKey();
},
child: Scaffold(
body: Padding(
padding: EdgeInsets.fromLTRB(20, 40, 20, 0),
child: Column(children: [
Row(children: [
Icon(Icons.timer,
size: 50),
Container(
width: 50,
child:TimerTxt(),
),
Container(
padding: EdgeInsets.only(left:40),
child:
TextButton.icon(onPressed: () {
_clickTimer();
},
label: Text('$_currentState',
style: TextStyle(
color: Colors.black,
),
),
icon: Icon(
_playIcon,
size: 30,
color: Colors.black,
),
style: ElevatedButton.styleFrom(
minimumSize: Size(100, 30),
elevation: 10,
primary: _playCol,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(90)
)
),
)
),
Container(
padding: EdgeInsets.only(left: 70),
child:
IconButton(
onPressed: back,
icon: Icon(Icons.arrow_back,
color: Colors.greenAccent[400],),
iconSize: 30,
)),
],),
Divider(
height: 20,
color: Colors.lightGreenAccent[400],
thickness: 1.5,
),
Stack(
children: [
Padding(padding: EdgeInsets.only(top: 30),
child: Image.asset("assets/images/bombgame.png"),
),
Positioned(
top: _chkConposTop(),
left: _chkConpos(),
child: Text('$currentCon',
style: TextStyle(
fontSize: _chkConLen(),
color: Colors.black,
fontWeight: FontWeight.bold
),
))
],
),
Container(
padding: EdgeInsets.all(30),
child:
Center( child:
changeImg(),
)
)
],),
)
),
);
}
}
var _currentTimer; //타이머
String? currentCon; //주제선정
◐막힌부분
1. 글자수에 따라 글자 위치가 달라져서 맞추는게 까다로웠다. 아마 이렇게 하드하게 말고 심플하게 할 수 있는 방법이 있을건데.. 그냥 하드하게 했다. 나중에 심플한 방법 찾으면 글 수정하겠습니다.
2. 이미지 전환, 타이머가 1초 남았을 때 다른 gif이미지로 변경하는 부분인데 CircleAvator를 썼더니 바뀌는 gif와 크기가 달라 보기 싫었다. 그래서 그냥 이미지로 변경하게 했더니 무슨 에러인지 모르겠지만 에러남 그래서 Widget함수를 만들어서 게임 진행 여부보고 return하게 해줬더니 잘 된다 :D
'언어 > Dart & Flutter' 카테고리의 다른 글
[Flutter] connectivity_plus 네트워크 상태 읽기 (0) | 2022.11.21 |
---|---|
Flutter Project : 오프라인 게임 지원 앱 만들기 -4 (0) | 2022.06.07 |
Flutter Project : 오프라인 게임 지원앱 만들기 -2 (0) | 2022.06.06 |
Flutter Project : 오프라인 게임 지원 앱 만들어보기 (0) | 2022.06.05 |
Flutter Project : 오프라인 게임 지원 앱 만들어보기(기획) (0) | 2022.06.05 |