Lập trình

Lập trình

Thứ Bảy, 26 tháng 3, 2016

[Viết game Pacman] Game pacman bằng C++ Tut 2 – Xây dựng map

  

  Ở bài lần trước ta đã nêu ý là coi màn hình là một mảng 2 chiều, nên ta đã tạo class xoay quang đối tượng matrix đó.

Trước hết ta nhìn code lại code của file header:

class Matrix
{
private:
       int matrix[XMAX + 3][YMAX + 3];
       ToaDo pacman;
       computer m_com1, m_com2, m_com3, m_com4;
public:
       Matrix();
       ~Matrix();
       void drawMatrix();
       void updateMatrix();
       void creatMap();
       void completeMap();
       void controlPacman();
       void drawScore();
       void checkWin();
       inline void checkLost();
       void veLive();

       // Computer
       void initComputer();
       void moveComputer1();
       void moveComputer2();
       void moveComputer3();
       void moveComputer4();

       void moveComputers();
       void restoreCell(int x, int y);
};

I, Trước hết ta làm một vài thao tác trong hàm khởi tạo gồm:
 + Sử dụng hàm resizeConsole(int, int) trong thư viện GameLib.h mà ta đã tạo ở tut 1.

       resizeConsole(1000, 800);

 + Cài các giá trị mặc định cho các phần tử trong mảng 2 chiều là SPACE (0) – tức là lúc mới vào, mọi điểm trên map đều là dấu châm mà pacman có thể ăn để tăng điểm.

       for (int i = 0; i <= XMAX; i++){
              for (int j = 0; j <= YMAX; j++){
                     matrix[i][j] = SPACE;
              }
       }

+ Dĩ nhiên ta tạo tường (WALL ) để pacman không đi ra khỏi map:
 Tạo tường thì ta tạo cả trên và dưới:
       for (int i = 0; i <= XMAX; i++){
              matrix[i][YMIN] = matrix[i][YMAX] = WALL;
       }

       for (int i = 0; i <= YMAX; i++){
              matrix[XMIN][i] = matrix[XMAX][i] = WALL;
       }
Như vậy trên mảng biểu diễn màn hình đã có tường.

Bước tiếp theo ta cần thiết lập tọa độ ban đầu của pacman trong mảng, và Score (điểm), mạng sống (live) :

       pacman.x = XMAX - 1;
       pacman.y = YMAX - 1;

       matrix[pacman.x][pacman.y] = 2;
       pacman.Score = 0;
       pacman.live = 3;

Như vậy thật dễ dàng hoàn tất hàm khởi tạo Matrix().

II. Cài đặt hàm drawMatrix()
            Ở trên ta đã cài đặt xong các giá trị của mảng matrix, cái mà nó biểu diễn toàn bộ màn hình chơi. Vậy biểu diễn trên mảng thì ta cũng phải vẽ ra màn hình cái mà mảng đã biểu diễn cho nó chứ.
Vậy ta cùng làm việc trong hàm drawMatrix(), tức là hàm trung chuyển từ mảng ra màn hình.

            Như ta đã lên ý tưởng, mảng matrix biểu diễn cho màn hình các đối tượng sau: dấu “.”, cái này khi PacMan ăn thì sẽ tăng điểm lên; tường (WALL) , pacman và dấu trắng (dấu cách). Như vậy để biểu diễn tường, pacman, màu tường, màu pacman ta cần khai báo các hằng sau:


       const int X0 = 20;
       const int Y0 = 15;
       const char wall = 219;
       const int colorWall = 9;
       const int colorScore = 13;
       const char pacman = 2;
       const char colorPacman = 11;


Ở đâu ta không được nhầm lẫn giữa X0, Y0 ở đây với XMIN và YMIN ở file header. Nó khác nhau ở chỗ: XMIN và YMIN là biểu diễn cột và dòng nhỏ nhất của mảng matrix còn X0 và Y0 biểu thị tung độ và hoành độ nhỏ nhất để biểu diễn các đối tượng ra màn hình chính:
            Ví dụ: Khi pacman có tung độ x, y thì ta gotoxy(XMIN + x, YMIN + y); rồi vẽ đối tượng này.

X0 và Y0 có công dụng duy nhất là làm cho map cân xứng và hợp lý hơn ở trên console.

 Ta khai báo wall = 219 là “chất liệu” xây dựng ra cái tường, khi đến tọa độ của tường ta in cái kí tự có mã ASCII là 219 ra ; colorWall là màu của tường. colorScore = 13 là màu của điểm Score (cái score: XX mà bạn thấy ở hình đầu đó). Pacman = 2 tương tự như wall = 219, pacman này dùng làm “chất liệu” để vẽ Pacman ra màn hình, colorPacman là màu mà ta muốn biểu trị pacman.

            Như vậy ở đây ta phải dùng hàm gotoxy(int x, int y) và textcolor(int mau) đưa con trỏ đên vị trí (x, y)  và thay đổi màu vẽ thành màu có số hiệu mau. Hai hàm trên ta đã khai báo và cài đặt ở thư viện GameLib.h, như vậy khi cài đặt các hàm trong file Matrix.cpp ta cần include file GameLib.h vào.

            Ok, giờ là bước quan trọng nhất, ta vẽ mảng matrix ra màn hình:


       for (int i = XMIN; i <= XMAX; i++){
              for (int j = YMIN; j <= YMAX; j++){

                     gotoxy(i + X0, j + Y0);

                     if (matrix[i][j] == SPACE){
                           textcolor(colorScore);
                           std::cout << ".";
                     }

                     if (matrix[i][j] == 1){
                           textcolor(colorWall);
                           std::cout << wall;
                     }

                     if (matrix[i][j] == 2){
                           textcolor(colorPacman);
                           std::cout << pacman;
                     }
                     if (matrix[i][j] == -1){
                           std::cout << " ";
                     }
              }
       }
            Như thông lệ, ta cần 2 vòng for để truy xuất hết các giá trị phần tử của matrix.  Các giá trị SPACE (0), 1, 2, -1 trong mảng tượng trưng cho dấu ‘.’ ; tường; pacman; và dấu cách trên màn hình.

III, Tạo map với creatMap()
            Nếu để map như đã cài đặt ban đầu trong hàm khởi tạo thì không có gì là thú vị cả, ta cần map có nhiều tường hơn. Muốn như vậy thật dễ dàng, ta chỉ cần thêm vào trong mảng matrix là sau đó sử dụng drawMatrix() là đã có một map đẹp theo ý muốn.

      
       for (int i = YMIN + 5; i <= YMIN + 17; i++){
              matrix[5][i] = 1;
              matrix[10][i] = 1;
              matrix[15][i] = 1;
              matrix[20][i] = 1;
              matrix[25][i] = 1;
       }

       for (int i = XMIN + 5; i <= XMIN + 25; i++){
              matrix[i][YMAX - 10] = matrix[i][YMAX - 7] = matrix[i][YMAX - 3] = 1;
       }
}

Với các giá trị đầu của i và j bạn có thể thay đổi theo ý của các bạn để được một map theo ý của các bạn.

Vậy đã xong creatMap(), giờ ta chỉ cần in nó ra màn hình là xong. Để cho gọn ta dùng thêm hàm completeMap() gồm:

void Matrix::completeMap(){
       creatMap();
       drawMatrix();
}

            Để tạo map và vẽ map luôn.
Như vậy việc tạo map đã xong, tiếp theo ta cần làm là điều khiển Pacman. Hẹn gặp các bạn ở tut sau nhé. Cảm ơn các bạn đã theo dõi.

Thứ Sáu, 25 tháng 3, 2016

[Viết game PacMan] Game pacman bằng C++ Tut 1 - Ý tưởng.



Hôm nay chúng ta cùng tìm hiểu cách viết game Pacman bằng C++, nó thực sự rất đơn giản khi ta phân nhỏ việc nó ra. Trước tiên ta cùng lên ý tưởng cho file Matrix.h: http://ghinhap.com/Matrix.h

I.      Để có pacman ý tưởng của ta là: vẽ đồ họa, tạo map, một con pacman do người điều khiển, và vài con pacman random chạy.
 Trong phần vẽ ta cần vẽ tường – pacman gặp nó thì không thể đi tiếp, các dấu chấm – pacman ăn trong quá trình đi.
 Pacman cần người điều khiển từ việc ấn bàn phím .
 Còn pacman máy thì random việc nhập từ bàn phím của con người để tự chạy, hoặc mình cài đặt sẵn đường chạy cho nó. 
  Ta thấy rằng để mọi việc dễ dàng cho biểu diễn các đối tượng và xử lý, ta cài đặt một mảng 2 chiều đặt là matrix vì nếu ta coi màn hình là một mảng 2 chiều thì rõ ràng mọi phần tử trên màn hình đều có thể biểu diễn được trong mảng đó bằng các giá trị, cho nó vào một lớp:

Ta tạo file header chứa class Matrix biểu diễn tất cả những gì trên màn hình thông qua một mảng 2 chiều.

class Matrix
{
private:
            int matrix[XMAX + 3][YMAX + 3];
            ToaDo pacman;
            computer m_com1, m_com2, m_com3, m_com4;
}

- Dễ thấy ngoài tạo map thì ToaDo pacman là ta thiết lập tọa độ cho PacMan với kiểu dữ liệu do ta tạo : ToaDo
struct ToaDo{
     int x;
     int y;
     int prevKey;
     int Score;
     int live;
};
Các biến trên lần lượt có tác dụng như sau: x, y là xác định tọa độ để xử lý vị trí của PacMan, prevKey lưu trữ giá trị giá trị key mà đã ấn vào trước. Cụ thể như sau: Trong thân Game, nó chạy một vòng lặp, trong vòng lặp đó nó bắt xem ta có ấn nút gì không, nếu ấn sang trái thì pacman sang trái,… Trong trường hợp ta không bấm key nào thì nó chạy với giá trị prevKey tức là key lần trước.
- Score là lưu điểm mà pacman đã ăn được.

- Ngoài ra để xử lý PacMan hiệu quả và dễ dàng hơn ta đặt thêm một enum:
enum movePacman {LEFT = 0, RIGHT, UP, DOWN, NO};
Cái enum này cần về sau để tượng trương cho giá trị prevKey: nếu bằng LEFT (0) thì cứ sang trái, RIGHT(1) thì cứ sang phải, …
- Bên cạnh đó, như ở trên ta đã nói, nếu coi các phần tử xuất hiện trên màn hình cho vào một mảng thì có thể dễ dàng biểu diễn nó thong qua các giá trị. Vì vậy ta đặt một vài macro để định nghĩa các giá trị sau cho tiện sử dụng cũng như dễ đọc:

#define XMAX 30
#define YMAX 30
#define XMIN 0
#define YMIN 0
#define WALL 1
#define SPACE 0
Trong đó XMAX  biểu thị số hàng max của mảng để biểu diễn màn hình, YMAX là số cột max, XMIN và YMIN là số hàng, cột min. Trong mảng Matrix thì ta qui định WALL (1) là giá trị tượng trương cho tường, nếu pacman gặp tường thì sẽ không đi được nữa. Giá trị SPACE(0) tượng trương là tượng trưng cho chỗ đường không có gì, mà sau này ta đặt nó là một dấu chấm, khi pacman ăn thì sẽ tăng điểm.
Ngoài ra chúng ta cần một vài hàm sau trong thư viện  GameLib.h để dùng cho việc vẽ các đối tượng ra màn hình cho đẹp:

#include <Windows.h>

#ifndef GAMELIB_H
#define GAMELIB_H
// Hàm thay d?i kích c? c?a khung cmd.
void resizeConsole(int width, int height)
{
       HWND console = GetConsoleWindow();
       RECT r;
       GetWindowRect(console, &r);
       MoveWindow(console, r.left, r.top, width, height, TRUE);
}

// Hàm tô màu.
void textcolor(int x)
{
       HANDLE mau;
       mau = GetStdHandle(STD_OUTPUT_HANDLE);
       SetConsoleTextAttribute(mau, x);
}

// Hàm d?ch chuy?n con tr? d?n t?a d? x, y.
void gotoxy(int x, int y)
{
       HANDLE hConsoleOutput;
       COORD Cursor_an_Pos = { x - 1, y - 1 };
       hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
       SetConsoleCursorPosition(hConsoleOutput, Cursor_an_Pos);
}

// Hàm xóa màn hình.
void XoaManHinh()
{
       HANDLE hOut;
       COORD Position;
       hOut = GetStdHandle(STD_OUTPUT_HANDLE);
       Position.X = 0;
       Position.Y = 0;
       SetConsoleCursorPosition(hOut, Position);
}


#endif

Vậy việc lên ý tưởng đã xong. Tut sau ta bắt tay vào viết game nhé.
Cảm ơn các bạn đã xem.