해당 포스트에는 클래스와 생성자에 대한 내용을 주로 다룹니다. 만약 클래스와 생성자에 대해서 잘 모른다면 아래 강의들을 보고 모두 이해하고 와주십시오.
게임 진행에 필요한 건물 카드 및 주요건물에 대한 정보, 플레이어의 정보와 게임 진행에 필요한 클래스를 만들어 게임에 대한 정보를 쉽게 알아볼 수 있도록 정리 할 것입니다.
우선 lib폴더에 models라는 폴더를 하나 만들어 정리해주십시오. 그리고 models 폴더 아래에 center_building_card.dart, major_building_card.dart, player.dart, game.dart 파일을 만들어주세요. socket_service.dart파일은 서버 통신과 관련된 파일이기 때문에 다음에 다루도록 하겠습니다.
enum TriggerTurn {
MyTurn,
OpponentTurn,
EveryTurn
}
class CenterBuildingCard {
String name;
String type;
int cost;
List<int> triggerValue;
TriggerTurn triggerTurn;
String effect;
int effectValue;
int availableCount;
String imagePath;
CenterBuildingCard({
required this.name,
required this.type,
required this.cost,
required this.triggerValue,
required this.triggerTurn,
required this.effect,
required this.effectValue,
required this.availableCount,
required this.imagePath
});
}
보드판에 중앙에 오는 건물 카드 정보들을 담을 클래스입니다.
ㆍ건물의 이름
ㆍ종류 (작물, 자원 등등)
ㆍ건물의 가격
ㆍ주사위 눈금 발동조건 (밀밭 = 1, 목장 = 2, ...)
ㆍ누구 턴에 효과를 발동 시킬 것인가 (내 턴, 상대 턴, 모두의 턴)
ㆍ건물의 효과 (돈 얻기, 돈 뺏기, 건물 종류당 돈 얻기, 특수 건물 효과)
ㆍ효과 발동시 주는 돈 (빵집 = 1, 편의점 = 3, ...)
ㆍ살 수 있는 갯수
ㆍ카드 이미지 경로
enum은 관련이 있는 상수들의 집합으로 나의 턴, 상대의 턴, 모두의 턴을 상수로 저장하기에 효과적이기에 선언하였습니다.
class MajorBuildingCard {
final String name;
final int cost;
final String backImagePath;
final String frontImagePath;
bool isActive;
MajorBuildingCard({
required this.name,
required this.cost,
required this.backImagePath,
required this.frontImagePath,
this.isActive = false,
});
}
플레이어들의 주요 건물 카드 정보들을 담을 클래스입니다.
ㆍ건물의 이름
ㆍ건물의 가격
ㆍ뒷면 카드 이미지 경로
ㆍ앞면 카드 이미지 경로
ㆍ구매 여부
주요 건물은 기본적으로 구매가 안되어있는 상태이기 때문에 false로 값을 초기화 해놓았습니다.
import 'center_building_card.dart';
import 'major_building_card.dart';
class Player {
int money = 3; // Default money
List<CenterBuildingCard> centerBuildings = []; // Player's buildings
List<MajorBuildingCard> majorBuildings = []; // Player's major buildings
int id;
bool currentPlayerTurn = false;
Player({
required this.id
});
}
플레이어의 정보를 담을 클래스입니다.
ㆍ돈 액수
ㆍ가진 건물 리스트
ㆍ주요 건물 리스트
ㆍ플레이어 ID
ㆍ현재 턴 여부
import 'player.dart';
import 'center_building_card.dart';
import 'major_building_card.dart';
class MiniVillGame {
final int numOfPlayers;
List<Player> players = [];
List<CenterBuildingCard> centerCards = [];
List<MajorBuildingCard> majorCards = [];
MiniVillGame(this.numOfPlayers) {
// Initialize players with default money and centerBuildings
for (int i = 0; i < numOfPlayers; i++) {
players.add(Player(id: i));
}
// Initialize center cards
centerCards = [
CenterBuildingCard(
name: '밀밭',
type: '작물',
cost: 1,
triggerValue: [1],
triggerTurn: TriggerTurn.EveryTurn,
effect: 'plus',
effectValue: 1,
availableCount: 6,
imagePath: 'assets/center_card/center_card_0.jpg'),
CenterBuildingCard(
name: '목장',
type: '가축',
cost: 1,
triggerValue: [2],
triggerTurn: TriggerTurn.EveryTurn,
effect: 'plus',
effectValue: 1,
availableCount: 6,
imagePath: 'assets/center_card/center_card_1.jpg'),
CenterBuildingCard(
name: '빵집',
type: '서비스',
cost: 1,
triggerValue: [2, 3],
triggerTurn: TriggerTurn.MyTurn,
effect: 'plus',
effectValue: 1,
availableCount: 6,
imagePath: 'assets/center_card/center_card_2.jpg'),
CenterBuildingCard(
name: '카페',
type: '커피',
cost: 2,
triggerValue: [3],
triggerTurn: TriggerTurn.OpponentTurn,
effect: 'steal',
effectValue: 1,
availableCount: 6,
imagePath: 'assets/center_card/center_card_3.jpg'),
CenterBuildingCard(
name: '편의점',
type: '서비스',
cost: 2,
triggerValue: [4],
triggerTurn: TriggerTurn.MyTurn,
effect: 'plus',
effectValue: 3,
availableCount: 6,
imagePath: 'assets/center_card/center_card_4.jpg'),
CenterBuildingCard(
name: '숲',
type: '자원',
cost: 3,
triggerValue: [5],
triggerTurn: TriggerTurn.EveryTurn,
effect: 'plus',
effectValue: 1,
availableCount: 6,
imagePath: 'assets/center_card/center_card_5.jpg'),
CenterBuildingCard(
name: '전시장',
type: '특수',
cost: 8,
triggerValue: [6],
triggerTurn: TriggerTurn.MyTurn,
effect: 'special-building',
effectValue: 1,
availableCount: 4,
imagePath: 'assets/center_card/center_card_6.jpg'),
CenterBuildingCard(
name: 'TV 방송국',
type: '특수',
cost: 7,
triggerValue: [6],
triggerTurn: TriggerTurn.MyTurn,
effect: 'special-steal',
effectValue: 5,
availableCount: 4,
imagePath: 'assets/center_card/center_card_7.jpg'),
CenterBuildingCard(
name: '경기장',
type: '특수',
cost: 6,
triggerValue: [6],
triggerTurn: TriggerTurn.MyTurn,
effect: 'all-steal',
effectValue: 2,
availableCount: 4,
imagePath: 'assets/center_card/center_card_8.jpg'),
CenterBuildingCard(
name: '치즈 공장',
type: '공장',
cost: 5,
triggerValue: [7],
triggerTurn: TriggerTurn.MyTurn,
effect: 'plus-building-cheese',
effectValue: 3,
availableCount: 6,
imagePath: 'assets/center_card/center_card_9.jpg'),
CenterBuildingCard(
name: '가구 공장',
type: '공장',
cost: 3,
triggerValue: [8],
triggerTurn: TriggerTurn.MyTurn,
effect: 'plus-building-gagoo',
effectValue: 3,
availableCount: 6,
imagePath: 'assets/center_card/center_card_10.jpg'),
CenterBuildingCard(
name: '광산',
type: '자원',
cost: 6,
triggerValue: [9],
triggerTurn: TriggerTurn.EveryTurn,
effect: 'plus',
effectValue: 5,
availableCount: 6,
imagePath: 'assets/center_card/center_card_11.jpg'),
CenterBuildingCard(
name: '패밀리 레스토랑',
type: '커피',
cost: 3,
triggerValue: [9, 10],
triggerTurn: TriggerTurn.OpponentTurn,
effect: 'steal',
effectValue: 2,
availableCount: 6,
imagePath: 'assets/center_card/center_card_12.jpg'),
CenterBuildingCard(
name: '사과밭',
type: '작물',
cost: 3,
triggerValue: [10],
triggerTurn: TriggerTurn.EveryTurn,
effect: 'plus',
effectValue: 3,
availableCount: 6,
imagePath: 'assets/center_card/center_card_13.jpg'),
CenterBuildingCard(
name: '농산물 시장',
type: '시장',
cost: 2,
triggerValue: [11, 12],
triggerTurn: TriggerTurn.MyTurn,
effect: 'plus-building-farm',
effectValue: 2,
availableCount: 6,
imagePath: 'assets/center_card/center_card_14.jpg')
];
majorCards = [
MajorBuildingCard(
name: '기차역',
cost: 4,
backImagePath: 'assets/major_card/major_card_back_0.jpg',
frontImagePath: 'assets/major_card/major_card_front_0.jpg'),
MajorBuildingCard(
name: '쇼핑몰',
cost: 10,
backImagePath: 'assets/major_card/major_card_back_1.jpg',
frontImagePath: 'assets/major_card/major_card_front_1.jpg'),
MajorBuildingCard(
name: '놀이공원',
cost: 16,
backImagePath: 'assets/major_card/major_card_back_2.jpg',
frontImagePath: 'assets/major_card/major_card_front_2.jpg'),
MajorBuildingCard(
name: '라디오 방송국',
cost: 22,
backImagePath: 'assets/major_card/major_card_back_3.jpg',
frontImagePath: 'assets/major_card/major_card_front_3.jpg')
];
for (int i = 0; i < numOfPlayers; i++) {
players[i].centerBuildings.add(centerCards[0]);
players[i].centerBuildings.add(centerCards[2]);
players[i].majorBuildings.add(MajorBuildingCard(
name: '기차역',
cost: 4,
backImagePath: 'assets/major_card/major_card_back_0.jpg',
frontImagePath: 'assets/major_card/major_card_front_0.jpg'));
players[i].majorBuildings.add(MajorBuildingCard(
name: '쇼핑몰',
cost: 10,
backImagePath: 'assets/major_card/major_card_back_1.jpg',
frontImagePath: 'assets/major_card/major_card_front_1.jpg'));
players[i].majorBuildings.add(MajorBuildingCard(
name: '놀이공원',
cost: 16,
backImagePath: 'assets/major_card/major_card_back_2.jpg',
frontImagePath: 'assets/major_card/major_card_front_2.jpg'));
players[i].majorBuildings.add(MajorBuildingCard(
name: '라디오 방송국',
cost: 22,
backImagePath: 'assets/major_card/major_card_back_3.jpg',
frontImagePath: 'assets/major_card/major_card_front_3.jpg'));
}
}
void rollDice(int diceValue) {
// 주사위 효과 이벤트
}
void nextTurn() {
// 턴 넘기기 이벤트
}
void socketNextTurn(){
// 서버 통신으로 턴 넘기기 이벤트
}
}
주사위나 게임 로직과 관련된 부분은 모두 제외하고 레이아웃을 구성하기 위한 기본적인 게임 세팅에 대한 내용만 모두 적었습니다.
우선 생성자의 매개변수로 플레이어 총 인원수 값을 받아와서 그에 맞게 플레이어를 생성해냅니다. 그리고 중앙 건물 카드와, 주요 건물카드 리스트에 카드 정보에 맞도록 추가해줍니다.
카드를 모두 추가해줬다면 플레이어들에게 기본 건물(밀밭, 빵집)과 주요 건물 카드를 나눠줍니다.
카드를 나눠주는 부분은 게임 로직을 구현할때 필요한 부분이니 일단 생략하고 싶으면 생략해도 괜찮습니다.
import 'models/game.dart';
...
class GameScreen extends StatefulWidget {
final int numOfPlayers;
final bool createJoin;
final String roomCode;
final String userName;
GameScreen(
{required this.numOfPlayers,
required this.createJoin,
required this.roomCode,
required this.userName});
_GameScreenState createState() => _GameScreenState();
}
class _GameScreenState extends State<GameScreen>
with SingleTickerProviderStateMixin, WidgetsBindingObserver {
late MiniVillGame game;
void initState() {
super.initState();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
game = MiniVillGame(widget.numOfPlayers);
...
}
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
double sideSpaceWidth = screenWidth * 0.2;
...
return Scaffold(
body: Row(
children: [
//게임스크린 (플레이어 영역)
Container(
...
),
//게임스크린 (게임 보드 영역)
Expanded(
...
),
//게임스크린 (주사위 영역)
Container(
...
),
],
),
);
}
// 커스텀 위젯 생성
...
}
클래스 전체에서 game.dart안의 정보를 활용하기 위해 late를 이용해서
late MiniVillGame game;
을 선언한뒤에 initState에서 바로
game = MiniVillGame(widget.numOfPlayers);
으로 값을 지정해줍니다.
이렇게 game변수를 선언해두면 GameScreen 위젯 클래스 내에서 game.dart
의 정보들을 활용할 수 있습니다.
예를들어 game.centerCards[0].imagePath
를 코드에 작성하면 가장 첫번째로 등록한 카드인 밀밭의 이미지 경로를 얻어올 수 있습니다.
다음 포스팅부터는 해당 내용을 이용해서 레이아웃을 구성하는 법을 이어나가겠습니다. 게임 보드판 레이아웃 구현때 뵙겠습니다 😎