-
24-09-2015, 07:11 PM #1Junior Member
- Ngày tham gia
- Sep 2015
- Đang ở
- Số 60 Thái Hà, Đống Đa, Hà Nội
- Bài viết
- 0
[Game Advanced Tetris và mã nguồn] - Những vấn đề xoay quanh CFW, API, MFC, CLR
Khi bắt đầu đề tài này mình cũng mất đôi ba ngày tự trả lời cho các câu hỏi :
_ Có nên thực hiện không khi trên DĐ cũng đã có các bạn khác thực hiện rồi dù bằng ngôn ngữ khác.
_ Có phải vì các câu hỏi của các bạn khác mà vội vàng đưa ra đề tài chẳng có gì là mới mẻ.
_ Nếu thực hiện, có phải là mình xem thường khả năng của các bạn khác.
_ Cuối cùng, có thực sự giúp ích gì cho các bạn khác không.
Sau gần một tuần đắn đo, mình quyết định sẽ khởi động dự án Advanced Tetris vì các ý sau :
_ Thực tập lại cách viết mã theo tinh thần văn ôn võ luyện.
_ Không trả lời trực tiếp các thắc mắc, mà để các bạn đã có câu hỏi trước đó tự tham khảo và áp dụng cho bài toán của riêng mình.
_ Với các bạn đã đi trước, luôn mong muốn các góp ý trên tinh thần xây dựng. Nguồn động lực chính để mình viết và học hỏi là những kỹ thuật mới, những tư duy logic về thuật toán và về cấu trúc dữ liệu - Đây mới là cái đáng để quan tâm nhất. Một chương trình thì chỉ là một chương trình, ai viết cũng được, nhưng để bắt kịp những ý tưởng tiến bộ, thì một ngày đường ta sẽ học được một sàng khôn. Mong chờ những ý kiến xây dựng của các bạn.
_ Bài viết hay dự án này không hề là khuôn mẫu, nó chỉ là tập hợp những kỹ thuật mình đã làm qua vì mục đích cơm áo gạo tiền, nó bừa bộn; nó lộn xộn; thậm chí nó có thể là một mớ hỗn độn những khai báo; những lớp; những hàm không đâu vào đâu. Mình sẽ cố gắng viết sao cho dễ hiểu nếu được, viết sao cho các bạn ở mức sơ khởi cũng có thể hiểu và có thể xây dựng các ứng dụng của riêng mình.
Những thay đổi giữa Advanced Tetris so với Classic Tetris:
- Cho phép người chơi chuyển bật cách chơi : Cổ điển - Cải tiến.Trong cách chơi cổ điển thì chỉ có khối gạch 4 viên gạch không có gì khác mà bạn đã từng chơi. Dùng các khối gạch có từ 1 đến 5 viên gạch trong cách chơi cải tiến.Trong cải tiến khối gạch chỉ có 1 viên gạch duy nhất sẽ có thêm chức năng cứu nguy - có khả năng di chuyển xuyên qua các viên gạch khác và điền vào lỗ trống.
Bên dưới là phác thảo khung chơi và các kích thước cần để ý.
View more random threads:
- Kiểm tra số nguyên tố bằng cách tạo nhiều luồng(Multi Thread)
- Ogre, Lập trình game với Ogre graphic engine
- Hướng Dẫn Cách Sử Dụng WTL wizards trong VS 2008
- Using __cpuid to get CPU information!!!
- Cửa Hàng Cài Phần Mềm Cad Nhanh Chóng Tại Nhà Quận 6
- Image Scale
- Một số kĩ thuật cơ bản với Irrlicht
- Một số hàm về Message
- Sử dụng SEH để bắt lỗi hệ thống
- Hotgirl Trâm Anh lộ clip nóng mới nhất
-
27-09-2015, 07:52 PM #2Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
Cấu tạo của các khối gạch
Với số viên gạch trong khối gạch là từ 1 - 5, chúng ta sẽ có tất cả 28 kiểu khối gạch, trong mỗi kiểu sẽ có 1 hoặc 2 hoặc 4 bề mặt thể hiện.
Thường thì chúng ta nghĩ ngay tới kiểu đặt một biến mảng tọa độ ô cho 1 khối gạch. Ví dụ như khối gạch chữ T có 4 ô có thể đặt như :
POINT ptCellT[4] = { {x0,y0}, {x1,y1}, {x2,y2}, {x3,y3} };
int iIndexRotate = 1;
COLORREF crColor = RGB( rand()&255, rand()&255, rand()&255 );
Cách đặt biến mảng như vậy không có gì sai cả, tuy nhiên sau này sẽ rất khó khăn khi đi vào tính toán, chúng ta sẽ quay lại ý này khi vào thực tế.
Cách mình dùng ở đây là tạo mặt nạ cho tất cả các khối gạch và các mặt nạ xoay có thể có trong trò chơi.
Các mặt nạ đều có cùng kích thước ngang dọc đều là một hằng, hình 2 phía bên dưới là mô tả cho 2 kiểu gạch
Do chức năng Upload đang trục trặc nên chưa thể đưa mã nguồn lên, tạm thời mình phân tích dần dần, mã bằng chữ nên chắc chẳng thú vị gì nhỉ.
-
29-09-2015, 08:02 AM #3Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
Tạo khung cho ứng dụng
Chắc các bạn đã từng chơi qua game dò mìn của Windows, có thủ thuật nhỏ mà mình muốn làm theo, đó là thay đổi kích thước cửa sổ bất kỳ khi nào người chơi thay đổi ma trận chơi.
Tất cả các dự án mình đều viết trên VS2013, các bạn viết trên IDE khác thì có thể gặp sai khác cấu hình, nếu có thì các bạn nêu lên chúng ta cùng xem.
Tạo khung cho các bạn chỉ học C:
1. Khởi động VS2013.
2. File -> New -> Project...
3. Chọn Visual C++, chọn Empty Project
4. Dặt tên cho dự án và nơi lưu trữ. Nhấn OK.
5. Chọn tab Solution Explorer
6. Nhấn chuột phải vào tên dự án -> Add -> New Item...
7. Chọn Header File (.h)
8. Nếu cần thì thay đổi tên tập tin .h xong rồi nhấn Add. IDE tạo ra tập tin .h và hiển thị để sẵn sàng soạn thảo.
Làm lại từ bước 6 và trong bước 7 chọn C++ File (.cpp), đổi tên tập tin .cpp nếu cần. Nhấn Add
Làm lại từ 6, mở rộng Visual C++ nếu nó chưa mở, chọn Resource, khung kế bên chọn Resource File (.rc), đổi tên tập tin nếu cần. Nhấn Add, IDE tạo cho chúng ta 2 tập tin .rc và .h
Mình chọn tên cho 3 tập tin theo gợi ý của IDE là : Header.h và Source.cpp và Resource.rc. Resource.h đã được IDE thêm vào. Đây là 4 tập tin chính cho dự án.
Tạo tài nguyên Icon cho dự án :
1. Chọn tab Resource View
2. Nhấn chuột phải vào Resource.rc -> Add Resource...
3. Chọn Icon -> New.
4. Nếu cần thì vẽ lại các Icon với các kích thước khác nhau, nhấn chuột phải vào định danh của icon rồi bật cửa sổ thuộc tính, thay định danh thành IDI_ICON_TETRIS.
Tạo tài nguyên phím tắt cho dự án :
1. Chọn tab Resource View
2. Nhấn chuột phải vào Resource.rc -> Add Resource...
3. Chọn Accelerator -> New, thay đổi định danh thành IDR_ACCEL_TETRIS
4. Lần lượt tạo ra 6 phím tắt :
_ ID : IDC_LEFT_ARROW, IDC_RIGHT_ARROW, IDC_UP_ARROW, IDC_DOWN_ARROW, IDC_ENTER, IDC_SPACE
_ Modifier : None, None, None, None, None, None
_ Key : VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, VK_RETURN, VK_SPACE
_ Type : VIRTKEY, VIRTKEY, VIRTKEY, VIRTKEY, VIRTKEY, VIRTKEY
Tạo tài nguyên Bitmap để vẽ các nút nhấn:
1. Sưu tầm hình vẽ button và chỉnh sửa tới kích thước 120x30 lưu thành tập tin Bitmap trong thư mục của dự án.
2. Chọn tab Resource View
3. Nhấn chuột phải vào Resource.rc -> Add Resource...
4. Chọn Bitmap -> Import.
5. điều hướng tới tập tin Bitmap ở trên -> Open
6. Thay định danh thành IDB_BITMAP_BUTTON
Khi chúng ta soạn thảo tài nguyên có thể IDE nhầm lẫn nên chúng ta phải qua bước kiểm tra tập tin Resource.h. Mở nó lên nếu không đúng hay bị chồng lấp thì sửa lại theo mã :
Mã://{{NO_DEPENDENCIES}}// Microsoft Visual C++ generated include file.// Used by Resource.rc//#define IDI_ICON_TETRIS 101#define IDR_ACCEL_TETRIS 102#define IDB_BITMAP_BUTTON 103#define IDC_LEFT_ARROW 40001#define IDC_RIGHT_ARROW 40002#define IDC_UP_ARROW 40003#define IDC_DOWN_ARROW 40004#define IDC_ENTER 40005#define IDC_SPACE 40006 // Next default values for new objects// #ifdef APSTUDIO_INVOKED#ifndef APSTUDIO_READONLY_SYMBOLS#define _APS_NEXT_RESOURCE_VALUE 104#define _APS_NEXT_COMMAND_VALUE 40007#define _APS_NEXT_CONTROL_VALUE 1001#define _APS_NEXT_SYMED_VALUE 101#endif#endif
Mã:#include<Windows.h>#include<time.h>#include"resource.h"#define APPNAME (TEXT("Advanced Tetris")) // Tên lớp, tiêu đề#define MYSUBKEY (TEXT("SOFTWARE\\MHoang\\TetrisCFW")) // Khóa con chứa dữ liệu thiết lập trước #define NUMCOLS 15 // Số cột mặc định là 15#define NUMROWS 20 // Số dòng mặc định là 20#define CELLSIZE 30 // Kích thước cạnh 1 viên gạch mặc định là 30 pixels#define ADVANCED TRUE // Chế độ chơi mặc định là cải tiến#define DROPSPEED 1000 // Tốc độ rơi mặc định ban đầu của khối gạch ( 1 giây 1 lần) #define SPACESIZE 40 // Khoảng cách dùng để canh chỉnh độ thưa dày giữa các đối tượng trên màn hình#define CXCONTROL 120 // Chiều rộng các điều khiển#define CYCONTROL 30 // Chiều cao các điều khiển button#define NUMBLOCKS 28 // Số kiểu khối gạch#define NEXTSIZE 20 // Kích thước cạnh của viên gạch vẽ trong khung chờ #define ID_TIMER_DROP 1 // Định danh bộ định thời cho các khối gạch đi xuống #define IDC_BUTTON_BOARD 1001#define IDC_BUTTON_WAIT 1002#define IDC_BUTTON_OPTIONS 1003#define IDC_BUTTON_PAUSE 1004#define IDC_BUTTON_START 1005 typedef struct{ int cNumCols; // Số cột int cNumRows; // Số dòng int nCellSize; // Kích thước cạnh viên gạch - cũng là kích thước ô trên ma trận chơi.} DOCUMENT;typedef DOCUMENT* PDOCUMENT; typedef struct{ HWND hbtBoard; // Khung chơi chính HWND hbtWait; // Khối gạch chờ HWND hbtOptions; // Nút nhấn Options HWND hbtPause; // Nut nhấn Pause HWND hbtStart; // Nút nhấn Start} CONTROLS;typedef CONTROLS* PCONTROLS; typedef struct{ HBITMAP hbmBackGround; // Bitmap vẽ nền cửa sổ chính HBITMAP hbmBackBoard; // Bitmap vẽ nền cửa sổ hoạt động HBITMAP hbmControl; // Bitmap vẽ nền các nút nhấn} IMAGES;typedef IMAGES* PIMAGES;
Mã:#include"Header.h" void ReadDwordFromRegistry(LPCTSTR pValueName, LPDWORD pdwValue){ DWORD dw = REG_DWORD; DWORD dwSize = sizeof(DWORD); RegGetValue(HKEY_CURRENT_USER, MYSUBKEY, pValueName, KEY_READ, &dw, pdwValue, &dwSize);}void WriteDwordToRegistry(LPCTSTR pValueName, LPDWORD pdwValue){ HKEY hkey; DWORD dw; if (RegCreateKeyEx(HKEY_CURRENT_USER, MYSUBKEY, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &dw) == ERROR_SUCCESS) { RegSetValueEx(hkey, pValueName, 0, REG_DWORD, (LPBYTE)pdwValue, sizeof(DWORD)); RegCloseKey(hkey); }}void ReadStringFromRegistry(LPCTSTR pValueName, LPTSTR szString){ DWORD dw = REG_SZ; DWORD dwSize = MAX_PATH; RegGetValue(HKEY_CURRENT_USER, MYSUBKEY, pValueName, KEY_READ, &dw, (LPBYTE)szString, &dwSize);}void WriteStringToRegistry(LPCTSTR pValueName, LPCTSTR szString){ HKEY hkey; DWORD dw; if (RegCreateKeyEx(HKEY_CURRENT_USER, MYSUBKEY, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &dw) == ERROR_SUCCESS) { RegSetValueEx(hkey, pValueName, 0, REG_SZ, (LPBYTE)szString, strlen(szString) + 1); RegCloseKey(hkey); }}void LoadSetupFromRegistry(PDOCUMENT pDocument){ ReadDwordFromRegistry(TEXT("NumCols"), (PDWORD)&pDocument->cNumCols); ReadDwordFromRegistry(TEXT("NumRows"), (PDWORD)&pDocument->cNumRows); ReadDwordFromRegistry(TEXT("CellSize"), (PDWORD)&pDocument->nCellSize);}void SaveSetupToRegistry(PDOCUMENT pDocument){ WriteDwordToRegistry(TEXT("NumCols"), (PDWORD)&pDocument->cNumCols); WriteDwordToRegistry(TEXT("NumRows"), (PDWORD)&pDocument->cNumRows); WriteDwordToRegistry(TEXT("CellSize"), (PDWORD)&pDocument->nCellSize);} void CalculateBoardSize(PDOCUMENT pDocument, int & cxBoardWindow, int & cyBoardWindow){ RECT r = { 0, 0, pDocument->cNumCols * pDocument->nCellSize, pDocument->cNumRows * pDocument->nCellSize }; AdjustWindowRectEx(&r, 0, FALSE, WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME); cxBoardWindow = r.right - r.left; cyBoardWindow = r.bottom - r.top;}void CalculateWindowSize(int & cxWindow, int & cyWindow, int & cxClient, int & cyClient){ RECT r = { 0, 0, cxClient, cyClient }; AdjustWindowRect(&r, WS_CAPTION, FALSE); cxWindow = r.right - r.left; cyWindow = r.bottom - r.top;}void CalculateWorkArea(int & cxWork, int & cyWork){ RECT r; SystemParametersInfo(SPI_GETWORKAREA, NULL, &r, NULL); cxWork = r.right - r.left; cyWork = r.bottom - r.top;} void DrawCells(HDC hdcMem, PDOCUMENT pDocument){}void DrawBlockDrop(HDC hdcMem, PDOCUMENT pDocument){}void DrawButtonBoard(LPDRAWITEMSTRUCT pd, HBITMAP hbmBoard, PDOCUMENT pDocument){ HDC hdcMem, hdcImage; HBITMAP hbm; int cxClientBoard, cyClientBoard; hdcMem = CreateCompatibleDC(pd->hDC); hdcImage = CreateCompatibleDC(pd->hDC); cxClientBoard = pd->rcItem.right - pd->rcItem.left; cyClientBoard = pd->rcItem.bottom - pd->rcItem.top; hbm = CreateCompatibleBitmap(pd->hDC, cxClientBoard, cyClientBoard); SelectObject(hdcMem, hbm); SelectObject(hdcImage, hbmBoard); BitBlt(hdcMem, 0, 0, cxClientBoard, cyClientBoard, hdcImage, 0, 0, SRCCOPY); DeleteDC(hdcImage); // Vẽ lên hdcMem tất cả các viên gạch và khối gạch đang hoạt động ở đây DrawCells(hdcMem, pDocument); DrawBlockDrop(hdcMem, pDocument); // Xong BitBlt(pd->hDC, 0, 0, cxClientBoard, cyClientBoard, hdcMem, 0, 0, SRCCOPY); DeleteObject(hbm); DeleteDC(hdcMem);}void DrawButtonNext(LPDRAWITEMSTRUCT pd, PDOCUMENT pDocument){ HDC hdcMem; HBITMAP hbm; int cxClientWait, cyClientWait; hdcMem = CreateCompatibleDC(pd->hDC); cxClientWait = pd->rcItem.right - pd->rcItem.left; cyClientWait = pd->rcItem.bottom - pd->rcItem.top; hbm = CreateCompatibleBitmap(pd->hDC, cxClientWait, cyClientWait); SelectObject(hdcMem, hbm); // Tô màu FillRect(hdcMem, &pd->rcItem, (HBRUSH)GetStockObject(GRAY_BRUSH)); // Vẽ khối gạch chờ lên ở đây // Vẽ từ DC ảo lên DC button BitBlt(pd->hDC, 0, 0, cxClientWait, cyClientWait, hdcMem, 0, 0, SRCCOPY); DeleteObject(hbm); DeleteDC(hdcMem);}void DrawButtonOptions(LPDRAWITEMSTRUCT pd, HBITMAP hbmControl, PDOCUMENT pDocument){ HDC hdcMem; hdcMem = CreateCompatibleDC(pd->hDC); SelectObject(hdcMem, hbmControl); BitBlt(pd->hDC, 0, 0, pd->rcItem.right - pd->rcItem.left, pd->rcItem.bottom - pd->rcItem.top, hdcMem, 0, 0, SRCCOPY); DeleteDC(hdcMem); // Vẽ chữ SetTextColor(pd->hDC, RGB(0, 0, 255)); SetBkMode(pd->hDC, TRANSPARENT); DrawText(pd->hDC, TEXT("Options ..."), -1, &pd->rcItem, DT_SINGLELINE | DT_CENTER | DT_VCENTER);}void DrawButtonPause(LPDRAWITEMSTRUCT pd, HBITMAP hbmControl, PDOCUMENT pDocument){ HDC hdcMem; hdcMem = CreateCompatibleDC(pd->hDC); SelectObject(hdcMem, hbmControl); BitBlt(pd->hDC, 0, 0, pd->rcItem.right - pd->rcItem.left, pd->rcItem.bottom - pd->rcItem.top, hdcMem, 0, 0, SRCCOPY); DeleteDC(hdcMem); // Vẽ chữ SetTextColor(pd->hDC, RGB(0, 0, 255)); SetBkMode(pd->hDC, TRANSPARENT); DrawText(pd->hDC, TEXT("Pause"), -1, &pd->rcItem, DT_SINGLELINE | DT_CENTER | DT_VCENTER);}void DrawButtonStart(LPDRAWITEMSTRUCT pd, HBITMAP hbmControl, PDOCUMENT pDocument){ HDC hdcMem; hdcMem = CreateCompatibleDC(pd->hDC); SelectObject(hdcMem, hbmControl); BitBlt(pd->hDC, 0, 0, pd->rcItem.right - pd->rcItem.left, pd->rcItem.bottom - pd->rcItem.top, hdcMem, 0, 0, SRCCOPY); DeleteDC(hdcMem); // Vẽ chữ SetTextColor(pd->hDC, RGB(0, 0, 255)); SetBkMode(pd->hDC, TRANSPARENT); DrawText(pd->hDC, TEXT("Start"), -1, &pd->rcItem, DT_SINGLELINE | DT_CENTER | DT_VCENTER);} void OnCreate(HINSTANCE hInstance, HWND hParent, PDOCUMENT pDocument, PCONTROLS pControls, PIMAGES pImages){ int cxBoardClient, cyBoardClient, cxBoardWindow, cyBoardWindow; int cxClient, cyClient, cxWindow, cyWindow; int cxWork, cyWork; // Tạo ra các cửa sổ con pControls->hbtBoard = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME, TEXT("button"), TEXT(""), WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 0, 0, 0, 0, hParent, (HMENU)IDC_BUTTON_BOARD, hInstance, NULL); pControls->hbtWait = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME, TEXT("button"), TEXT(""), WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 0, 0, 0, 0, hParent, (HMENU)IDC_BUTTON_WAIT, hInstance, NULL); pControls->hbtOptions = CreateWindow(TEXT("button"), TEXT(""), WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 0, 0, 0, 0, hParent, (HMENU)IDC_BUTTON_OPTIONS, hInstance, NULL); pControls->hbtPause = CreateWindow(TEXT("button"), TEXT(""), WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 0, 0, 0, 0, hParent, (HMENU)IDC_BUTTON_PAUSE, hInstance, NULL); pControls->hbtStart = CreateWindow(TEXT("button"), TEXT(""), WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 0, 0, 0, 0, hParent, (HMENU)IDC_BUTTON_START, hInstance, NULL); // Tạo tài liệu mặc định srand((unsigned int)time(0)); pDocument->cNumCols = NUMCOLS; pDocument->cNumRows = NUMROWS; pDocument->nCellSize = CELLSIZE; // Nạp chồng tài liệu từ Registry LoadSetupFromRegistry(pDocument); // Tính toán các kích thước của Board cxBoardClient = pDocument->cNumCols * pDocument->nCellSize; cyBoardClient = pDocument->cNumRows * pDocument->nCellSize; CalculateBoardSize(pDocument, cxBoardWindow, cyBoardWindow); // Tính toán các kích thước của cửa sổ chính cxClient = SPACESIZE + cxBoardWindow + SPACESIZE + CXCONTROL + SPACESIZE; cyClient = SPACESIZE + cyBoardWindow + SPACESIZE; CalculateWindowSize(cxWindow, cyWindow, cxClient, cyClient); // Tính toán các kích thước vùng làm việc CalculateWorkArea(cxWork, cyWork); // Di chuyển tất cả các cửa sổ MoveWindow(hParent, (cxWork - cxWindow) / 2, (cyWork - cyWindow) / 2, cxWindow, cyWindow, FALSE); MoveWindow(pControls->hbtBoard, SPACESIZE, SPACESIZE, cxBoardWindow, cyBoardWindow, FALSE); MoveWindow(pControls->hbtWait, SPACESIZE + cxBoardWindow + SPACESIZE, SPACESIZE, CXCONTROL, CXCONTROL, FALSE); MoveWindow(pControls->hbtOptions, SPACESIZE + cxBoardWindow + SPACESIZE, SPACESIZE + cyBoardWindow - 110, CXCONTROL, CYCONTROL, FALSE); MoveWindow(pControls->hbtPause, SPACESIZE + cxBoardWindow + SPACESIZE, SPACESIZE + cyBoardWindow - 70, CXCONTROL, CYCONTROL, FALSE); MoveWindow(pControls->hbtStart, SPACESIZE + cxBoardWindow + SPACESIZE, SPACESIZE + cyBoardWindow - 30, CXCONTROL, CYCONTROL, FALSE); // Tạo ra tất cả các bitmap với kích thước vừa với cửa sổ pImages->hbmControl = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_BUTTON)); pImages->hbmBackBoard = (HBITMAP)LoadImage(NULL, TEXT("BackBoard.bmp"), IMAGE_BITMAP, cxBoardClient, cyBoardClient, LR_LOADFROMFILE); pImages->hbmBackGround = (HBITMAP)LoadImage(NULL, TEXT("BackGround.bmp"), IMAGE_BITMAP, cxClient, cyClient, LR_LOADFROMFILE);}void OnDrawItem(LPDRAWITEMSTRUCT pd, PIMAGES pImages, PDOCUMENT pDocument){ switch (pd->CtlID) { case IDC_BUTTON_BOARD: DrawButtonBoard(pd, pImages->hbmBackBoard, pDocument); break; case IDC_BUTTON_WAIT: DrawButtonNext(pd, pDocument); break; case IDC_BUTTON_OPTIONS: DrawButtonOptions(pd, pImages->hbmControl, pDocument); break; case IDC_BUTTON_PAUSE: DrawButtonPause(pd, pImages->hbmControl, pDocument); break; case IDC_BUTTON_START: DrawButtonStart(pd, pImages->hbmControl, pDocument); break; }}void OnPaint(HWND hwnd, HBITMAP hbmBackGround){ HDC hdc, hdcMem; PAINTSTRUCT ps; RECT r; GetClientRect(hwnd, &r); hdc = BeginPaint(hwnd, &ps); if (hbmBackGround) { hdcMem = CreateCompatibleDC(hdc); SelectObject(hdcMem, hbmBackGround); BitBlt(hdc, 0, 0, r.right - r.left, r.bottom - r.top, hdcMem, 0, 0, SRCCOPY); DeleteDC(hdcMem); } EndPaint(hwnd, &ps);}void OnClose(HWND hwnd){ if (IDYES == MessageBox(hwnd, TEXT("Are you quit ?"), APPNAME, MB_YESNO | MB_ICONQUESTION)) DestroyWindow(hwnd);}void OnDestroy(PDOCUMENT pDocument){ PostQuitMessage(0);}void OnOptionsClick(){}void OnPauseClick(){}void OnStartClick(HWND hwnd, PDOCUMENT pDocument, PCONTROLS pControls){}void OnDropTimer(){}void OnLeftArrow(PDOCUMENT pDocument, PCONTROLS pControls){}void OnRightArrow(PDOCUMENT pDocument, PCONTROLS pControls){}void OnDownArrow(PDOCUMENT pDocument, PCONTROLS pControls){}void OnUpArrow(PDOCUMENT pDocument){}void OnEnterPress(){}void OnSpacePress(){} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam){ static HINSTANCE hInstance; static CONTROLS Controls; static IMAGES Images; static DOCUMENT Document; switch (message) { case WM_CREATE: hInstance = ((LPCREATESTRUCT)lparam)->hInstance; OnCreate(hInstance, hwnd, &Document, &Controls, &Images); return 0; case WM_CLOSE: OnClose(hwnd); return 0; case WM_DESTROY: OnDestroy(&Document); return 0; case WM_DRAWITEM: OnDrawItem((LPDRAWITEMSTRUCT)lparam, &Images, &Document); return 0; case WM_PAINT: OnPaint(hwnd, Images.hbmBackGround); return 0; case WM_TIMER: switch (wparam) { case ID_TIMER_DROP: OnDropTimer(); break; } return 0; case WM_COMMAND: switch (LOWORD(wparam)) { case IDC_BUTTON_OPTIONS: if (HIWORD(wparam) == BN_CLICKED) OnOptionsClick(); return 0; case IDC_BUTTON_PAUSE: return 0; case IDC_BUTTON_START: if (HIWORD(wparam) == BN_CLICKED) OnStartClick(hwnd, &Document, &Controls); return 0; case IDC_ENTER: OnEnterPress(); return 0; case IDC_SPACE: OnSpacePress(); return 0; case IDC_LEFT_ARROW: OnLeftArrow(&Document, &Controls); return 0; case IDC_RIGHT_ARROW: OnRightArrow(&Document, &Controls); return 0; case IDC_DOWN_ARROW: OnDownArrow(&Document, &Controls); return 0; case IDC_UP_ARROW: OnUpArrow(&Document); return 0; } break; } return DefWindowProc(hwnd, message, wparam, lparam);}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmd, int nShow){ WNDCLASS w; HACCEL hAccel; HWND hwnd; MSG msg; w.cbClsExtra = 0; w.cbWndExtra = 0; w.hbrBackground = NULL; w.hCursor = LoadCursor(NULL, IDC_ARROW); w.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON_TETRIS)); w.hInstance = hInstance; w.lpfnWndProc = WndProc; w.lpszClassName = APPNAME; w.lpszMenuName = NULL; w.style = CS_HREDRAW | CS_VREDRAW; if (!RegisterClass(&w)) { MessageBox(NULL, TEXT("Error : RegisterClass"), APPNAME, MB_OK | MB_ICONINFORMATION); return 0; } hwnd = CreateWindow(APPNAME, APPNAME, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); if (!hwnd) { MessageBox(NULL, TEXT("Error : CreateWindow"), APPNAME, MB_OK | MB_ICONINFORMATION); return 0; } ShowWindow(hwnd, nShow); UpdateWindow(hwnd); hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCEL_TETRIS)); while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(hwnd, hAccel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam;}
Tương tự nếu có BackGround.bmp thì nền cửa sổ chính sẽ được vẽ từ nó.
-
02-10-2015, 01:41 PM #4Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
Tạm gác qua phần diễn đạt thuật toán, mình đưa cái [Advanced Tetris.exe] lên các bạn chạy và kiểm lỗi giùm.
Các bạn nhớ sưu tầm 2 tập tin "BackBoard.bmp" và "BackGround.bmp" và để sát .exe đã được bung ra cho nó bớt khô cứng nhé.
Mã nguồn sẽ đưa lên sau khi tiếp thu ý kiến của các bạn và làm gọn lại.
-
03-10-2015, 08:14 AM #5Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
Có phiên bản cho linux không? Tui dùng linux. [IMG]images/smilies/icon_question.gif[/IMG]
-
03-10-2015, 05:39 PM #6Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
Ổ cứng của mình đã format theo cách dồn hết vào 1 phân vùng nên không cài thêm Linux được. Tuy nhiên phần mã các giải thuật sẽ có thể giúp bạn tự chuyển sang con Chim cánh cụt, sau này có điều kiện thì mình sẽ thực hiện bổ sung. Chào bạn.
-
07-10-2015, 10:32 AM #7Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
Cấu tạo của các khối gạch - tiếp theo
Với cấu tạo của một khối gạch như vậy, chúng ta thấy chỉ cần một số int32 là đủ nắm giữ bố cục của một bề mặt của 1 khối gạch. Do đó cỏ thể dùng mảng 4 phấn tử int32 để lưu trữ 4 bề mặt có thể có của khối gạch bất kỳ, và một hằng mảng toàn cục g_BlockImage[28][4] là có thể truy vết bất kỳ khối gạch nào.
Mã:#define NUMBLOCKS 28 // Số kiểu khối gạchconst int g_BlockImage[NUMBLOCKS][4] = { 0x00001000, 0x00001000, 0x00001000, 0x00001000, // 0: Block 1 viên duy nhất 0x00003180, 0x00003180, 0x00003180, 0x00003180, // 1: Block 4 viên tạo hình vuông 0x00003C00, 0x00021084, 0x00003C00, 0x00021084, // 2: Block 4 viên tạo que 0x000030C0, 0x00023100, 0x000030C0, 0x00023100, // 3: Block 4 viên chữ Z 0x00001980, 0x00043080, 0x00001980, 0x00043080, // 4: Block 4 viên chữ S 0x00003900, 0x00061080, 0x00013800, 0x000210C0, // 5: Block 4 viên chữ L 0x00003840, 0x00021180, 0x00043800, 0x00031080, // 6: Block 4 viên Chữ J 0x00003880, 0x00023080, 0x00023800, 0x00021880, // 7: Block 4 viên chữ T 0x00023880, 0x00023880, 0x00023880, 0x00023880, // 8: Block 5 viên chữ thập 0x00001800, 0x00001080, 0x00001800, 0x00001080, // 9: Block 2 viên tạo que 0x00003800, 0x00021080, 0x00003800, 0x00021080, // 10: Block 3 viên tạo que 0x00007C00, 0x00421084, 0x00007C00, 0x00421084, // 11: Block 5 viên tạo que 0x000070C0, 0x00423100, 0x00061C00, 0x00011884, // 12: Block 5 viên chữ Z thừa 0x00001D80, 0x00043084, 0x00037000, 0x00421840, // 13: Block 5 viên chữ S thừa 0x00001880, 0x00003080, 0x00023000, 0x00021800, // 14: Block 3 viên tạo góc vuông 0x00072100, 0x00070840, 0x000109C0, 0x000421C0, // 15: Block 5 viên tạo góc vuông 0x00003D00, 0x00061084, 0x00017800, 0x004210C0, // 16: Block 5 viên chữ L thừa 0x00007840, 0x00421180, 0x00043C00, 0x00031084, // 17: Block 5 viên chữ J thừa 0x00071080, 0x00013840, 0x000211C0, 0x00043900, // 18: Block 5 viên chữ T 0x000038C0, 0x00023180, 0x00063800, 0x00031880, // 19: Block 5 viên hình vuông đính kèm trên trái 0x00003980, 0x00063080, 0x00033800, 0x000218C0, // 20: Block 5 viên hình vuông đính kèm trên phải 0x00003C80, 0x00023084, 0x00027800, 0x00421880, // 21: Block 5 viên Chữ T lệch trái 0x00007880, 0x00423080, 0x00023C00, 0x00021884, // 22: Block 5 viên Chữ T lệch phải 0x000310C0, 0x00003940, 0x00061180, 0x00053800, // 23: Block 5 viên chữ C 0x000610C0, 0x00013900, 0x000610C0, 0x00013900, // 24: Block 5 viên Chữ Z lớn 0x00031180, 0x00043840, 0x00031180, 0x00043840, // 25: Block 5 viên Chữ S lớn 0x000230C0, 0x00023900, 0x00061880, 0x00013880, // 26: Block 5 viên Chữ L đeo ba lô 0x00021980, 0x00043880, 0x00033080, 0x00023840, // 27: Block 5 viên Chữ J đeo ba lô};
Ví dụ lấy khối gạch kiểu chữ C ở chỉ mục 23, các mặt nạ bit như sau :
Mã:// 0, 0, 0, 0, 0, // Nhị phân : 00000 00110 00100 00110 00000 = 0 0000 0011 0001 0000 1100 0000 = 0x310C0// 0, 0, 1, 1, 0,// 0, 0, 1, 0, 0,// 0, 0, 1, 1, 0,// 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, // Nhị phân : 00000 00000 01110 01010 00000 = 0 0000 0000 0011 1001 0100 0000 = 0x3940// 0, 0, 0, 0, 0,// 0, 1, 1, 1, 0,// 0, 1, 0, 1, 0,// 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, // Nhị phân : 00000 01100 00100 01100 00000 = 0 0000 0110 0001 0001 1000 0000 = 0x61180// 0, 1, 1, 0, 0,// 0, 0, 1, 0, 0,// 0, 1, 1, 0, 0,// 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, // Nhị phân : 00000 01010 01110 00000 00000 = 0 0000 0101 0011 1000 0000 0000 = 0x53800// 0, 1, 0, 1, 0,// 0, 1, 1, 1, 0,// 0, 0, 0, 0, 0,// 0, 0, 0, 0, 0,
Khi tạo các mặt nạ các bạn nên cẩn thận vì nó không trực quan, cái .exe ở trên chạy không đúng với bề mặt thứ 2 chữ L và bề mặt thứ 3 của 5 viên góc vuông (do sơ ý khi đánh máy).
- - - Nội dung đã được cập nhật ngày 07-10-2015 lúc 11:21 AM - - -
Cấu tạo các mặt nạ xoay
Khi xoay 1 khối gạch theo 1 góc vuông 90 độ, chúng ta phải bảo đảm rằng khi quay nó sẽ không bị vướng vào các viên gạch có sẵn trên ma trận chơi. Cũng như ở trên, mình thấy tạo sẵn các mặt nạ xoay vẫn là tốt hơn đi kiểm tra từng viên trong khối. Sau đây là hằng mảng toàn cục khác lưu trữ tất cả các mặt nạ xoay của các kiểu khối gạch
Mã:const int g_RotateMask[NUMBLOCKS][4] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 0: RotateMask 1 viên duy nhất 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 1: RotateMask 4 viên tạo hình vuông 0x000600E7, 0x00042C63, 0x000600E7, 0x00042C63, // 2: RotateMask 4 viên tạo que 0x00060100, 0x000400C0, 0x00060100, 0x000400C0, // 3: RotateMask 4 viên chữ Z 0x00042000, 0x00000940, 0x00042000, 0x00000940, // 4: RotateMask 4 viên chữ S 0x000600C0, 0x00012900, 0x000600C0, 0x00012900, // 5: RotateMask 4 viên chữ L 0x00060180, 0x00052800, 0x000300C0, 0x00002940, // 6: RotateMask 4 viên Chữ J 0x00060140, 0x00050900, 0x000500C0, 0x00012140, // 7: RotateMask 4 viên chữ T 0x00050140, 0x00050140, 0x00050140, 0x00050140, // 8: RotateMask 5 viên chữ thập 0x000000C0, 0x00000840, 0x000000C0, 0x00000840, // 9: RotateMask 2 viên tạo que 0x000600C0, 0x00012900, 0x000600C0, 0x00012900, // 10: RotateMask 3 viên tạo que 0x01CE00E7, 0x018C6C63, 0x01CE00E7, 0x018C6C63, // 11: RotateMask 5 viên tạo que 0x01CE0100, 0x00358C00, 0x000100E7, 0x00006358, // 12: RotateMask 5 viên chữ Z thừa 0x00042067, 0x00034318, 0x01CC0840, 0x00318580, // 13: RotateMask 5 viên chữ S thừa 0x00002040, 0x00060100, 0x00050800, 0x000100C0, // 14: RotateMask 3 viên tạo góc vuông 0x00000840, 0x00000180, 0x00042000, 0x00030000, // 15: RotateMask 5 viên tạo góc vuông 0x000600E7, 0x00016B18, 0x01CE00C0, 0x0031AD00, // 16: RotateMask 5 viên chữ L thừa 0x01CE0180, 0x0035AC00, 0x000300E7, 0x00006B58, // 17: RotateMask 5 viên chữ J thừa 0x00002940, 0x00060180, 0x00052800, 0x000300C0, // 18: RotateMask 5 viên chữ T 0x00060100, 0x00050800, 0x000100C0, 0x000020C0, // 19: RotateMask 5 viên hình vuông đính kèm trên trái 0x00060040, 0x00010900, 0x000400C0, 0x00012100, // 20: RotateMask 5 viên hình vuông đính kèm bên phải 0x00060167, 0x00054B18, 0x01CD00C0, 0x0031A540, // 21: RotateMask 5 viên Chữ T lệch trái 0x01CE0140, 0x00358D00, 0x000500E7, 0x00016358, // 22: RotateMask 5 viên Chữ T lệch phải 0x00002900, 0x00060080, 0x00012800, 0x000200C0, // 23: RotateMask 5 viên chữ C 0x00012900, 0x000600C0, 0x00012900, 0x000600C0, // 24: RotateMask 5 viên Chữ Z lớn 0x00042840, 0x00600180, 0x00042840, 0x00600180, // 25: RotateMask 5 viên Chữ S lớn 0x00050900, 0x000500C0, 0x00012140, 0x00060140, // 26: RotateMask 5 viên Chữ L đeo ba lô 0x00052040, 0x00030140, 0x00040940, 0x00050180, // 27: RotateMask 5 viên Chữ J đeo ba lô};
Mã:// Bề mặt cần xoay // Bề mặt xoay tới // Mặt nạ xoay // Nhị phân Thập lục // Face0// 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, // 00000 01100 00000 00111 00111 = 0x600E7// 0, 0, 0, 0, 0, // 0, 1, 1, 0, 0, // 0, 1, 1, 0, 0, // 0, 1, 1, 1, 1, // 0, 0, 1, 0, 0, // 0, 0, 0, 0, 0,// 0, 1, 0, 0, 0, // 0, 0, 1, 0, 0, // 0, 0, 1, 1, 1,// 0, 0, 0, 0, 0, // 0, 0, 1, 0, 0, // 0, 0, 1, 1, 1, // Face1// 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, // 00000 00010 11010 11000 11000 = 0x16B18// 0, 1, 1, 0, 0, // 0, 0, 0, 1, 0, // 0, 0, 0, 1, 0,// 0, 0, 1, 0, 0, // 1, 1, 1, 1, 0, // 1, 1, 0, 1, 0,// 0, 0, 1, 0, 0, // 0, 0, 0, 0, 0, // 1, 1, 0, 0, 0,// 0, 0, 1, 0, 0, // 0, 0, 0, 0, 0, // 1, 1, 0, 0, 0, // Face2// 0, 0, 0, 0, 0, // 0, 0, 1, 0, 0, // 1, 1, 1, 0, 0, // 11100 11100 00000 00110 00000 = 0x1CE00C0// 0, 0, 0, 1, 0, // 0, 0, 1, 0, 0, // 1, 1, 1, 0, 0,// 1, 1, 1, 1, 0, // 0, 0, 1, 0, 0, // 0, 0, 0, 0, 0,// 0, 0, 0, 0, 0, // 0, 0, 1, 1, 0, // 0, 0, 1, 1, 0,// 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, // Face3// 0, 0, 1, 0, 0, // 0, 0, 0, 0, 0, // 0, 0, 0, 1, 1, // 00011 00011 01011 01000 00000 = 0x31AD00// 0, 0, 1, 0, 0, // 0, 0, 0, 0, 0, // 0, 0, 0, 1, 1,// 0, 0, 1, 0, 0, // 0, 1, 1, 1, 1, // 0, 1, 0, 1, 1,// 0, 0, 1, 1, 0, // 0, 1, 0, 0, 0, // 0, 1, 0, 0, 0,// 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0,
Chú ý là không phải tất cả các bề mặt đều xoay theo chiều kim đồng hồ. Có những bề mặt như của chữ Z thì từ face0 -> face1 theo kim đồng hồ nhưng từ face1 -> face2 lại quay ngược lại, thực chất face0 và face2 đều là một.
Cũng như các mặt nạ bề mặt, các mặt nạ xoay khi tạo ra cũng rất dễ nhầm lẫn, chưa chắc trong mảng trên mình đã đặt cờ bit đúng toàn bộ, các bạn phát hiện sai sót thì báo nhé.
- - - Nội dung đã được cập nhật ngày 07-10-2015 lúc 03:32 PM - - -
Cấu tạo mảng hiển thị và mảng thực tế
Trong số rất nhiều cách làm việc với mảng, để tránh vượt quá chỉ mục mảng mà không cần kiểm tra chặt chẽ biến chạy, nhiều người thường dùng phương pháp đơn giản là bao thêm bên ngoài mảng một số các phần tử cộng thêm, khi đó mảng thực tế sẽ phình to hơn mảng ban đầu nhưng bù lại mã sẽ gọn gàng hơn.
Trong hình trên mô tả cho ngữ cảnh : Người chơi chọn lựa khung chơi là 10x10, chương trình làm việc thực tế trên khung chơi 16x16, một khối gạch Z lúc mới đưa vào chỉ "thò một chân" và phần còn lại "còn trong bóng tối". Thiết kế theo kiểu này có người gọi là mailbox, có người gọi là lính canh - gọi là gì thì nó cũng giúp chúng ta nhiều.
Khối gạch trong trò chơi chỉ di chuyển 3 hướng : sang phải; sang trái; xuống dưới. Khi đáp ứng các chỉ lệnh điều khiển từ người dùng, chương trình cần phải xem khối gạch có vượt ra các biên đó không nên tất cả các "lính canh" luôn luôn được đặt về 1 - Nghĩa là nơi đây đang có gạch không thể di chuyển đè lên được. Phần bên trên không cần thiết phải "canh" hết, ngay khi chỉ "thò một chân" thôi, người chơi vần di chuyển khối gạch sang trái hay phải bình thường.
Ngoài ra trong khi đáp ứng di chuyển của người chơi, chương trình cũng phải xác định xem các di chuyển có đè qua các viên gạch đã có sẵn trong phần hiển thị không. Một lần nữa, chúng ta lại dùng mặt nạ để thao tác.
Một khối gạch có 5x5=25 ô nên mặt nạ cũng chỉ áp đặt cho mảng con 5x5 trong mảng thực tế. Lấy lại hình trên, ta thấy viên gạch Z đang được định vị với 4 ô có màu cam, nhưng thực chất mặt nạ của nó đang chiếm trọn ma trận từ hàng 0->4 và từ cột 6->10, nếu cho nó di chuyển xuống 1 hàng thì mặt nạ của nó nằm từ hàng 1->5 và cột vẫn giữ nguyên. Từ đây chúng ta chỉ cần nhận mặt nạ từ hàng 1->5 và cột từ 6->10 của mảng thực, sau đó một phép toán thao tác Bit & là biết ngay di chuyển được hay không.
Bên dưới là các mặt nạ cho từng ô chính xác trong từng khối gạch hay trong một mảng 5x5 xác định của mảng thực
Mã:#define CELLSPERBLOCK 25 // Số ô trên 1 khốiconst int g_BrickMask[CELLSPERBLOCK] = { 0x01000000, // 0000 0001 0000 0000 0000 0000 0000 0000 - Mặt nạ ô 0 0x00800000, // 0000 0000 1000 0000 0000 0000 0000 0000 - Mặt nạ ô 1 0x00400000, // 0000 0000 0100 0000 0000 0000 0000 0000 - Mặt nạ ô 2 0x00200000, // 0000 0000 0010 0000 0000 0000 0000 0000 - Mặt nạ ô 3 0x00100000, // 0000 0000 0001 0000 0000 0000 0000 0000 - Mặt nạ ô 4 0x00080000, // 0000 0000 0000 1000 0000 0000 0000 0000 - Mặt nạ ô 5 0x00040000, // 0000 0000 0000 0100 0000 0000 0000 0000 - Mặt nạ ô 6 0x00020000, // 0000 0000 0000 0010 0000 0000 0000 0000 - Mặt nạ ô 7 0x00010000, // 0000 0000 0000 0001 0000 0000 0000 0000 - Mặt nạ ô 8 0x00008000, // 0000 0000 0000 0000 1000 0000 0000 0000 - Mặt nạ ô 9 0x00004000, // 0000 0000 0000 0000 0100 0000 0000 0000 - Mặt nạ ô 10 0x00002000, // 0000 0000 0000 0000 0010 0000 0000 0000 - Mặt nạ ô 11 0x00001000, // 0000 0000 0000 0000 0001 0000 0000 0000 - Mặt nạ ô 12 0x00000800, // 0000 0000 0000 0000 0000 1000 0000 0000 - Mặt nạ ô 13 0x00000400, // 0000 0000 0000 0000 0000 0100 0000 0000 - Mặt nạ ô 14 0x00000200, // 0000 0000 0000 0000 0000 0010 0000 0000 - Mặt nạ ô 15 0x00000100, // 0000 0000 0000 0000 0000 0001 0000 0000 - Mặt nạ ô 16 0x00000080, // 0000 0000 0000 0000 0000 0000 1000 0000 - Mặt nạ ô 17 0x00000040, // 0000 0000 0000 0000 0000 0000 0100 0000 - Mặt nạ ô 18 0x00000020, // 0000 0000 0000 0000 0000 0000 0010 0000 - Mặt nạ ô 19 0x00000010, // 0000 0000 0000 0000 0000 0000 0001 0000 - Mặt nạ ô 20 0x00000008, // 0000 0000 0000 0000 0000 0000 0000 1000 - Mặt nạ ô 21 0x00000004, // 0000 0000 0000 0000 0000 0000 0000 0100 - Mặt nạ ô 22 0x00000002, // 0000 0000 0000 0000 0000 0000 0000 0010 - Mặt nạ ô 23 0x00000001, // 0000 0000 0000 0000 0000 0000 0000 0001 - Mặt nạ ô 24};
Mã:int i, j, n = 0, iMask = 0; for (i = iRow; i < iRow + 5; i++) for (j = iCol; j < iCol + 5; j++) { if (pCell[i][j].bBrick) iMask |= g_BrickMask[n]; n++; } return iMask;
Và bên dưới là mã xem có di chuyển được không sẽ có dạng
Mã:if ( ! (iMask & matnakhoigach) ) // Không có sự chồng lấp - có thể di chuyển xuống dưới { // Thuộc tính dòng của khối gạch ++; // Cập nhật màn hình }
-
20-10-2015, 10:25 AM #8Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
Bên dưới là mã nguồn dự án Advanced Tetris được viết theo OOP kết hợp với API, mời các bạn chạy thử.
-
20-11-2015, 09:25 AM #9Junior Member
- Ngày tham gia
- Sep 2015
- Bài viết
- 0
Cảm ơn bạn về bài viết nó rất hay... mình đang cần đến nó.
Ngọc Bích xanh bản chất thuộc dòng đá đá hoa (jade). Và cẩm thạch là tên gọi chung của ngọc bích. Vì thực chất chúng thuộc dòng đá đa khoáng được hình thành từ chất Silicat dưới dạng dioxy. Ngọc bích...
Chia sẻ Vòng tay ngọc bích xanh là...