모바일 맞고 게임5-3(게임 내 카드 처리 구현)
DevSource/맞고 2012. 12. 27. 18:56 |이제 플레이어와 컴퓨터에게 모두 카드를 나누어 주었습니다.
이제 남은건 플레이어가 카드를 내면, 바닥의 패 중에 같은 종류의 카드가 있는지 비교해서,
같은 종류의 카드가 있다면 먹고 없다면 그냥 바닥에 버리는 작업이 필요하겠네요.
같은 종류의 카드인지 비교하는 건 카드 인덱스를 4로 나누워 주면 된다고, 방금 말씀드렸습니다.
카드를 비교하는 방법을 알았으니, 카드를 내고 뒤집는 동작만 구현하면 되겠네요.
카드를 내는 작업도 후다닥 해치워 버릴 수도 있겠지만,
그렇게 하면, 플레이어가 자신이 무슨 카드를 먹었는지, 컴퓨터가 뭘 먹었는지 분간을 할수가 없겠죠?
카드를 내는 것 역시, 일정 delay가 지난 후에 다음 동작을 수행하도록 할 필요가 있겠네요.
GameView 클래스의 키입력 부분에 다음과 같이 추가해줍니다.
/** * 키 입력. */ public void keyPressed(int keyCode) { switch(keyCode) { |
해당 숫자를 누르면, 카드를 낼 것이므로, 숫자 입력 부분에다가 카드를 내는 동작을 구현해 주어야 하겠지요?
case KEY_NUM0:
.
.
.
case KEY_NUM9
이렇게 지정해 주어도 되겠지만, 편의상, 함수호출하기도 쉽게, default에다가 구현을 했습니다.
숫자 0의 ASCII CODE 값은 48 이므로, 0이 눌렸을때 keyCode에서 48을 빼면, 그 값이 0이 되겠지요.
1, 2, 3, 4 .... 모두 마찬가지로, 해당 키코드에서 48을 빼면 그에 해당하는 정수 값을 얻어 올수 있습니다.
만약, 0 에서 9까지의 숫자키가 눌렸고, 게임이 진행중이라면, 해당 카드를 내라는 뜻이겠죠.
throwCard 함수에 누른 번호를 넘겨 주면, 해당 번호의 카드가 바닥에 내어 질 것입니다.
카드를 낸 후에는 다시 sortMonth() 함수를 호출해서 각 월의 카드를 정렬해 주고 있습니다.
자, 그럼 throwCard 함수를 보도록 할까요.
/** * 카드를 낸다. * @param numKey */ private void throwCard(int numKey) { byte handCard, reverseCard; int handCardIdx, reverseCardIdx; numKey = (numKey == 0)? 9 : (short)(numKey - 1); handCard = room.getUserHand(curTurn, numKey); // 누른 번호의 슬롯에 카드가 없다면, if(room.getUserHand(curTurn, numKey) == room.CARD_NULL) { System.out.println(numKey + "번 카드는 존재하지 않음."); // 그냥 종료. return; } // 추가 카드라면, if( room.isAdditionalCard(handCard) ) { // 해당 피를 먹고, room.addPee(curTurn, handCard); // 가운데서 새로운 피를 가져옴. room.setUserHand(curTurn, numKey, room.getTopCard()); repaints(); // 그냥 종료. return; } else // 아무것도 아니라면, { // 손에 든 카드를 냄. handCardIdx = room.throwCard(curTurn, handCard); // 낸 자리의 카드 삭제. room.setUserHand(curTurn, numKey, room.CARD_NULL); // 빈 공간을 메꿈. room.deleteEmptySpace(curTurn); repaints(); Sleep.wait(this, 300); } // 중앙의 카드를 뒤집음. reverseCard = room.getTopCard(); System.out.println("뒤집은 카드는 : " + reverseCard); do { // 추가 카드라면, if(room.isAdditionalCard(reverseCard)) { // 해당 피를 플레이어가 먹고, room.addPee(curTurn, reverseCard); // 다시 한장 뒤집고, 체크. reverseCard = room.getTopCard(); repaints(); Sleep.wait(this, 300); } else // 추가 카드가 아니라면, { // 뒤집은 카드를 낸다. reverseCardIdx = room.throwCard(curTurn, reverseCard); repaints(); Sleep.wait(this, 300); break; } } while(true); // 손에서 냈던 카드와 뒤집어서 낸 카드가 같은 슬롯에 있다면, if(handCardIdx == reverseCardIdx) { int i, j; // 뻑 체크. for(i=0; i<4; i++) { if(room.getMonth(handCardIdx)[i] == room.CARD_NULL) { switch(i) { case 2: // 손에서 낸 카드와, 뒤집어 낸 카드 둘뿐이라면, // 두장 다 먹는다. room.addPae(curTurn, room.getMonth(handCardIdx)[0]); room.addPae(curTurn, room.getMonth(handCardIdx)[1]); room.getMonth(handCardIdx)[0] = room.CARD_NULL; room.getMonth(handCardIdx)[1] = room.CARD_NULL; repaints(); break; case 3: // 손에서 낸 카드와, 뒤집어 낸 카드와 원래 카드 한장. System.out.println(" # Msg : 뻑!!"); // 아무것도 먹지 못하고 턴을 변경. break; } } // end if(room.getMonth(handCardIdx)[i] == room.CARD_NULL). else { if(i == 3) { // 모두 먹는다. for(j=0; j<4; j++) { room.addPae(curTurn, room.getMonth(handCardIdx)[j]); room.getMonth(handCardIdx)[j] = room.CARD_NULL; } } } } } else // 손에서 낸 카드와 뒤집어 낸 카드가 다른 슬롯에 있다면, { room.processCard(curTurn, handCardIdx); room.processCard(curTurn, reverseCardIdx); if(room.bSelectTwoCard) // 두장의 카드중 선택해야 한다면, { curViewState = State.GAME_SELECTTWOCARDS; repaints(); return; } } curTurn = (curTurn==User.PLAYER)? User.COMPUTER : User.PLAYER; repaints(); } |
게임을 실행했을때 숫자를 출력하는 순서가 다음과 같죠.
|
카드의 번호는 0, 1, 2, .... , 8, 9. 와 같이 0 부터 9까지 이지만,
실제 게임 상에 출력되는 숫자는, 1, 2, 3, ... , 9, 0 과 같이 1 부터 0 까지입니다.
즉, 0번을 눌렀을때, 0번 카드를 내면 이상한 결과가 나오겠지요.
0번을 누르면, 실제 카드 인덱스에서는 9번 카드를 내야 합니다.
그래서 가장 첫줄에서 numKey를 다음과 같이 변경해 줍니다.
numKey = (numKey == 0)? 9 : (short)(numKey - 1); |
numKey가 0이라면 9번 카드를 뒤집고, 아니라면 numKey에서 1을 뺀 인덱스의 카드를 뒤집어라.
뭐 이런 뜻이 되겠네요.
그 뒤, room 클래스의 getUserHand() 함수를 이용해서, 해당 슬롯의 카드 인덱스를 얻어 온 후,
만약 이 카드가 CARD_NULL 이라면, 빈 공간을 선택한 것이므로, 아무런 처리도 하지 않고 return 해 줍니다.
만약 이 카드가 추가 카드라면,
// 추가 카드라면, if( room.isAdditionalCard(handCard) ) { // 해당 피를 먹고, room.addPee(curTurn, handCard); // 가운데서 새로운 피를 가져옴. room.setUserHand(curTurn, numKey, room.getTopCard()); repaints(); // 그냥 종료. return; } else // 아무것도 아니라면, { // 손에 든 카드를 냄. handCardIdx = room.throwCard(curTurn, handCard); // 낸 자리의 카드 삭제. room.setUserHand(curTurn, numKey, room.CARD_NULL); // 빈 공간을 메꿈. room.deleteEmptySpace(curTurn); repaints(); Sleep.wait(this, 300); } |
추가카드는 사용자가 먹고, 서비스패가 있던 자리에는 중앙의 카드를 뒤집어 새로운 카드를 가져옵니다.
만약에 추가 카드가 아닌 다른 카드라면, room 클래스의 throwCard()를 호출해 카드를 바닥에 냅니다.
room 클래스의 throwCard() 함수를 한번 보면,
/** * 카드를 냄. * @param userType * @param cardNum * @return */ public int throwCard(int userType, int cardNum) { for(i=0; i<12; i++) { // 같은 종류의 카드를 발견했다면, if(cardsMonth[i][0]/4 == cardNum/4) { // 널 카드라면, 다음 루프. if(cardsMonth[i][0] == CARD_NULL) continue; for(j=0; j<4; j++) { if(cardsMonth[i][j] == CARD_NULL) { cardsMonth[i][j] = (byte)cardNum; return i; } } } } // 한바퀴 돌았지만, 같은 종류의 카드를 발견하지 못했다면, for(i=0; i<12; i++) { // 아무곳이나 빈곳에 카드를 붙임. if(cardsMonth[i][0] == CARD_NULL) { cardsMonth[i][0] = (byte)cardNum; return i; } } return -1; } |
이 함수는 루프를 돌다가 같은 종류의 카드를 발견 하면, 그 월의 맨 뒤에 카드를 붙여줍니다.
만약에 같은 종류의 카드를 발견하지 못했다면, 아무곳이나 빈 곳에 카드를 붙여주고요.
만약에 냈다면, 몇월에 카드를 붙였는지를 리턴해 줍니다.
일단은 사용자에게 사용자가 냈다는 걸 보여주기 위해, 어디에다 냈는지만 기억해 둡니다.
그리고 다시 Sleep클래스의 wait() 함수를 이용해서 잠시 시간을 지연 시킵니다.
맞고에서 한 사람이 카드를 내면 다음엔 중앙의 카드를 뒤집어서 또 비교를 하죠.
중앙의 카드를 뒤집었을때 추가 카드가 나왔다면, 사용자가 먹고, 중앙의 카드를 한번 더 뒤집어야합니다.
do { // 추가 카드라면, if(room.isAdditionalCard(reverseCard)) { // 해당 피를 플레이어가 먹고, room.addPee(curTurn, reverseCard); // 다시 한장 뒤집고, 체크. reverseCard = room.getTopCard(); repaints(); Sleep.wait(this, 300); } else // 추가 카드가 아니라면, { // 뒤집은 카드를 낸다. reverseCardIdx = room.throwCard(curTurn, reverseCard); repaints(); Sleep.wait(this, 300); break; } } while(true); |
그래서 위와 같이 while 루프를 돌면서, 추가 카드가 아닌 것이 나올 때까지, 계속 뒤집어 줍니다.
이제, 손에 들고 있던 카드와 중앙에서 뒤집은 카드를 모두 냈습니다.
손에 들고 있던 카드를 낸 월은 handCard에,
중앙에서 뒤집은 카드를 낸 월은 reverseCard에 저장이 되어있습니다.
이걸 handCard와 reverseCard를 낸 월이 같을때와 같지 않을때로 나누어서 생각해야 합니다.
왜냐 하면, 만약, handCard와 reverseCard가 같은 월에 있다면, 뻑의 위험이 있기 때문이죠.
// 손에서 냈던 카드와 뒤집어서 낸 카드가 같은 슬롯에 있다면, if(handCardIdx == reverseCardIdx) { int i, j; // 뻑 체크. for(i=0; i<4; i++) { if(room.getMonth(handCardIdx)[i] == room.CARD_NULL) { switch(i) { case 2: // 손에서 낸 카드와, 뒤집어 낸 카드 둘뿐이라면, |
만약, handCard와 reverseCard가 같을 때,
한 슬롯 안에 카드가 두장 뿐이라면, 쪽이 되겠네요. 지금은 애니메이션 처리는 구현하지 않았으므로,
임시로 println() 함수를 이용해서 debug 창에만 출력을 해 줍니다.
한 슬롯 안에 카드가 세장이라면, 손에서 낸 카드와, 뒤집어 낸 카드와 원래 카드가 한장 더 있다는거네요.
그러면 바로 이것이 "뻑!!" 인것이죠. 역시 마찬가지로 애니메이션 처리는 아직 구현하지 않았으므로,
임시로 println() 함수를 이용해서 debug 창에만 출력을 해 주었습니다.
그러나, 해당 월을 쭉 살펴 보았는데, CARD_NULL 인 것이 없다면, 해당 월이 가득 찬...
즉, 카드 4장이 한 슬롯에 있다는 의미겠죠. 그럴때는 4장을 모두 해당 플레이어가 먹게 됩니다.
else // 손에서 낸 카드와 뒤집어 낸 카드가 다른 슬롯에 있다면, { room.processCard(curTurn, handCardIdx); room.processCard(curTurn, reverseCardIdx); if(room.bSelectTwoCard) // 두장의 카드중 선택해야 한다면, { curViewState = State.GAME_SELECTTWOCARDS; repaints(); return; } } |
이번에는 handCard와 reverseCard가 다른 슬롯에 있을때의 처리를 해 줍니다.
각자 다른 슬롯에 있다면, 슬롯 마다 각각 처리를 해 주어야 겠네요.
각각의 슬롯에 붙여진 카드를 처리해 주는 함수는 processCard() 함수 입니다.
/** * 낸 카드를 처리한다. * @param userType * @param monthIdx */ public void processCard(byte userType, int monthIdx) { for(i=0; i<4; i++) { if(cardsMonth[monthIdx][i] == CARD_NULL) { if(i == 0 || i == 1 ) // 슬롯에 아무것도 없거나, 한장 뿐이면, { ; } |
앞서, twogo1p.GameView 클래스의 throwCard() 함수와 비슷한 형태로 검사를 합니다.
해당 월을 루프를 돌면서 검사를 해서,
슬롯에 플레이어가 낸 카드 한장과 원래 카드 한장이 있다면, 둘다 먹어야 하겠지요.
슬롯에 낸 카드와 원래 카드가 두장이 있다면, 둘중 하나를 선택해야 합니다.
그런데 두장의 카드가 같은 종류의 카드라면, 즉 둘다 피이거나, 열이거나 하는 경우에는, 선택할 필요가 없겠죠.
그래서 같은 종류의 카드 일때에는 그냥 컴퓨터가 알아서 렌덤으로 둘중 하나를 먹고 루프를 빠져나갑니다.
그러나 둘다 다른 종류의 카드라면, 플레이어에게 어떤 카드를 먹을 것인지 선택할 수 있도록 해 주어야합니다.
// 두장이 다른 카드라면, 둘중 하나 선택. bSelectTwoCard = true; |
room 클래스 내에서는, 키 입력을 받을 수 없으므로,
processCard() 함수를 빠져 나간 뒤에 두장의 카드를 선택 받기 위해서,
bSelectTwoCard 라는 함수가 true 일대에는, 두장의 카드 중 하나를 선택해야 한다는 의미가 됩니다.
slot[0]과 slot[1]에는, 선택해야 할 카드가 있는 월의 인덱스가 들어가고,
slotLast[0]과 slotLast[1] 에는 해당 카드 수가 들어갑니다.
위와 같이 해 준뒤에, processCard() 함수를 벗어 난 뒤에,
if(room.bSelectTwoCard) // 두장의 카드중 선택해야 한다면, { curViewState = State.GAME_SELECTTWOCARDS; repaints(); return; } |
위와 같이, bSelectTwoCard 플래그를 체크해 주어,
카드를 선택해야 한다면, curViewState를 State.GAME_SELECTTWOCARDS로 변경해서,
두장의 카드중 하나를 선택하는 키 입력을 받습니다.
아래는 GameView 클래스의 keyPressed() 함수 중, 숫자 키 입력을 처리 하는 부분에 추가된 부분입니다.
if(curViewState == State.GAME_SELECTTWOCARDS) { int index; System.out.println(room.slot[0] + ", " + room.slot[1]); if(room.slot[0] != room.CARD_NULL) index = 0; else /* if(room.slot[1] != room.CARD_NULL) */ index = 1; if(room.getMonth(room.slot[index])[numKey-1] != room.CARD_NULL) room.addPae(curTurn, room.getMonth(room.slot[index])[numKey-1]); if(room.getMonth(room.slot[index])[room.slotLast[index]] != room.CARD_NULL) room.addPae(curTurn, |
복잡해보이지만, 1번을 누르면, 1번 카드를 먹고, 2번을 누르면 2번 카드를 먹게 되는 간단한 코드입니다.
if(room.getMonth(room.slot[index])[numKey-1] != room.CARD_NULL) room.addPae(curTurn, room.getMonth(room.slot[index])[numKey-1]); if(room.getMonth(room.slot[index])[room.slotLast[index]] |
1번을 누르면 numkey 에 1이 들어 오므로, 1번 을 누르면 0번 슬롯을 선택하고,
2번을 누르면 1번 슬롯의 카드를 addPae() 함수를 이용해서 플레이어가 먹고,
slotLast에 저장된 마지막 인덱스의 카드(사용자가 낸 카드도)도 먹어주어야 겠지요.
그 다음 해당 월에 중간 중간 카드를 먹어서 생긴 공백을 sortMonth() 함수를 이용해서 제거해주고,
repaints()로 화면을 다시 갱신해 줍니다.
두장의 카드를 선택중일때에는 단순히 화면에 어떤 카드를 선택할 것인지 물어 보면 됩니다.
그러나 아직 이번시간에는 디스플레이 요소들은 삽입하지 않았으므로,
글씨를 출력해서 어떤 카드를 선택 할 것인지를 물어보게 했습니다.
두 장의 카드를 선택중일 때의 화면은 drawSelectTwoCards() 함수로 그려줍니다.
/** * 카드 둘중 하나를 선택할때... * @param g */ |
간단히 drawRunningGame() 을 호출해서 게임 진행중의 화면을 먼저 그려준 뒤,
문자 열을 출력 합니다. 조금 허접한 문자열이 출력 되겠지만,
다음 시간에 디스플레이 요소를 삽입해서 멋지게 물어본다면 그럴 듯 해지겠지요^^;
'DevSource > 맞고' 카테고리의 다른 글
모바일 맞고 게임6-1(맞고 게임룰 설명) (0) | 2012.12.27 |
---|---|
모바일 맞고 게임5-4(획득 카드 보기 화면 구현) (0) | 2012.12.27 |
모바일 맞고 게임5-2(카드 나눠주기 구현) (0) | 2012.12.27 |
모바일 맞고 게임5-1(실제 맞고 게임의 구현) (0) | 2012.12.27 |
모바일 맞고 게임4-2(Room 클래스 살펴보기) (0) | 2012.12.27 |