-
17-02-2014, 08:39 AM #1Silver member
- Ngày tham gia
- Sep 2015
- Đang ở
- Hà Nội
- Bài viết
- 0
Thực hành lập trình Game với VC++6.0 sử dụng DirectX : Tank2D
NGÀY 1 :
Mình không được học chuyên ngành, cũng không rành tiếng Anh, đến với lập trình chỉ là một sự ngẫu nhiên, một đam mê theo kiểu "tay trái". Không muốn múa rìu qua mắt thợ, Game này mình viết chỉ để học tập, để thử lòng kiên trì, xin các bạn góp ý thêm trong quá trình xây dựng dự án. Vì là một Newbee nên kiểu Code của mình có nhiều ngờ nghệch, chỉ xin các bạn đừng cười.
Trước tiên, chương trình Tank2D tạo ra, thêm bớt, xóa rất nhiều các đối tượng, vì vậy trước tiên mình sẽ mã hóa một lớp có tên CPtrArray. Trong thư viện MFC của Microsoft cũng có những lớp tương tự nhưng mình không muốn sử dụng, vì nó sẽ làm chương trình thực thi của bạn tăng kích thước đáng kể. Hơn nữa, mình muốn viết một chương trình theo kiểu "copy là chạy", giảm thiểu tới mức dễ dàng nhất cho người sử dụng.
Mã:#include <windows.h>class CPtrArray{private: int cCount; PDWORD pVoid; BOOL bClass;public: CPtrArray(BOOL isClass) { cCount = 0; pVoid = NULL; bClass = isClass;} ~CPtrArray() { cCount = 0; if(pVoid) {RemoveAll(); free(pVoid); pVoid = NULL;}} int GetSize() { return cCount;} PVOID GetAt(int iIndex) { if(iIndex >= cCount || cCount < 1) return NULL; return (PVOID)pVoid[iIndex]; } BOOL Add(PVOID pThis) { PDWORD pNew; if(pNew = (PDWORD)malloc(sizeof(PVOID)*(cCount+1))) { for(int i=0;i<cCount;i++) pNew[i] = (DWORD)pVoid[i]; free(pVoid); pNew[i] = (DWORD)pThis; pVoid = pNew; cCount++; return TRUE; } return FALSE; } BOOL RemoveAt(int iIndex) { if(iIndex < cCount) { PDWORD pNew; if(pNew = (PDWORD)malloc(sizeof(PVOID)*(cCount-1))) { int i; for(i=0;i<iIndex;i++) pNew[i] = (DWORD)pVoid[i]; for(i=iIndex;i<cCount-1;i++) pNew[i] = (DWORD)pVoid[i+1]; if(bClass) delete ((PVOID)pVoid[iIndex]); else free((PVOID)pVoid[iIndex]); free(pVoid); pVoid = pNew; cCount--; return TRUE; } } return FALSE; } void RemoveAll() { PVOID p; for(int i=0;i<GetSize();i++) if(p = GetAt(i)) { if(bClass) delete p; else free(p); } free(pVoid); pVoid = NULL; cCount = 0; }};
View more random threads:
- Mã nguồn chương trình nghe file midi!
- Chương trình bắn pháo hoa sử dụng OpenGL và SDL trong VC++6.0
- CD/DVD-Rom TrayManager v2.0 viết bằng C++
- [Game: HangMan Deluxe v1.0 - by bvKim]
- Source code chương trình "Tính điểm tổng kết cuối năm cấp 3"
- Source code KMS Server kích hoạt Windows và Office
- Source Chương trình soạn thảo văn bản C++
- demo multi thread + CCriticalSection
- Phần mềm minh họa hệ mật mã khóa công khai (RSA)
- Source code hack plant vs zombie (Demo global hook dễ hiểu)
-
18-02-2014, 10:04 AM #2Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
NGÀY 2: Tạo lớp CWaveSound
Trong trò chơi Tank2D, chúng ta cần phải xử lý âm thanh trong các ngữ cảnh sau:
- Thực hiện âm nhạc nền khi ở trong các màn hình hội thoại, khi trong chế độ [ PAUSE ], khi chờ nhận sự kiện nhập liệu từ người chơi. Âm nhạc nền có thể chơi từ điều khiển cửa sổ MCI của Windows, chương trình này sẻ chơi nhạc nền từ tập tin BackSound.mp3, BackSound.mid, BackSound.wav nếu nó tìm được theo thứ tự vừa rồi.
- Các tiếng động tương tác : Tank khai hỏa, đạn nổ, hết 1 vòng, thua cuộc, v.v... Các tiếng động này có thể được phát cùng một thời điểm và có thể chồng lấp lên nhau nên không thể đơn giản dùng hàm PlaySound(), thay vào đó chúng ta sẽ sử dụng DirectSound cho mục đích này. Sau đây là mã hóa lớp CWaveSound ( Để tiện cho sau này, mình cũng đặt tất cả các chỉ thị tiền xử lý #include và #pragma ở đầu tập tin cpp. Lưu ý là dự án chỉ có duy nhất 1 tập tin mã nguồn Tank2D.cpp, 1 tập tin tài nguyên Tank2D.rc)
Mã:#define INITGUID#include<windows.h>#include<windowsx.h>#include<commctrl.h>#include<shlobj.h>#include<ddraw.h>#include<dinput.h>#include<dsound.h>#include<time.h>#include<math.h>#include<vfw.h>#include"resource.h"#pragma comment(lib,"comctl32.lib")#pragma comment(lib,"ddraw.lib")#pragma comment(lib,"dinput.lib")#pragma comment(lib,"dsound.lib")#pragma comment(lib,"winmm.lib")#pragma comment(lib,"vfw32.lib")#pragma comment(lib,"msimg32.lib")// Các định nghĩa #define khác ở đây// Các kiểu liệt kê enum đặt ở đây// Các định nhgĩa kiểu cấu trúc typedef struct đặt ở đây// Đặt khai báo của lớp CPtrArray của ngày 1 ở đâyclass CWaveSound{private: BOOL Open(char *pszFileName,HMMIO *phmmioIn,WAVEFORMATEX **ppwfxInfo,MMCKINFO *pckInRIFF) { HMMIO hmmioIn; MMCKINFO ckIn; // chunk info. for general use. PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in. WORD cbExtraAlloc; // Extra bytes for waveformatex BOOL bTrue; *ppwfxInfo = NULL; hmmioIn = NULL; if((hmmioIn = mmioOpen(pszFileName, NULL, MMIO_ALLOCBUF | MMIO_READ)) == NULL) goto ERROR_READING_WAVE; if((int)mmioDescend(hmmioIn, pckInRIFF, NULL, 0) != 0) goto ERROR_READING_WAVE; if((pckInRIFF->ckid != FOURCC_RIFF) || (pckInRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E'))) goto ERROR_READING_WAVE; ckIn.ckid = mmioFOURCC('f', 'm', 't', ' '); if((int)mmioDescend(hmmioIn, &ckIn, pckInRIFF, MMIO_FINDCHUNK) != 0) goto ERROR_READING_WAVE; if(ckIn.cksize < (long) sizeof(PCMWAVEFORMAT)) goto ERROR_READING_WAVE; if(mmioRead(hmmioIn, (HPSTR) &pcmWaveFormat, (long) sizeof(pcmWaveFormat)) != (long) sizeof(pcmWaveFormat)) goto ERROR_READING_WAVE; if(pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM) cbExtraAlloc = 0; else if(mmioRead(hmmioIn, (LPSTR) &cbExtraAlloc,(long) sizeof(cbExtraAlloc)) != (long) sizeof(cbExtraAlloc)) goto ERROR_READING_WAVE; if((*ppwfxInfo = (WAVEFORMATEX *)GlobalAlloc(GMEM_FIXED, sizeof(WAVEFORMATEX)+cbExtraAlloc)) == NULL) goto ERROR_READING_WAVE; memcpy(*ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat)); (*ppwfxInfo)->cbSize = cbExtraAlloc; if(cbExtraAlloc != 0) if(mmioRead(hmmioIn, (LPSTR) (((BYTE*)&((*ppwfxInfo)->cbSize))+sizeof(cbExtraAlloc)),(long) (cbExtraAlloc)) != (long) (cbExtraAlloc)) goto ERROR_READING_WAVE; if(mmioAscend(hmmioIn, &ckIn, 0) != 0) goto ERROR_READING_WAVE; goto TEMPCLEANUP; ERROR_READING_WAVE: bTrue = FALSE; if(*ppwfxInfo != NULL) { GlobalFree(*ppwfxInfo); *ppwfxInfo = NULL; } if(hmmioIn != NULL) { mmioClose(hmmioIn, 0); hmmioIn = NULL; } TEMPCLEANUP: *phmmioIn = hmmioIn; return bTrue; } BOOL Data(HMMIO *phmmioIn,MMCKINFO *pckIn,MMCKINFO *pckInRIFF) { mmioSeek(*phmmioIn, pckInRIFF->dwDataOffset + sizeof(FOURCC), SEEK_SET); pckIn->ckid = mmioFOURCC('d', 'a', 't', 'a'); if(mmioDescend(*phmmioIn, pckIn, pckInRIFF, MMIO_FINDCHUNK)==0) return TRUE; return FALSE; } BOOL Read(HMMIO hmmioIn,UINT cbRead,BYTE *pbDest,MMCKINFO *pckIn,UINT *cbActualRead) { MMIOINFO mmioinfoIn; // current status of <hmmioIn> UINT cT,cbDataIn; if(mmioGetInfo(hmmioIn,&mmioinfoIn,0) != 0) goto ERROR_CANNOT_READ; cbDataIn = cbRead; if(cbDataIn > pckIn->cksize) cbDataIn = pckIn->cksize; pckIn->cksize -= cbDataIn; for(cT=0;cT<cbDataIn;cT++) { if(mmioinfoIn.pchNext == mmioinfoIn.pchEndRead) { if(mmioAdvance(hmmioIn, &mmioinfoIn, MMIO_READ) != 0) goto ERROR_CANNOT_READ; if(mmioinfoIn.pchNext == mmioinfoIn.pchEndRead) goto ERROR_CANNOT_READ; } *((BYTE*)pbDest+cT) = *((BYTE*)mmioinfoIn.pchNext++); } if(mmioSetInfo(hmmioIn, &mmioinfoIn, 0) != 0) goto ERROR_CANNOT_READ; *cbActualRead = cbDataIn; return TRUE; ERROR_CANNOT_READ: *cbActualRead = 0; return FALSE; } BOOL Load(LPSTR szFile,UINT *cbSize,WAVEFORMATEX **ppwfxInfo,BYTE **ppbData) { HMMIO hmmioIn; MMCKINFO ckInRiff; MMCKINFO ckIn; UINT cbActualRead; BOOL bTrue=TRUE; *ppbData = NULL; *ppwfxInfo = NULL; *cbSize = 0; if(!this->Open(szFile,&hmmioIn,ppwfxInfo,&ckInRiff)) goto ERROR_LOADING; if(!this->Data(&hmmioIn,&ckIn,&ckInRiff)) goto ERROR_LOADING; if((*ppbData = (BYTE *)GlobalAlloc(GMEM_FIXED,ckIn.cksize)) == NULL) goto ERROR_LOADING; if(!this->Read(hmmioIn,ckIn.cksize,*ppbData,&ckIn,&cbActualRead)) goto ERROR_LOADING; *cbSize = cbActualRead; goto DONE_LOADING; ERROR_LOADING: bTrue = FALSE; if(*ppbData != NULL) { GlobalFree(*ppbData); *ppbData = NULL; } if(*ppwfxInfo != NULL) { GlobalFree(*ppwfxInfo); *ppwfxInfo = NULL; } DONE_LOADING: if(hmmioIn != NULL) { mmioClose(hmmioIn, 0); hmmioIn = NULL; } return bTrue; }public: BOOL bLoop; LPDIRECTSOUNDBUFFER lpdsb; CWaveSound() { lpdsb = NULL; bLoop = FALSE;} ~CWaveSound() { if(lpdsb) { lpdsb->Stop(); lpdsb->Release();}} BOOL Play(LPSTR szFile,LPDIRECTSOUND lpds,BOOL loop) { DSBUFFERDESC dsbd; WAVEFORMATEX * pwfx=NULL; PBYTE pdata=NULL; UINT uSize; if(!this->Load(szFile,&uSize,&pwfx,&pdata)) return FALSE; memset(&dsbd, 0, sizeof(DSBUFFERDESC)); dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwFlags = DSBCAPS_STATIC|DSBCAPS_CTRLDEFAULT|DSBCAPS_GETCURRENTPOSITION2; dsbd.dwBufferBytes = uSize; dsbd.lpwfxFormat = pwfx; if(SUCCEEDED(lpds->CreateSoundBuffer(&dsbd,&this->lpdsb,NULL))) { BYTE *pbData = NULL; BYTE *pbData2 = NULL; DWORD dwLength; DWORD dwLength2; this->lpdsb->Lock(0,uSize,(void**)&pbData,&dwLength,(void**)&pbData2,&dwLength2,0L); memcpy(pbData,pdata,uSize); this->lpdsb->Unlock(pbData,uSize,NULL,0); this->lpdsb->SetVolume(0); this->lpdsb->SetPan(0); this->bLoop = loop; this->lpdsb->Play(0,0,loop?DSBPLAY_LOOPING:0); GlobalFree(pwfx); GlobalFree(pdata); return TRUE; } GlobalFree(pwfx); GlobalFree(pdata); return FALSE; }};
-
21-02-2014, 09:04 AM #3Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
NGÀY 3: Các tác vụ với những giá trị của Cells trong ma trận của Game.
Trong Tank2D vùng chơi là tập hợp của 1 ma trận 2 chiều 13x13 LargeCells, mỗi LargeCell có kích thước 32Pixels x 32Pixels. (Pixel - Đơn vị điểm ảnh trên màn hình)
Mỗi LargeCell lại là tập hợp của ma trận 2x2 MediumCells, mỗi MediumCell có kích thước 16Pixels x 16Pixels.
Mỗi MediumCell là tập hợp của ma trận 2x2 SmallCells, mỗi SmallCell có kích thước 8Pixels x 8Pixels.
Chúng ta có tất cả 7 kiểu giá trị cho SmallCells là : Free,Brick,Steel,River,Cover,Glide,House gọi theo tiếng Việt là ô trống, gạch, thép, sông, ngụy trang, ô trượt và bộ chỉ huy.
Thêm vào phần định nghĩa của tập tin Tank2D.cpp các định nghĩa và liệt kê sau
Mã:#define SMALL 8#define MEDIUM (SMALL*2)#define LARGE (SMALL*4)enum {TC_FREE=0,TC_BRICK,TC_STEEL,TC_RIVER,TC_COVER,TC_GLIDE,TC_HOUSE};
Mã:void Cells_CreateValueDefault(int pCells[52][52]){ int x,y; for(x=0;x<4;x++) for(y=0;y<4;y++) pCells[x][y] = TC_FREE; // Vi tri xuat phat ben trai cua EnemyTank for(x=24;x<28;x++) for(y=0;y<4;y++) pCells[x][y] = TC_FREE; // Vi tri xuat phat chinh giua cua EnemyTank for(x=48;x<52;x++) for(y=0;y<4;y++) pCells[x][y] = TC_FREE; // Vi tri xuat phat ben phai cua EnemyTank for(x=16;x<36;x++) for(y=44;y<52;y++) pCells[x][y] = TC_FREE; // Tao vung trong xung quanh bo chi huy for(x=22;x<30;x++) for(y=46;y<52;y++) pCells[x][y] = TC_BRICK; // Tao vung gach xung quanh bo chi huy for(x=24;x<28;x++) for(y=48;y<52;y++) pCells[x][y] = TC_HOUSE; // Vi tri cua bo chi huy}void Cells_CreateValueRandom(int pCells[52][52]){ int x,y,m,n,iValue; for(x=0;x<52;x+=4) for(y=0;y<52;y+=4) { if(rand()%6==0) iValue = TC_BRICK; else if(rand()%6==0) iValue = TC_STEEL; else if(rand()%10==0) iValue = TC_RIVER; else if(rand()%6==0) iValue = TC_COVER; else if(rand()%6==0) iValue = TC_SLIDE; else iValue = TC_FREE; for(m=x;m<x+4;m++) for(n=y;n<y+4;n++) pCells[m][n] = iValue; } Cells_CreateValueDefault(pCells); // Gan cac gia tri mac dinh cho mot so Cells}
NGÀY 4: Dữ liệu của mỗi vòng chơi.
Chúng ta cần thêm vài khai báo vào phần đầu của tập tin Tank2D.cpp
Mã:#include<shlwapi.h>#pragma comment(lib,"shlwapi.lib")typedef struct{ int iCells[52][52]; // Ma tran gia tri int iStyleTank[30]; // Kieu Tank cua 30 EnemyTank int iStyleCard[5]; // Kieu Card cua 5 BonusCard}DATALEVEL,*PDATALEVEL;
Chúng ta cũng qui định các Tank thứ 6,12,18,24,30 (index là 5,11,17,23,29) khi bị Tank ta bắn trúng sẽ xuất hiện các thẻ tăng cường, trường iStyleCard lưu định danh kiểu từng Card.
Để thống nhất nguồn lưu và nạp dữ liệu trong trò chơi, chúng ta sẽ điều hướng tất cả các tác vụ tập tin vào thư mục Tank2D, thư mục này nằm trong thư mục chứa tập tin thực thi
Tank2D.exe khi đã được biên dịch. Ở đây, để tránh gây khó hiểu cho các bạn mới làm quen với VC++6.0, mình sơ lược lại cách tạo các tập tin trong dự án này.
1.Khởi động Microsoft Visual C++6.0, trình đơn File->New.
2.Trong hộp thoại New chọn Tab Projects.
3.Chọn Win32 Application, nhập tên của dự án là Tank2D, điều hướng nơi cấp phát thư mục, check Create new workspace, check Win32 trong Platforms. Nhấn OK. Nhấn Finish, Nhấn OK.
4.File->New->Files. Chọn C++ Source File, điền tên tập tin là Tank2D, nhấn OK. Chúng ta đã tạo ra tập tin Tank2D.cpp trong dự án.
5.File->New->Files. Chọn Resource Script, điền tên tập tin là Tank2D, nhấn OK. Chúng ta đã tạo ra tập tin Tank2D.rc trong dự án.
Dữ liệu của mỗi vòng chơi sẽ được truy xuất theo các tập tin " Tank2D/Level%i.lev ", %i được thay thế bằng Level + 1 ( Vì các tập tin sẽ bắt đầu từ 1 còn biến lưu lại bắt đầu từ 0).
Sau đây là cài đặt của 2 hàm lưu và nạp dữ liệu vòng chơi.
Mã:BOOL Level_LoadData(PDATALEVEL pDataLevel,int iLevel){ CHAR szFolder[MAX_PATH],szFile[MAX_PATH]; HANDLE hFile; DATALEVEL Data; DWORD dw; BOOL bFlag; GetModuleFileName(NULL,szFolder,MAX_PATH); PathRemoveFileSpec(szFolder); lstrcat(szFolder,"\\Tank2D"); if(!PathIsDirectory(szFolder)) return FALSE; wsprintf(szFile,"%s\\Level%i.lev",szFolder,iLevel+1); hFile = CreateFile(szFile,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if(hFile == INVALID_HANDLE_VALUE) return FALSE; if(GetFileSize(hFile,NULL) != sizeof(DATALEVEL)) { CloseHandle(hFile); return FALSE; } bFlag = ReadFile(hFile,&Data,sizeof(DATALEVEL),&dw,NULL); CloseHandle(hFile); if(!bFlag || dw != sizeof(DATALEVEL)) return FALSE; // Sau nay se them phan kiem tra su hop le cua cac truong trong cau truc Data o day CopyMemory(pDataLevel,&Data,sizeof(DATALEVEL)); return TRUE;}BOOL Level_SaveData(PDATALEVEL pDataLevel,int iLevel){ CHAR szFolder[MAX_PATH],szFile[MAX_PATH]; HANDLE hFile; DWORD dw; BOOL bFlag; GetModuleFileName(NULL,szFolder,MAX_PATH); PathRemoveFileSpec(szFolder); lstrcat(szFolder,"\\Tank2D"); if(!PathIsDirectory(szFolder)) return FALSE; wsprintf(szFile,"%s\\Level%i.lev",szFolder,iLevel+1); hFile = CreateFile(szFile,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); if(hFile == INVALID_HANDLE_VALUE) return FALSE; bFlag = WriteFile(hFile,pDataLevel,sizeof(DATALEVEL),&dw,NULL); CloseHandle(hFile); if(!bFlag || dw != sizeof(DATALEVEL)) { DeleteFile(szFile); return FALSE; } return TRUE;}
Đính chính: Trong hàm Cells_CreateValueRandom() của ngày 3, bạn sửa dòng lệnh
Mã:else if(rand()%6==0) iValue = TC_SLIDE;
Mã:else if(rand()%6==0) iValue = TC_GLIDE;
- - - Nội dung đã được cập nhật ngày 21-02-2014 lúc 02:04 PM - - -
<font color="#0000FF">NGÀY 5: Dữ liệu được thiết lập trước của game Tank2D
Chúng ta thêm vào một kiểu cấu trúc trong phần khai báo của Tank2D.cpp
Mã:typedef struct{ COLORREF crScreen; // Mau chu dao cua man hinh COLORREF crBack; // Mau nen khung choi COLORREF crFrame; // Mau khung choi COLORREF crTitle; // Mau Title COLORREF crText; // Mau text BOOL sndBackSound; // Cho phep choi am thanh nen ? BOOL sndWinSound; // Cho phep choi am thanh thang vong choi ? BOOL sndLostSound; // Cho phep choi am thanh thua vong choi ? BOOL sndBonusSound; // Cho phep choi am thanh thuong diem hoac nhan the tang cuong ? BOOL sndMineSound; // Cho phep choi am thanh min no ? BOOL sndEnemyShoot; // Cho phep choi am thanh EnemyShoot ? BOOL sndEnemySmallBullet; // Cho phep choi am thanh EnemySmallBullet ? BOOL sndEnemyLargeBullet; // Cho phep choi am thanh EnemyLargeBullet ? BOOL sndOurShoot; // Cho phep choi am thanh OurShoot ? BOOL sndOurSmallBullet; // Cho phep choi am thanh OurBullet ? BOOL sndOurLargeBullet; // Cho phep choi am thanh OurLargeBullet ?}DATASETUP,*PDATASETUP;
Tiếp sau đây là các hàm lưu và nạp dữ liệu cho cấu trúc này.( Chú ý đường dẫn của tập tin là " Tank2D/Setup.set ").
Mã:BOOL Setup_LoadData(PDATASETUP pDataSetup){ CHAR szText[MAX_PATH]; HANDLE hFile; DATASETUP Data; DWORD dw; BOOL bFlag; GetModuleFileName(NULL,szText,MAX_PATH); PathRemoveFileSpec(szText); lstrcat(szText,"\\Tank2D"); if(!PathIsDirectory(szText)) return FALSE; lstrcat(szText,"\\Setup.set"); 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(DATASETUP)) { CloseHandle(hFile); return FALSE; } bFlag = ReadFile(hFile,&Data,sizeof(DATASETUP),&dw,NULL); CloseHandle(hFile); if(!bFlag || dw != sizeof(DATASETUP)) return FALSE; CopyMemory(pDataSetup,&Data,sizeof(DATASETUP)); return TRUE;}BOOL Setup_SaveData(PDATASETUP pDataSetup){ 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,"\\Setup.set"); 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,pDataSetup,sizeof(DATASETUP),&dw,NULL); CloseHandle(hFile); if(!bFlag || dw != sizeof(DATASETUP)) { DeleteFile(szText); return FALSE; } return TRUE;}
-
26-02-2014, 10:45 AM #4Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
NGÀY 8: Một số tham khảo về DirectDraw DirectX.
Trong lập trình Windows thông thường, khi muốn vẽ ra cửa sổ, lập trình viên sẽ sử dụng các API GDI để đáp ứng cho thông điệp WM_PAINT như sau:
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps); // ps đã được khai báo là biến cấu trúc PAINTSTRUCT
// Mã lệnh thao tác vẽ ở đây
EndPaint(hwnd,&ps);
return 0;
và trong các thông điệp khác như sau:
hdc = GetDC(hwnd);
// Mã lệnh vẽ ở đây
ReleaseDC(hwnd,hdc);
return 0;
điều này là thỏa đáng cho các chương trình ở dạng tĩnh. Khi cần các tác vụ vẽ liên tục, Windows đôi khi không vẽ gì cho đến khi đến lệnh vẽ cuối nó sẽ tổng hợp và vẽ lại 1 lần, điều này gây ra cảm giác chương trình có lỗi. Để tránh điều này, các lập trình viên sẽ đưa các tác vụ vẽ này vào luồng việc riêng. Tuy nhiên, trong các chương trình Game tương tác và hành động, một số lượng rất lớn các hình ảnh cần phải vẽ sao cho đồng bộ với thời gian, đồng bộ với nhập liệu, điều này phải nhờ đến Directdraw của DirectX.
Các hệ điều hành hiện nay của Windows thường được cài đặt DirectX với các phiên bản lớn hơn 10, DirectDraw đã được bao gồm trong DirectGraphic. Để trung thành với tiêu chí " copy là chạy", mình sử dụng Directdraw nguyên thủy. Bạn có thể làm khác nhưng nhớ rằng, nếu lập trình theo " hàng mới", bạn có thể phải nạp bộ " DirectX SDK", bạn phải thay đổi vài cái gì đó trong
dẫn hướng Tools -> Options -> Directories. Và khi đó, bạn cũng phải để ý tới sự bực tức của người chơi khi Windows báo lỗi hoặc bắt họ phải cài đặt một cái gì đó ( thông thường là các tập tin thư viện liên kết động, từ xa xưa đã có thuật ngữ " địa ngục thư viện liên kết động " mà).
DirectDraw sử dụng các bề mặt để đẩy hình ảnh lên màn hình, phần lớn chúng ta cần làm là vẽ tất cả những gì cần vẽ lên bề mặt đó.
Sau đây là một hàm cần thiết cho các tác vụ DirectX sau này.
Mã:DWORD DirectX_ColorMatch(LPDIRECTDRAWSURFACE pdds,COLORREF rgb){ COLORREF rgbT; HDC hdc; DWORD dw = CLR_INVALID; DDSURFACEDESC ddsd; HRESULT hres; if(rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK) { rgbT = GetPixel(hdc,0,0); SetPixel(hdc,0,0,rgb); pdds->ReleaseDC(hdc); } ddsd.dwSize = sizeof(ddsd); while((hres = pdds->Lock(NULL,&ddsd,0,NULL)) == DDERR_WASSTILLDRAWING); if(hres == DD_OK) { dw = *(DWORD *)ddsd.lpSurface; if(ddsd.ddpfPixelFormat.dwRGBBitCount < 32) dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount)-1; pdds->Unlock(NULL); } if(rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK) { SetPixel(hdc,0,0,rgbT); pdds->ReleaseDC(hdc); } return dw;}
- - - Nội dung đã được cập nhật ngày 26-02-2014 lúc 03:45 PM - - -</font>
<font color="#0000FF">NGÀY 9: Các kiểm tra trước khi cho Game hoạt động.
Chúng ta sẽ kiểm tra và thoát chương trình sớm trong các trường hợp sau:
1. Đã có 1 thể hiện khác của Tank2D.exe.
2. Chương trình được khởi động từ nơi chứa không phải là ổ đĩa cứng của máy và không phải từ USB.
Mã:BOOL App_EnableRun(){ UINT uType; if(FindWindow("Tank2D","Tank2D")) // Đã có 1 thể hiện khác, cho Game thoát ra sớm. return FALSE; uType = GetDriveType(NULL); if(uType!=DRIVE_FIXED) { if(uType == DRIVE_REMOVABLE) MessageBox(NULL,"Chuong trinh co the bi cac trinh Anti_virus khong cho hoat dong. Neu gap truong hop nay, ban hay copy Tank2D.exe vao may, khoi dong lai !","Tank2D",MB_OK|MB_ICONINFORMATION); else if(uType == DRIVE_CDROM) { MessageBox(NULL,"Chuong trinh khong the chay tu CDROM, copy Tank2D.exe vao trong may, khoi dong lai !","Tank2D",MB_OK|MB_ICONEXCLAMATION); return FALSE; } else { MessageBox(NULL,"Ban phai copy Tank2D.exe vao trong may roi khoi dong lai !","Tank2D",MB_OK|MB_ICONEXCLAMATION); return FALSE; } } return TRUE;}
Vì chúng ta sẽ kiểm tra và có thể tạo các tập tin trong thư mục <Tank2D> ở cùng thư mục chương trình. Vì vậy chúng ta phải ngăn ngừa việc ghi vào các nơi cấp phát không thể ghi được
như ổ CD hay các ổ đĩa không xác định kiểu. Đối với USB, chúng ta có thể cho phép ghi nhưng một số chương trình Anti_Virus thì không. Truy xuất ghi ra các nơi lưu trữ ngoại vi sẽ bị xem
là " mã độc" và sẽ bị "Tiên trảm hậu tấu","Giết lầm hơn bỏ sót" ( đương nhiên không phải tất cả là thế). Vì vậy chúng ta chỉ cảnh báo nhưng vẫn cho chương trình tiếp tục.
[IMG]images/smilies/17.gif[/IMG]
-
27-02-2014, 11:41 AM #5Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
NGÀY 10: Tiếp tục các kiểm tra trước.
Ở đây, bạn hãy bổ sung thêm 2 tài nguyên bitmap như sau:
1. id : IDB_BULLN, tên tập tin liên quan : BullN.bmp, 1 khung 8x8 Pixels, vẽ viên đạn tròn màu xám (Bullet Normal).
2. id : IDB_BULLF, tên tập tin liên quan : BullF.bmp, 1 khung 8x8 Pixels, vẽ viên đạn tròn màu lửa (Bullet Fire).
Mã:BOOL App_CheckBMPFile(HINSTANCE hInstance,PCHAR pszFolder,PCHAR pszName,UINT id){ CHAR szText[MAX_PATH]; HDC hdc; HBITMAP hBitmap; BOOL bFlag; wsprintf(szText,"%s\\%s",pszFolder,pszName); if(!PathFileExists(szText)) { hBitmap = LoadBitmap(hInstance,MAKEINTRESOURCE(id)); hdc = GetDC(NULL); bFlag = Bitmap_CreateFile(szText,Bitmap_CreateInfoStruct(hBitmap),hBitmap,hdc); ReleaseDC(NULL,hdc); DeleteObject(hBitmap); if(!bFlag) // Khong co tap tin, cung khong tao ra duoc { wsprintf(szText,"Loi: Khong the tao ra tap tin < %s >, chuong trinh cham dut !",pszName); MessageBox(NULL,szText,"Tank2D",MB_OK|MB_ICONEXCLAMATION); return FALSE; } } return TRUE;}BOOL App_UpdateFiles(HINSTANCE hInstance){ CHAR szFolder[MAX_PATH]; int i; PCHAR pszName[27] = { "Brick.bmp","Steel.bmp","Cover.bmp","River.bmp","Glide.bmp","House.bmp","Card1.bmp","Card2.bmp","Card3.bmp","Card4.bmp", "Card5.bmp","Card6.bmp","Card7.bmp","Card8.bmp","Card9.bmp","Card10.bmp","Card11.bmp","Fire.bmp","Smoke.bmp","Tank1.bmp", "Tank2.bmp","Tank3.bmp","Tank4.bmp","TankL.bmp","TankR.bmp","BullN.bmp","BullF.bmp" }; UINT id[27] = { IDB_BRICK,IDB_STEEL,IDB_COVER,IDB_RIVER,IDB_GLIDE,IDB_HOUSE,IDB_CARD1,IDB_CARD2,IDB_CARD3,IDB_CARD4, IDB_CARD5,IDB_CARD6,IDB_CARD7,IDB_CARD8,IDB_CARD9,IDB_CARD10,IDB_CARD11,IDB_FIRE,IDB_SMOKE,IDB_TANK1, IDB_TANK2,IDB_TANK3,IDB_TANK4,IDB_TANKL,IDB_TANKR,IDB_BULLN,IDB_BULLF }; GetModuleFileName(NULL,szFolder,MAX_PATH); PathRemoveFileSpec(szFolder); lstrcat(szFolder,"\\Tank2D"); if(!PathIsDirectory(szFolder)) // Thu muc la khong co san CreateDirectory(szFolder,NULL); if(!PathIsDirectory(szFolder)) { MessageBox(NULL,"Khong the tao ra thu muc < Tank2D > tai thu muc chuong trinh","Tank2D",MB_OK|MB_ICONEXCLAMATION); return FALSE; } else // Da co thu muc { for(i=0;i<27;i++) if(!App_CheckBMPFile(hInstance,szFolder,pszName[i],id[i])) return FALSE; } return TRUE;}
Tạm nghỉ ở đây thôi, có bạn nào thấy cách mình trình bày là rối rắm không, hãy góp ý để mình sửa lại mã cho tốt hơn. Thân mến!
[IMG]images/smilies/17.gif[/IMG] [IMG]images/smilies/17.gif[/IMG]
-
04-03-2014, 09:12 AM #6Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
NGÀY 11: Tạo các tài nguyên tùy biến, tạo tập tin dữ liệu vòng từ tài nguyên trong chương trình.
Trước tiên các bạn hãy sửa kiểu các trường của cấu trúc DATALEVEL như sau:
Mã:typedef struct{ BYTE iCells[52][52]; // Ma tran gia tri BYTE iStyleTank[30]; // Kieu Tank cua 30 EnemyTank BYTE iStyleCard[5]; // Kieu Card cua 5 BonusCard}DATALEVEL,*PDATALEVEL;
Các bạn cũng sửa 2 hàm liên quan là;
void Cells_CreateValueDefault(int pCells[52][52]) thành void Cells_CreateValueDefault(BYTE pCells[52][52])
void Cells_CreateValueRandom(int pCells[52][52]) thành void Cells_CreateValueRandom(BYTE pCells[52][52])
Chắc chắn cữa sổ "Workspace" hiển thị.
Chọn Tab "ResourceView".
Lặp : Nhấn chuột phải vào "Tank2D resources", chọn "Import ...", điều hướng tới thư mục chứa 35 tập tin ".lev", chọn "level1.lev", nhấn <Import>
Trong hộp thoại "Custom Resource Type", gõ tên kiểu tài nguyên là "LEVEL", nhấn OK. IDE sẽ tạo ra kiểu tài nguyên "LEVEL" và id của tài nguyên này là IDR_LEVEL1.
Lặp lại từ "Lặp" để tạo ra tất cả các id cho tới IDR_LEVEL35. ( Chú thích 1).
Trước khi cho Game hiển thị trên màn hình, chúng ta sẽ kiểm tra và tạo ra ( nếu cần) 35 tập tin từ "Level1.lev" cho tới "Level35.lev" trong thư mục <Tank2D>
Mã:void App_CheckLevelFile(){ CHAR szFolder[MAX_PATH]; CHAR szFile[MAX_PATH]; HANDLE hFile; DWORD dw,dwSize; HRSRC hFind,hLoad; PCHAR pLock; BOOL bFlag; int i; GetModuleFileName(NULL,szFolder,MAX_PATH); PathRemoveFileSpec(szFolder); lstrcat(szFolder,"\\Tank2D"); for(i=0;i<35;i++) { wsprintf(szFile,"%s\\Level%i.lev",szFolder,i+1); if(!PathFileExists(szFile)) { if(INVALID_HANDLE_VALUE!=(hFile=CreateFile(szFile,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL))) { bFlag = TRUE; if(hFind = FindResource(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_LEVEL1+i),"LEVEL")) if(hLoad = (HRSRC)LoadResource(GetModuleHandle(NULL),hFind)) if(pLock = (PCHAR)LockResource(hLoad)) { dwSize = SizeofResource(GetModuleHandle(NULL),hFind); if(!WriteFile(hFile,pLock,dwSize,&dw,NULL) || dwSize != dw) bFlag = FALSE; } CloseHandle(hFile); if(!bFlag) DeleteFile(szFile); } } }}
35 tập tin Level ( Level1.lev -> Level35.lev) do mình tự tạo ra dựa theo nguyên bản của "Battle City". Mỗi tập tin khoảng 3Kb.
Bạn nào biết cách thì xin chỉ cho mình cách gắn kèm 35 tập tin này vào bài viết để cùng tham khảo. Cám ơn !
[IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG][IMG]images/smilies/17.gif[/IMG]
-
05-03-2014, 11:48 AM #7Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
NGÀY 12: Copy các tập tin âm thanh của Windows làm âm thanh của chương trình.
Chúng ta sẽ tạo ra (nếu chưa có) 8 tập tin âm thanh cho Tank2D là :
"BackSound.mid", Âm thanh chơi nền
"Bonus.wav", Thưởng điểm
"TankShoot.wav", Tank ta bắn
"ETankShoot.wav", Tank địch bắn
"BullN.wav", Đạn thường của ta nổ
"BullF.wav", Đạn lửa của ta nổ
"EBullN.wav", Đạn thường của địch nổ
"EBullF.wav", Đạn lửa của địch nổ
Các âm thanh trên sẽ được Copy từ thư mục Media của Windows.
Các âm thanh khác sẽ được người chơi thêm vào khi cần tới.
Mã:void App_CheckSoundFile(){ CHAR szDestFolder[MAX_PATH],szSourFolder[MAX_PATH]; CHAR szDestFile[MAX_PATH],szSourFile[MAX_PATH]; int i; PCHAR pszSour[] = { "onestop.mid", // Back "chimes.wav", // Bonus "start.wav", // TankShoot "start.wav", // ETankShoot "recycle.wav" // Burn "recycle.wav" // Burn "recycle.wav" // Burn "recycle.wav" // Burn }; PCHAR pszDest[] = { "BackSound.mid", "Bonus.wav" "TankShoot.wav", "ETankShoot.wav", "BullN.wav", "BullF.wav", "EBullN.wav", "EBullF.wav" }; GetWindowsDirectory(szSourFolder,MAX_PATH); lstrcat(szSourFolder,"\\Media"); GetModuleFileName(NULL,szDestFolder,MAX_PATH); PathRemoveFileSpec(szDestFolder); lstrcat(szDestFolder,"\\Tank2D"); for(i=0;i<8;i++) { wsprintf(szSourFile,"%s\\%s",szSourFolder,pszSour[i]); wsprintf(szDestFile,"%s\\%s",szDestFolder,pszDest[i]); if(!PathFileExists(szDestFile)) if(CopyFile(szSourFile,szDestFile,TRUE)) SetFileAttributes(szDestFile,FILE_ATTRIBUTE_NORMAL); }}
[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-03-2014 lúc 04:48 PM - - -
Trước khi cho hiển thị cửa sổ, chúng ta cũng cần tạo bảng phím tắt để sử dụng trong Game.
Từ IDE chọn trình đơn Insert -> Resource... -> Insert Resource -> Accelerator -> New. Thay đổi id của bảng phím tắt thành IDR_ACCEL.
Chúng ta tạo các id của từng phím tắt theo danh sách id, key và type như sau:
1. id IDC_ESCAPE, key VK_ESCAPE, type VIRTKEY.
2. id IDC_F1, key VK_F1, type VIRTKEY.
3. id IDC_F2, key VK_F2, type VIRTKEY.
4. id IDC_F3, key VK_F3, type VIRTKEY.
5. id IDC_F4, key VK_F4, type VIRTKEY.
6. id IDC_F5, key VK_F5, type VIRTKEY.
7. id IDC_F6, key VK_F6, type VIRTKEY.
8. id IDC_F7, key VK_F7, type VIRTKEY.
9. id IDC_F8, key VK_F8, type VIRTKEY.
10. id IDC_F9, key VK_F9, type VIRTKEY.
11. id IDC_F10, key VK_F10, type VIRTKEY.
12. id IDC_F11, key VK_F11, type VIRTKEY.
13. id IDC_F12, key VK_F12, type VIRTKEY.
14. id IDC_PAUSE, key VK_PAUSE, type VIRTKEY.
15. id IDC_INSERT, key VK_INSERT, type VIRTKEY.
16. id IDC_DELETE, key VK_DELETE, type VIRTKEY.
17. id IDC_HOME, key VK_HOME, type VIRTKEY.
18. id IDC_END, key VK_END, type VIRTKEY.
19. id IDC_PAGEUP, key VK_PRIOR, type VIRTKEY.
20. id IDC_PAGEDOWN, key VK_NEXT, type VIRTKEY.
21. id IDC_ENTER, key VK_RETURN, type VIRTKEY.
Tất cả là 21 phím đủ dùng cho hiện tại và phát triển sau này.
Ngoài ra trong trò chơi, chúng ta sử sụng thêm một số phím và con chuột để người chơi thao tác khi chương trình ở trạng thái <PLAY>,
các cài đặt này một số sẽ được lập trình với DirectInput, một số khác sẽ xử lý trong các thông điệp Windows.
Phím <Space bar> chỉ định TankL (Tank của ta khởi tạo ở bên trái) khai hỏa.
Các phím mũi tên sẽ thay đổi hướng và tịnh tiến TankL theo thời gian nhấn và giữ các phím này.
Nút chuột trái chỉ định TankR khai hỏa.
Nút chuột phải điều khiển TankR tịnh tiến theo hướng đã định sẵn.
Khi di chuyển chuột, chương trình sẽ tính toán khoảng dời x và y để xác định hướng di chuyển của TankR.
Ngoài ra chúng ta còn tạo Logic xử lý nút chuột giữa được nhấn tương đương như phím <Enter> được nhấn để tạo thuận lợi cho những người " sống chết với chuột".
Thôi, ngày 12 đến đây thôi, mỏi tay rồi.
[IMG]images/smilies/clap_grin.gif[/IMG] [IMG]images/smilies/clap_grin.gif[/IMG] [IMG]images/smilies/clap_grin.gif[/IMG]
-
08-03-2014, 05:26 PM #8Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
Cám ơn chủ topic rất nhiều. Mình mới bắt đầu học C++ nên những bài viết thế này rất bổ ích. Mong chờ những bài viết tiếp theo.
-
09-03-2014, 08:32 AM #9Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
NGÀY 15 : DirectSound và DirectInput
Thêm các khai báo biến toàn cục
Mã:LPDIRECTSOUND g_lpDS; // DirectSoundLPDIRECTINPUT g_lpDI; // DirectInputLPDIRECTINPUTDEVICE g_lpKeyboard; // Thiet bi KeyboardLPDIRECTINPUTDEVICE g_lpMouse; // Thiet bi MouseHANDLE g_hEvent; // Event Mouse
Mã:BOOL DirectX_InitDS(HWND hwnd){ if(DirectSoundCreate(NULL,&g_lpDS,NULL) != DS_OK) return FALSE; if(g_lpDS->SetCooperativeLevel(hwnd,DSSCL_NORMAL) != DS_OK) return FALSE; return TRUE;}void DirectX_DeleteDS(){ if(g_lpDS) { g_lpDS->Release(); g_lpDS = NULL; }}
Mã:BOOL DirectX_InitDI(HINSTANCE hInstance,HWND hwnd){ DIPROPDWORD dipdw = {sizeof(DIPROPDWORD),sizeof(DIPROPHEADER),0,DIPH_DEVICE,16}; if(DirectInputCreate(hInstance,0x0300,&g_lpDI,NULL) != DI_OK) return FALSE; if(g_lpDI->CreateDevice(GUID_SysKeyboard,&g_lpKeyboard,NULL) != DI_OK) return FALSE; if(g_lpDI->CreateDevice(GUID_SysMouse,&g_lpMouse,NULL) != DI_OK) return FALSE; if(g_lpKeyboard->SetDataFormat(&c_dfDIKeyboard) != DI_OK) return FALSE; if(g_lpMouse->SetDataFormat(&c_dfDIMouse) != DI_OK) return FALSE; if(g_lpKeyboard->SetCooperativeLevel(hwnd,DISCL_NONEXCLUSIVE|DISCL_FOREGROUND) != DI_OK) return FALSE; if(g_lpMouse->SetCooperativeLevel(hwnd,DISCL_NONEXCLUSIVE|DISCL_FOREGROUND) != DI_OK) return FALSE; if(g_lpKeyboard->Acquire() != 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; 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;} g_lpDI->Release(); g_lpDI = NULL; }}
chơi Game ( trên chợ vi tính Tôn Thất Tùng - Bùi Thị Xuân có giá dao động khoảng 100K ). Về mặt lập trình, Windows cũng hỗ trợ cho thiết bị này rất nhiệt tình và DirectInput cũng vậy,
tuy nhiên hiện tại mình chưa nghiên cứu kỹ cho khía cạnh này. Mình sẽ lập trình cho Joystick trong các phiên bản nâng cấp của Tank2D.
Cám ơn sự quan tâm của các bạn !
[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 09-03-2014 lúc 01:32 PM - - -</font>
<font color="#0000FF">NGÀY 16 : Nhận dữ liệu và trạng thái của Chuột và Bàn phím
Ở đây mình tạm phân chia ra 2 kiểu nhận dữ liệu là nhận Thụ động và Chủ động.
Nhận Thụ động là nhận khi có một sự kiện nào đó được báo vào hàm xử lý thông điệp của chương trình ( WindowProc).
Ví dụ : Người chơi nhấn phím <A>, sau nhiều thông điệp khác nhau sẽ có 1 thông điệp tới chương trình là WM_CHAR với wParam là mã Ascii của kí tự A, mã kí tự A được nhận thụ động.
Nhận Chủ động là mã trong chương trình tự tìm kiếm dữ liệu nhập mà nó cần thiết.
Ví dụ : Truy cập vào bộ đệm bàn phím của Windows, truy cập nơi lưu trữ trạng thái của chuột, dữ liệu lấy về là Chủ động.
Trở lại với trò chơi, chúng ta nhận thấy một vài điều phải lưu ý như sau :
Khi TankL khai hỏa với phím <Spacebar> được nhấn, từng viên đạn sẽ lần lượt được bắn ra nếu thuộc tính liên thanh còn hiệu lực. Nếu chúng ta nhận dữ liệu theo kiểu Thụ động
thì chỉ bắn được duy nhất 1 viên đạn, người chơi phải nhả phím ra và nhấn lại 1 lần nữa thì viên đạn kế tiếp mới được bắn, đây không phải cách xử lý mà ta muốn. Vì vậy chúng ta nhận
dữ liệu phím <Spacebar> theo cách Chủ động.
Với các phím Arrow, khi nhấn TankL sẽ đổi hướng => Nhận Thụ động. Nhưng khi nhấn và giữ thì TankL sẽ tiến tới theo hướng có sẵn => Phải nhận Chủ động, như vậy là với các phím mũi tên chúng ta phải dùng cả 2 cách để nhận giữ liệu.
Tương tự như phím <Spacebar>, Nút chuột trái sẽ nhận dữ liệu Chủ động.
Hướng di chuyển của TankR là nhận Chủ động.
Di chuyển tiến lên của TankR cũng là nhận Chủ động.
Chúng ta có thể cố gắng lập trình để nhận dữ liệu nhập hoàn toàn trong các thông điệp, ví dụ : Chúng ta có thể biết một phím có đang nhấn hay không bằng cách đặt biến theo dõi,
và trong khi xử lý WM_KEYDOWN, WM_KEYUP cho phù hợp nhưng mã sẽ rắc rối hơn và đôi khi là không kiểm soát được. DirectInput là hỗ trợ tuyệt vời cho nhận dữ liệu Chủ động từ
Mouse và Keyboard.
Thêm một kiểu liệt kê các hướng trong trò chơi là NULL, sang trái, lên trên, sang phải, xuống dưới
Mã:enum {FM_NULL=0,FM_DOWN,FM_LEFT,FM_UP,FM_RIGHT};
Mã:typedef struct{ int iRotateFrend; BOOL bLeftPress; BOOL bRightPress;}INPUTMOUSE,*PINPUTMOUSE;
Mã:BOOL DirectX_GetInputMouse(PINPUTMOUSE pInput){ HRESULT hr; DIDEVICEOBJECTDATA od[10]; DWORD dw,dwElements = 10; // Nhan 10 phan tu int dwX=0,dwY=0; int dxABS,dyABS; BOOL bMoved = FALSE; ZeroMemory(pInput,sizeof(INPUTMOUSE)); hr = g_lpMouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),od,&dwElements,0); if(hr != DI_OK) { if(hr == DIERR_INPUTLOST) g_lpMouse->Acquire(); return FALSE; } for(dw=0;dw<dwElements;dw++) { switch(od[dw].dwOfs) { case DIMOFS_X: dwX = od[dw].dwData; bMoved = TRUE; break; case DIMOFS_Y: dwY = od[dw].dwData; bMoved = TRUE; break; case DIMOFS_BUTTON0: pInput->bLeftPress = (od[dw].dwData & 0x80) ? TRUE:FALSE; break; case DIMOFS_BUTTON1: pInput->bRightPress = (od[dw].dwData & 0x80) ? TRUE:FALSE; break; } } if(bMoved) { dxABS = abs(dwX); dyABS = abs(dwY); if(dxABS>2 || dyABS>2) { if(dxABS > dyABS) // quay ngang pInput->iRotateFrend = (dwX<0) ? FM_LEFT:FM_RIGHT; else if(dxABS < dyABS) // quay doc pInput->iRotateFrend = (dwY<0) ? FM_UP:FM_DOWN; else // dxABS == dyABS { if(dwX<0 && dwY<0) pInput->iRotateFrend = (rand()%2) ? FM_LEFT:FM_UP; else if(dwX<0 && dwY>0) pInput->iRotateFrend = (rand()%2) ? FM_LEFT:FM_DOWN; else if(dwX>0 && dwY<0) pInput->iRotateFrend = (rand()%2) ? FM_UP:FM_RIGHT; else pInput->iRotateFrend = (rand()%2) ? FM_DOWN:FM_RIGHT; } } } return TRUE;}
Trước tiên ít nhất phải có độ dời x hoặc độ dời y phải lớn hơn 2 - điều này để tránh cho chương trình quá nhạy cảm với di chuyển chuột.
Nếu độ dời x lớn hơn độ dời y, ta sẽ cho yêu cầu đổi hướng của TankR sang trái nếu vector là âm và ngược lại.
Nếu độ dời x nhỏ hơn độ dời y, ta sẽ cho yêu cầu đổi hướng của TankR lên trên nếu vector là âm và ngược lại.
Trong trường hợp 2 độ dời là bằng nhau ( gọi nôm na là trên đường phân giác của 2 trục di chuyển ) ta lấy hướng yêu cầu là ngẫu nhiên trên 2 hương này.
Nên nhớ, Ở đây chúng ta lấy về 1 cấu trúc dữ liệu mà được yêu cầu cho TankR, còn có thể cho TankR thực hiện theo yêu cầu này hay không còn
tùy thuộc vào các điều kiện khác ( Giả sử như đang kẹt đường thì Tank không thể tiến lên được ).
Thôi, hôm nay chỉ tới đây thôi, thân ái !
[IMG]images/smilies/17.gif[/IMG] [IMG]images/smilies/17.gif[/IMG] [IMG]images/smilies/17.gif[/IMG]
-
12-03-2014, 09:24 AM #10Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
NGÀY 17 : Nhận dữ liệu từ bàn phím và chuột tiếp theo.
Thêm một cấu trúc để nhận dữ liệu của Keyboard
Mã:typedef struct{ BOOL bSpace; // Spacebar dang nhan hay tha ? TRUE:nhan FALSE:tha BOOL bLeft; // Left Arrow BOOL bUp; // Up Arrow BOOL bRight; BOOL bDown;}INPUTKEYBOARD,*PINPUTKEYBOARD;
Mã:BOOL DirectX_GetInputKeyboard(PINPUTKEYBOARD pInput){ HRESULT hr; CHAR szBuf[256]; ZeroMemory(pInput,sizeof(INPUTKEYBOARD)); hr = g_lpKeyboard->GetDeviceState(sizeof(szBuf),&szBuf); if(hr != DI_OK) { if(hr == DIERR_INPUTLOST) g_lpKeyboard->Acquire(); return FALSE; } if(szBuf[DIK_SPACE] & 0x80) pInput->bSpace ^= 1; if(szBuf[DIK_LEFT] & 0x80) pInput->bLeft ^= 1; if(szBuf[DIK_UP] & 0x80) pInput->bUp ^= 1; if(szBuf[DIK_RIGHT] & 0x80) pInput->bRight ^= 1; if(szBuf[DIK_DOWN] & 0x80) pInput->bDown ^= 1; return TRUE;}
Khác chăng là ở đây ta nhận yêu cầu tịnh tiến TankL 1 cách tường minh theo 4 phím mũi tên.
Ở cấu trúc INPUTKEYBOARD, lúc đầu mình định khai báo là một tập hợp cờ Bit đặt trong biến DWORD dwFlag và dùng các toán hạng Bitwise để tính toán
nhưng cảm thấy sẽ khó hiểu với các bạn mới học C++ nên thôi. Các toán hạng ^= là để chuyển hệ bật/tắt các biến boolean.
pInput->bSpace ^= 1; tương đương với pInput->bSpace = pInput->bSpace ? FALSE:TRUE;
- - - Nội dung đã được cập nhật ngày 11-03-2014 lúc 12:12 PM - - -</font>
NGÀY 18 : Vẽ các Cells
Mã:BOOL DirectX_DrawBricks(BYTE pCells[52][52],int xFrame,int yFrame){ HRESULT hr; int x,y; for(x=0;x<52;x++) for(y=0;y<52;y++) if(pCells[x][y] == TC_BRICK) { hr = g_lpBack->BltFast(xFrame+x*SMALL,yFrame+y*SMALL,g_lpBrick,NULL,DDBLTFAST_SRCCOLORKEY); if(hr != DD_OK && hr != DDERR_WASSTILLDRAWING) // Khong phai OK va khong phai dang con ve { if(hr != DDERR_SURFACELOST) // Cung khong phai be mat da mat => các lỗi khác return FALSE; if(!DirectX_RestoreSurfaceAll()) // Phuc hoi sai return FALSE; } } return TRUE;}
Hàm duyệt từng SmallCell, nếu Cell có định danh là Brick => Truyền khối Bít từ g_lpBrick tới g_lpBack.
Mã:BOOL DirectX_DrawSteels(BYTE pCells[52][52],int xFrame,int yFrame){ HRESULT hr; int x,y; for(x=0;x<52;x+=2) for(y=0;y<52;y+=2) if(pCells[x][y] == TC_STEEL) { hr = g_lpBack->BltFast(xFrame+x*SMALL,yFrame+y*SMALL,g_lpSteel,NULL,DDBLTFAST_SRCCOLORKEY); if(hr != DD_OK && hr != DDERR_WASSTILLDRAWING) { if(hr != DDERR_SURFACELOST) return FALSE; if(!DirectX_RestoreSurfaceAll()) return FALSE; } } return TRUE;}
Mã:BOOL DirectX_DrawRivers(BYTE pCells[52][52],int xFrame,int yFrame){ HRESULT hr; int x,y; for(x=0;x<52;x+=4) for(y=0;y<52;y+=4) if(pCells[x][y] == TC_RIVER) { hr = g_lpBack->BltFast(xFrame+x*SMALL,yFrame+y*SMALL,g_lpRiver,NULL,DDBLTFAST_SRCCOLORKEY); if(hr != DD_OK && hr != DDERR_WASSTILLDRAWING) { if(hr != DDERR_SURFACELOST) return FALSE; if(!DirectX_RestoreSurfaceAll()) return FALSE; } } return TRUE;}BOOL DirectX_DrawCovers(BYTE pCells[52][52],int xFrame,int yFrame){ HRESULT hr; int x,y; for(x=0;x<52;x+=4) for(y=0;y<52;y+=4) if(pCells[x][y] == TC_COVER) { hr = g_lpBack->BltFast(xFrame+x*SMALL,yFrame+y*SMALL,g_lpCover,NULL,DDBLTFAST_SRCCOLORKEY); if(hr != DD_OK && hr != DDERR_WASSTILLDRAWING) { if(hr != DDERR_SURFACELOST) return FALSE; if(!DirectX_RestoreSurfaceAll()) return FALSE; } } return TRUE;}BOOL DirectX_DrawGlides(BYTE pCells[52][52],int xFrame,int yFrame){ HRESULT hr; int x,y; for(x=0;x<52;x+=4) for(y=0;y<52;y+=4) if(pCells[x][y] == TC_GLIDE) { hr = g_lpBack->BltFast(xFrame+x*SMALL,yFrame+y*SMALL,g_lpGlide,NULL,DDBLTFAST_SRCCOLORKEY); if(hr != DD_OK && hr != DDERR_WASSTILLDRAWING) { if(hr != DDERR_SURFACELOST) return FALSE; if(!DirectX_RestoreSurfaceAll()) return FALSE; } } return TRUE;}
Mã:BOOL DirectX_DrawHouse(BYTE pCells[52][52],int xFrame,int yFrame){ HRESULT hr; if(pCells[24][48] == TC_HOUSE) { hr = g_lpBack->BltFast(xFrame+24*SMALL,yFrame+48*SMALL,g_lpHouse,NULL,DDBLTFAST_SRCCOLORKEY); if(hr != DD_OK && hr != DDERR_WASSTILLDRAWING) { if(hr != DDERR_SURFACELOST) return FALSE; if(!DirectX_RestoreSurfaceAll()) return FALSE; } } return TRUE;}
Bạn nhớ rằng tất cả các tác vụ vẽ của chúng ta là ở trên g_lpBack ( không phải ở trên bề mặt chủ Master) và
khi truyền lên màn hình thì lại truyền từ g_lpMaster ( không phải bề mặt Back) thông qua phương thức Flip sẽ nói tới sau này.
Ngày hôm nay xin dừng ở đây, cám ơn!
[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 11-03-2014 lúc 05:45 PM - - -
NGÀY 19 : Vẽ các Tank
Để vẽ các Tank, chúng ta cần có tọa độ, hướng di chuyển, khung hiện hành và một số thuộc tính khác.
Thêm vào định nghĩa 2 cấu trúc mới cho TankE và Tank của người chơi.
Mã:typedef struct{ BOOL bCard; // Tank nay bi ban co tao the ? BOOL bBullF; // Tank nay ban dan lua ? int iFrame; // Khung hien hanh trong bitmap int iFrend; // Huong di chuyen hien hanh int iPower; // Suc manh cua Tank tu 1->5 int iRequest; // 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 iSmart; // Muc do tinh quai cua Tank tu 0->2 int iSpeed; // Toc do di chuyen tu 1->3 Pixels trong 1 lan int iStyle; // Kieu Tank tu 0->49 int x,y; // Toa do LeftTop cua TankE tinh tu goc tren trai trong khung choi}ENEMYTANK,*PENEMYTANK;typedef struct{ BOOL bReady; // Tank da san sang ? BOOL bRiver; // Tank co the vuot song ? BOOL bSafety; // Tank an toan trong che do duoc bao ve ? BOOL bBullF; // Tank nay ban dan lua ? BOOL bRequestMove; // Yeu cau tien toi ? BOOL bRequestShoot; // Yeu cau ban ? int cBulletJoin; // So dan noi tiep nhau duoc phep ban tu 1->3 int cLife; // So lan song cua Tank int iFrame; // Khung hien hanh trong bitmap int iFrend; // Huong di chuyen hien hanh 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 PVOID pBull[3]; // Con tro toi cac vien dan int x,y; // Toa do LeftTop cua TankE tinh tu goc tren trai trong khung choi}TANK,*PTANK;
Với Tank ta, khi iPower là 0, Tank khởi tạo lại với trường cLife bị trừ 1, nếu trường cLife là 0, Tank ta bị loại hoàn toàn.
Vì chúng ta phải xác định số lượng đạn của Tank người chơi hiển thị trên màn hình cho yêu cầu bắn liên thanh nên biến pBull sẽ lưu 3 con trỏ của 3 viên đạn nếu có.
Thêm vào các biến toàn cục mới
Mã:CPtrArray g_arTankE(FALSE); // Array TankETANK g_TankL; // TankLTANK g_TankR; // TankR
Mã:BOOL DirectX_DrawTankE(CPtrArray * arTankE,int xFrame,int yFrame){ int i,cCount; PENEMYTANK pTankE; RECT r; HRESULT hr; cCount = arTankE->GetSize(); for(i=0;i<cCount;i++) if(pTankE = (PENEMYTANK)arTankE->GetAt(i)) { SetRect(&r, pTankE->iFrame*LARGE, (pTankE->iFrend-1)*LARGE, (pTankE->iFrame+1)*LARGE, pTankE->iFrend*LARGE); hr = g_lpBack->BltFast(xFrame+pTankE->x,yFrame+pTankE->y,g_lpTankE[pTankE->iStyle],&r,DDBLTFAST_SRCCOLORKEY); if(hr != DD_OK && hr != DDERR_WASSTILLDRAWING) { if(hr != DDERR_SURFACELOST) return FALSE; if(!DirectX_RestoreSurfaceAll()) return FALSE; } } return TRUE;}
4 Khung hàng trên cùng được vẽ cho Tank di chuyển xuống dưới FM_DOWN.
4 Khung hàng thứ hai vẽ cho Tank di chuyển sang trái FM_LEFT.
4 Khung hàng thứ ba vẽ cho Tank di chuyển lên trên FM_UP.
4 Khung hàng dưới cùng vẽ cho Tank di chuyển sang trái FM_RIGHT.
Câu lệnh SetRect xác định chính xác vùng hình ảnh của Bitmap cần hiển thị theo số khung và hướng.
g_lpTankE[pTankE->iStyle] xác định Bitmap nào được vẽ.
Tiếp theo là các hàm vẽ TankL và TankR
Mã:BOOL DirectX_DrawTankL(int xFrame,int yFrame){ RECT r; HRESULT hr; if(g_TankL.bReady) { SetRect(&r, g_TankL.iFrame*LARGE, (g_TankL.iFrend-1)*LARGE, (g_TankL.iFrame+1)*LARGE, g_TankL.iFrend*LARGE); hr = g_lpBack->BltFast(xFrame+g_TankL.x,yFrame+g_TankL.y,g_lpTankL,&r,DDBLTFAST_SRCCOLORKEY); if(hr != DD_OK && hr != DDERR_WASSTILLDRAWING) { if(hr != DDERR_SURFACELOST) return FALSE; if(!DirectX_RestoreSurfaceAll()) return FALSE; } } return TRUE;}BOOL DirectX_DrawTankR(int xFrame,int yFrame){ RECT r; HRESULT hr; if(g_TankR.bReady) { SetRect(&r, g_TankR.iFrame*LARGE, (g_TankR.iFrend-1)*LARGE, (g_TankR.iFrame+1)*LARGE, g_TankR.iFrend*LARGE); hr = g_lpBack->BltFast(xFrame+g_TankR.x,yFrame+g_TankR.y,g_lpTankR,&r,DDBLTFAST_SRCCOLORKEY); if(hr != DD_OK && hr != DDERR_WASSTILLDRAWING) { if(hr != DDERR_SURFACELOST) return FALSE; if(!DirectX_RestoreSurfaceAll()) return FALSE; } } return TRUE;}
Chúng ta sẽ vẽ các thuộc tính cần thiết bên dưới nơi hiển thị lúc đầu của Tank.
- - - Nội dung đã được cập nhật ngày 12-03-2014 lúc 02:24 PM - - -
<font color="#0000FF">NGÀY 20 : Vẽ Bullet, Card, Fire, Smoke.
Thêm vào khai báo định nghĩa các cấu trúc sau
Mã:typedef struct{ BOOL bBullF; // La dan lua int iFrend; // Huong di chuyen hien hanh int iSpeed; // Toc do di chuyen tu 5->10 Pixels trong 1 lan int x,y; // Toa do LeftTop tinh theo khung choi}BULLETE,*PBULLETE;typedef struct{ BOOL bBullF; // La dan lua int iFrend; // Huong di chuyen hien hanh int iSpeed; // Toc do di chuyen tu 5->10 Pixels trong 1 lan PVOID pTank; // TankL hay TankR ban ra int x,y; // Toa do LeftTop tinh theo khung choi}BULLET,*PBULLET;typedef struct{ int cDelay; // So lan lam tre truoc khi huy int iStyle; // Kieu card tu 0->10 int x,y; // Toa do LeftTop tinh theo khung choi}CARD,*PCARD;typedef struct{ int iFrame; // Khung trong bitmap int x,y; // Toa do LeftTop tinh theo khung choi }FIRE,*PFIRE;typedef struct{ int cDelay; // So lan lam tre de ve khung khac int iFrame; // Khung trong bitmap int x,y; // Toa do LeftTop tinh theo khung choi}SMOKE,*PSMOKE;
Vì Tank của ta có thể bắn liên tục với số đạn là trường cBulletJoin trong cấu trúc TANK nên ta phải biết được số đạn mà Tank đã bắn mà
vẫn còn hiện diện trên màn hình, do đó cấu trúc BULLET (cấu trúc đạn của ta) cần lưu con trỏ tới Tank cha của nó để thông báo ngược
trở lại khi nó nổ -> Tank cha sẽ đặt lại NULL cho con trỏ của viên đạn mà nó bắn.
Trường cDelay của CARD chỉ định số lần hiển thị sẽ bị trừ dần, nếu bằng 0 tức là hết thời gian, Card sẽ bị hủy.
Trường cDelay của SMOKE chỉ là làm chậm lại hình ảnh đám khói mà thôi.
Tiếp theo khai báo một số biến toàn cục theo dõi đạn, card, fire, smoke.
Mã:CPtrArray g_arBullE(FALSE); // BullECPtrArray g_arBullL(FALSE); // BullLCPtrArray g_arBullR(FALSE); // BullRCPtrArray g_arCard(FALSE); // CardCPtrArray g_arSmoke(FALSE); // SmokeCPtrArray g_arFire(FALSE); // Fire
Sau đây là các hàm vẽ các đối tượng trên
Mã:BOOL DirectX_DrawBulletE(CPtrArray * arBulletE,int xFrame,int yFrame){ int i,cCount; PBULLETE pBulletE; HRESULT hr; cCount = arBulletE->GetSize(); for(i=0;i<cCount;i++) if(pBulletE = (PBULLETE)arBulletE->GetAt(i)) { hr = g_lpBack->BltFast(xFrame+pBulletE->x,yFrame+pBulletE->y,pBulletE->bBullF ? g_lpBullF : g_lpBullN,NULL,DDBLTFAST_SRCCOLORKEY); if(hr != DD_OK && hr != DDERR_WASSTILLDRAWING) { if(hr != DDERR_SURFACELOST) return FALSE; if(!DirectX_RestoreSurfaceAll()) return FALSE; } } return TRUE;}BOOL DirectX_DrawBulletL(CPtrArray * arBulletL,int xFrame,int yFrame){ int i,cCount; PBULLET pBulletL; HRESULT hr; cCount = arBulletL->GetSize(); for(i=0;i<cCount;i++) if(pBulletL = (PBULLET)arBulletL->GetAt(i)) { hr = g_lpBack->BltFast(xFrame+pBulletL->x,yFrame+pBulletL->y,pBulletL->bBullF ? g_lpBullF : g_lpBullN,NULL,DDBLTFAST_SRCCOLORKEY); if(hr != DD_OK && hr != DDERR_WASSTILLDRAWING) { if(hr != DDERR_SURFACELOST) return FALSE; if(!DirectX_RestoreSurfaceAll()) return FALSE; } } return TRUE;}BOOL DirectX_DrawBulletR(CPtrArray * arBulletR,int xFrame,int yFrame){ int i,cCount; PBULLET pBulletR; HRESULT hr; cCount = arBulletR->GetSize(); for(i=0;i<cCount;i++) if(pBulletR = (PBULLET)arBulletR->GetAt(i)) { hr = g_lpBack->BltFast(xFrame+pBulletR->x,yFrame+pBulletR->y,pBulletR->bBullF ? g_lpBullF : g_lpBullN,NULL,DDBLTFAST_SRCCOLORKEY); if(hr != DD_OK && hr != DDERR_WASSTILLDRAWING) { if(hr != DDERR_SURFACELOST) return FALSE; if(!DirectX_RestoreSurfaceAll()) return FALSE; } } return TRUE;}BOOL DirectX_DrawCards(CPtrArray * arCard,int xFrame,int yFrame){ int i,cCount; PCARD pCard; HRESULT hr; cCount = arCard->GetSize(); for(i=0;i<cCount;i++) if(pCard = (PCARD)arCard->GetAt(i)) { hr = g_lpBack->BltFast(xFrame+pCard->x,yFrame+pCard->y,g_lpCard[pCard->iStyle],NULL,DDBLTFAST_SRCCOLORKEY); if(hr != DD_OK && hr != DDERR_WASSTILLDRAWING) { if(hr != DDERR_SURFACELOST) return FALSE; if(!DirectX_RestoreSurfaceAll()) return FALSE; } } return TRUE;}BOOL DirectX_DrawSmoke(CPtrArray * arSmoke,int xFrame,int yFrame){ int i,cCount; PSMOKE pSmoke; HRESULT hr; RECT r; cCount = arSmoke->GetSize(); for(i=0;i<cCount;i++) if(pSmoke = (PSMOKE)arSmoke->GetAt(i)) { SetRect(&r,pSmoke->iFrame*88,0,(pSmoke->iFrame+1)*88,96); hr = g_lpBack->BltFast(xFrame+pSmoke->x,yFrame+pSmoke->y,g_lpSmoke,&r,DDBLTFAST_SRCCOLORKEY); if(hr != DD_OK && hr != DDERR_WASSTILLDRAWING) { if(hr != DDERR_SURFACELOST) return FALSE; if(!DirectX_RestoreSurfaceAll()) return FALSE; } } return TRUE;}BOOL DirectX_DrawFire(CPtrArray * arFire,int xFrame,int yFrame){ int i,cCount; PFIRE pFire; HRESULT hr; RECT r; cCount = arFire->GetSize(); for(i=0;i<cCount;i++) if(pFire = (PFIRE)arFire->GetAt(i)) { SetRect(&r,pFire->iFrame*40,0,(pFire->iFrame+1)*40,40); hr = g_lpBack->BltFast(xFrame+pFire->x,yFrame+pFire->y,g_lpFire,&r,DDBLTFAST_SRCCOLORKEY); if(hr != DD_OK && hr != DDERR_WASSTILLDRAWING) { if(hr != DDERR_SURFACELOST) return FALSE; if(!DirectX_RestoreSurfaceAll()) return FALSE; } } return TRUE;}
Công việc chủ yếu là duyệt qua tất cả các phần tử của mảng, tính toán tọa độ đích, rect trong Bitmap, xác định bề mặt rồi truyền khối Bit tới g_lpBack.
Ngày hôm nay đã hơi nhiều, mỏi tay rồi, nghỉ thôi.
Tạm biệt.
[IMG]images/smilies/17.gif[/IMG] [IMG]images/smilies/17.gif[/IMG] [IMG]images/smilies/17.gif[/IMG]
Pallet nhựa Long An đã trở thành một trong những lựa chọn phổ biến cho nhu cầu vận chuyển và lưu trữ hàng hóa trong nhiều ngành công nghiệp. Với đặc tính nhẹ nhàng, chắc chắn và dễ vận chuyển, các...
Thanh lý pallet nhựa Long An giá rẻ