Chào mừng đến với Diễn đàn lập trình - Cộng đồng lập trình.
Trang 2 của 3 Đầu tiênĐầu tiên 123 CuốiCuối
Kết quả 11 đến 20 của 28
  1. #11
    NGÀY 21: Các tính toán để di chuyển Tank

    Kiểm tra Tank bị chặn bởi khung chơi

    Mã:
    BOOL TankE_HitBorder(PENEMYTANK pTank){    if(pTank->iFrend == FM_LEFT     && pTank->x-1 < 0)          return TRUE;        // Dung bien ben trai    if(pTank->iFrend == FM_UP       && pTank->y-1 < 0)          return TRUE;        // Dung bien phia tren    if(pTank->iFrend == FM_RIGHT    && pTank->x+1 > LARGE*12)   return TRUE;        // Dung bien ben phai    if(pTank->iFrend == FM_DOWN     && pTank->y+1 > LARGE*12)   return TRUE;        // Dung bien phia duoi    return FALSE;}BOOL Tank_HitBorder(PTANK pTank){    if(pTank->iFrend == FM_LEFT     && pTank->x-1 < 0)          return TRUE;        // Dung bien ben trai    if(pTank->iFrend == FM_UP       && pTank->y-1 < 0)          return TRUE;        // Dung bien phia tren    if(pTank->iFrend == FM_RIGHT    && pTank->x+1 > LARGE*12)   return TRUE;        // Dung bien ben phai    if(pTank->iFrend == FM_DOWN     && pTank->y+1 > LARGE*12)   return TRUE;        // Dung bien phia duoi    return FALSE;}
    Kiểm tra Tank bị chặn bởi các Cells

    Mã:
    BOOL TankE_HitCell(PENEMYTANK pTank,BYTE pCells[52][52]){    POINT       Cell[4];    int         i;    BYTE        iStyle;     if(pTank->iFrend == FM_LEFT)                // Tank dang di chuyen sang trai    {        for(i=0;i<4;i++)        {            Cell[i].x = (pTank->x-1)/SMALL;            Cell[i].y = pTank->y/SMALL + i;        }    }    else if(pTank->iFrend == FM_UP)             // Tank dang di chuyen di len    {        for(i=0;i<4;i++)        {            Cell[i].x = pTank->x/SMALL + i;            Cell[i].y = (pTank->y-1)/SMALL;        }    }    else if(pTank->iFrend == FM_RIGHT)          // Tank dang di chuyen sang phai    {        for(i=0;i<4;i++)        {            Cell[i].x = (pTank->x+LARGE)/SMALL;            Cell[i].y = pTank->y/SMALL + i;        }    }    else                                        // Tank dang di chuyen di xuong    {        for(i=0;i<4;i++)        {            Cell[i].x = pTank->x/SMALL + i;            Cell[i].y = (pTank->y+LARGE)/SMALL;        }    }    for(i=0;i<4;i++)    // Tank se bi can khi dung phai: Brick,Steel,River,House    {        iStyle = pCells[Cell[i].x][Cell[i].y];        if(iStyle == TC_BRICK || iStyle == TC_STEEL || iStyle == TC_RIVER || iStyle == TC_HOUSE)            return TRUE;    }    return FALSE;}BOOL Tank_HitCell(PTANK pTank,BYTE pCells[52][52]){    POINT       Cell[4];    int         i;    BYTE        iStyle;     if(pTank->iFrend == FM_LEFT)                // Tank dang di chuyen sang trai    {        for(i=0;i<4;i++)        {            Cell[i].x = (pTank->x-1)/SMALL;            Cell[i].y = pTank->y/SMALL + i;        }    }    else if(pTank->iFrend == FM_UP)             // Tank dang di chuyen di len    {        for(i=0;i<4;i++)        {            Cell[i].x = pTank->x/SMALL + i;            Cell[i].y = (pTank->y-1)/SMALL;        }    }    else if(pTank->iFrend == FM_RIGHT)          // Tank dang di chuyen sang phai    {        for(i=0;i<4;i++)        {            Cell[i].x = (pTank->x+LARGE)/SMALL;            Cell[i].y = pTank->y/SMALL + i;        }    }    else                                        // Tank dang di chuyen di xuong    {        for(i=0;i<4;i++)        {            Cell[i].x = pTank->x/SMALL + i;            Cell[i].y = (pTank->y+LARGE)/SMALL;        }    }    for(i=0;i<4;i++)    // Tank se bi can khi dung phai: Brick,Steel,House. Can xem xet Tank co vuot song hay khong ?    {        iStyle = pCells[Cell[i].x][Cell[i].y];        if(iStyle == TC_BRICK || iStyle == TC_STEEL || iStyle == TC_HOUSE)            return TRUE;        if(!pTank->bRiver && iStyle == TC_RIVER)            return TRUE;    }    return FALSE;}
    Kiểm tra Tank bị chặn bởi TankE

    Mã:
    BOOL TankE_HitTankE(PENEMYTANK pTank,CPtrArray * arTankE){    PENEMYTANK      pAnother;    int             i,cCount;     cCount = arTankE->GetSize();    for(i=0;i<cCount;i++)    if(pAnother = (PENEMYTANK)arTankE->GetAt(i))    if(pTank != pAnother)    {        if(pTank->iFrend == FM_LEFT)                    // Sang trai        {            if(pTank->x-1 >= pAnother->x)            if(abs(pTank->x - pAnother->x) <= LARGE)            if(abs(pTank->y - pAnother->y) < LARGE)                return TRUE;        }        else if(pTank->iFrend == FM_UP)                 // Di len        {            if(pTank->y-1 >= pAnother->y)            if(abs(pTank->x - pAnother->x) < LARGE)            if(abs(pTank->y - pAnother->y) <= LARGE)                return TRUE;        }        else if(pTank->iFrend == FM_RIGHT)              // Sang phai        {            if(pTank->x+1 <= pAnother->x)            if(abs(pTank->x - pAnother->x) <= LARGE)            if(abs(pTank->y - pAnother->y) < LARGE)                return TRUE;        }        else                                            // Di xuong        {            if(pTank->y+1 <= pAnother->y)            if(abs(pTank->x - pAnother->x) < LARGE)            if(abs(pTank->y - pAnother->y) <= LARGE)                return TRUE;        }    }    return FALSE;}BOOL Tank_HitTankE(PTANK pTank,CPtrArray * arTankE){    PENEMYTANK      pTankE;    int             i,cCount;     cCount = arTankE->GetSize();    for(i=0;i<cCount;i++)    if(pTankE = (PENEMYTANK)arTankE->GetAt(i))    {        if(pTank->iFrend == FM_LEFT)                    // Sang trai        {            if(pTank->x-1 >= pTankE->x)            if(abs(pTank->x - pTankE->x) <= LARGE)            if(abs(pTank->y - pTankE->y) < LARGE)                return TRUE;        }        else if(pTank->iFrend == FM_UP)                 // Di len        {            if(pTank->y-1 >= pTankE->y)            if(abs(pTank->x - pTankE->x) < LARGE)            if(abs(pTank->y - pTankE->y) <= LARGE)                return TRUE;        }        else if(pTank->iFrend == FM_RIGHT)              // Sang phai        {            if(pTank->x+1 <= pTankE->x)            if(abs(pTank->x - pTankE->x) <= LARGE)            if(abs(pTank->y - pTankE->y) < LARGE)                return TRUE;        }        else                                            // Di xuong        {            if(pTank->y+1 <= pTankE->y)            if(abs(pTank->x - pTankE->x) < LARGE)            if(abs(pTank->y - pTankE->y) <= LARGE)                return TRUE;        }    }    return FALSE;}
    Kiểm tra Tank bị chặn bởi Tank ta

    Mã:
    BOOL TankE_HitTank(PENEMYTANK pTank){    if(g_TankL.bReady)    {        if(pTank->iFrend == FM_LEFT)                    // Sang trai        {            if(pTank->x-1 >= g_TankL.x)            if(abs(pTank->x - g_TankL.x) <= LARGE)            if(abs(pTank->y - g_TankL.y) < LARGE)                return TRUE;        }        else if(pTank->iFrend == FM_UP)                 // Di len        {            if(pTank->y-1 >= g_TankL.y)            if(abs(pTank->x - g_TankL.x) < LARGE)            if(abs(pTank->y - g_TankL.y) <= LARGE)                return TRUE;        }        else if(pTank->iFrend == FM_RIGHT)              // Sang phai        {            if(pTank->x+1 <= g_TankL.x)            if(abs(pTank->x - g_TankL.x) <= LARGE)            if(abs(pTank->y - g_TankL.y) < LARGE)                return TRUE;        }        else                                            // Di xuong        {            if(pTank->y+1 <= g_TankL.y)            if(abs(pTank->x - g_TankL.x) < LARGE)            if(abs(pTank->y - g_TankL.y) <= LARGE)                return TRUE;        }    }    if(g_TankR.bReady)    {        if(pTank->iFrend == FM_LEFT)                    // Sang trai        {            if(pTank->x-1 >= g_TankR.x)            if(abs(pTank->x - g_TankR.x) <= LARGE)            if(abs(pTank->y - g_TankR.y) < LARGE)                return TRUE;        }        else if(pTank->iFrend == FM_UP)                 // Di len        {            if(pTank->y-1 >= g_TankR.y)            if(abs(pTank->x - g_TankR.x) < LARGE)            if(abs(pTank->y - g_TankR.y) <= LARGE)                return TRUE;        }        else if(pTank->iFrend == FM_RIGHT)              // Sang phai        {            if(pTank->x+1 <= g_TankR.x)            if(abs(pTank->x - g_TankR.x) <= LARGE)            if(abs(pTank->y - g_TankR.y) < LARGE)                return TRUE;        }        else                                            // Di xuong        {            if(pTank->y+1 <= g_TankR.y)            if(abs(pTank->x - g_TankR.x) < LARGE)            if(abs(pTank->y - g_TankR.y) <= LARGE)                return TRUE;        }    }    return FALSE;}BOOL Tank_HitTank(PTANK pTank){    PTANK       pAnother;     if(!pTank || !g_TankL.bReady || !g_TankR.bReady)        return FALSE;    if(pTank == &g_TankL)   pAnother = &g_TankR;    else                    pAnother = &g_TankL;     if(pTank->iFrend == FM_LEFT)                    // Sang trai    {        if(pTank->x-1 >= pAnother->x)        if(abs(pTank->x - pAnother->x) <= LARGE)        if(abs(pTank->y - pAnother->y) < LARGE)            return TRUE;    }    else if(pTank->iFrend == FM_UP)                 // Di len    {        if(pTank->y-1 >= pAnother->y)        if(abs(pTank->x - pAnother->x) < LARGE)        if(abs(pTank->y - pAnother->y) <= LARGE)            return TRUE;    }    else if(pTank->iFrend == FM_RIGHT)              // Sang phai    {        if(pTank->x+1 <= pAnother->x)        if(abs(pTank->x - pAnother->x) <= LARGE)        if(abs(pTank->y - pAnother->y) < LARGE)            return TRUE;    }    else                                            // Di xuong    {        if(pTank->y+1 <= pAnother->y)        if(abs(pTank->x - pAnother->x) < LARGE)        if(abs(pTank->y - pAnother->y) <= LARGE)            return TRUE;    }    return FALSE;}
    Tất cả các hàm trên không khó hiểu lắm vì nó chỉ thiên về tính toán.
    ( Nếu thấy khó hiểu, các bạn cứ nêu ra mình sẽ giải thích tỉ mỉ hơn).
    Sau đây là 2 hàm tổng hợp các hàm trên

    Mã:
    BOOL TankE_CanStepByStep(PENEMYTANK pTank,BYTE pCells[52][52]){    if(TankE_HitBorder(pTank))              return FALSE;    if(TankE_HitCell(pTank,pCells))         return FALSE;    if(TankE_HitTankE(pTank,&g_arTankE))    return FALSE;    if(TankE_HitTank(pTank))                return FALSE;    return TRUE;}BOOL Tank_CanStepByStep(PTANK pTank,BYTE pCells[52][52]){    if(Tank_HitBorder(pTank))               return FALSE;    if(Tank_HitCell(pTank,pCells))          return FALSE;    if(Tank_HitTankE(pTank,&g_arTankE))     return FALSE;    if(Tank_HitTank(pTank))                 return FALSE;    return TRUE;}
    "CanStepByStep" có thể hiểu là "Có thể di chuyển Tank theo hướng có sẵn 1 Pixel".
    Và khi đã "CanStepByStep" thì tại sao không "StepByStep"

    Mã:
    void TankE_StepByStep(PENEMYTANK pTank){    if(pTank->iFrend == FM_LEFT)        pTank->x --;    else if(pTank->iFrend == FM_UP)     pTank->y --;    else if(pTank->iFrend == FM_RIGHT)  pTank->x ++;    else                                pTank->y ++;}void Tank_StepByStep(PTANK pTank){    if(pTank->iFrend == FM_LEFT)        pTank->x --;    else if(pTank->iFrend == FM_UP)     pTank->y --;    else if(pTank->iFrend == FM_RIGHT)  pTank->x ++;    else                                pTank->y ++;}
    Hai hàm cuối cùng của ngày hôm nay

    Mã:
    BOOL TankE_CanRotate4Frend(PENEMYTANK pTank){    if(pTank->x % MEDIUM == 0 && pTank->y % MEDIUM == 0)        return TRUE;    return FALSE;}BOOL Tank_CanRotate4Frend(PTANK pTank){    if(pTank->x % MEDIUM == 0 && pTank->y % MEDIUM == 0)        return TRUE;    return FALSE;}
    Trong trò chơi này, tất cả các TankE và Tank ta di chuyển theo " tọa độ x hoặc y theo đơn vị 2 SmallCells".
    Khi Tank di chuyển ngang, tọa độ y của nó luôn thỏa điều kiện : y % MEDIUM == 0.
    Khi Tank di chuyển dọc, tọa độ x của nó luôn thỏa điều kiện : x % MEDIUM == 0.
    Trước khi cho phép Tank bất kỳ chuyển hướng vuông góc với hướng đang có, chúng ta phải kiểm tra theo 2 hàm này.

    Ngày hôm nay mã nhiều rùi, nghỉ thui, hẹn gặp lại các huynh đệ.
    [IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG]

  2. #12
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    NGÀY 22: Tiếp tục các tính toán di chuyen cho Enemy Tank
    Thêm vào các biến toàn cục sau:

    Mã:
    CPtrArray               g_arWave(TRUE);             // WaveSoundDATASETUP               g_DataSetup;
    Mã:
    void TankE_BackRotate(PENEMYTANK pTank)     // Quay lui TankE{    if(pTank->iFrend == FM_LEFT)        pTank->iFrend = FM_RIGHT;    else if(pTank->iFrend == FM_UP)     pTank->iFrend = FM_DOWN;    else if(pTank->iFrend == FM_RIGHT)  pTank->iFrend = FM_LEFT;    else                                pTank->iFrend = FM_UP;}void TankE_RotateRandom(PENEMYTANK pTank){    if(pTank->iSmart > 0)   // Tăng cường xác suất TankE di chuyển tới bộ chỉ huy của ta    {        if(rand()%3 == 0)                   pTank->iFrend = FM_DOWN;        else if(rand()%3 == 0)        {            if(pTank->x > (SMALL*52)/2)     pTank->iFrend = FM_LEFT;            else                            pTank->iFrend = FM_RIGHT;        }        else                                pTank->iFrend = rand()%4 + 1;    }    else                                    pTank->iFrend = rand()%4 + 1;}
    Trong hàm quay ngẫu nhiên ở trên, nếu TankE có mức độ tinh quái bất kỳ, chúng ta cố gắng tăng xác suất nó di chuyển tới "khung thành" của bên ta.
    Điều này gây áp lực cho người chơi phải mau chóng bắn hạ nó nếu không muốn bị dồn vào thế thụ động.


    Mã:
    BOOL TankE_IsFaceTank(PENEMYTANK pTankE,PTANK pTank){    if(pTank->bReady)                               // Tank ta đang hoạt động    if(abs(pTankE->iFrend - pTank->iFrend) == 2)    // TankE và Tank ta đang di chuyển cùng phương    if(abs(pTankE->x - pTank->x) < LARGE || abs(pTankE->y - pTank->y) < LARGE)  // 2 Tank có thể nhìn thấy nhau, tiếp theo là kiểm tra đối diện    {        if((pTankE->iFrend == FM_LEFT   && pTankE->x > pTank->x)        || (pTankE->iFrend == FM_UP     && pTankE->y > pTank->y)        || (pTankE->iFrend == FM_RIGHT  && pTankE->x < pTank->x)        || (pTankE->iFrend == FM_DOWN   && pTankE->y < pTank->y))        return TRUE;    }    return FALSE;}
    Hàm trên xác định xem TankE có đối mặt với Tank của ta không.


    Mã:
    void TankE_Shoot(PENEMYTANK pTank){    PBULLETE        pBullE;    CWaveSound *    pWave;    CHAR            szWave[MAX_PATH];     if(pBullE = (PBULLETE)malloc(sizeof(BULLETE)))    {        // Chuyển giao các thuộc tính từ TankE cho viên đạn, tọa độ ban đầu là đầu nòng súng        pBullE->bBullF  = pTank->bBullF;        pBullE->iFrend  = pTank->iFrend;        pBullE->iSpeed  = pTank->iShoot;        if(pTank->iFrend == FM_LEFT)        {            pBullE->x       = pTank->x - SMALL/2;            pBullE->y       = pTank->y + SMALL + SMALL/2;        }        else if(pTank->iFrend == FM_UP)        {            pBullE->x       = pTank->x + SMALL + SMALL/2;            pBullE->y       = pTank->y - SMALL/2;        }        else if(pTank->iFrend == FM_RIGHT)        {            pBullE->x       = pTank->x + LARGE + SMALL/2;            pBullE->y       = pTank->y + SMALL + SMALL/2;        }        else        {            pBullE->x       = pTank->x + SMALL + SMALL/2;            pBullE->y       = pTank->y + LARGE + SMALL/2;        }        if(g_arBullE.Add(pBullE))        {            // Xem xét xuất âm thanh ra loa            if(g_DataSetup.sndEnemyShoot)            {                GetModuleFileName(NULL,szWave,MAX_PATH);                PathRemoveFileSpec(szWave);                lstrcat(szWave,"\\Tank2D\\ETankShoot.wav");                if(PathFileExists(szWave))                if(pWave = new CWaveSound())                {                    if(!g_arWave.Add(pWave))                        delete pWave;                    else                        pWave->Play(szWave,g_lpDS,FALSE);                }            }        }        else            free(pBullE);    }}
    Tham số duy nhất của hàm trên là con trỏ tới TankE mà bắn ra viên đạn.

    Sau đây là hàm cuối cùng của ngày hôm nay

    Mã:
    void TankE_Update(PENEMYTANK pTank,BYTE pCells[52][52]){    int         cStep;    BOOL        bStep;     if(TankE_CanRotate4Frend(pTank))    {        if((( pTank->iRequest == FM_LEFT || pTank->iRequest == FM_RIGHT ) && ( pTank->iFrend == FM_UP   || pTank->iFrend == FM_DOWN  ))         ||(( pTank->iRequest == FM_UP   || pTank->iRequest == FM_DOWN  ) && ( pTank->iFrend == FM_LEFT || pTank->iFrend == FM_RIGHT )))            pTank->iFrend = pTank->iRequest;        else if(rand()%10 == 0)            TankE_RotateRandom(pTank);        pTank->iRequest = FM_NULL;    }    cStep = pTank->iSpeed;    bStep = FALSE;    while(cStep>0)    {        if(TankE_CanStepByStep(pTank,pCells))        {            TankE_StepByStep(pTank);            bStep = TRUE;            cStep --;        }        else        {            if(rand()%50==0)                TankE_Shoot(pTank);            else if(rand()%50==0)            {                TankE_BackRotate(pTank);                pTank->iRequest = rand()%4 + 1;            }            break;        }    }    if(bStep)    {        if(++pTank->iFrame == 4)             pTank->iFrame = 0;        if(rand()%150==0)            TankE_Shoot(pTank);    }    if(pTank->iSmart > 1 && rand()%20 == 0)     if(TankE_IsFaceTank(pTank,&g_TankL) || TankE_IsFaceTank(pTank,&g_TankR))        // Khi đối mặt với Tank ta sẽ khai hỏa tức thì        TankE_Shoot(pTank);}
    Hàm này thật sự rất khó mã, mình phải thay đổi hàng chục lần và tạm chấp nhận với cài đặt như trên. Diễn giải như sau:
    Đầu tiên xem xét Tank có ở vị trí quay được 4 hướng không, nếu được -> xem xét yêu cầu đổi hướng và hướng hiện tại. Nếu là vuông góc thì đổi hướng di chuyển theo hướng yêu cầu.
    Nếu không chúng ta ngẫu nhiên có thể đổi hướng TankE một cách ngẫu nhiên. Sau đó tắt yêu cầu đổi hướng TankE.
    Chúng ta sẽ cho Tank tiến từng bước một cho tới khi bước đủ số bước hoặc không thể tiến được. Nếu là không thể tiến được, chúng ta sẽ cho Tank bắn ngẫu nhiên hoặc cho Tank quay lui và bật yêu cầu đổi hướng mới, song song đó nếu Tank bước được ít nhất 1 bước thì biến lưu có di chuyển được bật.
    Nếu biến lưu được bật, thay đổi khung hiển thị tới vị trí kế tiếp và xem xét cho Tank khai hỏa.
    Cuối cùng nếu TankE có thuộc tính thông minh lớn hơn 1 và đối mặt với Tank ta, chúng ta cũng xem xét cho TankE bắn.

    Ngày hôm nay tới đây thôi, chào tạm biệt !!! [IMG]images/smilies/17.gif[/IMG] [IMG]images/smilies/17.gif[/IMG] [IMG]images/smilies/17.gif[/IMG]

    - - - Nội dung đã được cập nhật ngày 16-03-2014 lúc 02:33 PM - - -</font>

    <font color="#0000FF">NGÀY 23:
    Tính toán để di chuyển Tank của chúng ta.

    Trước khi đi vào chủ điểm của ngày hôm nay, các bạn sửa giùm dòng mã 15 trong hàm TankE_Update() như sau:

    cStep = pTank->iSpeed;
    thành

    cStep = pTank->iSpeed * (TankE_MoveOnGlide(pTank,pCells) ? 2:1 );
    Tiếp theo tạo 2 hàm mới và đặt trước TankE_Update() như sau:

    Mã:
    BOOL TankE_MoveOnGlide(PENEMYTANK pTank,BYTE pCells[52][52]){    POINT       Cell[4];    int         i;     if(pTank->iFrend == FM_LEFT)                // Tank dang di chuyen sang trai    {        for(i=0;i<4;i++)        {            Cell[i].x = pTank->x/SMALL;            Cell[i].y = pTank->y/SMALL + i;        }    }    else if(pTank->iFrend == FM_UP)             // Tank dang di chuyen di len    {        for(i=0;i<4;i++)        {            Cell[i].x = pTank->x/SMALL + i;            Cell[i].y = pTank->y/SMALL;        }    }    else if(pTank->iFrend == FM_RIGHT)          // Tank dang di chuyen sang phai    {        for(i=0;i<4;i++)        {            Cell[i].x = (pTank->x+LARGE-1)/SMALL;            Cell[i].y = pTank->y/SMALL + i;        }    }    else                                        // Tank dang di chuyen di xuong    {        for(i=0;i<4;i++)        {            Cell[i].x = pTank->x/SMALL + i;            Cell[i].y = (pTank->y+LARGE-1)/SMALL;        }    }    for(i=0;i<4;i++)    if(pCells[Cell[i].x][Cell[i].y] != TC_GLIDE)        return FALSE;    return TRUE;}BOOL Tank_MoveOnGlide(PTANK pTank,BYTE pCells[52][52]){    POINT       Cell[4];    int         i;     if(pTank->iFrend == FM_LEFT)                // Tank dang di chuyen sang trai    {        for(i=0;i<4;i++)        {            Cell[i].x = pTank->x/SMALL;            Cell[i].y = pTank->y/SMALL + i;        }    }    else if(pTank->iFrend == FM_UP)             // Tank dang di chuyen di len    {        for(i=0;i<4;i++)        {            Cell[i].x = pTank->x/SMALL + i;            Cell[i].y = pTank->y/SMALL;        }    }    else if(pTank->iFrend == FM_RIGHT)          // Tank dang di chuyen sang phai    {        for(i=0;i<4;i++)        {            Cell[i].x = (pTank->x+LARGE-1)/SMALL;            Cell[i].y = pTank->y/SMALL + i;        }    }    else                                        // Tank dang di chuyen di xuong    {        for(i=0;i<4;i++)        {            Cell[i].x = pTank->x/SMALL + i;            Cell[i].y = (pTank->y+LARGE-1)/SMALL;        }    }    for(i=0;i<4;i++)    if(pCells[Cell[i].x][Cell[i].y] != TC_GLIDE)        return FALSE;    return TRUE;}
    Hai hàm này chỉ là xác định xem Tank có ở trên Cells trượt hay không thôi.


    Có lẽ chúng ta phải thay đổi kiểu cấu trúc TANK cho phù hợp theo yêu cầu phát sinh:

    Mã:
    typedef struct{    BOOL        bBullF;         // Tank nay ban dan lua ?    BOOL        bReady;         // Tank da san sang ?    BOOL        bRiver;         // Tank co the vuot song ?    int         cBulletJoin;    // So dan noi tiep nhau duoc phep ban tu 1->3    int         cLife;          // So lan song cua Tank    int         cSafety;        // So lan con lai Tank an toan trong che do duoc bao ve ? Khoi tao 1000    int         cTimes;         // So lan lam tre giua 2 vien dan    int         iFrame;         // Khung hien hanh trong bitmap    int         iFrend;         // Huong di chuyen hien hanh    int         iFroze;         // Thoi gian dong bang con lai - Khoi tao tu dau la 300    int         iPower;         // Suc manh cua Tank tu 1->5    int         iRequestFrend;  // Huong di chuyen duoc yeu cau    int         iShoot;         // Toc do di chuyen cua dan duoc ban tu Tank nay tu 5->10 Pixels trong 1 lan    int         iSpeed;         // Toc do di chuyen tu 1->3 Pixels trong 1 lan    int         x,y;            // Toa do LeftTop cua TankE tinh tu goc tren trai trong khung choi}TANK,*PTANK;
    Thêm 1 hàm cho phép Tank ta bắn

    Mã:
    void Tank_Shoot(PTANK pTank){    PBULLET         pBull;    CWaveSound *    pWave;    CHAR            szWave[MAX_PATH];    int             i;     if(pBull = (PBULLET)malloc(sizeof(BULLET)))    {        //         pBull->bBullF   = pTank->bBullF;        pBull->iFrend   = pTank->iFrend;        pBull->iSpeed   = pTank->iShoot;        if(pTank->iFrend == FM_LEFT)        {            pBull->x        = pTank->x - SMALL/2;            pBull->y        = pTank->y + SMALL + SMALL/2;        }        else if(pTank->iFrend == FM_UP)        {            pBull->x        = pTank->x + SMALL + SMALL/2;            pBull->y        = pTank->y - SMALL/2;        }        else if(pTank->iFrend == FM_RIGHT)        {            pBull->x        = pTank->x + LARGE + SMALL/2;            pBull->y        = pTank->y + SMALL + SMALL/2;        }        else        {            pBull->x        = pTank->x + SMALL + SMALL/2;            pBull->y        = pTank->y + LARGE + SMALL/2;        }        pBull->pTank = pTank;        if(pTank == & g_TankL)        {            if(g_arBullL.Add(pBull))            {                for(i=0;i<g_TankL.cBulletJoin;i++)                if(!g_TankL.pBull[i])                {                    g_TankL.pBull[i] = pBull;                    break;                }                if(g_DataSetup.sndOurShoot)                {                    GetModuleFileName(NULL,szWave,MAX_PATH);                    PathRemoveFileSpec(szWave);                    lstrcat(szWave,"\\Tank2D\\TankShoot.wav");                    if(PathFileExists(szWave))                    if(pWave = new CWaveSound())                    {                        if(!g_arWave.Add(pWave))                            delete pWave;                        else                            pWave->Play(szWave,g_lpDS,FALSE);                    }                }            }            else                free(pBull);        }        if(pTank == & g_TankR)        {            if(g_arBullR.Add(pBull))            {                for(i=0;i<g_TankR.cBulletJoin;i++)                if(!g_TankR.pBull[i])                {                    g_TankR.pBull[i] = pBull;                    break;                }                if(g_DataSetup.sndOurShoot)                {                    GetModuleFileName(NULL,szWave,MAX_PATH);                    PathRemoveFileSpec(szWave);                    lstrcat(szWave,"\\Tank2D\\TankShoot.wav");                    if(PathFileExists(szWave))                    if(pWave = new CWaveSound())                    {                        if(!g_arWave.Add(pWave))                            delete pWave;                        else                            pWave->Play(szWave,g_lpDS,FALSE);                    }                }            }            else                free(pBull);        }    }}
    Hàm này khác chút ít so với hàm TankE_Shoot() ở chỗ phải xác định thêm Tank bắn là TankL hay TankR và lưu trữ mối tương quan Cha-Con giữa Tank-Bullet

    Sau đây là hàm cuối của ngày hôm nay, hàm này cũng thuộc hàng nhức xương khớp

    Mã:
    void Tank_Update(BYTE pCells[52][52]){    INPUTKEYBOARD       Keyboard;    INPUTMOUSE          Mouse;    int                 cStep;    BOOL                bStep;     if(g_TankL.iFroze > 0)        g_TankL.iFroze --;    if(g_TankL.bReady && g_TankL.iFroze == 0)    if(DirectX_GetInputKeyboard(&Keyboard))    {        if(Keyboard.bLeft)          g_TankL.iRequestFrend = FM_LEFT;        else if(Keyboard.bUp)       g_TankL.iRequestFrend = FM_UP;        else if(Keyboard.bRight)    g_TankL.iRequestFrend = FM_RIGHT;        else if(Keyboard.bDown)     g_TankL.iRequestFrend = FM_DOWN;        else                        g_TankL.iRequestFrend = FM_NULL;         if(g_TankL.iRequestFrend != FM_NULL)        {            if(g_TankL.iRequestFrend != g_TankL.iFrend)                 // Neu khac huong            {                if(abs(g_TankL.iRequestFrend - g_TankL.iFrend) == 2)    // Yeu cau quay nguoc                    g_TankL.iFrend = g_TankL.iRequestFrend;                else if(Tank_CanRotate4Frend(&g_TankL))                 // Quay vuong goc                    g_TankL.iFrend = g_TankL.iRequestFrend;            }            // Di chuyen Tank            cStep = g_TankL.iSpeed * (Tank_MoveOnGlide(&g_TankL,pCells) ? 2:1 );            bStep = FALSE;            while(cStep>0)            {                if(Tank_CanStepByStep(&g_TankL,pCells))                {                    Tank_StepByStep(&g_TankL);                    bStep = TRUE;                    cStep --;                }                else                    break;            }            if(bStep)            {                if(++ g_TankL.iFrame == 4)                    g_TankL.iFrame = 0;            }        }        // Nguoi choi dang nhan nut ban        if(Keyboard.bSpace)        if(++ g_TankL.cTimes >= 8)        {            g_TankL.cTimes = 0;            if(g_arBullL.GetSize() < g_TankL.cBulletJoin)                Tank_Shoot(&g_TankL);        }    }    if(g_TankR.iFroze > 0)        g_TankR.iFroze --;    if(g_TankR.bReady && g_TankR.iFroze == 0)    if(DirectX_GetInputMouse(&Mouse))    {        g_TankR.iRequestFrend = Mouse.iRotateFrend;        if(g_TankR.iRequestFrend != FM_NULL)        if(g_TankR.iRequestFrend != g_TankR.iFrend)        {            if(abs(g_TankR.iRequestFrend - g_TankR.iFrend) == 2)    // Yeu cau quay nguoc                g_TankR.iFrend = g_TankR.iRequestFrend;            else                                                    // Yeu cau quay vuong goc            {                if(Tank_CanRotate4Frend(&g_TankR))                                      g_TankR.iFrend = g_TankR.iRequestFrend;                else                                                // Neu chua the quay                {                    // Chúng ta xem xét 2 vị trí gần nhất mà Tank có thể quay được. Ưu tiên cho vị trí ở phía trước nếu Tank có thể di chuyển theo hướng đó mà không bị cản.                    // Trong trường hợp cả 2 vị trí là không thể di chuyển tới, cho Tank di chuyển tới được bao nhiêu cũng được.                    int     xTank = g_TankR.x;                    int     yTank = g_TankR.y;                    int     iFrend = g_TankR.iFrend;                    int     cStepForward = 0,cStepBack = 0;                    BOOL    bForward = FALSE, bBack = FALSE;                     while(Tank_CanStepByStep(&g_TankR,pCells) && cStepForward < MEDIUM)                    {                        cStepForward ++;                        Tank_StepByStep(&g_TankR);                        if(Tank_CanRotate4Frend(&g_TankR))                        {                            bForward = TRUE;                            break;                        }                    }                    g_TankR.x = xTank;                    g_TankR.y = yTank;                    if(iFrend == FM_LEFT)       g_TankR.iFrend = FM_RIGHT;                    else if(iFrend == FM_UP)    g_TankR.iFrend = FM_DOWN;                    else if(iFrend == FM_RIGHT) g_TankR.iFrend = FM_LEFT;                    else                        g_TankR.iFrend = FM_UP;                    while(Tank_CanStepByStep(&g_TankR,pCells) && cStepBack < MEDIUM)                    {                        cStepBack ++;                        Tank_StepByStep(&g_TankR);                        if(Tank_CanRotate4Frend(&g_TankR))                        {                            bBack = TRUE;                            break;                        }                    }                    g_TankR.x = xTank;                    g_TankR.y = yTank;                    if(bForward && bBack)                    {                        if(cStepForward <= cStepBack)   { cStep = cStepForward; g_TankR.iFrend = iFrend;}                        else                            cStep = cStepBack;                    }                    else if(bForward && !bBack)                    {                        cStep = cStepForward;                        g_TankR.iFrend = iFrend;                    }                    else if(!bForward && bBack)                        cStep = cStepBack;                    else                    {                        cStep = cStepForward; g_TankR.iFrend = iFrend;                    }                    //                    bStep = FALSE;                    while(cStep>0)                    {                        if(Tank_CanStepByStep(&g_TankR,pCells))                        {                            Tank_StepByStep(&g_TankR);                            bStep = TRUE;                            cStep --;                            if(Tank_CanRotate4Frend(&g_TankR))                            {                                g_TankR.iFrend = g_TankR.iRequestFrend;                                break;                            }                        }                        else                            break;                    }                    if(bStep)                    if(++ g_TankR.iFrame == 4)                        g_TankR.iFrame = 0;                }            }        }        // Di chuyen        if(Mouse.bRightPress)        {            cStep = g_TankR.iSpeed * (Tank_MoveOnGlide(&g_TankR,pCells) ? 2:1 );            bStep = FALSE;            while(cStep>0)            {                if(Tank_CanStepByStep(&g_TankR,pCells))                {                    Tank_StepByStep(&g_TankR);                    bStep = TRUE;                    cStep --;                }                else                    break;            }            if(bStep)            if(++ g_TankR.iFrame == 4)                g_TankR.iFrame = 0;        }        // Khai hoa        if(Mouse.bLeftPress)        if(++ g_TankR.cTimes >= 8)        {            g_TankR.cTimes = 0;            if(g_arBullR.GetSize() < g_TankR.cBulletJoin)                Tank_Shoot(&g_TankR);        }    }}
    Hàm cũng nhận Logic xử lý tương tự như TankE_Update() nhưng lấy dữ liệu theo cách Chủ động, các thao tác sẽ cố gắng phù hợp với sự điều khiển từ người chơi,
    hoàn toàn không có sự ngẫu nhiên nào ở đây.
    Viết được tới đây đã thấy nhức cả đầu, hoa mắt. Chương trình này chỉ nhỏ xíu mà đã vậy, mới thấy cảm phục các nhà làm phần mềm lắm thay !!!

    Dừng thôi ( Có ai muốn nhậu không hè ) [IMG]images/smilies/17.gif[/IMG] [IMG]images/smilies/17.gif[/IMG] [IMG]images/smilies/17.gif[/IMG]

  3. #13
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    NGÀY 24: Tính toán để di chuyển những viên đạn


    Mã:
    BOOL BulletE_HitBorder(PBULLETE pBullE){    if((pBullE->iFrend == FM_LEFT   && pBullE->x < 0)                   // Dung bien ben trai    || (pBullE->iFrend == FM_UP     && pBullE->y < 0)                   // Dung bien phia tren    || (pBullE->iFrend == FM_RIGHT  && pBullE->x > LARGE*13 - SMALL)    // Dung bien ben phai    || (pBullE->iFrend == FM_DOWN   && pBullE->y > LARGE*13 - SMALL))   // Dung bien phia duoi        return TRUE;    return FALSE;}BOOL Bullet_HitBorder(PBULLET pBull){    if((pBull->iFrend == FM_LEFT    && pBull->x < 0)                    // Dung bien ben trai    || (pBull->iFrend == FM_UP      && pBull->y < 0)                    // Dung bien phia tren    || (pBull->iFrend == FM_RIGHT   && pBull->x > LARGE*13 - SMALL)     // Dung bien ben phai    || (pBull->iFrend == FM_DOWN    && pBull->y > LARGE*13 - SMALL))    // Dung bien phia duoi        return TRUE;    return FALSE;}
    Các hàm này chỉ là trả về TRUE nếu viên đạn đã đụng vào khung chơi.


    Mã:
    BOOL BulletE_HitCell(PBULLETE pBullE,BYTE pCells[52][52])       // Ghi nho vien dan chi co the dung truc tiep 2 Cells{    POINT       Cell[4],Next[4];    int         i,x,y;    BYTE        iCell[4],iNext[4];    BOOL        bHitCell;     if(pBullE->iFrend == FM_LEFT)               // BulletE dang di chuyen sang trai    {        for(i=0;i<4;i++)        {            Cell[i].x = pBullE->x/SMALL;            Cell[i].y = pBullE->y/SMALL + i - 1;            Next[i].x = Cell[i].x - ((Cell[i].x > 0) ? 1:0);            Next[i].y = Cell[i].y;        }    }    else if(pBullE->iFrend == FM_UP)                // BulletE dang di chuyen di len    {        for(i=0;i<4;i++)        {            Cell[i].x = pBullE->x/SMALL + i - 1;            Cell[i].y = pBullE->y/SMALL;            Next[i].x = Cell[i].x;            Next[i].y = Cell[i].y - ((Cell[0].y > 0) ? 1:0);        }    }    else if(pBullE->iFrend == FM_RIGHT)         // BulletE dang di chuyen sang phai    {        for(i=0;i<4;i++)        {            Cell[i].x = pBullE->x/SMALL;            Cell[i].y = pBullE->y/SMALL + i - 1;            Next[i].x = Cell[i].x + ((Cell[0].x < 51) ? 1:0);            Next[i].y = Cell[i].y;        }    }    else                                        // BulletE dang di chuyen di xuong    {        for(i=0;i<4;i++)        {            Cell[i].x = pBullE->x/SMALL + i - 1;            Cell[i].y = pBullE->y/SMALL;            Next[i].x = Cell[i].x;            Next[i].y = Cell[i].y + ((Cell[0].y < 51) ? 1:0);        }    }    for(i=0;i<4;i++)    {        iCell[i] = pCells[Cell[i].x][Cell[i].y];        iNext[i] = pCells[Next[i].x][Next[i].y];    }    bHitCell = FALSE;    if(iCell[1] == TC_BRICK || iCell[1] == TC_STEEL || iCell[1] == TC_HOUSE    || iCell[2] == TC_BRICK || iCell[2] == TC_STEEL || iCell[2] == TC_HOUSE)        bHitCell = TRUE;    if(iCell[1] == TC_HOUSE || iCell[2] == TC_HOUSE)    {        for(x=24;x<28;x++)        for(y=48;y<52;y++)            pCells[x][y] = TC_FREE;     // Vi tri cua bo chi huy    }    if(iCell[1] == TC_BRICK)                                        // Neu Cell thu 2 la Brick    {        pCells[Cell[1].x][Cell[1].y] = TC_FREE;                     // Pha huy Brick        if(iCell[0] == TC_BRICK)                                    // Neu Cell dau tien la Brick            pCells[Cell[0].x][Cell[0].y] = TC_FREE;                 // Pha huy Brick    }    else if(iCell[1] == TC_STEEL && pBullE->bBullF)                 // Neu Cell thu 2 la Steel va dan la dan lua    {        pCells[Cell[1].x][Cell[1].y] = TC_FREE;                     // Pha huy Steel        pCells[Cell[0].x][Cell[0].y] = TC_FREE;        pCells[Next[1].x][Next[1].y] = TC_FREE;        pCells[Next[0].x][Next[0].y] = TC_FREE;    }    if(iCell[2] == TC_BRICK)    {        pCells[Cell[2].x][Cell[2].y] = TC_FREE;        if(iCell[3] == TC_BRICK)            pCells[Cell[3].x][Cell[3].y] = TC_FREE;    }    else if(iCell[2] == TC_STEEL && pBullE->bBullF)    {        pCells[Cell[2].x][Cell[2].y] = TC_FREE;                     // Pha huy Steel        pCells[Cell[3].x][Cell[3].y] = TC_FREE;        pCells[Next[2].x][Next[2].y] = TC_FREE;        pCells[Next[3].x][Next[3].y] = TC_FREE;    }    return bHitCell;}BOOL Bullet_HitCell(PBULLET pBull,BYTE pCells[52][52])      // Ghi nho vien dan chi co the dung truc tiep 2 Cells{    POINT       Cell[4],Next[4];    int         i,x,y;    BYTE        iCell[4],iNext[4];    BOOL        bHitCell;     if(pBull->iFrend == FM_LEFT)                // BulletE dang di chuyen sang trai    {        for(i=0;i<4;i++)        {            Cell[i].x = pBull->x/SMALL;            Cell[i].y = pBull->y/SMALL + i - 1;            Next[i].x = Cell[i].x - ((Cell[i].x > 0) ? 1:0);            Next[i].y = Cell[i].y;        }    }    else if(pBull->iFrend == FM_UP)             // BulletE dang di chuyen di len    {        for(i=0;i<4;i++)        {            Cell[i].x = pBull->x/SMALL + i - 1;            Cell[i].y = pBull->y/SMALL;            Next[i].x = Cell[i].x;            Next[i].y = Cell[i].y - ((Cell[i].y > 0) ? 1:0);        }    }    else if(pBull->iFrend == FM_RIGHT)          // BulletE dang di chuyen sang phai    {        for(i=0;i<4;i++)        {            Cell[i].x = pBull->x/SMALL;            Cell[i].y = pBull->y/SMALL + i - 1;            Next[i].x = Cell[i].x + ((Cell[i].x < 51) ? 1:0);            Next[i].y = Cell[i].y;        }    }    else                                        // BulletE dang di chuyen di xuong    {        for(i=0;i<4;i++)        {            Cell[i].x = pBull->x/SMALL + i - 1;            Cell[i].y = pBull->y/SMALL;            Next[i].x = Cell[i].x;            Next[i].y = Cell[i].y + ((Cell[i].y < 51) ? 1:0);        }    }    for(i=0;i<4;i++)    {        iCell[i] = pCells[Cell[i].x][Cell[i].y];        iNext[i] = pCells[Next[i].x][Next[i].y];    }    bHitCell = FALSE;    if(iCell[1] == TC_BRICK || iCell[1] == TC_STEEL || iCell[1] == TC_HOUSE    || iCell[2] == TC_BRICK || iCell[2] == TC_STEEL || iCell[2] == TC_HOUSE)        bHitCell = TRUE;    if(iCell[1] == TC_HOUSE || iCell[2] == TC_HOUSE)    {        for(x=24;x<28;x++)        for(y=48;y<52;y++)            pCells[x][y] = TC_FREE;     // Vi tri cua bo chi huy    }    if(iCell[1] == TC_BRICK)                                        // Neu Cell thu 2 la Brick    {        pCells[Cell[1].x][Cell[1].y] = TC_FREE;                     // Pha huy Brick        if(iCell[0] == TC_BRICK)                                    // Neu Cell dau tien la Brick            pCells[Cell[0].x][Cell[0].y] = TC_FREE;                 // Pha huy Brick    }    else if(iCell[1] == TC_STEEL && pBull->bBullF)                  // Neu Cell thu 2 la Steel va dan la dan lua    {        pCells[Cell[1].x][Cell[1].y] = TC_FREE;                     // Pha huy Steel        pCells[Cell[0].x][Cell[0].y] = TC_FREE;        pCells[Next[1].x][Next[1].y] = TC_FREE;        pCells[Next[0].x][Next[0].y] = TC_FREE;    }    if(iCell[2] == TC_BRICK)    {        pCells[Cell[2].x][Cell[2].y] = TC_FREE;        if(iCell[3] == TC_BRICK)            pCells[Cell[3].x][Cell[3].y] = TC_FREE;    }    else if(iCell[2] == TC_STEEL && pBull->bBullF)    {        pCells[Cell[2].x][Cell[2].y] = TC_FREE;                     // Pha huy Steel        pCells[Cell[3].x][Cell[3].y] = TC_FREE;        pCells[Next[2].x][Next[2].y] = TC_FREE;        pCells[Next[3].x][Next[3].y] = TC_FREE;    }    return bHitCell;}
    Việc ban đầu của hàm là xác định 4 SmallCells đối diện với hướng di chuyển của đạn.
    Kế đó là xác định 4 SmallCells mà núp sau lưng của 4 SmallCells ban đầu.
    Vì viên đạn luôn luôn đụng vào khoảng giữa của 2 SmallCells nên chúng ta xem xét theo từng Cell
    Nếu Cell là Brick => hủy Cell và xem Cell cạnh nó phía ngoài rìa là Brick thì hủy luôn.
    Nếu Cell là Steel và thuộc tính của đạn là đạn lửa => hủy tất cả 4 SmallCells mà đang chứa giá trị TC_STEEL. Bao gồm Cell này, Cell sau lưng, Cell ngoài rìa, Cell sau lưng và ngoài rìa.


    Mã:
    BOOL BulletE_HitTank(PBULLETE pBullE,PTANK pTank){    PSMOKE      pSmoke;     if(pTank->bReady)    if(abs(pBullE->x-pTank->x) < (LARGE+SMALL)/2 && abs(pBullE->y-pTank->y) < (LARGE+SMALL)/2)    {        if(pTank->bSafety)        {            pTank->bBullF   = FALSE;            pTank->bRiver   = FALSE;            if((--pTank->cBulletJoin) < 1)                pTank->cBulletJoin = 1;            if((--pTank->iShoot) < 5)                pTank->iShoot = 5;            if((--pTank->iSpeed) < 1)                pTank->iSpeed = 1;            if((--pTank->iPower) == 0)          // Tank se mat 1 mang            {                pTank->iPower = 5;                // Tao dam chay                if(pSmoke = (PSMOKE)malloc(sizeof(SMOKE)))  // Kich thuoc 1 khung la 88x96                {                    pSmoke->iFrame  = 0;                    pSmoke->x       = pTank->x - (88-LARGE)/2;                    pSmoke->y       = pTank->y - (96-LARGE)/2;                    if(!g_arSmoke.Add(pSmoke))                        free(pSmoke);                }                if((--pTank->cLife) == 0)       // Game Over voi Tank nay                    pTank->bReady = FALSE;                else                            // Khoi tao lai Tank ta                {                    pTank->bBullF           = FALSE;                    pTank->bReady           = TRUE;                    pTank->bRiver           = FALSE;                    pTank->bSafety          = FALSE;                    pTank->cBulletJoin      = 1;                    pTank->cTimes           = 0;                    pTank->iFrame           = 0;                    pTank->iFrend           = FM_UP;                    pTank->iFroze           = 0;                    pTank->iPower           = 5;                    pTank->iRequestFrend    = FM_NULL;                    pTank->iShoot           = 5;                    pTank->iSpeed           = 1;                    for(int i=0;i<3;i++)                    if(pTank->pBull[i])                        pTank->pBull[i]     = NULL;                    pTank->x                = LARGE*((pTank == &g_TankL) ? 4:8);                    pTank->y                = 12*LARGE;                }            }        }        return TRUE;    }    return FALSE;}
    Hàm này không khó hiểu lắm. Nếu Tank ta trúng đạn, tất cả các thuộc tính sẽ theo chiều hướng giảm xuống.
    Nếu chỉ số sức mạnh giảm tới 0 -> Tank sẽ giảm số lần sống và khởi tạo lại vị trí ban đầu và cũng đặt lại chỉ số sức mạnh ở mức cao nhất.
    Nếu Tank bị giảm số lần sống tới 0, tắt cờ bReady, GameOver đối với Tank này.


    Mã:
    BOOL Bullet_HitTankE(PBULLET pBull,CPtrArray * arTankE){    PENEMYTANK  pTankE;    PCARD       pCard;    PSMOKE      pSmoke;    int         i;     for(i=0;i<arTankE->GetSize();i++)    if(pTankE = (PENEMYTANK)arTankE->GetAt(i))    if(abs(pBull->x-pTankE->x) < (LARGE+SMALL)/2 && abs(pBull->y-pTankE->y) < (LARGE+SMALL)/2)    {        if(pTankE->bCard)        {            pTankE->bCard = FALSE;            if(pCard = (PCARD)malloc(sizeof(CARD)))            {                pCard->cDelay   = 2000;                pCard->iStyle   = pTankE->iCard;                pCard->x        = (rand()%49)*SMALL;                pCard->y        = (rand()%49)*SMALL;                if(!g_arCard.Add(pCard))                    free(pCard);            }        }        if((--pTankE->iPower) < 1)        {            if(pSmoke = (PSMOKE)malloc(sizeof(SMOKE)))  // Kich thuoc 1 khung la 88x96            {                pSmoke->iFrame  = 0;                pSmoke->x       = pTankE->x - (88-LARGE)/2;                pSmoke->y       = pTankE->y - (96-LARGE)/2;                if(!g_arSmoke.Add(pSmoke))                    free(pSmoke);            }            arTankE->RemoveAt(i);        }        return TRUE;    }    return FALSE;}
    Khi đạn của ta bắn trúng TankE, nếu thuộc tính tạo thẻ hiện diện, chúng ta tạo và lưu thẻ này vào mảng, đồng thời tắt thuộc tính này.
    Nếu sức mạnh của TankE giảm tới 0, chúng ta tạo một đám cháy và lưu vào mảng khói, đồng thời xóa TankE này khỏi mảng TankE.

    "Vạn sự khởi đầu nan, gian nan bắt đầu nản" hì hì.
    Vui vậy thôi, sức chiến đấu vẫn còn dài dài. Hẹn gặp lại !

    [IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG]

    - - - Nội dung đã được cập nhật ngày 18-03-2014 lúc 12:07 PM - - -</font>

    <font color="#0000FF">NGÀY 25:
    Tính toán để di chuyển những viên đạn ( Tiếp theo )

    Trường hợp đạn của ta đụng Tank của ta

    Mã:
    BOOL Bullet_HitTank(PBULLET pBull)      // Đạn của ta đụng Tank của ta{    if(pBull->pTank == &g_TankL)    if(abs(pBull->x-g_TankR.x) < (LARGE+SMALL)/2 && abs(pBull->y-g_TankR.y) < (LARGE+SMALL)/2)    {        g_TankR.iFroze = 300;           // Tank bên phải bắt đầu tê liệt        return TRUE;    }    if(pBull->pTank == &g_TankR)    if(abs(pBull->x-g_TankL.x) < (LARGE+SMALL)/2 && abs(pBull->y-g_TankL.y) < (LARGE+SMALL)/2)    {        g_TankL.iFroze = 300;           // Đóng băng Tank bên trái        return TRUE;    }    return FALSE;}
    Trường hợp đạn của ta đụng đạn của ta

    Mã:
    BOOL Bullet_HitBullet(PBULLET pBull)        // Đạn của ta đụng đạn của ta{    PBULLET         pAnother;    int             i;     if(pBull->pTank == &g_TankL)    for(i=0;i<g_arBullR.GetSize();i++)      // Duyệt từng viên đạn của Tank ta còn lại    if(pAnother = (PBULLET)g_arBullR.GetAt(i))    if(abs(pBull->x - pAnother->x) < SMALL && abs(pBull->y - pAnother->y) < SMALL)    {        for(j=0;j<3;j++)        if(g_TankR.pBull[j] == pAnother)            g_TankR.pBull[j] = NULL;        g_arBullR.RemoveAt(i);              // Xóa viên đạn của Tank kia        return TRUE;    }     if(pBull->pTank == &g_TankR)    for(i=0;i<g_arBullL.GetSize();i++)    if(pAnother = (PBULLET)g_arBullL.GetAt(i))    if(abs(pBull->x - pAnother->x) < SMALL && abs(pBull->y - pAnother->y) < SMALL)    {        for(j=0;j<3;j++)        if(g_TankL.pBull[j] == pAnother)            g_TankL.pBull[j] = NULL;        g_arBullL.RemoveAt(i);        return TRUE;    }    return FALSE;}
    Trường hợp đạn địch đụng đạn ta

    Mã:
    BOOL BulletE_HitBullet(PBULLETE pBullE){    PBULLET     pBull;    int         i,j,cCount;     cCount = g_arBullL.GetSize();    for(i=0;i<cCount;i++)    if(pBull = (PBULLET)g_arBullL.GetAt(i))                                     // Duyet tung vien dan cua TankL    if(abs(pBullE->x - pBull->x) < SMALL && abs(pBullE->y - pBull->y) < SMALL)    {        for(j=0;j<3;j++)        if(g_TankL.pBull[j] == pBull)            g_TankL.pBull[j] = NULL;        g_arBullL.RemoveAt(i);        return TRUE;    }    cCount = g_arBullR.GetSize();    for(i=0;i<cCount;i++)    if(pBull = (PBULLET)g_arBullR.GetAt(i))                                     // Duyet tung vien dan cua TankR    if(abs(pBullE->x - pBull->x) < SMALL && abs(pBullE->y - pBull->y) < SMALL)    {        for(j=0;j<3;j++)        if(g_TankR.pBull[j] == pBull)            g_TankR.pBull[j] = NULL;        g_arBullR.RemoveAt(i);        return TRUE;    }    return FALSE;}
    Trường hợp đạn ta đụng đạn địch

    Mã:
    BOOL Bullet_HitBulletE(PBULLET pBull){    PBULLETE        pBullE;    int             i;     for(i=0;i<g_arBullE.GetSize();i++)    if(pBullE = (PBULLETE)g_arBullE.GetAt(i))    if(abs(pBullE->x - pBull->x) < SMALL && abs(pBullE->y - pBull->y) < SMALL)    {        g_arBullE.RemoveAt(i);        return TRUE;    }    return FALSE;}
    4 hàm tiếp theo dùng để di chuyển tất cả các viên đạn của ta và địch

    Mã:
    BOOL BulletE_CanStepByStep(PBULLETE pBullE,BYTE pCells[52][52]){    CHAR            szWave[MAX_PATH];    CWaveSound  *   pWave;     if(BulletE_HitBorder(pBullE) || BulletE_HitCell(pBullE,pCells) || BulletE_HitBullet(pBullE)    || BulletE_HitTank(pBullE,&g_TankL) || BulletE_HitTank(pBullE,&g_TankR))    {        if((g_DataSetup.sndEnemyLargeBullet && pBullE->bBullF)        || (g_DataSetup.sndEnemySmallBullet && !pBullE->bBullF))        {            GetModuleFileName(NULL,szWave,MAX_PATH);            PathRemoveFileSpec(szWave);            lstrcat(szWave,pBullE->bBullF ? "\\Tank2D\\EBullF.wav" : "\\Tank2D\\EBullN.wav");            if(PathFileExists(szWave))            if(pWave = new CWaveSound())            {                if(!g_arWave.Add(pWave))                    delete pWave;                else                    pWave->Play(szWave,g_lpDS,FALSE);            }        }        return FALSE;    }    return TRUE;}BOOL Bullet_CanStepByStep(PBULLET pBull,BYTE pCells[52][52]){    CHAR            szWave[MAX_PATH];    CWaveSound  *   pWave;     if(Bullet_HitBorder(pBull) || Bullet_HitCell(pBull,pCells) || Bullet_HitBullet(pBull)    || Bullet_HitBulletE(pBull)|| Bullet_HitTank(pBull) || Bullet_HitTankE(pBull,&g_arTankE))    {        if((g_DataSetup.sndOurLargeBullet && pBull->bBullF)        || (g_DataSetup.sndOurSmallBullet && !pBull->bBullF))        {            GetModuleFileName(NULL,szWave,MAX_PATH);            PathRemoveFileSpec(szWave);            lstrcat(szWave,pBull->bBullF ? "\\Tank2D\\BullF.wav" : "\\Tank2D\\BullN.wav");            if(PathFileExists(szWave))            if(pWave = new CWaveSound())            {                if(!g_arWave.Add(pWave))                    delete pWave;                else                    pWave->Play(szWave,g_lpDS,FALSE);            }        }        return FALSE;    }    return TRUE;}void BulletE_StepByStep(PBULLETE pBullE){    if(pBullE->iFrend == FM_LEFT)       pBullE->x --;    else if(pBullE->iFrend == FM_UP)    pBullE->y --;    else if(pBullE->iFrend == FM_RIGHT) pBullE->x ++;    else                                pBullE->y ++;}void Bullet_StepByStep(PBULLET pBull){    if(pBull->iFrend == FM_LEFT)        pBull->x --;    else if(pBull->iFrend == FM_UP)     pBull->y --;    else if(pBull->iFrend == FM_RIGHT)  pBull->x ++;    else                                pBull->y ++;}
    2 hàm trên chỉ là sử dụng các hàm đã xây dựng để kiểm tra các điều kiện mà trước khi cho đạn di chuyển, nó cũng phát âm thanh khi đạn đụng vào vật cản.

    Sau đây là 2 hàm cuối cùng của ngày hôm nay

    Mã:
    void BulletE_UpdateAll(CPtrArray * arBullE,BYTE pCells[52][52]){    PBULLETE        pBullE;    PFIRE           pFire;    int             i,cStep;     for(i=0;i<arBullE->GetSize();i++)    if(pBullE = (PBULLETE)arBullE->GetAt(i))                // Duyệt từng viên đạn của địch    {        cStep = pBullE->iSpeed;        while(cStep>0)        {            if(BulletE_CanStepByStep(pBullE,pCells))        // Có thể di chuyển            {                BulletE_StepByStep(pBullE);                 // Di chuyển                cStep --;            }            else                                            // Không di chuyển được - đã đụng phải vật cản.            {                if(pFire = (PFIRE)malloc(sizeof(FIRE)))     // Phát nổ                {                    pFire->cDelay   = 5;                    pFire->iFrame   = 0;                    pFire->x        = pBullE->x - (40-SMALL)/2;                    pFire->y        = pBullE->y - (40-SMALL)/2;                    if(!g_arFire.Add(pFire))                        free(pFire);                }                arBullE->RemoveAt(i);                       // Xóa viên đạn này                i--;                break;            }        }    }}void Bullet_UpdateAll(BYTE pCells[52][52]){    PBULLET         pBull;    PFIRE           pFire;    int             i,cStep;     // Update tat ca cac vien dan cua TankL    for(i=0;i<g_arBullL.GetSize();i++)    if(pBull = (PBULLET)g_arBullL.GetAt(i))                 // Duyệt từng viên đạn    {        cStep = pBull->iSpeed;        while(cStep>0)        {            if(Bullet_CanStepByStep(pBull,pCells))          // Có thể di chuyển ?            {                Bullet_StepByStep(pBull);                   // Di chuyển                cStep --;            }            else                                            // Không thể di chuyển            {                if(pFire = (PFIRE)malloc(sizeof(FIRE)))     // Phát nổ                {                    pFire->cDelay   = 5;                    pFire->iFrame   = 0;                    pFire->x        = pBull->x - (40-SMALL)/2;                    pFire->y        = pBull->y - (40-SMALL)/2;                    if(!g_arFire.Add(pFire))                        free(pFire);                }                g_arBullL.RemoveAt(i);                      // Xóa viên đạn này                i--;                break;            }        }    }    // Update tat ca cac vien dan cua TankR    for(i=0;i<g_arBullR.GetSize();i++)    if(pBull = (PBULLET)g_arBullR.GetAt(i))    {        cStep = pBull->iSpeed;        while(cStep>0)        {            if(Bullet_CanStepByStep(pBull,pCells))            {                Bullet_StepByStep(pBull);                cStep --;            }            else            {                if(pFire = (PFIRE)malloc(sizeof(FIRE)))                {                    pFire->cDelay   = 5;                    pFire->iFrame   = 0;                    pFire->x        = pBull->x - (40-SMALL)/2;                    pFire->y        = pBull->y - (40-SMALL)/2;                    if(!g_arFire.Add(pFire))                        free(pFire);                }                g_arBullR.RemoveAt(i);                i--;                break;            }        }    }}
    Cập nhật các viên đạn ít rắc rối hơn cập nhật các Tank, chỉ cần không di chuyển được thì phát nổ, chúng ta cũng không phải lo lắng logic chuột và bàn phím.
    Một chút khó khăn khi chúng ta phải xem xét để hủy các vật cản hay tạo các đối tượng mới như Card hay Smoke.
    Ngày nay tới đây thôi, tạm biệt !

    [IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG]

  4. #14
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    NGÀY 26: Cập nhật cho Fire, Smoke và Card


    Mã:
    void Fire_Update(){    PFIRE       pFire;    int         i;     for(i=0;i<g_arFire.GetSize();i++)    if(pFire = (PFIRE)g_arFire.GetAt(i))    if((++pFire->iFrame)>5)        g_arFire.RemoveAt(i);}
    Nếu hình ảnh nổ đã hiện thị qua hết 5 khung, chúng ta hủy nó.


    Mã:
    void Smoke_Update(){    PSMOKE      pSmoke;    int         i;     for(i=0;i<g_arSmoke.GetSize();i++)    if(pSmoke = (PSMOKE)g_arSmoke.GetAt(i))    if((--pSmoke->cDelay) <= 0)    {        pSmoke->cDelay = 5;        if(++pSmoke->iFrame > 14)            g_arSmoke.RemoveAt(i);    }}
    Nếu số lần chờ hạ xuống còn 0, chúng ta tăng số khung hiển thị, nếu số khung vượt quá 14, chúng ta hủy nó.


    Mã:
    void Card_Update(){    PCARD       pCard;    PENEMYTANK  pTankE;    PSMOKE      pSmoke;    int         i,j,x,y,xCard,yCard,xTankL,yTankL,xTankR,yTankR;     xTankL = g_TankL.x + MEDIUM;            // Tọa độ tâm x của TankL    yTankL = g_TankL.y + MEDIUM;            // Tọa độ tâm y của TankL    xTankR = g_TankR.x + MEDIUM;            // Tọa độ tâm x của TankR    yTankR = g_TankR.y + MEDIUM;            // Tọa độ tâm y của TankR     for(i=0;i<g_arCard.GetSize();i++)    if(pCard = (PCARD)g_arCard.GetAt(i))    // Duyệt từng Card    {        if((--pCard->cDelay)==0)            // Đã hết thời gian hiển thị -> Hủy Card            g_arCard.RemoveAt(i);        else        {            xCard = pCard->x + 12;              // Tọa độ tâm x của Card            yCard = pCard->y + 12;              // Tọa độ tâm y của Card            if(g_TankL.bReady && abs(xCard-xTankL) < 12+MEDIUM && abs(yCard-yTankL) < 12+MEDIUM)    // TankL - Card đụng nhau            {                switch(pCard->iStyle)                {                case 0:     g_TankL.cLife ++;                                           break;      // Card tăng mạng sống của Tank                case 1:     g_TankL.bBullF = TRUE;                                      break;      // Card cho phép Tank bắn đạn lửa                case 8:     g_TankL.bRiver = TRUE;                                      break;      // Card cho phép Tank vượt sông                case 9:     g_TankL.cSafety = 1000;                                     break;      // Card bảo vệ Tank khi bị bắn trúng                case 10:    g_TankL.iPower  = 5;                                        break;      // Card phục hồi sức mạnh Tank                case 3:     if(++g_TankL.iSpeed > 3)        g_TankL.iSpeed = 3;         break;      // Card tăng tốc độ di chuyển của Tank                case 4:     if(++g_TankL.iShoot > 10)       g_TankL.iShoot = 10;        break;      // Card tăng tốc độ của viên đạn được Tank bắn ra                case 7:     if(++g_TankL.cBulletJoin > 3)   g_TankL.cBulletJoin = 3;    break;      // Card tăng số đạn bắn liên thanh của Tank                case 2:                                                                             // Card nổ mìn tất cả các TankE                    for(j=0;j<g_arTankE.GetSize();j++)                    if(pTankE = (PENEMYTANK)g_arTankE.GetAt(j))                    {                        if(pSmoke = (PSMOKE)malloc(sizeof(SMOKE)))                        {                            pSmoke->cDelay  = 5;                            pSmoke->iFrame  = 0;                            pSmoke->x       = pTankE->x - (88-LARGE)/2;                            pSmoke->y       = pTankE->y - (96-LARGE)/2;                            if(!g_arSmoke.Add(pSmoke))                                free(pSmoke);                        }                    }                    g_arTankE.RemoveAll();                    break;                case 5:                                                                             // Card thép hóa tường bao bộ chỉ huy                    for(x=22;x<30;x++)                    for(y=46;y<52;y++)                        g_DataLevel.iCells[x][y] = TC_STEEL;        // Tao vung thep xung quanh bo chi huy                    for(x=24;x<28;x++)                    for(y=48;y<52;y++)                        g_DataLevel.iCells[x][y] = TC_HOUSE;        // Vi tri cua bo chi huy                    break;                case 6:                                                                             // Card đóng băng tất cả TankE                    for(j=0;j<g_arTankE.GetSize();j++)                    if(pTankE = (PENEMYTANK)g_arTankE.GetAt(j))                        pTankE->iFroze += 1000;                    break;                }                g_arCard.RemoveAt(i);                               // Hủy Card            }            else if(g_TankR.bReady && abs(xCard-xTankR) < 12+MEDIUM && abs(yCard-yTankR) < 12+MEDIUM)            {                switch(pCard->iStyle)                {                case 0:     g_TankR.cLife ++;                                           break;                case 1:     g_TankR.bBullF = TRUE;                                      break;                case 8:     g_TankR.bRiver = TRUE;                                      break;                case 9:     g_TankR.cSafety = 1000;                                     break;                case 10:    g_TankR.iPower  = 5;                                        break;                case 3:     if(++g_TankR.iSpeed > 3)        g_TankR.iSpeed = 3;         break;                case 4:     if(++g_TankR.iShoot > 10)       g_TankR.iShoot = 10;        break;                case 7:     if(++g_TankR.cBulletJoin > 3)   g_TankR.cBulletJoin = 3;    break;                case 2:                    for(j=0;j<g_arTankE.GetSize();j++)                    if(pTankE = (PENEMYTANK)g_arTankE.GetAt(j))                    {                        if(pSmoke = (PSMOKE)malloc(sizeof(SMOKE)))                        {                            pSmoke->cDelay  = 5;                            pSmoke->iFrame  = 0;                            pSmoke->x       = pTankE->x - (88-LARGE)/2;                            pSmoke->y       = pTankE->y - (96-LARGE)/2;                            if(!g_arSmoke.Add(pSmoke))                                free(pSmoke);                        }                    }                    g_arTankE.RemoveAll();                    break;                case 5:                    for(x=22;x<30;x++)                    for(y=46;y<52;y++)                        g_DataLevel.iCells[x][y] = TC_STEEL;        // Tao vung thep xung quanh bo chi huy                    for(x=24;x<28;x++)                    for(y=48;y<52;y++)                        g_DataLevel.iCells[x][y] = TC_HOUSE;        // Vi tri cua bo chi huy                    break;                case 6:                    for(j=0;j<g_arTankE.GetSize();j++)                    if(pTankE = (PENEMYTANK)g_arTankE.GetAt(j))                        pTankE->iFroze += 1000;                    break;                }                g_arCard.RemoveAt(i);            }        }    }}
    Hàm diễn giải các công việc phải làm khi Tank ta nhận được 1 thẻ tăng cường, cũng dễ hiểu như chú thích bên trong mà thôi.

    Chào thân ái! [IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG]

    - - - Nội dung đã được cập nhật ngày 20-03-2014 lúc 04:54 PM - - -</font>

    NGÀY 27: Vẽ chữ lên bề mặt Back

    Thêm vào các khai báo sau

    Mã:
    enum {SP_LEVEL=0,SP_PLAY,SP_WIN,SP_LOST};typedef struct{    BOOL        bBullF;    int         iPower;    int         iShoot;    int         iSmart;    int         iSpeed;}TYPETANK,*PTYPETANK;TYPETANK                g_TypeTank[50];HINSTANCE               g_hInst;HWND                    g_hwndMCI;BOOL                    g_bActive;BOOL                    g_bMoused;BOOL                    g_bPause;int                     g_IndexTank;int                     g_iStatus;int                     g_iLevel;
    Hàm sau kiểm tra xem bên nào thắng

    Mã:
    void App_CheckWinLost(){    if((!g_TankL.bReady && !g_TankR.bReady) || g_DataLevel.iCells[24][48] == TC_FREE)        g_iStatus = SP_LOST;    else if(g_IndexTank == 30 && g_arTankE.GetSize() == 0)        g_iStatus = SP_WIN;}
    Nếu cả 2 Tank của người chơi đã GameOver hoặc Bộ chỉ huy bị tiêu diệt => Người chơi đã thua tại vòng này.
    Nếu TankE đã nhập cuộc hết 30 Tank và mảng hiện tại không còn Tank nào => Người chơi đã thắng vòng này.

    Hàm đóng khung vùng chơi với độ dày là 4 Pixels với màu được thiết lập trước.

    Mã:
    void DirectX_DrawFrame(int xFrame,int yFrame){    HDC         hdc;    HBRUSH      hBrush;    RECT        r;    int         i;     if(g_lpBack->GetDC(&hdc) == DD_OK)    {        hBrush = CreateSolidBrush(g_DataSetup.crFrame);        for(i=1;i<4;i++)        {            SetRect(&r,xFrame-i,yFrame-i,xFrame+LARGE*13+1+i,yFrame+LARGE*13+1+i);            FrameRect(hdc,&r,hBrush);        }        DeleteObject(hBrush);        g_lpBack->ReleaseDC(hdc);    }}
    Hàm vẽ tên trò chơi

    Mã:
    void DirectX_DrawTitle(int iLevel,int xFrame,int yFrame){    CHAR        szTitle[MAX_PATH];    HDC         hdc;    HFONT       hFont;    RECT        r;     if(g_lpBack->GetDC(&hdc) == DD_OK)    {        SetBkMode(hdc,TRANSPARENT);        SetTextColor(hdc,g_DataSetup.crTitle);        SetRect(&r,xFrame,0,xFrame+LARGE*13,yFrame);        hFont = CreateFont(24,0,0,0,FW_BOLD,0,0,0,0,0,0,0,0,"MS Sans Serif");        SelectObject(hdc,hFont);        wsprintf(szTitle,"TANK2D - LEVEL %i",iLevel+1);        DrawText(hdc,szTitle,-1,&r,DT_SINGLELINE|DT_CENTER|DT_VCENTER);        DeleteObject(hFont);        g_lpBack->ReleaseDC(hdc);    }}
    Hàm vẽ chữ khi trạng thái chương trình đang tạm dừng

    Mã:
    void DirectX_DrawTextPause(int xFrame,int yFrame){    HDC         hdc;    RECT        r;     if(g_lpBack->GetDC(&hdc) == DD_OK)    {        SetBkMode(hdc,TRANSPARENT);        SetTextColor(hdc,g_DataSetup.crText);        SetRect(&r,xFrame,yFrame/2,xFrame+LARGE*13,yFrame);        DrawText(hdc,"PAUSE - Press < Pause > to Continue !",-1,&r,DT_SINGLELINE|DT_CENTER|DT_VCENTER);        g_lpBack->ReleaseDC(hdc);    }}
    Hàm vẽ chữ khi trạng thái chương trình là <SP_LEVEL>

    Mã:
    void DirectX_DrawTextLevel(int xFrame,int yFrame){    HDC         hdc;    RECT        r;     if(g_lpBack->GetDC(&hdc) == DD_OK)    {        SetBkMode(hdc,TRANSPARENT);        SetTextColor(hdc,g_DataSetup.crText);        SetRect(&r,xFrame,yFrame/2,xFrame+LARGE*13,yFrame);        DrawText(hdc,"Press < Enter > to Play !",-1,&r,DT_SINGLELINE|DT_CENTER|DT_VCENTER);        g_lpBack->ReleaseDC(hdc);    }}
    Hàm vẽ chữ khi trạng thái chương trình là <SP_WIN>

    Mã:
    void DirectX_DrawTextWin(int xFrame,int yFrame){    HDC         hdc;    RECT        r;     if(g_lpBack->GetDC(&hdc) == DD_OK)    {        SetBkMode(hdc,TRANSPARENT);        SetTextColor(hdc,g_DataSetup.crText);        SetRect(&r,xFrame,yFrame/2,xFrame+LARGE*13,yFrame);        DrawText(hdc,"YOU WIN - Press < Enter > for Next Level !",-1,&r,DT_SINGLELINE|DT_CENTER|DT_VCENTER);        g_lpBack->ReleaseDC(hdc);    }}
    Hàm vẽ chữ khi trạng thái chương trình là <SP_LOST>

    Mã:
    void DirectX_DrawTextLost(int xFrame,int yFrame){    HDC         hdc;    RECT        r;     if(g_lpBack->GetDC(&hdc) == DD_OK)    {        SetBkMode(hdc,TRANSPARENT);        SetTextColor(hdc,g_DataSetup.crText);        SetRect(&r,xFrame,yFrame/2,xFrame+LARGE*13,yFrame);        DrawText(hdc,"YOU LOST - Press < Enter > to Replay This Level !",-1,&r,DT_SINGLELINE|DT_CENTER|DT_VCENTER);        g_lpBack->ReleaseDC(hdc);    }}
    Hàm sau cùng của ngày hôm nay cập nhật tất cả các tương tác giữa người chơi và chương trình

    Mã:
    void App_Update(int iLevel){    PENEMYTANK  pTankE;    DDBLTFX     ddbltfx;    HRESULT     hr;    int         i;    int         xFrame = (GetSystemMetrics(SM_CXSCREEN) - LARGE*13)/2;    int         yFrame = (GetSystemMetrics(SM_CYSCREEN) - LARGE*13)/2;    RECT        r = { xFrame,yFrame,xFrame+LARGE*13,yFrame+LARGE*13};    // Xóa trống bề mặt Back    ddbltfx.dwSize      = sizeof(ddbltfx);    ddbltfx.dwFillColor = DirectX_ColorMatch(g_lpBack,g_DataSetup.crScreen);    while(1)    {        hr = g_lpBack->Blt(NULL,NULL,NULL,DDBLT_COLORFILL,&ddbltfx);        if(hr == DD_OK) break;        if(hr == DDERR_SURFACELOST) if(!DirectX_RestoreSurfaceAll()) return;        if(hr != DDERR_WASSTILLDRAWING) return;    }    // Tô màu vùng chơi    ddbltfx.dwFillColor = DirectX_ColorMatch(g_lpBack,g_DataSetup.crBack);    while(1)    {        hr = g_lpBack->Blt(&r,NULL,NULL,DDBLT_COLORFILL,&ddbltfx);        if(hr == DD_OK) break;        if(hr == DDERR_SURFACELOST) if(!DirectX_RestoreSurfaceAll()) return;        if(hr != DDERR_WASSTILLDRAWING) return;    }    // Xử lý chương trình theo từng trạng thái    switch(g_iStatus)    {    case SP_LEVEL:        DirectX_DrawTitle(iLevel,xFrame,yFrame);        DirectX_DrawFrame(xFrame,yFrame);         DirectX_DrawBricks(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawSteels(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawGlides(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawRivers(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawCovers(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawHouse(g_DataLevel.iCells,xFrame,yFrame);         DirectX_DrawTextLevel(xFrame,yFrame);        // Trong còn trong màn hình giới thiệu vòng, lặp lại âm thanh nền nếu MCI đã chơi hết tập tin hoặc bị tạm dừng        if(g_DataSetup.sndBackSound && g_hwndMCI)        {            TCHAR       szText[MAX_PATH];            if(MCIWndGetMode(g_hwndMCI,szText,MAX_PATH) == MCI_MODE_STOP)            {                MCIWndHome(g_hwndMCI);                MCIWndPlay(g_hwndMCI);            }        }        break;    case SP_PLAY:        if(!g_bPause)        {            for(i=0;i<g_arTankE.GetSize();i++)                  // Cap nhat TankE            if(pTankE = (PENEMYTANK)g_arTankE.GetAt(i))                TankE_Update(pTankE,g_DataLevel.iCells);            Tank_Update(g_DataLevel.iCells);                    // Cap nhat Tank            BulletE_UpdateAll(&g_arBullE,g_DataLevel.iCells);   // Cap nhat BullE            Bullet_UpdateAll(g_DataLevel.iCells);               // Cap nhat Bull             Fire_Update();            Smoke_Update();            Card_Update();             App_CheckWinLost();        }        DirectX_DrawTitle(iLevel,xFrame,yFrame);        DirectX_DrawFrame(xFrame,yFrame);         DirectX_DrawBricks(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawSteels(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawGlides(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawRivers(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawHouse(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawTankE(&g_arTankE,xFrame,yFrame);        DirectX_DrawTankL(xFrame,yFrame);        DirectX_DrawTankR(xFrame,yFrame);        DirectX_DrawBulletE(&g_arBullE,xFrame,yFrame);        DirectX_DrawBulletL(&g_arBullL,xFrame,yFrame);        DirectX_DrawBulletR(&g_arBullR,xFrame,yFrame);        DirectX_DrawFire(&g_arFire,xFrame,yFrame);        DirectX_DrawCovers(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawCards(&g_arCard,xFrame,yFrame);        DirectX_DrawSmoke(&g_arSmoke,xFrame,yFrame);         if(g_bPause)            DirectX_DrawTextPause(xFrame,yFrame);        break;    case SP_WIN:        Tank_Update(g_DataLevel.iCells);                    // Cap nhat Tank        BulletE_UpdateAll(&g_arBullE,g_DataLevel.iCells);   // Cap nhat BullE        Bullet_UpdateAll(g_DataLevel.iCells);               // Cap nhat Bull         Fire_Update();        Smoke_Update();        Card_Update();         DirectX_DrawTitle(iLevel,xFrame,yFrame);        DirectX_DrawFrame(xFrame,yFrame);         DirectX_DrawBricks(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawSteels(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawGlides(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawRivers(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawHouse(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawTankL(xFrame,yFrame);        DirectX_DrawTankR(xFrame,yFrame);        DirectX_DrawBulletE(&g_arBullE,xFrame,yFrame);        DirectX_DrawBulletL(&g_arBullL,xFrame,yFrame);        DirectX_DrawBulletR(&g_arBullR,xFrame,yFrame);        DirectX_DrawFire(&g_arFire,xFrame,yFrame);        DirectX_DrawCovers(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawCards(&g_arCard,xFrame,yFrame);        DirectX_DrawSmoke(&g_arSmoke,xFrame,yFrame);         DirectX_DrawTextWin(xFrame,yFrame);        break;    case SP_LOST:        for(i=0;i<g_arTankE.GetSize();i++)                  // Cap nhat TankE        if(pTankE = (PENEMYTANK)g_arTankE.GetAt(i))            TankE_Update(pTankE,g_DataLevel.iCells);        BulletE_UpdateAll(&g_arBullE,g_DataLevel.iCells);   // Cap nhat BullE        Bullet_UpdateAll(g_DataLevel.iCells);               // Cap nhat Bull         Fire_Update();        Smoke_Update();        Card_Update();         DirectX_DrawTitle(iLevel,xFrame,yFrame);        DirectX_DrawFrame(xFrame,yFrame);         DirectX_DrawBricks(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawSteels(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawGlides(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawRivers(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawHouse(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawTankE(&g_arTankE,xFrame,yFrame);        DirectX_DrawTankL(xFrame,yFrame);        DirectX_DrawTankR(xFrame,yFrame);        DirectX_DrawBulletE(&g_arBullE,xFrame,yFrame);        DirectX_DrawBulletL(&g_arBullL,xFrame,yFrame);        DirectX_DrawBulletR(&g_arBullR,xFrame,yFrame);        DirectX_DrawFire(&g_arFire,xFrame,yFrame);        DirectX_DrawCovers(g_DataLevel.iCells,xFrame,yFrame);        DirectX_DrawCards(&g_arCard,xFrame,yFrame);        DirectX_DrawSmoke(&g_arSmoke,xFrame,yFrame);         DirectX_DrawTextLost(xFrame,yFrame);        break;    }    // Duyệt qua mảng âm thanh, nếu âm thanh nào không còn chơi => Remove nó ra khỏi mảng.    for(i=0;i<g_arWave.GetSize();i++)    {        CWaveSound * pWave = (CWaveSound*)g_arWave.GetAt(i);        if(pWave)        if(pWave->lpdsb)        {            DWORD   dwStatus = 0;            if(pWave->lpdsb->GetStatus(&dwStatus) == DS_OK)            if(!(dwStatus & DSBSTATUS_PLAYING))                g_arWave.RemoveAt(i);        }    }    // Flip Screen - Chuyển hình ảnh từ bề mặt tổng lên màn hình    while(TRUE)    {        hr = g_lpMaster->Flip(NULL,0);        if(hr == DD_OK) break;        if(hr == DDERR_SURFACELOST) if(!DirectX_RestoreSurfaceAll()) return;        if(hr != DDERR_WASSTILLDRAWING) return;    }}
    Trong hàm đã có diễn giải sơ lược, các bạn chú ý thêm về thứ tự vẽ để không có hình nào khiếu nại rằng - "tui bị chơi ép".
    Ví dụ : Tank thì có thể ở trên River, Glide nhưng phải ở dưới Cover. Hoặc một đám khói thì phải ở trên cùng. v.v...

    Tới đây đã có thể coi chương trình là tạm ổn chỉ còn mã hóa 2 hàm chính trong chương trình Windows nữa là có thể biên dịch và chạy.
    Chương trình này không sử dụng MFC - Hai hàm còn lại là WinMain và WindowProc.

    Chào tạm biệt. [IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG]

    - - - Nội dung đã được cập nhật ngày 21-03-2014 lúc 03:21 PM - - -

    NGÀY 28: Chuẩn bị cho Biên dịch phiên bản tạm thời.

    Hàm sau đây vẽ các Text thuộc tính của Tank ta

    Mã:
    void DirectX_DrawTankProperties(PTANK pTank,int xFrame,int yFrame){    CHAR        szText[MAX_PATH];    HDC         hdc;    HFONT       hFont;    RECT        r;    UINT        uFormat;     if(pTank->bReady)    {        uFormat = (pTank == &g_TankL) ? (DT_LEFT|DT_SINGLELINE|DT_VCENTER) : (DT_RIGHT|DT_SINGLELINE|DT_VCENTER);        if(g_lpBack->GetDC(&hdc) == DD_OK)        {            SetBkMode(hdc,TRANSPARENT);            SetTextColor(hdc,g_DataSetup.crText);            hFont = CreateFont(8,0,0,0,FW_NORMAL,0,0,0,0,0,0,0,0,"MS Sans Serif");            SelectObject(hdc,hFont);             r.left   = xFrame;            r.right  = xFrame + LARGE*13;            r.top    = yFrame + LARGE*13 + 10;            r.bottom = r.top + 20;            wsprintf(szText,"Amout : %i",pTank->cLife);             // Số lần sống còn lại            DrawText(hdc,szText,-1,&r,uFormat);            r.top += 20; r.bottom += 20;            wsprintf(szText,"Power : %i",pTank->iPower);            // Sức mạnh hiện tại            DrawText(hdc,szText,-1,&r,uFormat);            r.top += 20; r.bottom += 20;            wsprintf(szText,"Move Speed : %i",pTank->iSpeed);       // Tốc độ di chuyển            DrawText(hdc,szText,-1,&r,uFormat);            r.top += 20; r.bottom += 20;            wsprintf(szText,"Shoot Speed : %i",pTank->iShoot);      // Tốc độ bắn            DrawText(hdc,szText,-1,&r,uFormat);              r.left   += 100;            r.right  -= 100;            r.top    = yFrame + LARGE*13 + 10;            r.bottom = r.top + 20;            wsprintf(szText,"Bullet : %i",pTank->cBulletJoin);      // Số đạn bắn liên thanh            DrawText(hdc,szText,-1,&r,uFormat);             if(pTank->cSafety > 0)            {                pTank->cSafety --;                r.top += 20; r.bottom += 20;                wsprintf(szText,"Safety : %i",pTank->cSafety);      // Số thời khắc an toàn còn lại mà Tank được bảo vệ                DrawText(hdc,szText,-1,&r,uFormat);            }            if(pTank->bBullF)            {                r.top += 20; r.bottom += 20;                wsprintf(szText,"+ FireBullet");                    // Tank bắn đạn lửa                DrawText(hdc,szText,-1,&r,uFormat);            }            if(pTank->bRiver)            {                r.top += 20; r.bottom += 20;                wsprintf(szText,"+ No River");                      // Tank có thể vượt sông                DrawText(hdc,szText,-1,&r,uFormat);            }             DeleteObject(hFont);            g_lpBack->ReleaseDC(hdc);        }    }}
    Hàm này bạn đặt phía trước cài đặt hàm App_Update(), nó chỉ hiển thị các thuộc tính cho người chơi dễ quan sát mà thôi.
    Hàm kế tiếp vẽ tất cả các TankE mà chưa tham chiến tại phần bên phải của khung chơi.

    Mã:
    void DirectX_DrawRightSide(int xFrame,int yFrame){    int         i,x,y;    RECT        r = {0,0,LARGE,LARGE}; // Lấy khung đầu tiên, dòng đầu tiên của Bitmap để vẽ.     // Lần lượt vẽ tất cả các TankE chưa tham chiến    for(i=29;i>=g_IndexTank;i--)    {        x = (29-i)%4;        y = (29-i)/4;        g_lpBack->BltFast(xFrame+LARGE*13+20+x*(LARGE+8),yFrame+y*(LARGE+8),g_lpTankE[g_DataLevel.iStyleTank[i]],&r,DDBLTFAST_SRCCOLORKEY);    }}
    Hàm này bạn cũng đặt trước App_Update().


    Mã:
    LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam){    CHAR                szFolder[MAX_PATH];    CHAR                szFile[MAX_PATH];    PENEMYTANK          pTankE;    int                 iStyleTank;    int                 i;     switch(message)    {    case WM_ACTIVATEAPP:        g_bActive = (BOOL)wparam;        if(g_bActive)        {            g_bMoused = FALSE;            if(g_lpKeyboard)                g_lpKeyboard->Acquire();            if(g_lpMouse)                g_lpMouse->Acquire();        }        else            g_bMoused = TRUE;        break;    case WM_CREATE:        GetModuleFileName(NULL,szFolder,MAX_PATH);        PathRemoveFileSpec(szFolder);        lstrcat(szFolder,"\\Tank2D");         wsprintf(szFile,"%s\\BackSound.mp3",szFolder);        if(!PathFileExists(szFile))        {            wsprintf(szFile,"%s\\BackSound.wav",szFolder);            if(!PathFileExists(szFile))                wsprintf(szFile,"%s\\BackSound.mid",szFolder);        }        if(g_hwndMCI = MCIWndCreate(hwnd,g_hInst,MCIWNDF_NOTIFYMODE|MCIWNDF_NOERRORDLG,szFile))        {            ShowWindow(g_hwndMCI,SW_HIDE);            if(g_DataSetup.sndBackSound)                MCIWndPlay(g_hwndMCI);        }        if(!Level_LoadData(&g_DataLevel,g_iLevel))        {            Cells_CreateValueRandom(g_DataLevel.iCells);            for(i=0;i<5;i++)                g_DataLevel.iStyleCard[i] = rand()%11;            for(i=0;i<30;i++)                g_DataLevel.iStyleTank[i] = rand()%4;            Level_SaveData(&g_DataLevel,g_iLevel);        }        // TankL        g_TankL.bBullF          = FALSE;        g_TankL.bReady          = TRUE;        g_TankL.bRiver          = FALSE;        g_TankL.cSafety         = 0;        g_TankL.cBulletJoin     = 1;        g_TankL.cLife           = 5;        g_TankL.cTimes          = 8;        g_TankL.iFrame          = 0;        g_TankL.iFrend          = FM_UP;        g_TankL.iFroze          = 0;        g_TankL.iPower          = 5;        g_TankL.iRequestFrend   = FM_NULL;        g_TankL.iShoot          = 5;        g_TankL.iSpeed          = 1;        g_TankL.x               = LARGE*4;        g_TankL.y               = 12*LARGE;        // TankR        g_TankR.bBullF          = FALSE;        g_TankR.bReady          = TRUE;        g_TankR.bRiver          = FALSE;        g_TankR.cSafety         = 0;        g_TankR.cBulletJoin     = 1;        g_TankR.cLife           = 5;        g_TankR.cTimes          = 8;        g_TankR.iFrame          = 0;        g_TankR.iFrend          = FM_UP;        g_TankR.iFroze          = 0;        g_TankR.iPower          = 5;        g_TankR.iRequestFrend   = FM_NULL;        g_TankR.iShoot          = 5;        g_TankR.iSpeed          = 1;        g_TankR.x               = LARGE*8;        g_TankR.y               = 12*LARGE;         for(i=0;i<50;i++)        {            g_TypeTank[i].bBullF    = (rand()%30 == 0) ? TRUE:FALSE;            g_TypeTank[i].iPower    = rand()%5 + 1;            g_TypeTank[i].iShoot    = rand()%6 + 5;            g_TypeTank[i].iSmart    = rand()%3;            g_TypeTank[i].iSpeed    = rand()%3 + 1;        }        break;    case WM_TIMER:        if(g_bPause)            return 0;        if(g_IndexTank < 30)        {            if(pTankE = (PENEMYTANK)malloc(sizeof(ENEMYTANK)))            {                iStyleTank = g_DataLevel.iStyleTank[g_IndexTank];                                pTankE->bBullF      = g_TypeTank[iStyleTank].bBullF;                pTankE->bCard       = (g_IndexTank % 6 == 0) ? TRUE:FALSE;                pTankE->iCard       = g_DataLevel.iStyleCard[g_IndexTank / 6];                pTankE->iFrame      = 0;                pTankE->iFrend      = FM_DOWN;                pTankE->iFroze      = 0;                pTankE->iPower      = g_TypeTank[iStyleTank].iPower;                pTankE->iRequest    = FM_NULL;                pTankE->iShoot      = g_TypeTank[iStyleTank].iShoot;                pTankE->iSmart      = g_TypeTank[iStyleTank].iSmart;                pTankE->iSpeed      = g_TypeTank[iStyleTank].iSpeed;                pTankE->iStyle      = iStyleTank;                pTankE->y           = 0;                if(g_IndexTank % 3 == 0)        pTankE->x = 0;              // TankE ben trai                else if(g_IndexTank % 3 == 1)   pTankE->x = LARGE * 6;      // TankE o giua                else                            pTankE->x = LARGE * 12;     // TankE ben phai                if(!g_arTankE.Add(pTankE))                    free(pTankE);                else                    g_IndexTank ++;            }        }        else            KillTimer(hwnd,1);        return 0;    case WM_SETCURSOR:        if(!g_bMoused)  SetCursor(NULL);        else            SetCursor(LoadCursor(NULL,IDC_ARROW));        return 0;    case WM_MBUTTONDOWN:        SendMessage(hwnd,WM_COMMAND,MAKEWPARAM(IDC_ENTER,0),0);        return 0;    case WM_COMMAND:        switch(LOWORD(wparam))        {        case IDC_ESCAPE:            SendMessage(hwnd,WM_CLOSE,0,0);            return 0;        case IDC_F1: // Chưa cài đặt            return 0;        case IDC_F2: // Chưa cài đặt            return 0;        case IDC_F3: // Chưa cài đặt            return 0;        case IDC_F4: // Chưa cài đặt            return 0;        case IDC_F5: // Chưa cài đặt            return 0;        case IDC_F6: // Chưa cài đặt            return 0;        case IDC_F7: // Chưa cài đặt            return 0;        case IDC_F8: // Chưa cài đặt            return 0;        case IDC_F9: // Chưa cài đặt            return 0;        case IDC_F10: // Chưa cài đặt            return 0;        case IDC_F11: // Chưa cài đặt            return 0;        case IDC_F12: // Chưa cài đặt            return 0;        case IDC_PAUSE:            if(g_iStatus == SP_PLAY)                g_bPause ^= 1;            return 0;        case IDC_INSERT: // Chưa cài đặt            return 0;        case IDC_DELETE: // Chưa cài đặt            return 0;        case IDC_HOME: // Chưa cài đặt            return 0;        case IDC_END: // Chưa cài đặt            return 0;        case IDC_PAGEUP:                    // Di chuyển lên một vòng            if(g_iStatus == SP_LEVEL)            if(g_iLevel > 0)            {                g_iLevel --;                if(!Level_LoadData(&g_DataLevel,g_iLevel)) // Nạp lại dữ liệu                {                    Cells_CreateValueRandom(g_DataLevel.iCells);                    for(i=0;i<5;i++)                        g_DataLevel.iStyleCard[i] = rand()%11;                    for(i=0;i<30;i++)                        g_DataLevel.iStyleTank[i] = rand()%4;                    Level_SaveData(&g_DataLevel,g_iLevel);                }            }            return 0;        case IDC_PAGEDOWN:                  // Di chuyển xuống một vòng            if(g_iStatus == SP_LEVEL)            {                g_iLevel ++;                if(!Level_LoadData(&g_DataLevel,g_iLevel)) // Nạp lại dữ liệu                {                    Cells_CreateValueRandom(g_DataLevel.iCells);                    for(i=0;i<5;i++)                        g_DataLevel.iStyleCard[i] = rand()%11;                    for(i=0;i<30;i++)                        g_DataLevel.iStyleTank[i] = rand()%4;                    Level_SaveData(&g_DataLevel,g_iLevel);                }            }            return 0;        case IDC_ENTER:            if(g_iStatus == SP_LEVEL)            {                g_iStatus = SP_PLAY;                if(g_hwndMCI)                    MCIWndStop(g_hwndMCI);                SendMessage(hwnd,WM_TIMER,0,0);// Cho 3 TankE xuất hiện khi bắt đầu chơi 1 vòng                SendMessage(hwnd,WM_TIMER,0,0);                SendMessage(hwnd,WM_TIMER,0,0);                SetTimer(hwnd,1,5000,NULL); // Định thời để lần lượt xuất hiện các Tank địch            }            else if(g_iStatus == SP_WIN)            {                g_iLevel ++;                if(!Level_LoadData(&g_DataLevel,g_iLevel))                {                    Cells_CreateValueRandom(g_DataLevel.iCells);                    for(i=0;i<5;i++)                        g_DataLevel.iStyleCard[i] = rand()%11;                    for(i=0;i<30;i++)                        g_DataLevel.iStyleTank[i] = rand()%4;                    Level_SaveData(&g_DataLevel,g_iLevel);                }                g_IndexTank = 0;                 g_arBullE.RemoveAll();                g_arBullL.RemoveAll();                g_arBullR.RemoveAll();                g_arCard.RemoveAll();                g_arFire.RemoveAll();                g_arSmoke.RemoveAll();                 g_TankL.cSafety         = 0;                g_TankL.iFrame          = 0;                g_TankL.iFrend          = FM_UP;                g_TankL.iFroze          = 0;                g_TankL.iRequestFrend   = FM_NULL;                g_TankL.x               = LARGE*4;                g_TankL.y               = 12*LARGE;                 g_TankR.cSafety         = 0;                g_TankR.iFrame          = 0;                g_TankR.iFrend          = FM_UP;                g_TankR.iFroze          = 0;                g_TankR.iRequestFrend   = FM_NULL;                g_TankR.x               = LARGE*8;                g_TankR.y               = 12*LARGE;                 g_iStatus = SP_LEVEL;                KillTimer(hwnd,1);            }            else if(g_iStatus == SP_LOST)            {                if(!Level_LoadData(&g_DataLevel,g_iLevel))                {                    Cells_CreateValueRandom(g_DataLevel.iCells);                    for(i=0;i<5;i++)                        g_DataLevel.iStyleCard[i] = rand()%11;                    for(i=0;i<30;i++)                        g_DataLevel.iStyleTank[i] = rand()%4;                    Level_SaveData(&g_DataLevel,g_iLevel);                }                g_arBullE.RemoveAll();                g_arBullL.RemoveAll();                g_arBullR.RemoveAll();                g_arCard.RemoveAll();                g_arFire.RemoveAll();                g_arSmoke.RemoveAll();                g_arTankE.RemoveAll();                g_IndexTank = 0;                 // TankL                g_TankL.bBullF          = FALSE;                g_TankL.bReady          = TRUE;                g_TankL.bRiver          = FALSE;                g_TankL.cSafety         = 0;                g_TankL.cBulletJoin     = 1;                g_TankL.cLife           = 5;                g_TankL.cTimes          = 8;                g_TankL.iFrame          = 0;                g_TankL.iFrend          = FM_UP;                g_TankL.iFroze          = 0;                g_TankL.iPower          = 5;                g_TankL.iRequestFrend   = FM_NULL;                g_TankL.iShoot          = 5;                g_TankL.iSpeed          = 1;                g_TankL.x               = LARGE*4;                g_TankL.y               = 12*LARGE;                // TankR                g_TankR.bBullF          = FALSE;                g_TankR.bReady          = TRUE;                g_TankR.bRiver          = FALSE;                g_TankR.cSafety         = 0;                g_TankR.cBulletJoin     = 1;                g_TankR.cLife           = 5;                g_TankR.cTimes          = 8;                g_TankR.iFrame          = 0;                g_TankR.iFrend          = FM_UP;                g_TankR.iFroze          = 0;                g_TankR.iPower          = 5;                g_TankR.iRequestFrend   = FM_NULL;                g_TankR.iShoot          = 5;                g_TankR.iSpeed          = 1;                g_TankR.x               = LARGE*8;                g_TankR.y               = 12*LARGE;                 g_iStatus = SP_LEVEL;                KillTimer(hwnd,1);            }            return 0;        }        break;    case WM_DESTROY:        KillTimer(hwnd,1);        if(g_hwndMCI)            MCIWndDestroy(g_hwndMCI);        g_arWave.RemoveAll();        g_arTankE.RemoveAll();        g_arBullE.RemoveAll();        g_arBullL.RemoveAll();        g_arBullR.RemoveAll();        g_arCard.RemoveAll();        g_arSmoke.RemoveAll();        g_arFire.RemoveAll();        DirectX_DeleteDD();        DirectX_DeleteDS();        DirectX_DeleteDI();        PostQuitMessage(0);        return 0;    }    return DefWindowProc(hwnd,message,wparam,lparam);}
    Nói chung là hàm này khá dài và nhiều nơi còn để lại cho các cài đặt cộng thêm, các chú thích còn ít do quá tập trung vào viết mã, các bạn cố gắng hiểu nhé.
    Mình cố gắng viết theo tiêu chuẩn của 1 hàm Xử lý thông điệp Windows ( các bạn nào đã học C for Windows chắc là nắm rõ).


    Mã:
    int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lp,int nShow){    MSG         msg;    WNDCLASS    w;    HWND        hwnd;    HACCEL      hAccel;     if(!App_EnableRun())                return 0;    if(!App_UpdateFiles(hInstance))     return 0;    srand(time(NULL));    App_CheckLevelFile();    App_CheckSoundFile();    if(!Setup_LoadData(&g_DataSetup))    {        g_DataSetup.crBack              = RGB(0,0,0);        g_DataSetup.crFrame             = RGB(255,102,0);        g_DataSetup.crScreen            = RGB(0,51,0);        g_DataSetup.crText              = RGB(0,255,255);        g_DataSetup.crTitle             = RGB(255,255,0);        g_DataSetup.sndBackSound        = TRUE;        g_DataSetup.sndBonusSound       = TRUE;        g_DataSetup.sndEnemyLargeBullet = FALSE;        g_DataSetup.sndEnemyShoot       = FALSE;        g_DataSetup.sndEnemySmallBullet = FALSE;        g_DataSetup.sndLostSound        = TRUE;        g_DataSetup.sndMineSound        = TRUE;        g_DataSetup.sndOurLargeBullet   = TRUE;        g_DataSetup.sndOurShoot         = TRUE;        g_DataSetup.sndOurSmallBullet   = TRUE;        g_DataSetup.sndWinSound         = TRUE;        Setup_SaveData(&g_DataSetup);    }        g_hInst = hInstance;    w.cbClsExtra    = 0;    w.cbWndExtra    = 0;    w.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);    w.hCursor       = LoadCursor(NULL,IDC_ARROW);    w.hIcon         = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_TANK2D));    w.hInstance     = hInstance;    w.lpfnWndProc   = WndProc;    w.lpszClassName = "Tank2D";    w.lpszMenuName  = NULL;    w.style         = CS_DBLCLKS;    if(!RegisterClass(&w))        return 0;    if(!(hAccel = LoadAccelerators(hInstance,MAKEINTRESOURCE(IDR_ACCEL))))        return 0;    if(!(hwnd = CreateWindowEx(0,w.lpszClassName,w.lpszClassName,WS_VISIBLE|WS_POPUP,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN),NULL,NULL,hInstance,NULL)))        return 0;    // Các khởi tạo DirectX chỉ được thực hiện sau khi cửa sổ đã hiển thị, nên chúng ta không khởi tạo trong thông điệp WM_CREATE.    if(!DirectX_InitDD(hwnd) || !DirectX_RestoreSurfaceAll() || !DirectX_InitDI(hInstance,hwnd) || !DirectX_InitDS(hwnd))    {        DestroyWindow(hwnd);        return 0;    }    while(TRUE)    {        if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))        {            if(!GetMessage(&msg,NULL,0,0))                return msg.wParam;            if(!TranslateAccelerator(hwnd,hAccel,&msg))             {                TranslateMessage(&msg);                DispatchMessage(&msg);            }        }        else if(g_bActive)            App_Update(g_iLevel);        else            WaitMessage();    }}
    Đây là hàm điểm nhập cho chương trình, vòng lặp nhận thông điệp đã được thay đổi phù hợp theo chương trình.
    Mình đã biên dịch và chạy tương đối ổ định, đang tiếp tục tìm các lỗi Logic, màn hình biên dịch như sau



    Thư mục dự án mình sẽ làm gọn và post lên trang kế tiếp.
    Chào thân ái.

    [IMG]images/smilies/opacli.gif[/IMG][IMG]images/smilies/opacli.gif[/IMG][IMG]images/smilies/opacli.gif[/IMG][IMG]images/smilies/opacli.gif[/IMG][IMG]images/smilies/opacli.gif[/IMG][IMG]images/smilies/opacli.gif[/IMG][IMG]images/smilies/opacli.gif[/IMG][IMG]images/smilies/opacli.gif[/IMG][IMG]images/smilies/opacli.gif[/IMG][IMG]images/smilies/opacli.gif[/IMG][IMG]images/smilies/opacli.gif[/IMG][IMG]images/smilies/opacli.gif[/IMG][IMG]images/smilies/opacli.gif[/IMG][IMG]images/smilies/opacli.gif[/IMG][IMG]images/smilies/opacli.gif[/IMG]

    <font color="silver">- - - Nội dung đã được cập nhật ngày 21-03-2014 lúc 03:52 PM - - -


    Đây là thư mục dự án Tank2D

  5. #15
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Ngày 29: Chức năng của F2

    Trong chương trình Tank2D còn rất nhiều điều chúng ta chưa xử lý, hôm nay mình viết tiếp các thao tác của người chơi khi thao tác
    thiết kế lại một vòng chơi bất kỳ. Như đã biết, một vòng chơi có 3 yếu tố : Cấu trúc khung chơi, các kiểu Tank. và các thẻ cộng thêm.
    Ngày hôm nay, mình sẽ mã thêm cho chức năng của phím F2 - Người chơi thay đổi kết cấu của 1 vòng chơi.
    Điều này cần thiết phải hiển thị 1 hộp thoại cho người chơi thay đổi vòng chơi một cách trực quan nhất.
    Từ IDE của VC++6.0, Insert->Resource...->Insert Resource->Dialog->New. Thay đổi id hộp thoại thành IDD_DIALOG_DESIGN
    Trong bản mẫu hôp thoại, xóa 2 button <OK> và <Cancel>, chúng ta không cần 2 button này.
    Tính toán ban đầu cho thấy chúng ta cần 52*52=2704 button cho các SmallCells, 30 button cho các hình ảnh Tank, 5 hình ảnh cho các Card, trình soạn thảo tài nguyên của
    Microsotft VC++6.0 không cho phép vượt quá 512 điều khiển trên khung hiển thị khi thiết kế. Vì vậy chúng ta sẽ dùng mã để thêm vào khi chượng trình thực thi.

    Trong hàm WndProc(), ở Đoạn mã xử lý thông điệp WM_COMMAND thêm vào như sau:

    Mã:
            case IDC_F2:            if(g_lpDD && g_iStatus == SP_LEVEL)            {                g_lpDD->FlipToGDISurface();                g_bMoused = TRUE;                SendMessage(hwnd,WM_SETCURSOR,0,0);                DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG_DESIGN),hwnd,DlgProc_Design);                g_bMoused = FALSE;                SendMessage(hwnd,WM_SETCURSOR,0,0);            }            return 0;
    Thêm một hàm xử lý cho hộp thoại, hàm này đặt trước WndProc()

    Mã:
    BOOL CALLBACK DlgProc_Design(HWND hDlg,UINT message,WPARAM wparam,LPARAM lparam){#define     IDC_BUTTON_RANDOM   10001#define     IDC_BUTTON_RESET    10002#define     IDC_BUTTON_UPDATE   10003#define     IDC_BUTTON_CLOSE    10004#define     IDC_COMBO_CURSOR    10005    static  HWND        hCell[52][52];      // 2704    static  HWND        hTank[30];          //    static  HWND        hCard[5];           //    static  HWND        hCombo;    static  DATALEVEL   Data;    static  int         iLevel;    static  HBRUSH      hbrBack;    static  int         iCursor;    static  BOOL        bChanged;    LPDRAWITEMSTRUCT    pd;    LPDIRECTDRAWSURFACE lpSur;    CHAR                szText[MAX_PATH];    RECT                r;    HBRUSH              hBrush;    HDC                 hdcSur;    HANDLE              hFile;    int                 i,x,y,x1,y1,m,n,cx,cy,value;     switch(message)    {    case WM_INITDIALOG:        SetClassLong(hDlg,GCL_HICON,(LONG)LoadIcon(g_hInst,MAKEINTRESOURCE(IDI_TANK2D)));        bChanged = FALSE;        iLevel = g_iLevel;        wsprintf(szText,"Design Level %i",iLevel+1);        SetWindowText(hDlg,szText);        if(!Level_LoadData(&Data,iLevel))        {            Cells_CreateValueRandom(Data.iCells);            for(i=0;i<30;i++)                Data.iStyleTank[i] = rand()%50;            for(i=0;i<5;i++)                Data.iStyleCard[i] = rand()%11;        }        else            Cells_CreateValueDefault(Data.iCells);        SetRect(&r,0,0,20+LARGE*13+20+40*4+20,20+LARGE*13+20+25+20);        AdjustWindowRect(&r,WS_CAPTION,FALSE);        cx = r.right-r.left;        cy = r.bottom-r.top;        x = (GetSystemMetrics(SM_CXSCREEN) - cx)/2;        y = (GetSystemMetrics(SM_CYSCREEN) - cy)/2;        MoveWindow(hDlg,x,y,cx,cy,FALSE);        for(x=0;x<52;x++)        for(y=0;y<52;y++)            hCell[x][y] = CreateWindow("button","",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,20+x*8,20+y*8,8,8,hDlg,(HMENU)(x+y*52),g_hInst,NULL);        for(i=0;i<30;i++)            hTank[i] = CreateWindow("button","",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,20+LARGE*13+20+(i%4)*40,20+(i/4)*40,32,32,hDlg,(HMENU)(5000+i),g_hInst,NULL);        for(i=0;i<5;i++)            hCard[i] = CreateWindow("button","",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,20+LARGE*13+20+i*30,20+40*8+20,SMALL*3,SMALL*3,hDlg,(HMENU)(6000+i),g_hInst,NULL);        hCombo = CreateWindow("combobox","",WS_VSCROLL|WS_CHILD|WS_VISIBLE|CBS_DROPDOWNLIST,20+LARGE*13+20,20+40*8+20+SMALL*3+20,40*4,100,hDlg,(HMENU)IDC_COMBO_CURSOR,g_hInst,NULL);        SendMessage(hCombo,CB_ADDSTRING,0,(LPARAM)"Change LargeCell");        SendMessage(hCombo,CB_ADDSTRING,0,(LPARAM)"Change MediumCell");        SendMessage(hCombo,CB_ADDSTRING,0,(LPARAM)"Change SmallCell");        SendMessage(hCombo,CB_SETCURSEL,iCursor,0);        CreateWindow("button","Random",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,20+LARGE,      20+LARGE*13+20,LARGE*3,25,hDlg,(HMENU)IDC_BUTTON_RANDOM,g_hInst,NULL);        CreateWindow("button","Reset", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,20+LARGE*5,    20+LARGE*13+20,LARGE*3,25,hDlg,(HMENU)IDC_BUTTON_RESET,g_hInst,NULL);        CreateWindow("button","Update",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,20+LARGE*9,    20+LARGE*13+20,LARGE*3,25,hDlg,(HMENU)IDC_BUTTON_UPDATE,g_hInst,NULL);        CreateWindow("button","Close", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,20+LARGE*14,   20+LARGE*13+20,LARGE*4,25,hDlg,(HMENU)IDC_BUTTON_CLOSE,g_hInst,NULL);        hbrBack = CreateSolidBrush(g_DataSetup.crScreen);        return TRUE;    case WM_DRAWITEM:        pd = (LPDRAWITEMSTRUCT) lparam;        if(pd->CtlID < 52*52)        {            x = pd->CtlID % 52;            y = pd->CtlID / 52;             if(Data.iCells[x][y] == TC_FREE)            {                hBrush = CreateSolidBrush(g_DataSetup.crBack);                FillRect(pd->hDC,&pd->rcItem,hBrush);                DeleteObject(hBrush);            }            else if(Data.iCells[x][y] == TC_BRICK)            {                if(g_lpBrick->GetDC(&hdcSur) == DD_OK)                {                    BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,0,0,SRCCOPY);                    g_lpBrick->ReleaseDC(hdcSur);                }            }            else if(Data.iCells[x][y] == TC_STEEL)            {                if(g_lpSteel->GetDC(&hdcSur) == DD_OK)                {                    if(x%2==0 && y%2==0)        BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,0,0,SRCCOPY);                    else if(x%2==0 && y%2!=0)   BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,0,SMALL,SRCCOPY);                    else if(x%2!=0 && y%2==0)   BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,SMALL,0,SRCCOPY);                    else                        BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,SMALL,SMALL,SRCCOPY);                    g_lpSteel->ReleaseDC(hdcSur);                }            }            else            {                if(Data.iCells[x][y] == TC_RIVER)           lpSur = g_lpRiver;                else if(Data.iCells[x][y] == TC_COVER)      lpSur = g_lpCover;                else if(Data.iCells[x][y] == TC_GLIDE)      lpSur = g_lpGlide;                else                                        lpSur = g_lpHouse;                if(lpSur->GetDC(&hdcSur) == DD_OK)                {                    if(x%4==0 && y%4==0)            BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,0,        0,      SRCCOPY);                    else if(x%4==0 && y%4==1)       BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,0,        SMALL,  SRCCOPY);                    else if(x%4==0 && y%4==2)       BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,0,        SMALL*2,SRCCOPY);                    else if(x%4==0 && y%4==3)       BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,0,        SMALL*3,SRCCOPY);                     else if(x%4==1 && y%4==0)       BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,SMALL,    0,      SRCCOPY);                    else if(x%4==1 && y%4==1)       BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,SMALL,    SMALL,  SRCCOPY);                    else if(x%4==1 && y%4==2)       BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,SMALL,    SMALL*2,SRCCOPY);                    else if(x%4==1 && y%4==3)       BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,SMALL,    SMALL*3,SRCCOPY);                     else if(x%4==2 && y%4==0)       BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,SMALL*2,  0,      SRCCOPY);                    else if(x%4==2 && y%4==1)       BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,SMALL*2,  SMALL,  SRCCOPY);                    else if(x%4==2 && y%4==2)       BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,SMALL*2,  SMALL*2,SRCCOPY);                    else if(x%4==2 && y%4==3)       BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,SMALL*2,  SMALL*3,SRCCOPY);                     else if(x%4==3 && y%4==0)       BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,SMALL*3,  0,      SRCCOPY);                    else if(x%4==3 && y%4==1)       BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,SMALL*3,  SMALL,  SRCCOPY);                    else if(x%4==3 && y%4==2)       BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,SMALL*3,  SMALL*2,SRCCOPY);                    else                            BitBlt(pd->hDC,0,0,SMALL,SMALL,hdcSur,SMALL*3,  SMALL*3,SRCCOPY);                    lpSur->ReleaseDC(hdcSur);                }            }        }        else if(pd->CtlID >= 5000 && pd->CtlID <= 5029)        {            if(g_lpTankE[Data.iStyleTank[29-(pd->CtlID - 5000)]]->GetDC(&hdcSur) == DD_OK)            {                BitBlt(pd->hDC,0,0,LARGE,LARGE,hdcSur,0,0,SRCCOPY);                g_lpTankE[Data.iStyleTank[29-(pd->CtlID - 5000)]]->ReleaseDC(hdcSur);            }        }        else if(pd->CtlID >= 6000 && pd->CtlID <= 6004)        {            if(g_lpCard[Data.iStyleCard[pd->CtlID - 6000]]->GetDC(&hdcSur) == DD_OK)            {                BitBlt(pd->hDC,0,0,SMALL*3,SMALL*3,hdcSur,0,0,SRCCOPY);                g_lpCard[Data.iStyleCard[pd->CtlID - 6000]]->ReleaseDC(hdcSur);            }        }        return TRUE;    case WM_COMMAND:        switch(LOWORD(wparam))        {        case IDC_COMBO_CURSOR:            if(HIWORD(wparam) == CBN_SELCHANGE)            {                i = SendMessage(hCombo,CB_GETCURSEL,0,0);                if(i != CB_ERR)                    iCursor = i;                return TRUE;            }            break;        case IDC_BUTTON_RANDOM:            Cells_CreateValueRandom(Data.iCells);            for(i=0;i<30;i++)                Data.iStyleTank[i] = rand()%50;            for(i=0;i<5;i++)                Data.iStyleCard[i] = rand()%11;            for(x=0;x<52;x++)            for(y=0;y<52;y++)                InvalidateRect(hCell[x][y],NULL,FALSE);            for(i=0;i<30;i++)                InvalidateRect(hTank[i],NULL,FALSE);            for(i=0;i<5;i++)                InvalidateRect(hCard[i],NULL,FALSE);            bChanged = TRUE;            return TRUE;        case IDC_BUTTON_RESET:            GetModuleFileName(NULL,szText,MAX_PATH);            PathRemoveFileSpec(szText);            lstrcat(szText,"\\Tank2D");            wsprintf(szText,"%s\\Level%i.lev",szText,iLevel+1);            if(INVALID_HANDLE_VALUE!=(hFile=CreateFile(szText,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL)))            {                HRSRC       hFind,hLoad;                PCHAR       pLock;                BOOL        bFlag = TRUE;                 if(hFind = FindResource(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_LEVEL1+iLevel),"LEVEL"))                if(hLoad = (HRSRC)LoadResource(GetModuleHandle(NULL),hFind))                if(pLock = (PCHAR)LockResource(hLoad))                {                    DWORD   dw,dwSize = SizeofResource(GetModuleHandle(NULL),hFind);                    if(!WriteFile(hFile,pLock,dwSize,&dw,NULL) || dwSize != dw)                        bFlag = FALSE;                }                CloseHandle(hFile);                if(!bFlag)                    DeleteFile(szText);                if(!Level_LoadData(&Data,iLevel))                {                    Cells_CreateValueRandom(Data.iCells);                    for(i=0;i<30;i++)                        Data.iStyleTank[i] = rand()%50;                    for(i=0;i<5;i++)                        Data.iStyleCard[i] = rand()%11;                }                else                    Cells_CreateValueDefault(Data.iCells);                for(x=0;x<52;x++)                for(y=0;y<52;y++)                    InvalidateRect(hCell[x][y],NULL,FALSE);                for(i=0;i<30;i++)                    InvalidateRect(hTank[i],NULL,FALSE);                for(i=0;i<5;i++)                    InvalidateRect(hCard[i],NULL,FALSE);                bChanged = TRUE;            }            return TRUE;        case IDC_BUTTON_UPDATE:            if(bChanged)            {                Level_SaveData(&Data,iLevel);                CopyMemory(&g_DataLevel,&Data,sizeof(DATALEVEL));                DirectX_RestoreSurfaceAll();                bChanged = FALSE;            }            return TRUE;        case IDC_BUTTON_CLOSE:            SendMessage(hDlg,WM_CLOSE,0,0);            return TRUE;        }        if(LOWORD(wparam) < 52*52)        {            x = LOWORD(wparam) % 52;            y = LOWORD(wparam) / 52;            if(y<4)            {                if(x<4)                 return 0;                if(x>=24 && x<28)       return 0;                if(x>47)                return 0;            }            if(x>=16 && x<36 && y>43)   return 0;             value = Data.iCells[x][y];            if(iCursor == 0)                // Thay doi 4x4            {                value++;                if(value == TC_HOUSE)                    value = TC_FREE;                x1 = x/4*4;                y1 = y/4*4;                for(m=x1;m<x1+4;m++)                for(n=y1;n<y1+4;n++)                {                    Data.iCells[m][n] = value;                    InvalidateRect(hCell[m][n],NULL,FALSE);                }            }            else if(iCursor == 1)       // Thay doi 2x2             {                if(value > TC_STEEL)                {                    iCursor = 0;                    SendMessage(hCombo,CB_SETCURSEL,0,0);                    value++;                    if(value == TC_HOUSE)                        value = TC_FREE;                    x1 = x/4*4;                    y1 = y/4*4;                    for(m=x1;m<x1+4;m++)                    for(n=y1;n<y1+4;n++)                    {                        Data.iCells[m][n] = value;                        InvalidateRect(hCell[m][n],NULL,FALSE);                    }                }                else                {                    value++;                    if(value > TC_STEEL)                        value = TC_FREE;                    x1 = x/2*2;                    y1 = y/2*2;                    for(m=x1;m<x1+2;m++)                    for(n=y1;n<y1+2;n++)                    {                        Data.iCells[m][n] = value;                        InvalidateRect(hCell[m][n],NULL,FALSE);                    }                }            }            else                        // Thay doi 1            {                if(value > TC_STEEL)                {                    iCursor = 0;                    SendMessage(hCombo,CB_SETCURSEL,0,0);                    value++;                    if(value == TC_HOUSE)                        value = TC_FREE;                    x1 = x/4*4;                    y1 = y/4*4;                    for(m=x1;m<x1+4;m++)                    for(n=y1;n<y1+4;n++)                    {                        Data.iCells[m][n] = value;                        InvalidateRect(hCell[m][n],NULL,FALSE);                    }                }                else if(value == TC_STEEL)                {                    iCursor = 1;                    SendMessage(hCombo,CB_SETCURSEL,1,0);                    value++;                    if(value > TC_STEEL)                        value = TC_FREE;                    x1 = x/2*2;                    y1 = y/2*2;                    for(m=x1;m<x1+2;m++)                    for(n=y1;n<y1+2;n++)                    {                        Data.iCells[m][n] = value;                        InvalidateRect(hCell[m][n],NULL,FALSE);                    }                }                else                {                    value++;                    if(value > TC_BRICK)                        value = TC_FREE;                    Data.iCells[x][y] = value;                    InvalidateRect(hCell[x][y],NULL,FALSE);                }            }            bChanged = TRUE;            return TRUE;        }        i = LOWORD(wparam);        if(i >= 5000 && i <= 5029)        {            if(++Data.iStyleTank[29-(i-5000)] >= 50)                Data.iStyleTank[29-(i-5000)] = 0;            SetFocus(hDlg);            bChanged = TRUE;            return TRUE;        }        break;    case WM_CTLCOLORDLG:        return (int)hbrBack;    case WM_CLOSE:        DeleteObject(hbrBack);        EndDialog(hDlg,0);        return TRUE;    }    return FALSE;}
    Mục đích của hàm thủ tục này thì có lẽ các bạn cũng nắm rõ - chỉ là theo tiêu chuẩn thông thường thôi.
    Ở đây, vì mình chỉ chạy theo mã hóa nên ít có chú thích, bạn nào thấy khó hiểu thì cứ nêu lên mình sẽ giải thích rõ hơn.

    Mong rằng các bạn có thể hiểu và góp ý thêm cho mình.

    Ngày hôm nay đến đây thôi, cũng mỏi tay rồi, hẹn ngày sau chúng ta sẽ xử lý F3 !



    [IMG]images/smilies/17.gif[/IMG] [IMG]images/smilies/17.gif[/IMG] [IMG]images/smilies/17.gif[/IMG]

    - - - Nội dung đã được cập nhật ngày 25-03-2014 lúc 03:08 PM - - -</font>

    <font color="#0000FF">NGÀY 30:
    Chức năng của phím F3

    Chúng ta sẽ cho người chơi thực hiện các thay đổi màu sắc bằng phím F3, màu sẽ được lưu trữ bên ngoài chương trình nên được sử dụng cho cả các lần chơi sau.
    Tạo một hộp thoại với id là IDD_DIALOG_COLOR.
    Ngoài 2 button có sẵn, chúng ta thêm vào 6 Button mới có id là : IDC_BUTTON1,IDC_BUTTON2,IDC_BUTTON3,IDC_BUTTON4,ID C_BUTTON5,IDC_BUTTON6.
    5 Button đầu có kiểu tự vẽ, button thứ 6 bình thường có Text là "Origin".
    Đổi Text button OK thành "Update".
    Đổi Text button Cancel thành "Close".
    Sắp xếp lại cho dễ nhìn như hình ở cuối ngày.

    Trong hàm WndProc(), ở Đoạn mã xử lý thông điệp WM_COMMAND thêm vào như sau:

    Mã:
    case IDC_F3:            if(g_lpDD && g_iStatus == SP_LEVEL)            {                g_lpDD->FlipToGDISurface();                g_bMoused = TRUE;                SendMessage(hwnd,WM_SETCURSOR,0,0);                DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG_COLOR),hwnd,DlgProc_Color);                g_bMoused = FALSE;                SendMessage(hwnd,WM_SETCURSOR,0,0);            }            return 0;
    Thêm một hàm xử lý cho hộp thoại, hàm này đặt trước WndProc()

    Mã:
    BOOL CALLBACK DlgProc_Color(HWND hDlg,UINT message,WPARAM wparam,LPARAM lparam){    static  HWND        hButton[5];    static  DATASETUP   Data;    static  BOOL        bChanged;    LPDRAWITEMSTRUCT    pd;    HBRUSH              hBrush;    CHOOSECOLOR         cc;    COLORREF            arColor[16];    COLORREF            cr;    CHAR                szText[MAX_PATH];     switch(message)    {    case WM_INITDIALOG:        SetClassLong(hDlg,GCL_HICON,(LONG)LoadIcon(g_hInst,MAKEINTRESOURCE(IDI_TANK2D)));        hButton[0] = GetDlgItem(hDlg,IDC_BUTTON1);        hButton[1] = GetDlgItem(hDlg,IDC_BUTTON2);        hButton[2] = GetDlgItem(hDlg,IDC_BUTTON3);        hButton[3] = GetDlgItem(hDlg,IDC_BUTTON4);        hButton[4] = GetDlgItem(hDlg,IDC_BUTTON5);        CopyMemory(&Data,&g_DataSetup,sizeof(DATASETUP));        bChanged = FALSE;        return TRUE;    case WM_DRAWITEM:        pd = (LPDRAWITEMSTRUCT)lparam;        if(pd->CtlID == IDC_BUTTON1)        cr = Data.crScreen; // Screen Color        else if(pd->CtlID == IDC_BUTTON2)   cr = Data.crBack;   // Back Color        else if(pd->CtlID == IDC_BUTTON3)   cr = Data.crFrame;  // Frame Color        else if(pd->CtlID == IDC_BUTTON4)   cr = Data.crTitle;  // Title Color        else                                cr = Data.crText;   // Text Color        hBrush = CreateSolidBrush(cr);        FillRect(pd->hDC,&pd->rcItem,hBrush);        DeleteObject(hBrush);        SetTextColor(pd->hDC, (~(cr << 8)) >> 8);               // Màu chữ là màu đảo của màu nền        SetBkMode(pd->hDC,TRANSPARENT);        if(pd->CtlID == IDC_BUTTON1)        wsprintf(szText,"Screen Color");        else if(pd->CtlID == IDC_BUTTON2)   wsprintf(szText,"Back Color");        else if(pd->CtlID == IDC_BUTTON3)   wsprintf(szText,"Frame Color");        else if(pd->CtlID == IDC_BUTTON4)   wsprintf(szText,"Title Color");        else                                wsprintf(szText,"Text Color");        DrawText(pd->hDC,szText,-1,&pd->rcItem,DT_SINGLELINE|DT_CENTER|DT_VCENTER);        return TRUE;    case WM_COMMAND:        switch(LOWORD(wparam))        {        case IDC_BUTTON1:        case IDC_BUTTON2:        case IDC_BUTTON3:        case IDC_BUTTON4:        case IDC_BUTTON5:            if(LOWORD(wparam) == IDC_BUTTON1)       cr = Data.crScreen; // Screen Color            else if(LOWORD(wparam) == IDC_BUTTON2)  cr = Data.crBack;   // Back Color            else if(LOWORD(wparam) == IDC_BUTTON3)  cr = Data.crFrame;  // Frame Color            else if(LOWORD(wparam) == IDC_BUTTON4)  cr = Data.crTitle;  // Title Color            else                                    cr = Data.crText;   // Text Color            ZeroMemory(&cc,sizeof(CHOOSECOLOR));            cc.lStructSize  = sizeof(CHOOSECOLOR);            cc.hwndOwner    = hDlg;            cc.lpCustColors = arColor;            cc.Flags        = CC_FULLOPEN|CC_RGBINIT;            cc.rgbResult    = cr;            if(ChooseColor(&cc))            // Show ChooseColor Dialog            if(cr != cc.rgbResult)            {                if(LOWORD(wparam) == IDC_BUTTON1)       { Data.crScreen = cc.rgbResult; InvalidateRect(hButton[0],NULL,FALSE);} // Screen Color                else if(LOWORD(wparam) == IDC_BUTTON2)  { Data.crBack   = cc.rgbResult; InvalidateRect(hButton[1],NULL,FALSE);} // Back Color                else if(LOWORD(wparam) == IDC_BUTTON3)  { Data.crFrame  = cc.rgbResult; InvalidateRect(hButton[2],NULL,FALSE);} // Frame Color                else if(LOWORD(wparam) == IDC_BUTTON4)  { Data.crTitle  = cc.rgbResult; InvalidateRect(hButton[3],NULL,FALSE);} // Title Color                else                                    { Data.crText   = cc.rgbResult; InvalidateRect(hButton[4],NULL,FALSE);} // Text Color                bChanged = TRUE;            }            return TRUE;        case IDC_BUTTON6:            Data.crScreen   = RGB(0,51,0);      InvalidateRect(hButton[0],NULL,FALSE);  // Screen Color            Data.crBack     = RGB(0,0,0);       InvalidateRect(hButton[1],NULL,FALSE);  // Back Color            Data.crFrame    = RGB(255,102,0);   InvalidateRect(hButton[2],NULL,FALSE);  // Frame Color            Data.crTitle    = RGB(255,255,0);   InvalidateRect(hButton[3],NULL,FALSE);  // Title Color            Data.crText     = RGB(0,255,255);   InvalidateRect(hButton[4],NULL,FALSE);  // Text Color            bChanged = TRUE;            return TRUE;        case IDOK:            if(bChanged)            {                CopyMemory(&g_DataSetup,&Data,sizeof(DATASETUP));                Setup_SaveData(&g_DataSetup);            }        case IDCANCEL:            SendMessage(hDlg,WM_CLOSE,0,0);            return TRUE;        }        break;    case WM_CLOSE:        EndDialog(hDlg,0);        return TRUE;    }    return FALSE;}
    Mã trong hàm này là dễ hiểu. Người chơi Click vào 1 trong 5 button có màu và thay đổi nó, chương trình đáp ứng bằng cách vẽ lại màu mới vào chính button đó.
    Button "Origin" là để lấy lại màu nguyên thủy ( màu mặc định lấy từ trong chương trình).
    Nếu người chơi chọn "Update", và nếu có bất kỳ 1 trong 5 màu đã thay đổi, chương trình sẽ cập nhật và lưu lại cho sau này.

    Có 1 chỗ mã hơi rắc rối : SetTextColor(pd->hDC, (~(cr << 8)) >> 8);
    Hiện tại, màu rgb được lưu trong 32bits, nhưng giá trị chỉ ở trong 24Bits cuối, 8Bits đầu phải là 0, vì vậy mới có cách tính trên.
    Ví dụ :
    _ Cho màu A là : 00000000 01010111 00110101 11110001
    _ Dịch trái 8Bits: 01010111 00110101 11110001 00000000
    _ Đảo màu đã dịch: 10101000 11001010 00001110 11111111
    _ Dịch phải 8Bits: 00000000 10101000 11001010 00001110
    Màu cuối cùng là màu đảo của A.



    Ngày hôm nay tới đây, tạm gác bút thôi. [IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG]

  6. #16
    Ngày tham gia
    Dec 2015
    Bài viết
    0
    NGÀY 31: Chức năng của phím F1

    Hầu hết các bạn nào đã học qua C for Windows hoặc VC đều có thể xuất một hộp thoại About một cách dễ dàng.
    Ngày nay, chúng ta sẽ thêm nó khi người sử dụng nhấn F1.
    Tạo một bản mẫu hộp thoại mới, thay đổi id = IDD_DIALOG_ABOUT, xóa button có sẵn OK.
    Đổi kiểu của button Cancel thành tự vẽ, canh chỉnh lại hộp thoại cho khoảng 6 dòng Text, bề ngang đủ chứa Text trong thanh địa chỉ
    mà bạn thấy ở phía trên, đây chỉ là tương đối thôi, sau khi biên dịch và chạy bạn có thể thay đổi lại cho vừa vặn.

    Mã cập nhật cho hàm WndProc, thông điệp WM_COMMAND, cho F1 như sau

    Mã:
    case IDC_F1:            if(g_lpDD && g_iStatus == SP_LEVEL)            {                g_lpDD->FlipToGDISurface();                g_bMoused = TRUE;                SendMessage(hwnd,WM_SETCURSOR,0,0);                DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG_ABOUT),hwnd,DlgProc_About);                g_bMoused = FALSE;                SendMessage(hwnd,WM_SETCURSOR,0,0);            }            return 0;
    Hàm xử lý thông điệp cho hộp thoại này như sau ( vẫn nhớ rằng đặt trước WndProc())

    Mã:
    BOOL CALLBACK DlgProc_About(HWND hDlg,UINT message,WPARAM wparam,LPARAM lparam){    LPDRAWITEMSTRUCT        pd;    HBRUSH                  hBrush;    HFONT                   hFont;    RECT                    r;    int                     i;    PCHAR                   psz[] =     {        "__________ GAME DIRECTX - TANK2D __________",        "Programer : Nguyen Minh Hoang",        "Language : C / C++",        "IDE : Microsoft Visual C++6.0",        "Building : 2-3 / 2014",        "http://diendan.congdongcviet.com/threads/t203373::thuc-hanh-lap-trinh-game-vc-6-0-su-dung-directx-tank2d.cpp"    };     switch(message)    {    case WM_INITDIALOG:        SetClassLong(hDlg,GCL_HICON,(LONG)LoadIcon(g_hInst,MAKEINTRESOURCE(IDI_TANK2D)));   // Nạp biểu tượng chính cho hộp thoại        GetClientRect(hDlg,&r);        MoveWindow(GetDlgItem(hDlg,IDCANCEL),0,0,r.right-r.left,r.bottom-r.top,FALSE);      // Mở rộng Button Cancel chiếm hết vùng Client        return TRUE;    case WM_DRAWITEM:        pd = (LPDRAWITEMSTRUCT)lparam;        hBrush = CreateSolidBrush(g_DataSetup.crScreen);        FillRect(pd->hDC,&pd->rcItem,hBrush);                                               // Tô màu button Cancel        DeleteObject(hBrush);        SetBkMode(pd->hDC,TRANSPARENT);        GetClientRect(GetDlgItem(hDlg,IDCANCEL),&r);        SetTextColor(pd->hDC,g_DataSetup.crTitle);        hFont = CreateFont(24,0,0,0,FW_BOLD,0,0,0,0,0,0,0,0,"MS Sans Serif");               // Tạo Font chữ lớn cho Title        SelectObject(pd->hDC,hFont);        r.top = 20; r.bottom = 50;        DrawText(pd->hDC,psz[0],-1,&r,DT_SINGLELINE|DT_CENTER|DT_VCENTER);        DeleteObject(hFont);        r.top += 50; r.bottom = r.top + 25;        SetTextColor(pd->hDC,g_DataSetup.crText);        hFont = CreateFont(8,0,0,0,FW_NORMAL,0,0,0,0,0,0,0,0,"MS Sans Serif");              // Tạo Font chữ nhỏ cho các Text        SelectObject(pd->hDC,hFont);        for(i=1;i<6;i++)        {            if(i==5)                SetTextColor(pd->hDC,g_DataSetup.crFrame);                                  // Tạo màu khác cho Link            DrawText(pd->hDC,psz[i],-1,&r,DT_SINGLELINE|DT_CENTER|DT_VCENTER);            r.top += 25; r.bottom = r.top + 25;        }        DeleteObject(hFont);        return TRUE;    case WM_COMMAND:        if(LOWORD(wparam) == IDCANCEL)        {            SendMessage(hDlg,WM_CLOSE,0,0);            return TRUE;        }        break;    case WM_CLOSE:        EndDialog(hDlg,0);        return TRUE;    }    return FALSE;}
    Thủ tục thông điệp này không có gì khó hiểu cả phải không các bạn. Chỉ là vẽ lên hộp thoại ( mà thực chất là vẽ lên Button) vài dòng chữ
    quảng cáo cho Game mà thôi ( cũng khuyến khích bạn thêm bất kỳ hoa lá cành ở hộp thoại này) . Khi thực thi nó trông sẽ như sau


    Ngày nay tới đây thôi, Byebye !!! [IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG]

  7. #17
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    NGÀY 32: Thay đổi hình ảnh bất kỳ với F4

    Trong các ngày đầu, chúng ta đã nói rằng sẽ để cho người chơi toàn quyền thay đổi các hình ảnh của chương trình.
    Chức năng này đáng ra không nên có nếu bạn là người có năng khiếu vẽ, do mình vẽ quá xấu nên phải bù vào bằng
    mã thôi ( Nếu vẽ tốt, chúng ta chỉ cần tạo 50 hình ảnh TankE và 2 Tank của ta rồi lưu vào tài nguyên, lúc đó cũng chẳng cần
    tới 4 hàm DirectX_RestoreSurfaceFromFile(), App_CheckBMPFile(), Bitmap_CreateFile(), Bitmap_CreateInfoStruct()).

    Tạo một bản mẫu hộp thoại mới, thay đổi id = IDD_DIALOG_IMAGE. Xóa tất cả các Button.
    Đưa vào 1 listbox với id = IDC_LIST1, nhấn phải vào nó chọn Properties, chuyển tới tab <Styles> bỏ dấu kiểm "Sort",
    chuyển tới tab <Extended Styles> check vào dấu kiểm "Modal frame" để cho khung dễ nhìn hơn.
    Đưa vào 1 Button với id = IDC_BUTTON1, trong hộp thuộc tính của nó, ở tab <Styles> Check thuộc tính "Owner draw",
    ở tab <Extended Styles> Check vào thuộc tính "Modal frame"
    Kéo dãn hộp thoại ra thêm và chỉnh sửa thêm sau khi biên dịch và chạy chương trình.

    Mã cập nhật cho hàm WndProc, thông điệp WM_COMMAND, cho F1 như sau

    Mã:
    case IDC_F4:            if(g_lpDD && g_iStatus == SP_LEVEL)            {                g_lpDD->FlipToGDISurface();                g_bMoused = TRUE;                SendMessage(hwnd,WM_SETCURSOR,0,0);                DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG_IMAGE),hwnd,DlgProc_Image);                g_bMoused = FALSE;                SendMessage(hwnd,WM_SETCURSOR,0,0);            }            return 0;
    Hàm xử lý thông điệp cho hộp thoại này như sau ( vẫn nhớ rằng đặt trước WndProc())

    Mã:
    BOOL CALLBACK DlgProc_Image(HWND hDlg,UINT message,WPARAM wparam,LPARAM lparam){    static  HWND        hList;    static  HWND        hbtOwnerDraw;    static  HBRUSH      hbrBack;    CHAR                szText[MAX_PATH],szFolder[MAX_PATH],szFile[MAX_PATH];    LPDIRECTDRAWSURFACE lpSur;    LPDRAWITEMSTRUCT    pd;    HDC                 hdcSur;    DDSURFACEDESC       ddsd;    int                 i,iIndex;    RECT                r;    SIZE                sizeTotal,sizeArray,sizeFrame;    OPENFILENAME        ofn;     switch(message)    {    case WM_INITDIALOG:        SetClassLong(hDlg,GCL_HICON,(LONG)LoadIcon(g_hInst,MAKEINTRESOURCE(IDI_TANK2D)));        hbrBack = CreateSolidBrush(g_DataSetup.crScreen);        hbtOwnerDraw = GetDlgItem(hDlg,IDC_BUTTON1);        hList = GetDlgItem(hDlg,IDC_LIST1);        // Bắt đầu đổ dữ liệu vào Listbox        for(i=0;i<50;i++)        {            wsprintf(szText,"Enemy Tank #%i",i+1);            SendMessage(hList,LB_ADDSTRING,0,(LPARAM)szText);        }        SendMessage(hList,LB_ADDSTRING,0,(LPARAM)"Left Tank");        SendMessage(hList,LB_ADDSTRING,0,(LPARAM)"Right Tank");        for(i=0;i<=10;i++)        {            wsprintf(szText,"Card #%i",i+1);            SendMessage(hList,LB_ADDSTRING,0,(LPARAM)szText);        }        SendMessage(hList,LB_ADDSTRING,0,(LPARAM)"Brick");        SendMessage(hList,LB_ADDSTRING,0,(LPARAM)"Steel");        SendMessage(hList,LB_ADDSTRING,0,(LPARAM)"River");        SendMessage(hList,LB_ADDSTRING,0,(LPARAM)"Cover");        SendMessage(hList,LB_ADDSTRING,0,(LPARAM)"Glide");        SendMessage(hList,LB_ADDSTRING,0,(LPARAM)"House");        SendMessage(hList,LB_ADDSTRING,0,(LPARAM)"Fire");        SendMessage(hList,LB_ADDSTRING,0,(LPARAM)"Smoke");        SendMessage(hList,LB_ADDSTRING,0,(LPARAM)"Fire Bullet");        SendMessage(hList,LB_ADDSTRING,0,(LPARAM)"Normal Bullet");        SendMessage(hList,LB_SETCURSEL,0,0);        SetFocus(hList);        return FALSE;    case WM_DRAWITEM:        pd = (LPDRAWITEMSTRUCT)lparam;        iIndex = SendMessage(hList,LB_GETCURSEL,0,0);        FillRect(pd->hDC,&pd->rcItem,(HBRUSH)GetStockObject(DKGRAY_BRUSH));     // Tô màu xám đậm cho Button        if(iIndex == LB_ERR)            return TRUE;        if(iIndex >= 0 && iIndex < 50)          lpSur = g_lpTankE[iIndex];      // 50 TankE        else if(iIndex == 50)                   lpSur = g_lpTankL;              // TankL        else if(iIndex == 51)                   lpSur = g_lpTankR;              // TankR        else if(iIndex > 51 && iIndex <= 62)    lpSur = g_lpCard[iIndex-52];    // 11 Card        else if(iIndex == 63)                   lpSur = g_lpBrick;              // Brick        else if(iIndex == 64)                   lpSur = g_lpSteel;              // Steel        else if(iIndex == 65)                   lpSur = g_lpRiver;              // River        else if(iIndex == 66)                   lpSur = g_lpCover;              // Cover        else if(iIndex == 67)                   lpSur = g_lpGlide;              // Glide        else if(iIndex == 68)                   lpSur = g_lpHouse;              // House        else if(iIndex == 69)                   lpSur = g_lpFire;               // Fire        else if(iIndex == 70)                   lpSur = g_lpSmoke;              // Smoke        else if(iIndex == 71)                   lpSur = g_lpBullF;              // Fire Bullet        else                                    lpSur = g_lpBullN;              // Normal Bullet        GetClientRect(hbtOwnerDraw,&r);        if(lpSur->GetDC(&hdcSur) == DD_OK)        {            ddsd.dwSize     = sizeof(ddsd);            ddsd.dwFlags    = DDSD_HEIGHT|DDSD_WIDTH;            if(lpSur->GetSurfaceDesc(&ddsd) == DD_OK)                BitBlt(pd->hDC,(r.right-r.left-ddsd.dwWidth)/2,(r.bottom-r.top-ddsd.dwHeight)/2-50,ddsd.dwWidth,ddsd.dwHeight,hdcSur,0,0,SRCCOPY);            lpSur->ReleaseDC(hdcSur);        }        if(iIndex >= 0 && iIndex < 50)      { sizeTotal.cx = 128;   sizeTotal.cy = 128; sizeArray.cx = 4;   sizeArray.cy = 4;   sizeFrame.cx = 32;  sizeFrame.cy = 32;} // 50 TankE        else if(iIndex == 50)               { sizeTotal.cx = 128;   sizeTotal.cy = 128; sizeArray.cx = 4;   sizeArray.cy = 4;   sizeFrame.cx = 32;  sizeFrame.cy = 32;} // TankL        else if(iIndex == 51)               { sizeTotal.cx = 128;   sizeTotal.cy = 128; sizeArray.cx = 4;   sizeArray.cy = 4;   sizeFrame.cx = 32;  sizeFrame.cy = 32;} // TankR        else if(iIndex>51 && iIndex<=62)    { sizeTotal.cx = 24;    sizeTotal.cy = 24;  sizeArray.cx = 1;   sizeArray.cy = 1;   sizeFrame.cx = 24;  sizeFrame.cy = 24;} // 11 Card        else if(iIndex == 63)               { sizeTotal.cx = 8;     sizeTotal.cy = 8;   sizeArray.cx = 1;   sizeArray.cy = 1;   sizeFrame.cx = 8;   sizeFrame.cy = 8; } // Brick        else if(iIndex == 64)               { sizeTotal.cx = 16;    sizeTotal.cy = 16;  sizeArray.cx = 1;   sizeArray.cy = 1;   sizeFrame.cx = 16;  sizeFrame.cy = 16;} // Steel        else if(iIndex == 65)               { sizeTotal.cx = 32;    sizeTotal.cy = 32;  sizeArray.cx = 1;   sizeArray.cy = 1;   sizeFrame.cx = 32;  sizeFrame.cy = 32;} // River        else if(iIndex == 66)               { sizeTotal.cx = 32;    sizeTotal.cy = 32;  sizeArray.cx = 1;   sizeArray.cy = 1;   sizeFrame.cx = 32;  sizeFrame.cy = 32;} // Cover        else if(iIndex == 67)               { sizeTotal.cx = 32;    sizeTotal.cy = 32;  sizeArray.cx = 1;   sizeArray.cy = 1;   sizeFrame.cx = 32;  sizeFrame.cy = 32;} // Glide        else if(iIndex == 68)               { sizeTotal.cx = 32;    sizeTotal.cy = 32;  sizeArray.cx = 1;   sizeArray.cy = 1;   sizeFrame.cx = 32;  sizeFrame.cy = 32;} // House        else if(iIndex == 69)               { sizeTotal.cx = 200;   sizeTotal.cy = 40;  sizeArray.cx = 5;   sizeArray.cy = 1;   sizeFrame.cx = 40;  sizeFrame.cy = 40;} // Fire        else if(iIndex == 70)               { sizeTotal.cx = 1232;  sizeTotal.cy = 96;  sizeArray.cx = 14;  sizeArray.cy = 1;   sizeFrame.cx = 88;  sizeFrame.cy = 96;} // Smoke        else if(iIndex == 71)               { sizeTotal.cx = 8;     sizeTotal.cy = 8;   sizeArray.cx = 1;   sizeArray.cy = 1;   sizeFrame.cx = 8;   sizeFrame.cy = 8; } // Fire Bullet        else                                { sizeTotal.cx = 8;     sizeTotal.cy = 8;   sizeArray.cx = 1;   sizeArray.cy = 1;   sizeFrame.cx = 8;   sizeFrame.cy = 8; } // Normal Bullet        SetBkMode(pd->hDC,TRANSPARENT);        SetTextColor(pd->hDC,RGB(0,0,255));        if(iIndex == 70)        // Smoke            DrawText(pd->hDC,"Bitmap too large for Display",-1,&pd->rcItem,DT_SINGLELINE|DT_CENTER|DT_VCENTER);        pd->rcItem.bottom -= 100;        wsprintf(szText,"Total Size(Pixels) : %i x %i",sizeTotal.cx,sizeTotal.cy);      // Kích thước Bitmap        DrawText(pd->hDC,szText,-1,&pd->rcItem,DT_SINGLELINE|DT_CENTER|DT_BOTTOM);        if(sizeArray.cx != 1 || sizeArray.cy != 1)                                      // Nếu Bitmap có hơn 1 khung        {            pd->rcItem.bottom += 25;            wsprintf(szText,"Frame Numbers : %i x %i",sizeArray.cx,sizeArray.cy);       // Hiển thi ma trận khung            DrawText(pd->hDC,szText,-1,&pd->rcItem,DT_SINGLELINE|DT_CENTER|DT_BOTTOM);             pd->rcItem.bottom += 25;            wsprintf(szText,"Frame Size(Pixels) : %i x %i",sizeFrame.cx,sizeFrame.cy);  // Hiển thị kích thước mỗi khung            DrawText(pd->hDC,szText,-1,&pd->rcItem,DT_SINGLELINE|DT_CENTER|DT_BOTTOM);        }         SetTextColor(pd->hDC,RGB(255,255,0));        pd->rcItem.bottom += 30;        DrawText(pd->hDC,"Click here to change the Image",-1,&pd->rcItem,DT_SINGLELINE|DT_CENTER|DT_BOTTOM);        return TRUE;    case WM_COMMAND:        switch(LOWORD(wparam))        {        case IDC_LIST1:            if(HIWORD(wparam) == LBN_SELCHANGE)            {                InvalidateRect(hbtOwnerDraw,NULL,FALSE);                return TRUE;            }            break;        case IDC_BUTTON1:            szFile[0] = '\0';            ZeroMemory(&ofn,sizeof(OPENFILENAME));            ofn.lStructSize     = sizeof(OPENFILENAME);            ofn.hwndOwner       = hDlg;            ofn.lpstrFile       = szFile;            ofn.nMaxFile        = sizeof(szFile);            ofn.lpstrFilter     = "Bitmap Files (*.bmp)\0*.bmp\0"; // Chỉ tìm tập tin Bitmap            ofn.nFilterIndex    = 1;            ofn.Flags           = OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST|OFN_EXPLORER;            if(GetOpenFileName(&ofn))            {                iIndex = SendMessage(hList,LB_GETCURSEL,0,0);                GetModuleFileName(NULL,szFolder,MAX_PATH);                PathRemoveFileSpec(szFolder);                lstrcat(szFolder,"\\Tank2D");                if(iIndex >= 0 && iIndex < 50)          { lpSur = g_lpTankE[iIndex]; wsprintf(szText,"\\Tank%i.bmp",iIndex+1);}     // 50 TankE                else if(iIndex == 50)                   { lpSur = g_lpTankL; wsprintf(szText,"\\TankL.bmp");}                       // TankL                else if(iIndex == 51)                   { lpSur = g_lpTankR; wsprintf(szText,"\\TankR.bmp");}                       // TankR                else if(iIndex > 51 && iIndex <= 62)    { lpSur = g_lpCard[iIndex-52]; wsprintf(szText,"\\Card%i.bmp",iIndex-51);}  // 11 Card                else if(iIndex == 63)                   { lpSur = g_lpBrick; wsprintf(szText,"\\Brick.bmp");}                       // Brick                else if(iIndex == 64)                   { lpSur = g_lpSteel; wsprintf(szText,"\\Steel.bmp");}                       // Steel                else if(iIndex == 65)                   { lpSur = g_lpRiver; wsprintf(szText,"\\River.bmp");}                       // River                else if(iIndex == 66)                   { lpSur = g_lpCover; wsprintf(szText,"\\Cover.bmp");}                       // Cover                else if(iIndex == 67)                   { lpSur = g_lpGlide; wsprintf(szText,"\\Glide.bmp");}                       // Glide                else if(iIndex == 68)                   { lpSur = g_lpHouse; wsprintf(szText,"\\House.bmp");}                       // House                else if(iIndex == 69)                   { lpSur = g_lpFire; wsprintf(szText,"\\Fire.bmp");}                         // Fire                else if(iIndex == 70)                   { lpSur = g_lpSmoke; wsprintf(szText,"\\Smoke.bmp");}                       // Smoke                else if(iIndex == 71)                   { lpSur = g_lpBullF; wsprintf(szText,"\\BullF.bmp");}                       // Fire Bullet                else                                    { lpSur = g_lpBullN; wsprintf(szText,"\\BullN.bmp");}                       // Normal Bullet                lstrcat(szFolder,szText);                if(CopyFile(szFile,szFolder,FALSE))                     // Copy hình ảnh về thư mục Tank2D của chương trình                {                    DirectX_RestoreSurfaceFromFile(lpSur,szFolder);     // Vẽ lại bề mặt liên quan                    InvalidateRect(hbtOwnerDraw,NULL,FALSE);            // Vẽ lại Button tự vẽ                }            }            return TRUE;        case IDOK:            return TRUE;        case IDCANCEL:            SendMessage(hDlg,WM_CLOSE,0,0);            return TRUE;        }        break;    case WM_CTLCOLORDLG:        return (int)hbrBack;    case WM_CLOSE:        DeleteObject(hbrBack);        EndDialog(hDlg,0);        return TRUE;    }    return FALSE;}
    Trong khi vẽ Button, chúng ta hiển thị vài thông tin về kích thước và số khung cho người sử chơi quyết định
    nên thay đổi hay không. Chương trình chấp nhận bất kỳ hình ảnh mới để thay đổi, chỉ là nếu nó không phù hợp lắm
    thì trách nhiệm đó thuộc về người chơi ( "Tui đã cung cấp thông tin đầy đủ rồi mà !!!").
    Hộp thoại này khi thực thi trông sẽ như sau



    Ngày hôm nay tới đây, chào tạm biệt các anh chị em. [IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG]

  8. #18
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    NGÀY 33: Chức năng về âm thanh của phím F5

    Tạo 1 hộp thoại mới với id = IDD_DIALOG_SOUND, xóa Button OK.
    Thêm Button id = IDC_BUTTON1, text = "Enable".
    Thêm Button id = IDC_BUTTON2, text = "Change".
    Xắp xếp 3 Button trên hàng ngang ở đáy hộp thoại.
    Thêm 1 điều khiển ListView có id = IDC_LIST1, mở thuộc tính, trong tab <Styles> combo View đặt ở "Report", check "Single Selection", check "Show selection always".
    trong tab <Extended Styles> check "Client edge", check "Modal frame".

    Mã cập nhật cho hàm WndProc, thông điệp WM_COMMAND, cho F5 như sau

    Mã:
    case IDC_F5:            if(g_lpDD && g_iStatus == SP_LEVEL)            {                g_lpDD->FlipToGDISurface();                g_bMoused = TRUE;                SendMessage(hwnd,WM_SETCURSOR,0,0);                DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG_SOUND),hwnd,DlgProc_Sound);                g_bMoused = FALSE;                SendMessage(hwnd,WM_SETCURSOR,0,0);            }            return 0;
    Hàm xử lý thông điệp cho hộp thoại này như sau ( vẫn nhớ rằng đặt trước WndProc())

    Mã:
    BOOL CALLBACK DlgProc_Sound(HWND hDlg,UINT message,WPARAM wparam,LPARAM lparam){    static  HWND        hList;    static  HBRUSH      hbrBack;    CHAR                szFolder[MAX_PATH],szText[MAX_PATH],szFile[MAX_PATH];    LVCOLUMN            lvc;    LVITEM              lvi;    OPENFILENAME        ofn;    int                 i,cCount;    PCHAR               psz[] = {"BackSound","Bonus","Lost","Mine","Win","EBullN","EBullF","ETankShoot","BullN","BullF","TankShoot"};     switch(message)    {    case WM_INITDIALOG:        SetClassLong(hDlg,GCL_HICON,(LONG)LoadIcon(g_hInst,MAKEINTRESOURCE(IDI_TANK2D)));        hbrBack = CreateSolidBrush(g_DataSetup.crScreen);        hList = GetDlgItem(hDlg,IDC_LIST1);        lvc.mask        = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM;        lvc.fmt         = LVCFMT_LEFT;        lvc.cx          = 80;        lvc.iSubItem    = 0;        lvc.pszText     = "Sound";        ListView_InsertColumn(hList,0,&lvc);    // Cột đầu tiên là "Sound"        lvc.fmt         = LVCFMT_CENTER;        lvc.cx          = 60;        lvc.iSubItem    = 1;        lvc.pszText     = "Enable";        ListView_InsertColumn(hList,1,&lvc);    // Cột thứ hai là "Enable"        lvc.fmt         = LVCFMT_LEFT;        lvc.cx          = 260;        lvc.iSubItem    = 2;        lvc.pszText     = "Location";        ListView_InsertColumn(hList,2,&lvc);    // Cột thứ 3 là đường dẫn tập tin âm thanh        // Tạo màu nền, màu text, tạo khung lưới, thiết lập kiểu chọn nguyên dòng        ListView_SetTextBkColor(hList,RGB(0,255,255));        ListView_SetBkColor(hList,RGB(0,255,255));        ListView_SetTextColor(hList,RGB(255,0,0));        ListView_SetExtendedListViewStyle(hList,LVS_EX_GRIDLINES|LVS_EX_FULLROWSELECT);        // Tạo ra 11 Item coh ListView        GetModuleFileName(NULL,szFolder,MAX_PATH);        PathRemoveFileSpec(szFolder);        lstrcat(szFolder,"\\Tank2D");        for(i=0;i<11;i++)        {            lvi.mask        = LVIF_TEXT;            lvi.iItem       = i;            lvi.iSubItem    = 0;            lvi.pszText     = psz[i];            ListView_InsertItem(hList,&lvi);        }        // Chèn chữ vào cột 2        ListView_SetItemText(hList,0,1,g_DataSetup.sndBackSound ? "x":" ");        ListView_SetItemText(hList,1,1,g_DataSetup.sndBonusSound ? "x":" ");        ListView_SetItemText(hList,2,1,g_DataSetup.sndLostSound ? "x":" ");        ListView_SetItemText(hList,3,1,g_DataSetup.sndMineSound ? "x":" ");        ListView_SetItemText(hList,4,1,g_DataSetup.sndWinSound ? "x":" ");        ListView_SetItemText(hList,5,1,g_DataSetup.sndEnemySmallBullet ? "x":" ");        ListView_SetItemText(hList,6,1,g_DataSetup.sndEnemyLargeBullet ? "x":" ");        ListView_SetItemText(hList,7,1,g_DataSetup.sndEnemyShoot ? "x":" ");        ListView_SetItemText(hList,8,1,g_DataSetup.sndOurSmallBullet ? "x":" ");        ListView_SetItemText(hList,9,1,g_DataSetup.sndOurLargeBullet ? "x":" ");        ListView_SetItemText(hList,10,1,g_DataSetup.sndOurShoot ? "x":" ");        // Chèn chữ vào cột 3 cho dòng đầu        wsprintf(szText,"%s\\BackSound.mid",szFolder);        if(PathFileExists(szText))            ListView_SetItemText(hList,0,2,szText);        wsprintf(szText,"%s\\BackSound.wav",szFolder);        if(PathFileExists(szText))            ListView_SetItemText(hList,0,2,szText);        wsprintf(szText,"%s\\BackSound.mp3",szFolder);        if(PathFileExists(szText))            ListView_SetItemText(hList,0,2,szText);        // và các dòng còn lại        for(i=1;i<11;i++)        {            wsprintf(szText,"%s\\%s.wav",szFolder,psz[i]);            if(PathFileExists(szText))                ListView_SetItemText(hList,i,2,szText);        }        return TRUE;    case WM_COMMAND:        switch(LOWORD(wparam))        {        case IDC_BUTTON1:            cCount = ListView_GetItemCount(hList);            for(i=0;i<cCount;i++)            if(LVIS_SELECTED == (ListView_GetItemState(hList,i,LVIS_SELECTED))) // Nhận Item được chọn            {                ListView_GetItemText(hList,i,1,szText,MAX_PATH);                if(lstrcmp(szText,"x") == 0)                {                    ListView_SetItemText(hList,i,1," ");                }                else                {                    ListView_SetItemText(hList,i,1,"x");                }                if      (i==0)  g_DataSetup.sndBackSound        ^= 1;                else if (i==1)  g_DataSetup.sndBonusSound       ^= 1;                else if (i==2)  g_DataSetup.sndLostSound        ^= 1;                else if (i==3)  g_DataSetup.sndMineSound        ^= 1;                else if (i==4)  g_DataSetup.sndWinSound         ^= 1;                else if (i==5)  g_DataSetup.sndEnemySmallBullet ^= 1;                else if (i==6)  g_DataSetup.sndEnemyLargeBullet ^= 1;                else if (i==7)  g_DataSetup.sndEnemyShoot       ^= 1;                else if (i==8)  g_DataSetup.sndOurSmallBullet   ^= 1;                else if (i==9)  g_DataSetup.sndOurLargeBullet   ^= 1;                else            g_DataSetup.sndOurShoot         ^= 1;                 Setup_SaveData(&g_DataSetup);                return TRUE;            }            MessageBox(hDlg,"You must Select a Item !","Change Sounds",MB_OK|MB_ICONINFORMATION);            return TRUE;        case IDC_BUTTON2:            cCount = ListView_GetItemCount(hList);            for(i=0;i<cCount;i++)            if(LVIS_SELECTED == (ListView_GetItemState(hList,i,LVIS_SELECTED))) // Nhận Item được chọn            {                szFile[0] = '\0';                ZeroMemory(&ofn,sizeof(OPENFILENAME));                ofn.lStructSize     = sizeof(OPENFILENAME);                ofn.hwndOwner       = hDlg;                ofn.lpstrFile       = szFile;                ofn.nMaxFile        = sizeof(szFile);                ofn.lpstrFilter     = (i==0) ? "Sound Files (*.mp3),(*.wav),(*.mid)\0*.mp3;*.wav;*.mid\0" : "Bitmap Files (*.wav)\0*.wav\0";                ofn.nFilterIndex    = 1;                ofn.Flags           = OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST|OFN_EXPLORER;                if(GetOpenFileName(&ofn))   // Nhận âm thanh mới                {                    // Nếu là BackSound                    if(i==0)                    {                        GetModuleFileName(NULL,szFolder,MAX_PATH);                        PathRemoveFileSpec(szFolder);                        lstrcat(szFolder,"\\Tank2D");                        wsprintf(szText,"%s\\BackSound.mid",szFolder); DeleteFile(szText);                        wsprintf(szText,"%s\\BackSound.wav",szFolder); DeleteFile(szText);                        wsprintf(szText,"%s\\BackSound.mp3",szFolder); DeleteFile(szText);                        if(lstrcmp(PathFindExtension(szFile),".mp3") == 0)                            wsprintf(szText,"%s\\BackSound.mp3",szFolder);                        else if(lstrcmp(PathFindExtension(szFile),".wav") == 0)                            wsprintf(szText,"%s\\BackSound.wav",szFolder);                        else                            wsprintf(szText,"%s\\BackSound.mid",szFolder);                    }                    else                    {                        ListView_GetItemText(hList,i,2,szText,MAX_PATH);                    }                    if(CopyFile(szFile,szText,FALSE))       // Thay đổi với tập tin mới                    {                        ListView_SetItemText(hList,i,2,szText);                    }                    else                    {                        ListView_SetItemText(hList,i,2,"");                    }                }                return TRUE;            }            MessageBox(hDlg,"You must Select a Item !","Change Sounds",MB_OK|MB_ICONINFORMATION);            return TRUE;        case IDCANCEL:            SendMessage(hDlg,WM_CLOSE,0,0);            return TRUE;        }        break;    case WM_CTLCOLORDLG:        return (int)hbrBack;    case WM_CLOSE:        DeleteObject(hbrBack);        EndDialog(hDlg,0);        return TRUE;    }    return FALSE;}
    Có lẽ trong hàm này cũng không có gì khó hiểu, bạn chú ý đặt các Macro trong cặp ngoặc vì điều này rất dễ nhầm với 1 hàm.
    Khi thực thi hộp thoại sẽ trông như hình bên dưới.

    Thư mục dự án trong đính kèm Tank2D.zip.
    Chương trình thực thi trong đính kèm Tank.zip.

    Ngày hôm nay tới đây thôi, chào tạm biệt. [IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG]



    - - - Nội dung đã được cập nhật ngày 30-03-2014 lúc 03:15 PM - - -</font>

    <font color="#0000FF">NGÀY 34:
    Thêm chức năng chỉnh sửa kiểu thuộc tính Tank cho F6.

    Các thuộc tính xác định sự nguy hiểm của 1 TankE là : Có bắn đạn lửa không, Tốc độ di chuyển, Tốc độ di chuyển của đạn, Chịu đựng được bao nhiêu viên đạn, Mức độ di chuyển thông minh.
    Nếu chúng ta lấy tất cả các hoán vị của 5 thuộc tính này để xác định kiểu thì số kiểu sẽ là rất lớn, không khoa học.
    Thay vào đó, chúng ta để cho người chơi tự xác định thuộc tính cho 50 kiểu TankE.

    Thêm vào 2 hàm lưu và nạp tập tin thuộc tính ở vị trí gần các hàm Setup_LoadData(),Setup_SaveData()

    Mã:
    BOOL TypeTank_Load(TYPETANK TypeTank[50]){    CHAR        szText[MAX_PATH];    HANDLE      hFile;    TYPETANK    Type[50];    DWORD       dw;    BOOL        bFlag;     GetModuleFileName(NULL,szText,MAX_PATH);    PathRemoveFileSpec(szText);    lstrcat(szText,"\\Tank2D");    if(!PathIsDirectory(szText))        return FALSE;    lstrcat(szText,"\\Type.typ");    hFile = CreateFile(szText,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);    if(hFile == INVALID_HANDLE_VALUE)        return FALSE;    if(GetFileSize(hFile,NULL) != sizeof(TYPETANK)*50)    {        CloseHandle(hFile);        return FALSE;    }    bFlag = ReadFile(hFile,Type,sizeof(TYPETANK)*50,&dw,NULL);    CloseHandle(hFile);    if(!bFlag || dw != sizeof(TYPETANK)*50)        return FALSE;    CopyMemory(TypeTank,Type,sizeof(TYPETANK)*50);    return TRUE;}BOOL TypeTank_Save(TYPETANK TypeTank[50]){    CHAR        szText[MAX_PATH];    HANDLE      hFile;    DWORD       dw;    BOOL        bFlag;     GetModuleFileName(NULL,szText,MAX_PATH);    PathRemoveFileSpec(szText);    lstrcat(szText,"\\Tank2D");    if(!PathIsDirectory(szText))        return FALSE;    lstrcat(szText,"\\Type.typ");    hFile = CreateFile(szText,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);    if(hFile == INVALID_HANDLE_VALUE)        return FALSE;    bFlag = WriteFile(hFile,TypeTank,sizeof(TYPETANK)*50,&dw,NULL);    CloseHandle(hFile);    if(!bFlag || dw != sizeof(TYPETANK)*50)    {        DeleteFile(szText);        return FALSE;    }    return TRUE;}
    Ghi nhớ chúng ta lấy tên của tập tin này là Type.typ cho dễ dàng truy xuất trong thư mục <Tank2D>

    Trong thủ tục xử lý thông điệp chính ( WndProc), trong WM_CREATE, xóa bỏ đoạn mã sau

    Mã:
    for(i=0;i<50;i++)        {            g_TypeTank[i].bBullF    = (rand()%30 == 0) ? TRUE:FALSE;            g_TypeTank[i].iPower    = rand()%5 + 1;            g_TypeTank[i].iShoot    = rand()%6 + 5;            g_TypeTank[i].iSmart    = rand()%3;            g_TypeTank[i].iSpeed    = rand()%3 + 1;        }
    Trong hàm WinMain, thêm đoạn mã sau vào trước dòng lưu thẻ thể hiện vào biến toàn cục.

    Mã:
    if(!TypeTank_Load(g_TypeTank))          // Đoạn mã mới    {        for(int i=0;i<50;i++)        {            g_TypeTank[i].bBullF    = (rand()%30 == 0) ? TRUE:FALSE;            g_TypeTank[i].iPower    = rand()%5 + 1;            g_TypeTank[i].iShoot    = rand()%6 + 5;            g_TypeTank[i].iSmart    = rand()%3;            g_TypeTank[i].iSpeed    = rand()%3 + 1;        }        TypeTank_Save(g_TypeTank);    }    g_hInst = hInstance;                    // Mã cũ
    Chúng ta đã sửa xong phần lưu xuất các thuộc tính Tank.
    Bây giờ là lúc tạo hộp thoại cho người chơi thay đổi trực quan các thuộc tính của 50 kiểu Tank.
    Tạo 1 hộp thoại mới với id = IDD_DIALOG_TANKE, mở hộp thuộc tính, trong tab <More Styles> check "Center".
    Thêm vào các điều khiển sau:
    1. Listbox: id = IDC_LIT1, trong tab <Styles> bỏ check "Sort", trong tab<Extended Styles> check "Modal frame".
    2. 4 Combobox: id từ IDC_COMBO1 tới IDC_COMBO4, cả 4 có kiểu giống nhau, trong <Styles> chọn "Drop List" trong combo "Type", bỏ check trong "Sort",
    trong khung thiết kế nhấn vào nút kéo xuống của từng combo và canh chỉnh chiều cao của nó.
    3. Checkbox: id = IDC_CHECK1, text = "Fire Bullet", check thuộc tính nâng cao "Modal frame".
    4. Button: id = IDC_BUTTON1, thay đổi thành button tự vẽ, check thuộc tính nâng cao "Modal frame".
    Đổi text của button OK thành "Update", đổi text của Cancel thành "Close".
    Sắp xếp lại tất cả cho dễ nhìn theo ý thích của bạn.

    Mã cập nhật cho hàm WndProc, thông điệp WM_COMMAND, cho F6 như sau

    Mã:
    case IDC_F6:            if(g_lpDD && g_iStatus == SP_LEVEL)            {                g_lpDD->FlipToGDISurface();                g_bMoused = TRUE;                SendMessage(hwnd,WM_SETCURSOR,0,0);                DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG_TANKE),hwnd,DlgProc_TankE);                g_bMoused = FALSE;                SendMessage(hwnd,WM_SETCURSOR,0,0);            }            return 0;
    Hàm xử lý thông điệp cho hộp thoại này như sau ( vẫn nhớ rằng đặt trước WndProc())

    Mã:
    BOOL CALLBACK DlgProc_TankE(HWND hDlg,UINT message,WPARAM wparam,LPARAM lparam){    static  HBRUSH      hbrBack;    static  HWND        hList,hbtOwner,hCheck;    static  HWND        hComboPower,hComboShoot,hComboSmart,hComboSpeed;    static  TYPETANK    TypeTank[50];    static  BOOL        bChanged;    CHAR                szText[MAX_PATH];    LPDRAWITEMSTRUCT    pd;    HDC                 hdcSur;    int                 i,iIndex;     switch(message)    {    case WM_INITDIALOG:        SetClassLong(hDlg,GCL_HICON,(LONG)LoadIcon(g_hInst,MAKEINTRESOURCE(IDI_TANK2D)));        hbrBack = CreateSolidBrush(g_DataSetup.crScreen);        hList = GetDlgItem(hDlg,IDC_LIST1);        hbtOwner = GetDlgItem(hDlg,IDC_BUTTON1);        hCheck = GetDlgItem(hDlg,IDC_CHECK1);        hComboPower = GetDlgItem(hDlg,IDC_COMBO1);        hComboShoot = GetDlgItem(hDlg,IDC_COMBO2);        hComboSmart = GetDlgItem(hDlg,IDC_COMBO3);        hComboSpeed = GetDlgItem(hDlg,IDC_COMBO4);        CopyMemory(&TypeTank,&g_TypeTank,sizeof(TYPETANK)*50);        bChanged = FALSE;        for(i=0;i<50;i++)       // Hiển thị 50 kiểu TankE trong List        {            wsprintf(szText," Tank #%i",i+1);            SendMessage(hList,LB_ADDSTRING,0,(LPARAM)szText);        }        SendMessage(hList,LB_SETCURSEL,0,0);        for(i=0;i<5;i++)        // Combo Power có 5 dòng        {            wsprintf(szText," Power = %i",i+1);            SendMessage(hComboPower,CB_ADDSTRING,0,(LPARAM)szText);        }        SendMessage(hComboPower,CB_SETCURSEL,TypeTank[0].iPower-1,0);        for(i=0;i<6;i++)        // Combo Shoot có 6 dòng        {            wsprintf(szText," ShootSpeed = %i",i+5);            SendMessage(hComboShoot,CB_ADDSTRING,0,(LPARAM)szText);        }        SendMessage(hComboShoot,CB_SETCURSEL,TypeTank[0].iShoot-5,0);        for(i=0;i<3;i++)        // Combo Smart có 3 dòng        {            wsprintf(szText," Smart = %i",i);            SendMessage(hComboSmart,CB_ADDSTRING,0,(LPARAM)szText);        }        SendMessage(hComboSmart,CB_SETCURSEL,TypeTank[0].iSmart,0);        for(i=0;i<3;i++)        // Combo Speed có 3 dòng        {            wsprintf(szText," Speed = %i",i+1);            SendMessage(hComboSpeed,CB_ADDSTRING,0,(LPARAM)szText);        }        SendMessage(hComboSpeed,CB_SETCURSEL,TypeTank[0].iSpeed-1,0);        CheckDlgButton(hDlg,IDC_CHECK1,TypeTank[0].bBullF ? BST_CHECKED : BST_UNCHECKED);        SetFocus(hList);        return FALSE;    case WM_DRAWITEM:        pd = (LPDRAWITEMSTRUCT)lparam;        FillRect(pd->hDC,&pd->rcItem,(HBRUSH)GetStockObject(DKGRAY_BRUSH)); // Tô màu xám đậm cho button        iIndex = SendMessage(hList,LB_GETCURSEL,0,0);        if(iIndex != LB_ERR)        if(g_lpTankE[iIndex])        if(g_lpTankE[iIndex]->GetDC(&hdcSur) == DD_OK)                      // Nhận Thiết bị ngữ cảnh sau đó BitBlt        {            BitBlt(pd->hDC,(pd->rcItem.right - pd->rcItem.left - LARGE)/2, (pd->rcItem.bottom - pd->rcItem.top - LARGE)/2,LARGE,LARGE,hdcSur,0,0,SRCCOPY);            g_lpTankE[iIndex]->ReleaseDC(hdcSur);        }        return TRUE;    case WM_COMMAND:        switch(LOWORD(wparam))        {        case IDC_LIST1:            if(HIWORD(wparam) == LBN_SELCHANGE)                 // Người chơi chuyển sang Tank khác            {                iIndex = SendMessage(hList,LB_GETCURSEL,0,0);                if(iIndex != LB_ERR)                {                    SendMessage(hComboPower,CB_SETCURSEL,TypeTank[iIndex].iPower-1,0);                    SendMessage(hComboShoot,CB_SETCURSEL,TypeTank[iIndex].iShoot-5,0);                    SendMessage(hComboSmart,CB_SETCURSEL,TypeTank[iIndex].iSmart,0);                    SendMessage(hComboSpeed,CB_SETCURSEL,TypeTank[iIndex].iSpeed-1,0);                    CheckDlgButton(hDlg,IDC_CHECK1,TypeTank[iIndex].bBullF ? BST_CHECKED : BST_UNCHECKED);                    InvalidateRect(hbtOwner,NULL,FALSE);                }                return TRUE;            }            break;        case IDC_COMBO1:            if(HIWORD(wparam) == CBN_SELCHANGE)     // Thay đổi Power            {                TypeTank[SendMessage(hList,LB_GETCURSEL,0,0)].iPower = SendMessage(hComboPower,CB_GETCURSEL,0,0) + 1;                bChanged = TRUE;                return TRUE;            }            break;        case IDC_COMBO2:            if(HIWORD(wparam) == CBN_SELCHANGE)     // Thay đổi Shoot            {                TypeTank[SendMessage(hList,LB_GETCURSEL,0,0)].iShoot = SendMessage(hComboShoot,CB_GETCURSEL,0,0) + 5;                bChanged = TRUE;                return TRUE;            }            break;        case IDC_COMBO3:            if(HIWORD(wparam) == CBN_SELCHANGE)     // Thay đổi Smart            {                TypeTank[SendMessage(hList,LB_GETCURSEL,0,0)].iSmart = SendMessage(hComboSmart,CB_GETCURSEL,0,0);                bChanged = TRUE;                return TRUE;            }            break;        case IDC_COMBO4:            if(HIWORD(wparam) == CBN_SELCHANGE)     // Thay đổi Speed            {                TypeTank[SendMessage(hList,LB_GETCURSEL,0,0)].iSpeed = SendMessage(hComboSpeed,CB_GETCURSEL,0,0) + 1;                bChanged = TRUE;                return TRUE;            }            break;        case IDC_CHECK1:                            // Bật/Tắt Fire Bullet            TypeTank[SendMessage(hList,LB_GETCURSEL,0,0)].bBullF = (BST_CHECKED == IsDlgButtonChecked(hDlg,IDC_CHECK1)) ? TRUE:FALSE;            bChanged = TRUE;            return TRUE;        case IDOK:            if(bChanged)        // Nếu có bất kỳ thay đổi            {                CopyMemory(&g_TypeTank,&TypeTank,sizeof(TYPETANK)*50);                TypeTank_Save(TypeTank);        // Lưu thay đổi cho sau này            }        case IDCANCEL:            SendMessage(hDlg,WM_CLOSE,0,0);            return TRUE;        }        break;    case WM_CTLCOLORDLG:        return (int)hbrBack;    case WM_CLOSE:        DeleteObject(hbrBack);        EndDialog(hDlg,0);        return TRUE;    }    return FALSE;}
    Hàm xử lý này cũng bình thường, mã không có gì rắc rối lắm, khi thực thi hộp thoại sẽ xuất hiện như hình bên dưới.



    Ngày nay tới đây thôi, tạm biệt. [IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG]

  9. #19
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    NGÀY 35: Cộng thêm hoa lá vào trò chơi, cộng chức năng F12.

    Trên toàn bộ màn hình khi chơi chúng ta thấy.
    Vùng chơi nằm ở giữa màn hình, các Title nằm ở phía trên, các thuộc tính Tank ta nằm ở dưới, 30 TankE mà sẽ tham chiến ở bên phải, còn lại vùng trống ở bên trái làm gì đây.
    Chưa nghĩ ra được gì nên mình sẽ thêm vào các đường Bezier chạy xung quanh vùng này ( chủ yếu là cho vui mắt thôi).

    Thêm vào 2 định nghĩa cấu trúc sau

    Mã:
    typedef struct{    COLORREF    cr;             // Màu của đường Bezier này    POINT       pt[4];          // Mảng cho 2 đầu mút và 2 điểm uốn    int         dx[4];          // Độ dời theo trục x của các điểm cho đường Bezier kế tiếp    int         dy[4];          // Độ dời theo trục y của các điểm cho đường Bezier kế tiếp}BEZIER,*PBEZIER;typedef struct{    int         cMax;           // So đường Bezier đồng thời hiển thị lớn nhất    int         xMax;           // Độ dời tối đa giữa 2 điểm tương ứng của 2 Bezier theo trục x    int         yMax;           // Độ dời tối đa giữa 2 điểm tương ứng của 2 Bezier theo trục x}PARAMBEZIER,*PPARAMBEZIER;
    Khai báo thêm biến toàn cục

    Mã:
    PARAMBEZIER             g_ParamBezier;              // ParamBezier
    Trong WinMain, thêm vào trước dòng gán thể hiện chương trình cho g_hInst

    Mã:
    g_ParamBezier.cMax  = (rand()%20)*5+5;    g_ParamBezier.xMax  = rand()%10+1;    g_ParamBezier.yMax  = rand()%10+1;    g_hInst = hInstance;                    // Mã cũ
    Thêm vào một hàm mới để vẽ và cập nhật Bezier, nên đặt nó cùng với những hàm (DirectX_Draw...)

    Mã:
    void DirectX_DrawAndUpdateBezier(LPDIRECTDRAWSURFACE pBack,PPARAMBEZIER pParam,int xFrame,int yFrame){    static  CPtrArray   aBezier(FALSE);    HDC         hdc;    PBEZIER     p,pBezier;    HPEN        hPen;    int         i,cBezier;    RECT        r = {0,yFrame,xFrame-5,yFrame+LARGE*13};    // r chứa hình chữ nhật mà các Bezier không thể vượt qua     if(!pBack)  return;    if(pBack->GetDC(&hdc) != DD_OK)        return;    for(i=aBezier.GetSize()-1;i>=pParam->cMax;i--)          // Xóa bớt nếu vừa thay đổi biến lưu tổng số đường trong pParam        aBezier.RemoveAt(i);    for(i=0;i<aBezier.GetSize();i++)                        // Duyệt từng Bezier    {        pBezier = (PBEZIER)aBezier.GetAt(i);        hPen = CreatePen(PS_SOLID,0,pBezier->cr);        SelectObject(hdc,hPen);        PolyBezier(hdc,pBezier->pt,4);                      // Vẽ nó ra        DeleteObject(hPen);    }    pBack->ReleaseDC(hdc);    if(NULL == (pBezier = (PBEZIER)malloc(sizeof(BEZIER)))) // Tạo 1 đường mới        return;    cBezier = aBezier.GetSize();    if(cBezier == 0)                                        // Nếu chưa có đường thì nào tạo ngẫu nhiên màu, độ dời cũng như tọa độ cho 4 điểm Bezier    {        pBezier->cr = RGB(rand()&255,rand()&255,rand()&255);        for(i=0;i<4;i++)        {            pBezier->dx[i]      = (rand()%pParam->xMax+1)*((rand()%2)?-1:1);            pBezier->dy[i]      = (rand()%pParam->yMax+1)*((rand()%2)?-1:1);            pBezier->pt[i].x    = rand()%(r.right-r.left);            pBezier->pt[i].y    = rand()%(r.bottom-r.top)+r.top;        }    }    else    //    {        if(cBezier == pParam->cMax) // Nếu đã đủ số lượng đường thì xóa đường đầu tiên trong mảng ( cũng là đường đã hiển thị lâu nhất)        {            aBezier.RemoveAt(0);            cBezier--;        }        p = (PBEZIER)aBezier.GetAt(cBezier-1);  // Cho một xác xuất để tạo màu mới hay sử dụng màu của đường cuối trong mảng để ...        pBezier->cr = (rand()%10>5) ? (RGB(rand()&255,rand()&255,rand()&255)):p->cr;    // ... Đổi màu đường Bezier này.        for(i=0;i<4;i++)        {            if(p->pt[i].x + p->dx[i] <= r.left)     // Thay đổi ngẫu nhiên các độ dời, đảo chiều theo x            {                p->dx[i] = (rand()%pParam->xMax+1)*((p->dx[i]>0) ? (-1):1);                p->dy[i] = (rand()%pParam->yMax+1)*((p->dy[i]>0) ? 1:(-1));            }            if(p->pt[i].y + p->dy[i] <= r.top)      // Thay đổi ngẫu nhiên các độ dời, đảo chiều theo y            {                p->dy[i] = (rand()%pParam->yMax+1)*((p->dy[i]>0) ? (-1):1);                p->dx[i] = (rand()%pParam->xMax+1)*((p->dx[i]>0) ? 1:(-1));            }            if(p->pt[i].x + p->dx[i] >= r.right-1)  // Thay đổi ngẫu nhiên các độ dời, đảo chiều theo x            {                p->dx[i] = (rand()%pParam->xMax+1)*((p->dx[i]>0) ? (-1):1);                p->dy[i] = (rand()%pParam->yMax+1)*((p->dy[i]>0) ? 1:(-1));            }            if(p->pt[i].y + p->dy[i] >= r.bottom-1) // Thay đổi ngẫu nhiên các độ dời, đảo chiều theo y            {                p->dy[i] = (rand()%pParam->yMax+1)*((p->dy[i]>0) ? (-1):1);                p->dx[i] = (rand()%pParam->xMax+1)*((p->dx[i]>0) ? 1:(-1));            }            // Đặt mới độ dời và tọa độ các đầu mút, điểm uốn.            pBezier->pt[i].x    = p->pt[i].x + p->dx[i];            pBezier->pt[i].y    = p->pt[i].y + p->dy[i];            pBezier->dx[i]      = p->dx[i];            pBezier->dy[i]      = p->dy[i];        }    }    aBezier.Add(pBezier);}
    Thêm vào hàm App_Update(), thêm vào 1 dòng mã thực hiện hàm trên

    Mã:
        // Mã đã có sẵn    ddbltfx.dwFillColor = DirectX_ColorMatch(g_lpBack,g_DataSetup.crBack);    while(1)    {        hr = g_lpBack->Blt(&r,NULL,NULL,DDBLT_COLORFILL,&ddbltfx);        if(hr == DD_OK) break;        if(hr == DDERR_SURFACELOST) if(!DirectX_RestoreSurfaceAll()) return;        if(hr != DDERR_WASSTILLDRAWING) return;    }    // Thêm dòng này vào    DirectX_DrawAndUpdateBezier(g_lpBack,&g_ParamBezier,xFrame,yFrame);
    Đến đây, chúng ta đã hoàn thành 1 nửa công việc của ngày hôm nay, biên dịch và thực thi, màn hình sẽ như sau.



    Tiếp theo, chúng ta sẽ cho thêm chức năng chỉnh sửa hiển thị của các đường Bezier bằng phím F12 ( không quan trọng nên cho nó ở F tận cùng).
    Tạo hộp thoại mới với id=IDD_DIALOG_BEZIER. Thay tên hộp thoại thành "Bezier Params", check thuộc tính nâng cao "Center".
    Thêm vào 3 Combobox với id từ IDC_COMBO1 tới IDC_COMBO3, đặt kiểu là "Drop list" rồi uncheck "Sort" cho cả 3, mở rộng chiều cao cho combo để chứa khoảng 20 dòng.

    Mã cập nhật cho hàm WndProc, thông điệp WM_COMMAND, cho F12 như sau

    Mã:
    case IDC_F12:            if(g_lpDD && g_iStatus == SP_LEVEL)            {                g_lpDD->FlipToGDISurface();                g_bMoused = TRUE;                SendMessage(hwnd,WM_SETCURSOR,0,0);                DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG_BEZIER),hwnd,DlgProc_Bezier);                g_bMoused = FALSE;                SendMessage(hwnd,WM_SETCURSOR,0,0);            }            return 0;
    Hàm xử lý thông điệp cho hộp thoại này như sau ( vẫn nhớ rằng đặt trước WndProc())

    Mã:
    BOOL CALLBACK DlgProc_Bezier(HWND hDlg,UINT message,WPARAM wparam,LPARAM lparam){    static  HBRUSH      hbrBack;    static  HWND        hComboC,hComboX,hComboY;    static  PARAMBEZIER Params;    static  BOOL        bChanged;    CHAR                szText[MAX_PATH];    int                 i;     switch(message)    {    case WM_INITDIALOG:        SetClassLong(hDlg,GCL_HICON,(LONG)LoadIcon(g_hInst,MAKEINTRESOURCE(IDI_TANK2D)));        hbrBack = CreateSolidBrush(g_DataSetup.crScreen);        hComboC = GetDlgItem(hDlg,IDC_COMBO1);        hComboX = GetDlgItem(hDlg,IDC_COMBO2);        hComboY = GetDlgItem(hDlg,IDC_COMBO3);        for(i=0;i<20;i++)        {            wsprintf(szText," Lines : %i",(i+1)*5);             // Hiển thị theo bước tăng 5, bắt đầu từ 5            SendMessage(hComboC,CB_ADDSTRING,0,(LPARAM)szText);            if(i == (g_ParamBezier.cMax-5)/5)                   // Chọn giá trị hiện hành                SendMessage(hComboC,CB_SETCURSEL,i,0);        }        for(i=0;i<20;i++)        {            wsprintf(szText," Max Step X : %i",i+1);            // Hiển thị theo bước tăng 1, bắt đầu từ 1            SendMessage(hComboX,CB_ADDSTRING,0,(LPARAM)szText);            if(i == g_ParamBezier.xMax-1)                       // Chọn giá trị hiện hành                SendMessage(hComboX,CB_SETCURSEL,i,0);            wsprintf(szText," Max Step Y : %i",i+1);            // Hiển thị theo bước tăng 1, bắt đầu từ 1            SendMessage(hComboY,CB_ADDSTRING,0,(LPARAM)szText);            if(i == g_ParamBezier.yMax-1)                       // Chọn giá trị hiện hành                SendMessage(hComboY,CB_SETCURSEL,i,0);        }        CopyMemory(&Params,&g_ParamBezier,sizeof(PARAMBEZIER));        bChanged = FALSE;        return TRUE;    case WM_COMMAND:        switch(LOWORD(wparam))        {        case IDC_COMBO1:        case IDC_COMBO2:        case IDC_COMBO3:            if(HIWORD(wparam) == CBN_SELCHANGE)            {                bChanged = TRUE;                return TRUE;            }            break;        case IDOK:            if(bChanged)    // Nếu có thay đổi, nhận các giá trị từ combo rồi lưu lại            {                i = SendMessage(hComboC,CB_GETCURSEL,0,0);                if(i != CB_ERR)                    Params.cMax = (i+1)*5;                i = SendMessage(hComboX,CB_GETCURSEL,0,0);                if(i != CB_ERR)                    Params.xMax = i+1;                i = SendMessage(hComboY,CB_GETCURSEL,0,0);                if(i != CB_ERR)                    Params.yMax = i+1;                CopyMemory(&g_ParamBezier,&Params,sizeof(PARAMBEZIER));            }        case IDCANCEL:            SendMessage(hDlg,WM_CLOSE,0,0);            return TRUE;        }        break;    case WM_CTLCOLORDLG:        return (int)hbrBack;    case WM_CLOSE:        DeleteObject(hbrBack);        EndDialog(hDlg,0);        return TRUE;    }    return FALSE;}
    Mã hộp thoại này bình thường, khi thực thi sẽ như sau



    Ngày nay viết nhiều rồi, nghỉ thôi, hẹn gặp lại. [IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG]

  10. #20
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    NGÀY 36: Thêm Logic xử lý Joystick cho chương trình

    Trong các ngày trước, chúng ta còn chừa lại phần mã xử lý thiết bị điều khiển Game cầm tay (Joystick), bây giờ là lúc thêm nó vào.
    Có thể chúng ta phải sửa lại rất nhiều hàm, vậy hãy hít một hơi dài và bắt đầu.

    Thêm vào 1 định nghĩa cấu trúc

    Mã:
    typedef struct{    BOOL        bShoot;         // Button1 dang nhan hay tha ? TRUE:nhan  FALSE:tha    BOOL        bLeft;          // Left Arrow    BOOL        bUp;            // Up Arrow    BOOL        bRight;    BOOL        bDown;}INPUTJOYSTICK,*PINPUTJOYSTICK;
    Thêm 2 biến toàn cục cho 2 Joystick

    Mã:
    // Mã đã có sẵnLPDIRECTINPUTDEVICE     g_lpKeyboard;               // Thiet bi KeyboardLPDIRECTINPUTDEVICE     g_lpMouse;                  // Thiet bi Mouse// Mã thêm mớiLPDIRECTINPUTDEVICE     g_lpJoystick1;              // Thiet bi Joystick1LPDIRECTINPUTDEVICE     g_lpJoystick2;              // Thiet bi Joystick2
    Thêm hàm để đếm và khởi tạo 2 Joystick

    Mã:
    BOOL CALLBACK DirectX_EnumAndCreateJoystick(LPCDIDEVICEINSTANCE pdinst,LPVOID pvRef){    static  int             iNum;    DIPROPRANGE             diprg;    DIPROPDWORD             dipdw;     if(iNum > 1)            // Nếu đã có đủ 2 Joystick thì dừng đếm        return DIENUM_STOP;    if(g_lpDI->CreateDevice(pdinst->guidInstance,(iNum==0) ? (&g_lpJoystick1):(&g_lpJoystick2),NULL) != DI_OK) // Tạo thiết bị Joystick        return DIENUM_CONTINUE;    if(iNum == 0)           // Thiet lap dinh dang va Cooper cho Joystick1    {        if(g_lpJoystick1->SetDataFormat(&c_dfDIJoystick) != DI_OK)        {            g_lpJoystick1->Release();            g_lpJoystick1 = NULL;            return DIENUM_CONTINUE;        }        if(g_lpJoystick1->SetCooperativeLevel((HWND)pvRef,DISCL_NONEXCLUSIVE | DISCL_FOREGROUND) != DI_OK)        {            g_lpJoystick1->Release();            g_lpJoystick1 = NULL;            return DIENUM_CONTINUE;        }    }    else                    // Thiet lap dinh dang va Cooper cho Joystick2    {        if(g_lpJoystick2->SetDataFormat(&c_dfDIJoystick) != DI_OK)        {            g_lpJoystick2->Release();            g_lpJoystick2 = NULL;            return DIENUM_CONTINUE;        }        if(g_lpJoystick2->SetCooperativeLevel((HWND)pvRef,DISCL_NONEXCLUSIVE | DISCL_FOREGROUND) != DI_OK)        {            g_lpJoystick2->Release();            g_lpJoystick2 = NULL;            return DIENUM_CONTINUE;        }    }    diprg.diph.dwSize       = sizeof(diprg);    diprg.diph.dwHeaderSize = sizeof(diprg.diph);    diprg.diph.dwHow        = DIPH_BYOFFSET;    diprg.lMin              = -1000;    diprg.lMax              = +1000;    if(iNum == 0)           // Thiet lap Min_Max cho X va Y cho Joystick1    {        diprg.diph.dwObj        = DIJOFS_X;        if(g_lpJoystick1->SetProperty(DIPROP_RANGE,&diprg.diph) != DI_OK)        {            g_lpJoystick1->Release();            g_lpJoystick1 = NULL;            return DIENUM_CONTINUE;        }        diprg.diph.dwObj        = DIJOFS_Y;        if(g_lpJoystick1->SetProperty(DIPROP_RANGE,&diprg.diph) != DI_OK)        {            g_lpJoystick1->Release();            g_lpJoystick1 = NULL;            return DIENUM_CONTINUE;        }    }    else                    // Thiet lap Min_Max cho X va Y cho Joystick2    {        diprg.diph.dwObj        = DIJOFS_X;        if(g_lpJoystick2->SetProperty(DIPROP_RANGE,&diprg.diph) != DI_OK)        {            g_lpJoystick2->Release();            g_lpJoystick2 = NULL;            return DIENUM_CONTINUE;        }        diprg.diph.dwObj        = DIJOFS_Y;        if(g_lpJoystick2->SetProperty(DIPROP_RANGE,&diprg.diph) != DI_OK)        {            g_lpJoystick2->Release();            g_lpJoystick2 = NULL;            return DIENUM_CONTINUE;        }    }    dipdw.diph.dwSize       = sizeof(dipdw);    dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);    dipdw.diph.dwHow        = DIPH_BYOFFSET;    dipdw.dwData            = 5000;    if(iNum == 0)           // Thiet lap Data cho Joystick1    {        dipdw.diph.dwObj        = DIJOFS_X;        if(g_lpJoystick1->SetProperty(DIPROP_DEADZONE,&dipdw.diph) != DI_OK)        {            g_lpJoystick1->Release();            g_lpJoystick1 = NULL;            return DIENUM_CONTINUE;        }        dipdw.diph.dwObj        = DIJOFS_Y;        if(g_lpJoystick1->SetProperty(DIPROP_DEADZONE,&dipdw.diph) != DI_OK)        {            g_lpJoystick1->Release();            g_lpJoystick1 = NULL;            return DIENUM_CONTINUE;        }    }    else                    // Thiet lap Data cho Joystick2    {        dipdw.diph.dwObj        = DIJOFS_X;        if(g_lpJoystick2->SetProperty(DIPROP_DEADZONE,&dipdw.diph) != DI_OK)        {            g_lpJoystick2->Release();            g_lpJoystick2 = NULL;            return DIENUM_CONTINUE;        }        dipdw.diph.dwObj        = DIJOFS_Y;        if(g_lpJoystick2->SetProperty(DIPROP_DEADZONE,&dipdw.diph) != DI_OK)        {            g_lpJoystick2->Release();            g_lpJoystick2 = NULL;            return DIENUM_CONTINUE;        }    }    if(iNum == 0)        g_lpJoystick1->Acquire();    else        g_lpJoystick2->Acquire();    iNum ++;    return DIENUM_CONTINUE;}
    Viết lại hàm DirectX_InitDI() và DirectX_DeleteDI() như sau

    Mã:
    BOOL DirectX_InitDI(HINSTANCE hInstance,HWND hwnd){    DIPROPDWORD dipdw = {sizeof(DIPROPDWORD),sizeof(DIPROPHEADER),0,DIPH_DEVICE,16};     if(DirectInputCreate(hInstance,DIRECTINPUT_VERSION,&g_lpDI,NULL) != DI_OK)                  return FALSE;    if(g_lpDI->CreateDevice(GUID_SysKeyboard,&g_lpKeyboard,NULL) != DI_OK)                      return FALSE;    if(g_lpKeyboard->SetDataFormat(&c_dfDIKeyboard) != DI_OK)                                   return FALSE;    if(g_lpKeyboard->SetCooperativeLevel(hwnd,DISCL_NONEXCLUSIVE|DISCL_FOREGROUND) != DI_OK)    return FALSE;    if(g_lpKeyboard->Acquire() != DI_OK)                                                        return FALSE;    if(g_lpDI->CreateDevice(GUID_SysMouse,&g_lpMouse,NULL) != DI_OK)                            return FALSE;    if(g_lpMouse->SetDataFormat(&c_dfDIMouse) != DI_OK)                                         return FALSE;    if(g_lpMouse->SetCooperativeLevel(hwnd,DISCL_NONEXCLUSIVE|DISCL_FOREGROUND) != DI_OK)       return FALSE;    if(!(g_hEvent = CreateEvent(NULL,FALSE,FALSE,NULL)))                                        return FALSE;    if(g_lpMouse->SetEventNotification(g_hEvent) != DI_OK)                                      return FALSE;    if(g_lpMouse->SetProperty(DIPROP_BUFFERSIZE,&dipdw.diph) != DI_OK)                          return FALSE;    if(g_lpMouse->Acquire() != DI_OK)                                                           return FALSE;     g_lpDI->EnumDevices(DIDEVTYPE_JOYSTICK,DirectX_EnumAndCreateJoystick,hwnd,DIEDFL_ATTACHEDONLY);    return TRUE;}void DirectX_DeleteDI(){    if(g_lpDI)    {        if(g_lpKeyboard)    {g_lpKeyboard->Unacquire(); g_lpKeyboard->Release(); g_lpKeyboard = NULL;}        if(g_lpMouse)       {g_lpMouse->Unacquire();    g_lpMouse->Release();    g_lpMouse = NULL;}        if(g_hEvent)        {CloseHandle(g_hEvent);     g_hEvent = NULL;}        if(g_lpJoystick1)   {g_lpJoystick1->Unacquire();    g_lpJoystick1->Release(); g_lpJoystick1 = NULL;}        if(g_lpJoystick2)   {g_lpJoystick2->Unacquire();    g_lpJoystick2->Release(); g_lpJoystick2 = NULL;}        g_lpDI->Release();        g_lpDI = NULL;    }}
    Thêm vào 1 hàm mới là DirectX_GetInputJoystick() nên đặt sát với DirectX_GetInputKeyboard()

    Mã:
    BOOL DirectX_GetInputJoystick(LPDIRECTINPUTDEVICE lpJoystick,PINPUTJOYSTICK pInput){    HRESULT         hr;    DIJOYSTATE      js;     ZeroMemory(pInput,sizeof(INPUTJOYSTICK));    hr = lpJoystick->GetDeviceState(sizeof(DIJOYSTATE),&js);    if(hr != DI_OK)    {        if(hr == DIERR_INPUTLOST)            lpJoystick->Acquire();        return FALSE;    }    if(js.lX < 0)                   pInput->bLeft   ^= 1;    if(js.lX > 0)                   pInput->bRight  ^= 1;    if(js.lY < 0)                   pInput->bUp     ^= 1;    if(js.lY > 0)                   pInput->bDown   ^= 1;    if(js.rgbButtons[0] & 0x80)     pInput->bShoot  ^= 1;    return TRUE;}
    Viết lại hàm Tank_Update()

    Mã:
    void Tank_Update(BYTE pCells[52][52]){    INPUTKEYBOARD       Keyboard;    INPUTMOUSE          Mouse;    INPUTJOYSTICK       Joystick1,Joystick2;    int                 cStep;    BOOL                bStep;     if(g_TankL.iFroze > 0)        g_TankL.iFroze --;    if(g_TankL.bReady && g_TankL.iFroze == 0)    {        if(DirectX_GetInputKeyboard(&Keyboard))        {            if(Keyboard.bLeft)          g_TankL.iRequestFrend = FM_LEFT;            else if(Keyboard.bUp)       g_TankL.iRequestFrend = FM_UP;            else if(Keyboard.bRight)    g_TankL.iRequestFrend = FM_RIGHT;            else if(Keyboard.bDown)     g_TankL.iRequestFrend = FM_DOWN;            else                        g_TankL.iRequestFrend = FM_NULL;             if(g_TankL.iRequestFrend != FM_NULL)            {                if(g_TankL.iRequestFrend != g_TankL.iFrend)                 // Neu khac huong                {                    if(abs(g_TankL.iRequestFrend - g_TankL.iFrend) == 2)    // Yeu cau quay nguoc                        g_TankL.iFrend = g_TankL.iRequestFrend;                    else if(Tank_CanRotate4Frend(&g_TankL))                 // Quay vuong goc                        g_TankL.iFrend = g_TankL.iRequestFrend;                }                // Di chuyen Tank                cStep = g_TankL.iSpeed * (Tank_MoveOnGlide(&g_TankL,pCells) ? 2:1 );                bStep = FALSE;                while(cStep>0)                {                    if(Tank_CanStepByStep(&g_TankL,pCells))                    {                        Tank_StepByStep(&g_TankL);                        bStep = TRUE;                        cStep --;                    }                    else                        break;                }                if(bStep)                {                    if(++ g_TankL.iFrame == 4)                        g_TankL.iFrame = 0;                }            }            // Nguoi choi dang nhan nut ban            if(Keyboard.bSpace)            if(++ g_TankL.cTimes >= 8)            {                g_TankL.cTimes = 0;                if(g_arBullL.GetSize() < g_TankL.cBulletJoin)                    Tank_Shoot(&g_TankL);            }        }        if(g_lpJoystick1)        if(DirectX_GetInputJoystick(g_lpJoystick1,&Joystick1))        {            if(Joystick1.bLeft)         g_TankL.iRequestFrend = FM_LEFT;            else if(Joystick1.bUp)      g_TankL.iRequestFrend = FM_UP;            else if(Joystick1.bRight)   g_TankL.iRequestFrend = FM_RIGHT;            else if(Joystick1.bDown)    g_TankL.iRequestFrend = FM_DOWN;            else                        g_TankL.iRequestFrend = FM_NULL;             if(g_TankL.iRequestFrend != FM_NULL)            {                if(g_TankL.iRequestFrend != g_TankL.iFrend)                 // Neu khac huong                {                    if(abs(g_TankL.iRequestFrend - g_TankL.iFrend) == 2)    // Yeu cau quay nguoc                        g_TankL.iFrend = g_TankL.iRequestFrend;                    else if(Tank_CanRotate4Frend(&g_TankL))                 // Quay vuong goc                        g_TankL.iFrend = g_TankL.iRequestFrend;                }                // Di chuyen Tank                cStep = g_TankL.iSpeed * (Tank_MoveOnGlide(&g_TankL,pCells) ? 2:1 );                bStep = FALSE;                while(cStep>0)                {                    if(Tank_CanStepByStep(&g_TankL,pCells))                    {                        Tank_StepByStep(&g_TankL);                        bStep = TRUE;                        cStep --;                    }                    else                        break;                }                if(bStep)                {                    if(++ g_TankL.iFrame == 4)                        g_TankL.iFrame = 0;                }            }            // Nguoi choi dang nhan nut ban            if(Joystick1.bShoot)            if(++ g_TankL.cTimes >= 8)            {                g_TankL.cTimes = 0;                if(g_arBullL.GetSize() < g_TankL.cBulletJoin)                    Tank_Shoot(&g_TankL);            }        }    }    if(g_TankR.iFroze > 0)        g_TankR.iFroze --;    if(g_TankR.bReady && g_TankR.iFroze == 0)    {        if(DirectX_GetInputMouse(&Mouse))        {            g_TankR.iRequestFrend = Mouse.iRotateFrend;            if(g_TankR.iRequestFrend != FM_NULL)            if(g_TankR.iRequestFrend != g_TankR.iFrend)            {                if(abs(g_TankR.iRequestFrend - g_TankR.iFrend) == 2)    // Yeu cau quay nguoc                    g_TankR.iFrend = g_TankR.iRequestFrend;                else                                                    // Yeu cau quay vuong goc                {                    if(Tank_CanRotate4Frend(&g_TankR))                                          g_TankR.iFrend = g_TankR.iRequestFrend;                    else                                                // Neu chua the quay                    {                    //                     //                    //                    //                    //                        int     xTank = g_TankR.x;                        int     yTank = g_TankR.y;                        int     iFrend = g_TankR.iFrend;                        int     cStepForward = 0,cStepBack = 0;                        BOOL    bForward = FALSE, bBack = FALSE;                         while(Tank_CanStepByStep(&g_TankR,pCells) && cStepForward < MEDIUM)                        {                            cStepForward ++;                            Tank_StepByStep(&g_TankR);                            if(Tank_CanRotate4Frend(&g_TankR))                            {                                bForward = TRUE;                                break;                            }                        }                        g_TankR.x = xTank;                        g_TankR.y = yTank;                        if(iFrend == FM_LEFT)       g_TankR.iFrend = FM_RIGHT;                        else if(iFrend == FM_UP)    g_TankR.iFrend = FM_DOWN;                        else if(iFrend == FM_RIGHT) g_TankR.iFrend = FM_LEFT;                        else                        g_TankR.iFrend = FM_UP;                        while(Tank_CanStepByStep(&g_TankR,pCells) && cStepBack < MEDIUM)                        {                            cStepBack ++;                            Tank_StepByStep(&g_TankR);                            if(Tank_CanRotate4Frend(&g_TankR))                            {                                bBack = TRUE;                                break;                            }                        }                        g_TankR.x = xTank;                        g_TankR.y = yTank;                        if(bForward && bBack)                        {                            if(cStepForward <= cStepBack)   { cStep = cStepForward; g_TankR.iFrend = iFrend;}                            else                            cStep = cStepBack;                        }                        else if(bForward && !bBack)                        {                            cStep = cStepForward;                            g_TankR.iFrend = iFrend;                        }                        else if(!bForward && bBack)                            cStep = cStepBack;                        else                        {                            cStep = cStepForward;                            g_TankR.iFrend = iFrend;                        }                        //                        bStep = FALSE;                        while(cStep>0)                        {                            if(Tank_CanStepByStep(&g_TankR,pCells))                            {                                Tank_StepByStep(&g_TankR);                                bStep = TRUE;                                cStep --;                                if(Tank_CanRotate4Frend(&g_TankR))                                {                                    g_TankR.iFrend = g_TankR.iRequestFrend;                                    break;                                }                            }                            else                                break;                        }                        if(bStep)                        if(++ g_TankR.iFrame == 4)                            g_TankR.iFrame = 0;                    }                }            }            // Di chuyen            if(Mouse.bRightPress)            {                cStep = g_TankR.iSpeed * (Tank_MoveOnGlide(&g_TankR,pCells) ? 2:1 );                bStep = FALSE;                while(cStep>0)                {                    if(Tank_CanStepByStep(&g_TankR,pCells))                    {                        Tank_StepByStep(&g_TankR);                        bStep = TRUE;                        cStep --;                    }                    else                        break;                }                if(bStep)                if(++ g_TankR.iFrame == 4)                    g_TankR.iFrame = 0;            }            // Khai hoa            if(Mouse.bLeftPress)            if(++ g_TankR.cTimes >= 8)            {                g_TankR.cTimes = 0;                if(g_arBullR.GetSize() < g_TankR.cBulletJoin)                    Tank_Shoot(&g_TankR);            }        }        if(g_lpJoystick2)        if(DirectX_GetInputJoystick(g_lpJoystick2,&Joystick2))        {            if(Joystick2.bLeft)         g_TankR.iRequestFrend = FM_LEFT;            else if(Joystick2.bUp)      g_TankR.iRequestFrend = FM_UP;            else if(Joystick2.bRight)   g_TankR.iRequestFrend = FM_RIGHT;            else if(Joystick2.bDown)    g_TankR.iRequestFrend = FM_DOWN;            else                        g_TankR.iRequestFrend = FM_NULL;             if(g_TankR.iRequestFrend != FM_NULL)            {                if(g_TankR.iRequestFrend != g_TankR.iFrend)                 // Neu khac huong                {                    if(abs(g_TankR.iRequestFrend - g_TankR.iFrend) == 2)    // Yeu cau quay nguoc                        g_TankR.iFrend = g_TankR.iRequestFrend;                    else if(Tank_CanRotate4Frend(&g_TankR))                 // Quay vuong goc                        g_TankR.iFrend = g_TankR.iRequestFrend;                }                // Di chuyen Tank                cStep = g_TankR.iSpeed * (Tank_MoveOnGlide(&g_TankR,pCells) ? 2:1 );                bStep = FALSE;                while(cStep>0)                {                    if(Tank_CanStepByStep(&g_TankR,pCells))                    {                        Tank_StepByStep(&g_TankR);                        bStep = TRUE;                        cStep --;                    }                    else                        break;                }                if(bStep)                {                    if(++ g_TankR.iFrame == 4)                        g_TankR.iFrame = 0;                }            }            // Nguoi choi dang nhan nut ban            if(Joystick2.bShoot)            if(++ g_TankR.cTimes >= 8)            {                g_TankR.cTimes = 0;                if(g_arBullR.GetSize() < g_TankR.cBulletJoin)                    Tank_Shoot(&g_TankR);            }        }    }}
    Trong xử lý mã, chúng ta chấp nhận tiếp tục chương trình nếu 2 Joystick không được khởi tạo, mã trong Tank_Update() sẽ kiểm tra 2 con trỏ tới thiết bị này nếu không NULL
    mới xử lý. Chúng ta cũng gán thiết bị được tìm thấy trước (Master Joystick) cho TankL và thấy sau cho bên phải.
    Biên dịch và chạy, chúng ta có thể thao tác với Joystick như sau:
    _ Nút số 1 dùng để bắn
    _ Nút tròn lớn 4 hướng dùng để di chuyển.


    Chào tạm biệt. [IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG]

 

 
Trang 2 của 3 Đầu tiênĐầu tiên 123 CuốiCuối

Quyền viết bài

  • Bạn Không thể gửi Chủ đề mới
  • Bạn Không thể Gửi trả lời
  • Bạn Không thể Gửi file đính kèm
  • Bạn Không thể Sửa bài viết của mình
  •