Công cụ bảo vệ mã nguồn .NET mạnh nhất, không thể unpack, miễn phí cho các khách hàng đầu tiên đăng ký.
Từ 1 tới 3 trên tổng số 3 kết quả

Đề tài: Mã nguồn trò chơi Rắn săn mồi

  1. #1
    Ngày gia nhập
    06 2013
    Bài viết
    74

    Mặc định Mã nguồn trò chơi Rắn săn mồi

    Chào các bạn hôm nay mình chia sẻ code của trò chơi rắn săn mồi được viểt bằng C++, trước đây mình chủ yếu code game hướng câu trúc, đây là lần đầu tiên mình code game bằng hướng đồi tượng. Mong các bạn nhận xét thật nhiều mình cảm ơn .

    snake.h
    Code:
    #include <Windows.h>
    #include <vector>
    
    #pragma once
    
    #define HEIGHT 20
    #define WIDTH 40
    #define X0 18
    #define Y0 10
    #define CHAR 219
    
    struct ToaDo{
    	int x0;
    	int y0;
    	int x;
    	int y;
    };
    
    enum STYLE{LEFT = 0, RIGHT, UP, DOWN};
    
    class snake
    {
    private:
    	ToaDo head;
    	std::vector<ToaDo>  tail;
    	bool gameOver;
    	int prev;
    	unsigned int score;
    	ToaDo tao;
    	int soDuoi;
    	int speed = 50;
    public:
    	snake();
    	~snake();
    	void veKhung();
    	void veRan();
    	void dieuKhien();
    	void xoaDiem(int x, int y);
    	void kiemTraThua();
    	void veTao();
    	void veDiem();
    	void kiemTraAn();
    	void initPrev(ToaDo& td);
    };

    snake.cpp
    Code:
    #include <iostream>
    #include <conio.h>
    #include "snake.h"
    #include <time.h>
    
    // Hàm thay đổ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ỏ đến tọa độ 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);
    }
    
    
    snake::snake()
    {
    	srand(time(NULL));
    	head.x = X0 + WIDTH / 2;
    	head.y = Y0 + HEIGHT / 2;
    
    	tao.x = X0 + 1 + rand() % (WIDTH - 1);
    	tao.y = Y0 + 1 + rand() % (HEIGHT - 1);
    
    	prev = RIGHT;
    	gameOver = false;
    	score = 0;
    	soDuoi = 1;
    
    	tail.push_back(head);
    }
    
    
    snake::~snake()
    {
    }
    
    void snake::veKhung(){
    	resizeConsole(800, 600);
    	SetConsoleTitle("Programmer: Tuan Nguyen Dinh - ndinhtuan15@gmail.com");
    	veTao();
    	veDiem();
    	veRan();
    
    
    	for (int i = X0; i <= X0 + WIDTH; i++){
    		textcolor(5);
    		gotoxy(i, Y0);
    		std::cout << char(CHAR);
    
    		gotoxy(i, Y0 + HEIGHT);
    		std::cout << char(CHAR);
    
    	}
    
    	for (int i = Y0; i <= Y0 + HEIGHT; i++){
    		gotoxy(X0, i);
    		std::cout << char(CHAR);
    
    		gotoxy(X0 + WIDTH, i);
    		std::cout << char(CHAR);
    	}
    	_getch();
    }
    
    void snake::veRan(){
    
    	textcolor(4);
    
    	for (int i = 0; i < tail.size(); i++){
    		if (i == 0){
    			gotoxy(tail[0].x, tail[0].y);
    			std::cout << "@";
    			//gotoxy(1, 1 + i); std::cout << tail[i].x0 << ";" << tail[i].y0 << "|" << tail[i].x << ";" << tail[i].y;
    		}
    		else{
    			initPrev(tail[i]);
    
    			gotoxy(tail[i].x, tail[i].y); std::cout << " ";
    
    			tail[i].x = tail[i - 1].x0;
    			tail[i].y = tail[i - 1].y0;
    
    			gotoxy(tail[i].x, tail[i].y); std::cout << "c";
    			//gotoxy(1, 1 + i); std::cout << tail[i].x0 << ";" << tail[i].y0 << "|" << tail[i].x << ";" << tail[i].y;
    		}
    	}
    	
    	Sleep(60 + speed);
    }
    
    void snake::dieuKhien(){
    	Sleep(15);
    	initPrev(tail[0]);
    	xoaDiem(head.x, head.y);
    	if (GetAsyncKeyState(VK_LEFT) && prev != RIGHT){
    		head.x--;
    		prev = LEFT;
    	}
    	else if (GetAsyncKeyState(VK_RIGHT) && prev != LEFT){
    		//xoaDiem(head.x, head.y);
    		head.x++;
    		prev = RIGHT;
    	}
    	else if (GetAsyncKeyState(VK_UP) && prev != DOWN){
    		//xoaDiem(head.x, head.y);
    		head.y--;
    		prev = UP;
    	}
    	else if (GetAsyncKeyState(VK_DOWN) && prev != UP){
    		//xoaDiem(head.x, head.y);
    		head.y++;
    		prev = DOWN;
    	}
    	else if (GetAsyncKeyState(32)){
    		gotoxy(2, 2);
    		system("pause");
    		gotoxy(2, 2);
    		std::cout << "                                                                      ";
    	}
    	else{
    		switch (prev){
    		case LEFT:
    			head.x--;
    			break;
    		case RIGHT:
    			head.x++;
    			break;
    		case UP:
    			head.y--;
    			break;
    		case DOWN:
    			head.y++;
    			break;
    		}
    	}
    
    	tail[0].x = head.x;
    	tail[0].y = head.y;
    
    }
    
    void snake::xoaDiem(int x, int y){
    	gotoxy(x, y);
    	std::cout << " ";
    }
    
    void snake::kiemTraThua(){
    	if (head.x <= X0 || head.x >= X0 + WIDTH){
    		gameOver = true;
    	}
    	if (head.y <= Y0 || head.y >= Y0 + HEIGHT){
    		gameOver = true;
    	}
    
    	// mode dam la chet
    	for (int i = 1; i < soDuoi; i++){
    		if (tail[0].x == tail[i].x && tail[0].y == tail[i].y){
    			gameOver = true;
    		}
    	}
    
    	if (gameOver){
    		gotoxy(X0 + WIDTH / 2 - 6, Y0 + HEIGHT / 2);
    		textcolor(9);
    		std::cout << "GAME OVER !";
    
    		std::cin.ignore(1);
    		//_getch();
    		exit(1);
    	}
    }
    
    void snake::veTao(){
    	textcolor(14);
    	gotoxy(tao.x, tao.y);
    	std::cout << "0";
    }
    
    void snake::veDiem(){
    	textcolor(15);
    	gotoxy(4 + WIDTH / 2, Y0 - 4);
    	std::cout << "Diem : " << score;
    }
    
    void snake::kiemTraAn(){
    	if (head.x == tao.x && head.y == tao.y){
    		score += 10;
    		soDuoi++;
    
    		if (score > 100){
    			speed = 0;
    		}
    
    		ToaDo t;
    		tail.push_back(t);
    
    		veDiem();
    		gotoxy(tao.x, tao.y);
    		std::cout << " ";
    		srand(time(NULL));
    		tao.x = X0 + 1 + rand() % (WIDTH - 1);
    		tao.y = Y0 + 1 + rand() % (HEIGHT - 1);
    		veTao();
    	}
    }
    
    void snake::initPrev(ToaDo& td){
    	td.x0 = td.x;
    	td.y0 = td.y;
    }
    main.cpp
    Code:
    #include <iostream>
    #include "snake.h"
    #include <conio.h>
    
    using namespace std;
    
    int main(){
    	snake ob;
    	ob.veKhung();
    
    	while (1){
    		ob.veRan();
    		ob.veTao();
    		
    		ob.dieuKhien();
    		ob.kiemTraAn();
    		ob.kiemTraThua();
    	}
    
    	_getch();
    	return 0;
    }
    Công cụ bảo vệ mã nguồn .NET mạnh nhất hiện tại, miễn phí cho các khách hàng đầu tiên đăng ký.

  2. #2
    Ngày gia nhập
    07 2011
    Bài viết
    474

    cái đầu tiên là phải viết comment. Ví dụ trong hàm veKhung có 2 cái for thì nên comment ở trên mỗi cái for bảo là cả đống code dưới để làm gì. Trong veRan cũng vậy, cái if để xử lý cái gì, cái else để xử lý cái gì. Trong dieuKhien thì tại sao gán tail[0] = head cũng nên comment 1 câu.

    cái thứ 2 là mỗi hàm/phương thức chỉ làm 1 nhiệm vụ đúng với tên của nó. Ví dụ hàm veRan chỉ nên vẽ con rắn ra màn hình, ko thay đổi gì tới con rắn hết => đây phải là const method: void veRan()const. Tại sao lại có gán tail[i] = tail[i-1] ở đây? Nếu muốn con rắn di chuyển thì nên tách ra void diChuyen().

    cái thứ 3 là sử dụng nạp chồng toán tử. Ví dụ trong code phải gán tail[i] = tail[i-1] thì nạp chồng toán tử trong ToaDo sao cho ghi code đúng như vậy, ko phải ghi tail[i].x = tail[i-1].x, tail[i].y = tail[i-1].y mất công.
    C++ Code:
    1. const ToaDo& operator=(const ToaDo& other)
    2. {
    3.     x = other.x;
    4.     y = other.y;
    5.     return *this;
    6. }
    tương tự cho head di chuyển up down left right thì viết 1 cái hàm cho ToaDo gọi là void move(int direction) cũng được. Viết vậy thì dieuKhien() sẽ rõ hơn, chỉ cần kiểm tra GetAsyncKeyState để thay đổi prev = UP / DOWN / LEFT / RIGHT là được. Còn head.x++ hay head.y++ thì để hàm diChuyen() lo, diChuyen sẽ gọi head.move(prev) chẳng hạn. Mỗi hàm chỉ làm 1 nhiệm vụ đúng tên của nó.
    C++ Code:
    1. void dieuKhien()
    2. {
    3.     if (GetAsyncKeyState(VK_UP) && direction != DOWN)
    4.         direction = UP;
    5.     else if (GetAsyncKeyState(VK_DOWN) && direction != UP)
    6.         direction = DOWN;
    7.     else if (GetAsyncKeyState(VK_LEFT) && direction != RIGHT)
    8.         direction = LEFT;
    9.     else if (GetAsyncKeyState(VK_RIGHT) && direction != LEFT)
    10.         direction = RIGHT;
    11. }

    cái thứ 4 là chọn tên cho phù hợp cái, ví dụ hướng đi con rắn mà chọn tên "prev" thì hơn kì, có thể chọn tên khác như headDirection hay direction hay dir. Hay cả cái thân (body) của con rắn mà đặt tên là "tail" . Với lại cần biến head làm gì, nếu có body rồi thì body[0] là tail/head, body[body.size()-1] là head/tail. Có thể là do cách xử lý con rắn của bạn nên cần tách ra làm head/tail. Theo ta chỉ cần 1 cái body là đủ Tên class cũng kì nữa: con rắn cần biến score và táo làm gì? nên đổi tên class thành SnakeGame cho đúng


    cái thứ 5, trong kiemtraThua():
    C++ Code:
    1.     for (int i = 1; i < soDuoi; i++){
    2.         if (tail[0].x == tail[i].x && tail[0].y == tail[i].y){
    3.             gameOver = true;
    4.         }
    5.     }
    có thể xài std::find trong<algorithm> để kiếm tail[0] trong tail[1...]. Có nhiều hàm có sẵn rồi khỏi cần viết lại làm gì.
    C++ Code:
    1. // tail collision
    2. gameOver = std::find(tail.begin()+1, tail.end(), tail[0]) != tail.end();
    Đã được chỉnh sửa lần cuối bởi INTP : 27-12-2015 lúc 10:42 PM.

  3. #3
    Ngày gia nhập
    06 2013
    Bài viết
    74

    Ok cảm ơn bạn . Cái head mĩnh cũng nghĩ bỏ đi nhưng trót viết lại lười xóa. Nhận xét của bạn rất bổ ích, mình có lẽ phải đọc nó nhiều lần . Cảm ơn bạn.
    Công cụ bảo vệ mã nguồn .NET mạnh nhất hiện tại, miễn phí cho các khách hàng đầu tiên đăng ký.
    Đã được chỉnh sửa lần cuối bởi theiron97 : 28-12-2015 lúc 12:14 AM.

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn