이번 시간에는 게임에 각종 디스플레이 요소를 씌워보는 작업을 하도록 하겠습니다.

이번 시간을 거쳐서 이제 진짜 그럴듯한 게임으로 거듭나는 것을 감상하실 수 있습니다.


가장 먼저 게임 내에서 디스플레이 요소를 출력하기 위한 CyDialog 클래스를 구현해보도록 하지요.

* CyDialog.java.
package common;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Graphics;

import com.skt.m.Graphics2D;

/**
 * 다이얼로그와 관련된 기능을 모아놓은 클래스.
 */

public class CyDialog {
    public final static byte SELECTTWOCARD = 0; // 두장의 카드 선택.
    public final static byte SELECTGOOKJIN = 1; // 국진 선택.
    public final static byte SELECTGOSTOP = 2; // 고/스톱 선택.
    public final static byte SELECTSHAKE = 3; // 흔듬 선택(플레이어).
    public final static byte SELECTBOMB = 4; // 폭탄 선택(플레이어).
    public final static byte RESULT = 5; // 결과 확인.
    public final static byte CONTINUEGAME = 6; // 게임 메뉴.

    public final static byte MSG_GO = 7; // 고.
    public final static byte MSG_STOP = 8; // 스톱.
    public final static byte MSG_PPUCK = 9; // 뻑.
    public final static byte MSG_JJOK = 10; // 쪽.
    public final static byte MSG_DDADAK = 11; // 따닥.
    public final static byte MSG_SSEUL = 12; // 쓸.
    public final static byte MSG_SHAKE = 13; // 흔듬(컴퓨터 턴).
    public final static byte MSG_BOMB = 14; // 폭탄(컴퓨터 턴).

    private Canvas parentCanvas;
    private short width, height;

    /*
     * Border Images.
     */
    private Image imgSelectTwoCard; 
    private Image imgSelectGookjin;
    private Image imgSelectGoStop;
    private Image imgSelectShake;
    private Image imgSelectBomb;
    private Image imgResult;
    private Image imgContinueGame; // 게임 중의 메뉴 화면.

    /*
     * Message Images.
     */
    private Image imgMsgGo; // 고를 선택했을때의 메시지.
    private Image imgMsgStop; // 스톱을 선택했을때의 메시지.
    private Image imgMsgPpuck; // 뻑을 당했을때의 메시지.
    private Image imgMsgJjok; // 쪽을 했을때의 메시지.
    private Image imgMsgDdadak; // 따닥 했을때의 메시지.
    private Image imgMsgSseul; // 쓸을 했을때의 메시지.
    private Image imgMsgShake; // 흔들었을때의 메시지.
    private Image imgMsgBomb; // 폭탄일대의 메시지.

    /**
     * Constructor.
     * @param parentCanvas
     */
    public CyDialog(Canvas parentCanvas)
    {
        this.parentCanvas = parentCanvas;

        width = (short) parentCanvas.getWidth();
        height = (short) (parentCanvas.getHeight()+16);

        loadImages(); // 이미지를 읽어옴.
    }

    /**
     * 다이얼로그에 필요한 각종 이미지를 로드한다.
     */
    private void loadImages()
    {
        try {
            /*
             * Load Border Images.
             */
            // 두장의 카드 선택 border.
            imgSelectTwoCard = Image.createImage("/image/gasktwocard.lbm");
            // 두장의 카드 선택 border.
            imgSelectGookjin = Image.createImage("/image/gaskgook.lbm");
            // 고/스톱 선택 border.
            imgSelectGoStop = Image.createImage("/image/gaskgostop.lbm");
            // 흔들기 선택 border.
            imgSelectShake = Image.createImage("/image/gaskshake.lbm");
            // 폭탄 선택 border.
            imgSelectBomb = Image.createImage("/image/gaskbomb.lbm");
            // 결과 화면.
            imgResult = Image.createImage("/image/resultbg.lbm");
            // 게임 메뉴 화면.
imgContinueGame = Image.createImage("/image/continuegame.lbm"); /* * Load Message Images. */ // 고를 선택했을때의 메시지. imgMsgGo = Image.createImage("/image/anigo.lbm"); // 스톱을 선택했을때의 메시지. imgMsgStop = Image.createImage("/image/anistop.lbm"); // 뻑을 당했을때의 메시지. imgMsgPpuck = Image.createImage("/image/anippuk.lbm"); // 쪽을 했을때의 메시지. imgMsgJjok = Image.createImage("/Image/anijjok.lbm"); // 따닥 했을때의 메시지. imgMsgDdadak = Image.createImage("/Image/aniddadak.lbm"); // 쓸을 했을때의 메시지. imgMsgSseul = Image.createImage("/image/aniclear.lbm"); // 흔들었을때의 메시지. imgMsgShake = Image.createImage("/image/anishake.lbm"); // 폭탄일때의 메시지. imgMsgBomb = Image.createImage("/image/anibomb.lbm"); } catch(Exception e) {} } /** * 다이얼로그의 border를 그려줌. * @param g * @param borderType */ public void drawBorder(Graphics g, byte borderType) { switch(borderType) { case SELECTTWOCARD: // 두장의 카드를 선택 중일때, g.drawImage(imgSelectTwoCard, width/2, height/2, Graphics.HCENTER|Graphics.VCENTER); break; case SELECTGOOKJIN: // 국진을 선택 중일때, g.drawImage(imgSelectGookjin, width/2, height/2, Graphics.HCENTER|Graphics.VCENTER); break; case SELECTGOSTOP: // 고/스톱을 선택 중일때, g.drawImage(imgSelectGoStop, width/2, height/2, Graphics.HCENTER|Graphics.VCENTER); break; case SELECTSHAKE: // 흔들기를 선택 중일때, g.drawImage(imgSelectShake, width/2, height/2, Graphics.HCENTER|Graphics.VCENTER); break; case SELECTBOMB: // 폭탄을 선택 중일때, g.drawImage(imgSelectBomb, width/2, height/2, Graphics.HCENTER|Graphics.VCENTER); break; case RESULT: // 결과 화면을 보는 중일때, g.drawImage(imgResult, width/2, height/2, Graphics.HCENTER|Graphics.VCENTER); break;
case CONTINUEGAME: // 게임 중의 메뉴 화면.
g.drawImage(imgContinueGame, width/2, height/2, Graphics.HCENTER|Graphics.VCENTER); } } /** * 메시지를 출력한다. */ public void drawMessage(Graphics g, byte messageType, byte cntGo) { switch(messageType) { case MSG_GO: // 고. Graphics2D g2d = Graphics2D.getGraphics2D(g); g2d.drawImage((width-38)/2, (height-18)/2, imgMsgGo, (cntGo-1)*38, 0, 38, 18, Graphics2D.DRAW_COPY); break; case MSG_STOP: // 스톱. g.drawImage(imgMsgStop, width/2, height/2, Graphics.HCENTER|Graphics.VCENTER); break; case MSG_PPUCK: // 뻑. g.drawImage(imgMsgPpuck, width/2, height/2, Graphics.HCENTER|Graphics.VCENTER); break; case MSG_JJOK: // 쪽. g.drawImage(imgMsgJjok, width/2, height/2, Graphics.HCENTER|Graphics.VCENTER); break; case MSG_SSEUL: // 쓸. g.drawImage(imgMsgSseul, width/2, height/2, Graphics.HCENTER|Graphics.VCENTER); break; case MSG_SHAKE: // 흔듬. g.drawImage(imgMsgShake, width/2, height/2, Graphics.HCENTER|Graphics.VCENTER); break; case MSG_BOMB: // 폭탄. g.drawImage(imgMsgBomb, width/2, height/2, Graphics.HCENTER|Graphics.VCENTER); break; } } /** * 자원 해제. */ public void cleanUp() { imgSelectTwoCard = null; imgSelectGookjin = null; imgSelectGoStop = null; imgSelectShake = null; imgSelectBomb = null; imgResult = null; imgMsgGo = null; imgMsgStop = null; imgMsgPpuck = null; imgMsgJjok = null; imgMsgDdadak = null; imgMsgSseul = null; imgMsgShake = null; imgMsgBomb = null; System.gc(); } }

역시나 별건 없죠? 예전과 동일합니다.

처음에 생성자에서 Canvas를 저장하고, 화면 사이즈를 초기화 한 후, 모든 이미지를 로드합니다.


그리고 drawBorder() 함수는, 단순히 화면 중앙에 Border 형식의 다이얼로그를 출력해줍니다.


다음에 나오는 drawMessage() 역시 마찬가지 함수입니다.

이 drawMessage()는 메시지 형식의 다이얼로그를 출력해준다는 것 만이 다르죠.


여태까지의 게임에서는 g.drawString() 함수를 이용해서, 모든 메시지를 처리했죠.

게임 종료 처리도 구현이 안되어 있었구요. 이번시간에 그걸 해보도록 하겠습니다.


먼저 두장의 카드중 하나를 선택하는 부분을 수정해보도록 할까요?

/**
 * 카드 둘중 하나를 선택할때...
 * @param g
 */
private void drawSelectTwoCards(Graphics g)
{
    byte index;

    drawRunningGame(g);
    /* 카드 두장 중 하나를 선택한다. */
    dialog.drawBorder(g, CyDialog.SELECTTWOCARD);

    // 두 종류의 카드를 보여줌.
    if(room.slot[0] != room.CARD_NULL)
        index = 0;
    else if(room.slot[1] != room.CARD_NULL)
        index = 1;
    else return;

    drawCard(40, 66, room.getMonth(room.slot[index])[0]);
    drawCard(65, 66, room.getMonth(room.slot[index])[1]);
}

지난시간과 거의 다름이 없지만, g.drawString() 이 함수가 삭제되고,

dialog.drawBorder(g, CyDialog.SELECTTWOCARD);

위 부분이 추가 되었죠.

그리고 이전에는 단순히 문자열만이 출력되어서, 어떤 카드중에 하나를 선택하라는 건지 알수가 없었죠.

이제는 맨 아래의 drawCard() 함수 두개가 선택해야 하는 카드를 화면에 그려주어,

어떤 카드 중에 선택을 하라는 것인지 확실히 알 수가 있습니다.


< 두장의 카드를 선택하는 화면 >


이제, 흔들기/폭탄시의 다이얼로그를 출력 해 보도록 할까요?

/**
 * 흔듬/폭탄 여부를 선택 중일때...
 * @param g
 */
private void drawSelectShake(Graphics g)
{
    drawRunningGame(g);
if(shakeType == SHAKE) // 흔듬 선택 중일때, dialog.drawBorder(g, CyDialog.SELECTSHAKE); else /* if(shakeType == BOMB) */ // 폭탄 선택 중일때, dialog.drawBorder(g, CyDialog.SELECTBOMB); }

흔들기/폭탄 선택 다이얼로그는 단순히, 이미지 한장을 출력해 주면 됩니다.

단지, 흔들기 일때의 이미지와, 폭탄일때의 이미지가 다르므로, 그것만 구분해서 출력해 주면 되겠죠.


< 흔듬 여부를 선택하는 화면 >


다음에 나오는 국진 선택화면이나, 고/스톱 선택화면은 모두 화면 중앙에 이미지를 출력하는것 뿐입니다.

/**
 * 국진의 사용을 선택 중일때,
 * @param g
 */
private void drawSelectGookjin(Graphics g)
{
    drawRunningGame(g);
    dialog.drawBorder(g, CyDialog.SELECTGOOKJIN);
}

/**
 * 고/스톱을 선택 중일때...
 * @param g
 */
private void drawSelectGoStop(Graphics g)
{
    drawRunningGame(g);
    dialog.drawBorder(g, CyDialog.SELECTGOSTOP);
}

그냥 현재 게임 화면을 먼저 그려준 후 , (drawRunningGame())

그 위에 각 상황에 맞는 이미지를 하나 출력 해 준 것 뿐이죠.

아래는 각각의 상황의 출력 결과입니다.



< 국진의 선택 화면 >

< 고/스톱 선택 화면 >


이번에는 결과 화면을 출력해 주도록 하겠습니다.

예전에는 그냥 g.drawString() 함수를 이용해서, "플레이어 승!", "컴퓨터 승!" 혹은 "나가리!" 와 같이,

단순히 문자열만 출력해주는 아~주 초라했던 인터페이스를 가지고 있었죠.


drawResult() 함수를 CyDialog 클래스를 이용해서 좀더 수정해 보았습니다.















☆

☆

☆







☆

☆

☆
/**
 * 결과 화면을 그려준다.
 * @param g
 */
private void drawResult(Graphics g)
{
    drawRunningGame(g);

    // 결과 창을 그려줌.
    dialog.drawBorder(g, CyDialog.RESULT);

    // 나가리라면...
    if(room.getNagari() == true)
    {
        if(gameEnd == false)
            gameEnd = true;

        g.setColor(0);
        g.drawString("나가리", width/2, 73, Graphics.HCENTER|Graphics.TOP);
    }
    else
    {
        /* 벌칙. */
        byte goBak; // 고박.
        byte peeBak; // 피박.
        byte kwangBak; // 광박.
        byte mungDda; // 멍따.

        int obtainedMoney=0; // 획득 머니.

        switch(curTurn)
        {
        case User.PLAYER: // 플레이어의 턴일때,
            g.setColor(0);
            g.drawString("플레이어 승", width/2, 73, 
                                Graphics.HCENTER|Graphics.TOP);

            // 상대방이 고를 한번 이상 했었다면, - 고박일경우 돈 두배 획득.
            goBak = (room.getCntGo(User.COMPUTER) >= 1)? 
                                (byte)2 : (byte)1; 
// 상대방의 피가 7장 이하라면, 피박. - 피박일경우 돈 두배 획득. peeBak = (room.getNumOfPee(User.COMPUTER) < 7)? (byte)2 : (byte)1;
// 상대방의 광이 없다면, 광박. - 광박일경우, 돈 두배 획득. kwangBak = (room.getNumOfKwang(User.COMPUTER) == 0)? (byte)2 : (byte)1;
// 상대방의 열이 7장 이상이라면, 멍따.
- 멍따일 경우, 돈 두배. mungDda = (room.getNumOfYeul(User.COMPUTER) >= 7)? (byte)2 : (byte)1; if(gameEnd == false) { gameEnd = true; obtainedMoney = room.MONEY_PER_POINT *room.getRealPoint(User.PLAYER) *goBak*kwangBak*peeBak*mungDda; // 플레이어의 돈 증가. room.addMoney(curTurn, obtainedMoney); // 컴퓨터의 돈 감소. room.addMoney(curTurn, -obtainedMoney); } g2d.drawImage(18, 45, sprWinLose, 0, 0, 15, 12, Graphics2D.DRAW_COPY); // 승. g.drawString("" + room.getCntGo(curTurn), 30, 59, Graphics.LEFT|Graphics.TOP); // 고 횟수. g.drawString("" + room.getRealPoint(curTurn), 80, 47, Graphics.LEFT|Graphics.TOP); // 점수. g.drawString("" + room.getCntShake(curTurn), 80, 59, Graphics.LEFT|Graphics.TOP); // 흔듬 횟수. g.drawString("획득 금액 +" + obtainedMoney, width/2, 89, Graphics.HCENTER|Graphics.TOP); break; case User.COMPUTER: // 컴퓨터의 턴일때, g.setColor(0); g.drawString("컴퓨터 승", width/2, 73, Graphics.HCENTER|Graphics.TOP); // 상대방이 고를 한번 이상 했었다면, goBak = (room.getCntGo(User.COMPUTER) >= 1)? (byte)2 : (byte)1; // 고박일경우 돈 두배 획득. // 상대방의 피가 7장 이하라면, 피박. peeBak = (room.getNumOfPee(User.PLAYER) < 7)? (byte)2 : (byte)1; // 피박일경우 돈 두배 획득. // 상대방의 광이 없다면, kwangBak = (room.getNumOfKwang(User.PLAYER) == 0)? (byte)2: (byte)1; // 광박일경우, 돈 두배 획득. // 상대방의 열이 7장 이상이라면, 멍따. mungDda = (room.getNumOfYeul(User.COMPUTER) >= 7)? (byte)2 : (byte)1; // 멍따일 경우, 돈 두배. if(gameEnd == false) { gameEnd = true; obtainedMoney = room.MONEY_PER_POINT *room.getRealPoint(User.COMPUTER) *goBak*kwangBak*peeBak*mungDda; // 플레이어의 돈 감소. room.addMoney(curTurn, -obtainedMoney); // 컴퓨터의 돈 증가. room.addMoney(curTurn, obtainedMoney); } g2d.drawImage(18, 45, sprWinLose, 15, 0, 15, 12, Graphics2D.DRAW_COPY); // 패. g.drawString("" + room.getCntGo(curTurn), 30, 59, Graphics.LEFT|Graphics.TOP); // 고 횟수. g.drawString("" + room.getRealPoint(curTurn), 80, 47, Graphics.LEFT|Graphics.TOP); // 점수. g.drawString("" + room.getCntShake(curTurn), 80, 59, Graphics.LEFT|Graphics.TOP); // 흔듬 횟수. g.drawString("획득 금액 +" + obtainedMoney, width/2, 89, Graphics.HCENTER|Graphics.TOP); } } }

파란색 별은 새롭게 추가된 부분, 주황색 별은 수정된 부분을 의미합니다.

소스가 조금 길긴 하지만, 자세히 보면, 이미지랑 문자열 출력해주는것 밖에 추가 된 것이 없죠^^;



가장 윗 부분을 보시면, 이제까지와 마찬가지로,

CyDialog 클래스의 drawBorder() 함수를 이용해서, 결과 화면을 그려주었습니다.

그리고 주황색 별()로 표시된 부분은 지난시간과 똑같지만, 문자열의 좌표가 약간 변경되었습니다.


그 다음에 추가된 부분들은 모두, 결과창 이미지의 좌표에 맞게 문자열을 출력해주는 부분들일 뿐입니다.

문자열들의 좌표는 포토샾에서 계산을 해서 집적 숫자 값으로 넘겨 주었습니다.


< 게임이 끝난후의 결과 화면 >

 

Posted by maysent
: