Chào mừng đến với Diễn đàn lập trình - Cộng đồng lập trình.
Trang 3 của 3 Đầu tiênĐầu tiên 123
Kết quả 21 đến 28 của 28
  1. #21
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    NGÀY 37: Thêm vào chức năng tính điểm cho người chơi, hiển thị 20 người chơi có số điểm cao nhất, cài đặt cho F11
    Trong trò chơi, chúng ta tìm cách xếp hạng theo thứ tự cho 20 người có kết quả cao nhất, nhưng lấy gì làm thước đo đây ?
    Nếu lấy vòng chơi thì không ổn rồi, vì phím PageUp và PageDown đã cho phép người chơi tùy nghi thay đổi vòng chơi rồi.
    Nghĩ tới nghĩ lui, mình quyết định lấy số điểm khi bắn TankE làm đơn vị tính điểm.
    Chúng ta sẽ quy định, người chơi bắn 1 viên đạn trúng TankE sẽ được cộng thêm 1 điểm, bắn cháy TankE sẽ được cộng thêm 2 điểm.
    Rồi, thống nhất như vậy và bắt tay vào làm thôi.

    Thêm 2 cấu trúc

    Mã:
    typedef struct{    CHAR        szName[MAX_PATH];       // Tên người chơi    CHAR        szDate[MAX_PATH];       // Chuỗi ngày tháng    DWORD       dwScore;                // Điểm số}SCORE,*PSCORE;typedef struct{    int         cCount;         // So người được lưu tên hiện tại - Cao nhất là 20    SCORE       Score[20];      // Cấu trúc Score của từng người}SCOREALL,*PSCOREALL;
    Thêm 2 biến toàn cục

    Mã:
    SCORE                   g_Score;                    // ScoreSCOREALL                g_ScoreAll;                 // ScoreAll
    Trong hàm Bullet_HitTankE() thay đổi đoạn mã sau

    Mã:
    // mã cũ            if((--pTankE->iPower) < 1)            {                if(pSmoke = (PSMOKE)malloc(sizeof(SMOKE)))  // Kich thuoc 1 khung la 88x96                {                    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);                }                arTankE->RemoveAt(i);            }            return TRUE;
    thành

    Mã:
    // Mã mới            if((--pTankE->iPower) < 1)            {                g_Score.dwScore += 1;                if(pSmoke = (PSMOKE)malloc(sizeof(SMOKE)))  // Kich thuoc 1 khung la 88x96                {                    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);                }                arTankE->RemoveAt(i);            }            g_Score.dwScore += 1;            return TRUE;
    Trong WndProc() thêm dòng mã sau:

    Mã:
    //                g_Score.dwScore = 0; // Thêm 1 dòng này vào mã đã có sẵn                if(!Level_LoadData(&g_DataLevel,g_iLevel)) // Mã cũ                {                    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);                }
    Trong WinMain() thêm các dòng như sau

    Mã:
    // Mã thêm vào    if(!Score_LoadData(&g_ScoreAll))    {        g_ScoreAll.cCount   = 0;        Score_SaveData(&g_ScoreAll);    }    // Mã cũ    g_ParamBezier.cMax  = (rand()%20)*5+5;    g_ParamBezier.xMax  = rand()%10+1;    g_ParamBezier.yMax  = rand()%10+1;
    Tạo mới 2 hàm Nạp và Lưu Score, nên đặt gần các hàm nạp lưu các đối tượng khác

    Mã:
    BOOL Score_LoadData(PSCOREALL pScoreAll){    CHAR        szText[MAX_PATH];    HANDLE      hFile;    SCOREALL    Data;    DWORD       dw;    BOOL        bFlag;     GetModuleFileName(NULL,szText,MAX_PATH);    PathRemoveFileSpec(szText);    lstrcat(szText,"\\Tank2D");    if(!PathIsDirectory(szText))        return FALSE;    lstrcat(szText,"\\Score.sco");    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(SCOREALL))    {        CloseHandle(hFile);        return FALSE;    }    bFlag = ReadFile(hFile,&Data,sizeof(SCOREALL),&dw,NULL);    CloseHandle(hFile);    if(!bFlag || dw != sizeof(SCOREALL))        return FALSE;    CopyMemory(pScoreAll,&Data,sizeof(SCOREALL));    return TRUE;}BOOL Score_SaveData(PSCOREALL pScoreAll){    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,"\\Score.sco");    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,pScoreAll,sizeof(SCOREALL),&dw,NULL);    CloseHandle(hFile);    if(!bFlag || dw != sizeof(SCOREALL))    {        DeleteFile(szText);        return FALSE;    }    return TRUE;}
    Trong WndProc(), thêm mã cho phím F11 như sau

    Mã:
    //        case IDC_F11:            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_SCORE),hwnd,DlgProc_Score);                g_bMoused = FALSE;                SendMessage(hwnd,WM_SETCURSOR,0,0);            }            return 0;
    Cũng trong WndProc(), thêm xử lý thông điệp WM_CLOSE như sau

    Mã:
    // Mã mới    case WM_CLOSE:        if(g_lpDD)        {            g_lpDD->FlipToGDISurface();            g_bMoused = TRUE;            SendMessage(hwnd,WM_SETCURSOR,0,0);            DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG_SCORE),hwnd,DlgProc_Score);            g_bMoused = FALSE;            SendMessage(hwnd,WM_SETCURSOR,0,0);        }        DestroyWindow(hwnd);        return 0;        // Mã cũ    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;
    Tạo hộp thoại mới với id = IDD_DIALOG_SCORE, đổi Title thành "Score".
    Thêm Listview có id = IDC_LIST1, đổi kiểu xem thành "Report", đặt thuộc tính "Client edge" và "Modal frame".
    Thêm Edit id = IDC_EDIT1, có kiểu canh Text là "Centered".
    Thêm Edit id = IDC_EDIT2, có kiểu canh Text là "Centered", check thuộc tính "Read-Only".
    Thay text của button OK thành "Import", thay text của button Cancel thành "Close".
    Canh chỉnh hộp thoại, ListView có chiều cao chứa khoảng trên 20 dòng. Chỉnh tạm thời thôi, khi chạy bạn chỉnh lại cho hoàn chỉnh.

    Sau đây là hàm xử lý thông điệp cho hộp thoại này ( Đặt trước WndProc())

    Mã:
    BOOL CALLBACK DlgProc_Score(HWND hDlg,UINT message,WPARAM wparam,LPARAM lparam){    static  HBRUSH      hbrBack;    static  HWND        hList,hEdit1,hEdit2;    LVCOLUMN            lvc;    LVITEM              lvi;    CHAR                szText[MAX_PATH];    SYSTEMTIME          st;    int                 i,cCount;     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);        hEdit1 = GetDlgItem(hDlg,IDC_EDIT1);        hEdit2 = GetDlgItem(hDlg,IDC_EDIT2);        lvc.mask        = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM;        lvc.fmt         = LVCFMT_CENTER;        lvc.cx          = 50;        lvc.iSubItem    = 0;        lvc.pszText     = "Index";        ListView_InsertColumn(hList,0,&lvc);    // Cột đầu tiên là số thứ tự        lvc.cx          = 150;        lvc.iSubItem    = 1;        lvc.pszText     = "Name";        ListView_InsertColumn(hList,1,&lvc);    // Cột thứ 2 là tên người chơi        lvc.cx          = 100;        lvc.iSubItem    = 2;        lvc.pszText     = "Score";        ListView_InsertColumn(hList,2,&lvc);    // Cột thứ 3 là Điểm củ người chơi        lvc.cx          = 200;        lvc.iSubItem    = 3;        lvc.pszText     = "Date";        ListView_InsertColumn(hList,3,&lvc);    // Cột cuối cùng là mốc thời gian của người chơi        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);        // Đổ dữ liệu vào ListView lấy nguồn từ biến toàn cục g_ScoreAll        for(i=0;i<g_ScoreAll.cCount;i++)        {            lvi.mask        = LVIF_TEXT;            lvi.iItem       = i;            lvi.iSubItem    = 0;            lvi.pszText     = szText;            wsprintf(szText,"%i",i+1);            ListView_InsertItem(hList,&lvi);            ListView_SetItemText(hList,i,1,g_ScoreAll.Score[i].szName);            wsprintf(szText,"%d",g_ScoreAll.Score[i].dwScore);            ListView_SetItemText(hList,i,2,szText);            ListView_SetItemText(hList,i,3,g_ScoreAll.Score[i].szDate);        }        // Nếu chưa có tên, đặt trước NoName cho người chơi        SetWindowText(hEdit1,(g_Score.szName[0] != '\0') ? g_Score.szName:"< No Name >");        wsprintf(szText,"%i",g_Score.dwScore);        SetWindowText(hEdit2,szText);        return TRUE;    case WM_COMMAND:        switch(LOWORD(wparam))        {        case IDOK:            GetWindowText(hEdit1,szText,GetWindowTextLength(hEdit1)+1);            if(szText[0] == '\0')   wsprintf(g_Score.szName,"< No Name >");            else                    wsprintf(g_Score.szName,szText);            GetLocalTime(&st);  // Nhận thời gian hệ thống            wsprintf(g_Score.szDate,"%02d:%02d:%02d   %02d/%02d/%d",st.wHour,st.wMinute,st.wSecond,st.wDay,st.wMonth,st.wYear);            // Tìm nơi chèn dữ liệu mới trong ListView            cCount = ListView_GetItemCount(hList);            for(i=0;i<cCount;i++)            {                ListView_GetItemText(hList,i,2,szText,MAX_PATH);                if(atoi(szText) <= (int)g_Score.dwScore)                    break;            }            lvi.mask        = LVIF_TEXT;            lvi.iItem       = i;            lvi.iSubItem    = 0;            lvi.pszText     = szText;            wsprintf(szText,"%i",i+1);            ListView_InsertItem(hList,&lvi);            ListView_SetItemText(hList,i,1,g_Score.szName);            wsprintf(szText,"%d",g_Score.dwScore);            ListView_SetItemText(hList,i,2,szText);            ListView_SetItemText(hList,i,3,g_Score.szDate);            i++; cCount ++;            while(i<cCount)            {                wsprintf(szText,"%i",i+1);                ListView_SetItemText(hList,i,0,szText);                i++;            }            if(cCount > 20)     // Nếu số dòng trong ListView vượt quá 20 thì xóa nó            {                ListView_DeleteItem(hList,cCount-1);                cCount --;            }            // Lưu lại thay đổi vào biến toàn cục            g_ScoreAll.cCount = cCount;            for(i=0;i<cCount;i++)            {                ListView_GetItemText(hList,i,1,g_ScoreAll.Score[i].szName,MAX_PATH);                ListView_GetItemText(hList,i,3,g_ScoreAll.Score[i].szDate,MAX_PATH/2);                ListView_GetItemText(hList,i,2,szText,MAX_PATH);                g_ScoreAll.Score[i].dwScore = atoi(szText);            }            Score_SaveData(&g_ScoreAll);    // Lưu ra tập tin            EnableWindow(GetDlgItem(hDlg,IDOK),FALSE); // Không cho người chơi lưu tiếp            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;}
    Hộp thoại này có thể xuất hiện bằng 2 cách, người chơi nhấn F11 hoặc thoát khỏi trò chơi.
    Mã tuy dài nhưng cũng không khó hiểu lắm, chủ yếu là khi người chơi nhấn <Import> thì mã hơi khó nhưng có các chỉ dẫn rồi, hy vọng các bạn hiểu.
    Khi thực thi, hộp thoại sẽ trông như sau



    Ngày nay tới đây thôi, muộn rồi, 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 05-04-2014 lúc 11:30 AM - - -</font>

    <font color="#0000FF">NGÀY 38:
    Những xử lý cuối cùng

    Ngày hôm nay, chúng ta sẽ thêm mã hiển thị các chức năng phím tắt ở phần trên cùng màn hình.
    Các phím chúng ta xử lý là: F1, F2, F3, F4, F5, F6, F11, F12, PageUp, PageDown. Như vậy là dư ra : F7, F8, F9, F10, Insert, Delete, Home, End. Chuỗi hiển thị sẽ như sau:

    F1: About F2: Design F3: Color F4: Image F5: Sound F6: Tank F11: Score F12: Bezier PageUp: Foward PageDown: Next
    Hàm cho công việc này như sau ( nên đặt trên hàm DirectX_DrawTitle())

    Mã:
    void DirectX_DrawTextTop(){    DDSURFACEDESC   ddsd;    HDC             hdc;    HFONT           hFont;    RECT            r;     ddsd.dwSize     = sizeof(ddsd);    ddsd.dwFlags    = DDSD_HEIGHT|DDSD_WIDTH;    if(g_lpBack->GetSurfaceDesc(&ddsd) == DD_OK)    if(g_lpBack->GetDC(&hdc) == DD_OK)    {        SetBkMode(hdc,TRANSPARENT);        SetTextColor(hdc, (~(g_DataSetup.crScreen << 8)) >> 8);        SetRect(&r,0,0,ddsd.dwWidth-1,ddsd.dwHeight-1);        hFont = CreateFont(8,0,0,0,FW_NORMAL,0,0,0,0,0,0,0,0,"MS Sans Serif");        SelectObject(hdc,hFont);        DrawText(hdc,"F1: About     F2: Design     F3: Color     F4: Image     F5: Sound     F6: Tank     F11: Score     F12: Bezier     PageUp: Foward     PageDown: Next",-1,&r,DT_SINGLELINE|DT_CENTER|DT_TOP);        DeleteObject(hFont);        g_lpBack->ReleaseDC(hdc);    }}
    Trong hàm App_Update(), thêm vào 1 dòng mã gọi DirectX_DrawTextTop() như sau

    Mã:
    // Mã đã hiện hữu    DirectX_DrawAndUpdateBezier(g_lpBack,&g_ParamBezier,xFrame,yFrame);    switch(g_iStatus)    {    case SP_LEVEL:        DirectX_DrawTextTop();  // Chỉ thêm vào duy nhất 1 dòng này        DirectX_DrawTitle(iLevel,xFrame,yFrame);        DirectX_DrawFrame(xFrame,yFrame);        DirectX_DrawRightSide(xFrame,yFrame);
    Khi thực thi chương trình, text sẽ hiển thị như hình dưới



    Ngày hôm nay là kết thúc phần phát triển của trò chơi. Cũng là tạm chia tay với các bạn trong đề tài này.
    Có lẽ bạn sẽ hỏi : Chương trình đã hoàn thành chưa ? Có cần phát triển gì thêm không ?
    Với mình : Không bao giờ cảm thấy hoàn thiện, vẫn còn muốn viết thêm nhiều nữa, nhưng phải dừng lại ở đâu đó.
    Thực ra lúc bắt đầu mình nghĩ sẽ mất khoảng nửa tháng cho trò chơi này, nhưng như bạn thấy thời gian đã gấp 3 lần so với dự tính.
    Mục tiêu cho thời gian tới :
    _ Dò tìm các lỗi đang tiềm ẩn nguy cơ gây bể vỡ chương trình.
    _ Rút gọn mã nguồn xuống còn phân nửa hiện tại ( còn khoảng 3000 so với khoảng 6000 dòng).
    _ Rút gọn kích thước tập tin thực thi Tank2D.exe xuống phân nửa hiện tại ( 532KB xuống còn khoảng 300KB - chế độ Release).

    Chương trình viết trên Microsoft VC++6.0, Hệ điều hành Windows SP#3, CPU : Intel(R) Celeron(R) CPU G550 @ 2.60GHz 1.88 GB of RAM.
    Chạy thử nghiệm chưa phát hiện ra lỗi nào, mong chờ các bạn chạy trên các máy khác nhau góp thêm ý kiến.
    Hãy cùng " Học hỏi và chia sẻ" với mình nhé. Byebye !!!

  2. #22
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Có 1 lỗi Logic trong phương thức hủy đối tượng của lớp CPtrArray:

    Mã:
    ......public:    CPtrArray(BOOL isClass) { cCount = 0; pVoid = NULL; bClass = isClass;}    //~CPtrArray()          { cCount = 0; if(pVoid) { RemoveAll(); free(pVoid); pVoid = NULL;}} // Lỗi Logic ở đây    ~CPtrArray()            { if(pVoid) { RemoveAll(); free(pVoid); pVoid = NULL;} cCount = 0;} // Sửa lại theo dòng này......

  3. #23
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    mình cũng đang tìm hiểu về C++ thấy cũng dễ nếu đã có kiến thức cơ bản

  4. #24
    Rất tỉ mỉ. Nhưng tại sao anh không viết dưới dạng OOP luôn. Viết dạng này quản lý code mệt lắm

  5. #25
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Cám ơn bạn, mình sẽ chuyển thể sang OOP. Cái này mình viết theo cách để mấy bạn chưa quen với lập trình hướng đối tượng có thể hiểu được.
    Phiên bản mới mình sẽ gom các hàm riêng lẻ vào lớp, chào thân ái.

  6. #26
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    em mới học C++, em viết trên visual studio 2012 thì hàm CWavesound bị lỗi cú pháp DSBCAPS_CTRLDEFAULT thì sửa thế nào bác

  7. #27
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Bạn thử thay DSBCAPS_CTRLDEFAULT bằng : DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY.
    Nếu bạn viết trên VS2012 thì chắc rằng còn phải thay đổi nhiều cái khác nữa. [IMG]images/smilies/thinking.gif[/IMG][IMG]images/smilies/thinking.gif[/IMG][IMG]images/smilies/thinking.gif[/IMG]

  8. #28
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    bai viết rất hay.

 

 
Trang 3 của 3 Đầu tiênĐầu tiên 123

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
  •