21xrx.com
2025-03-27 17:57:39 Thursday
文章检索 我的文章 写文章
C++编程教程:制作贪吃蛇游戏
2023-06-26 00:55:13 深夜i     15     0
C++ 编程教程 贪吃蛇 游戏制作 学习编程

贪吃蛇游戏是一款古老但经典的游戏,也是初学者入门编程的良好学习项目。本文将介绍使用C++语言制作贪吃蛇游戏的编程教程。

首先,我们需要准备一些必要的工具,如C++编译器和文本编辑器。建议初学者使用易于操作和功能完善的IDE集成环境,如Visual Studio等,以便更好地进行代码编写和调试。

接下来,我们需要确定游戏的基本规则和交互方式。贪吃蛇游戏的规则非常简单,游戏者需要控制一条小蛇在固定大小的矩形空间内移动,吃到食物得分并变长,但不得撞到自身或矩形边缘。游戏可使用键盘或鼠标进行控制。

然后,我们需要创建一个窗口,用来展示游戏场景和实现交互功能。在C++中,可以使用Windows API或SDL等库实现此功能。这里我们以Windows API为例,在编译过程中需要链接user32.lib库文件。创建窗口的部分代码如下:

#include <windows.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
  WNDCLASSEX wcex;
  HWND hWnd;
  MSG msg;
  TCHAR szWindowClass[] = TEXT("Snake");
  TCHAR szTitle[] = TEXT("Greedy Snake Game");
  wcex.cbSize = sizeof(WNDCLASSEX);
  wcex.style = CS_HREDRAW | CS_VREDRAW;
  wcex.lpfnWndProc = WndProc;
  wcex.cbClsExtra = 0;
  wcex.cbWndExtra = 0;
  wcex.hInstance = hInstance;
  wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
  wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  wcex.lpszMenuName = NULL;
  wcex.lpszClassName = szWindowClass;
  wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
  if (!RegisterClassEx(&wcex)) {
    MessageBox(NULL, TEXT("Window registration failed!"), TEXT("Greedy Snake Game"), NULL);
    return 1;
  }
  hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hInstance, NULL);
  if (!hWnd) {
    MessageBox(NULL, TEXT("Window creation failed!"), TEXT("Greedy Snake Game"), NULL);
    return 1;
  }
  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);
  while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
  PAINTSTRUCT ps;
  HDC hdc;
  switch (message) {
    case WM_PAINT:
      hdc = BeginPaint(hWnd, &ps);
      EndPaint(hWnd, &ps);
      break;
    case WM_DESTROY:
      PostQuitMessage(0);
      break;
    default:
      return DefWindowProc(hWnd, message, wParam, lParam);
  }
  return 0;
}

以上代码段创建了一个名为"Greedy Snake Game"的窗口,并注册了一个名为"Snake"的窗口类。在窗口处理函数WndProc中处理了窗口消息处理的部分。现在运行程序,将展示一个大小为640x480的窗口。

接下来,我们需要实现游戏的主要功能和逻辑。贪吃蛇的核心部分是实现蛇的移动和碰撞检测,还需要实现随机生成食物和计分。我们可以使用基本的数据结构,如数组和链表来实现。下面给出核心部分代码示例:

// 定义蛇的结构体
struct SnakeNode {
  int x;
  int y;
  SnakeNode* next;
};
SnakeNode* head; // 蛇头指针
SnakeNode* tail; // 蛇尾指针
int direction;  // 当前方向,1代表上,2代表下,3代表左,4代表右
int score;    // 得分
int food_x;    // 食物的横坐标
int food_y;    // 食物的纵坐标
void StartGame() {
  SnakeNode* newNode = new SnakeNode;
  head = newNode;
  tail = newNode;
  head->x = 10;
  head->y = 10;
  tail->x = 9;
  tail->y = 10;
  tail->next = head;
  direction = 4;
  score = 0;
  srand(time(NULL));
  GenerateFood();
}
void GenerateFood() {
  food_x = rand() % (640 / 10);
  food_y = rand() % (480 / 10);
}
void MoveSnake() {
  SnakeNode* newNode = new SnakeNode;
  newNode->x = head->x;
  newNode->y = head->y;
  switch (direction) {
    case 1:
      head->y--;
      break;
    case 2:
      head->y++;
      break;
    case 3:
      head->x--;
      break;
    case 4:
      head->x++;
      break;
    default:
      break;
  }
  if (head->x == food_x && head->y == food_y) {
    score += 10;
    GenerateFood();
    newNode->next = head;
    head = newNode;
  } else {
    newNode->next = head;
    head = newNode;
    SnakeNode* node = tail;
    while (node->next != head)
      node = node->next;
    
    tail = node;
    tail->next = NULL;
  }
}
bool CheckCollision() {
  SnakeNode* node = head->next;
  while (node) {
    if (node->x == head->x && node->y == head->y)
      return true;
    
    node = node->next;
  }
  if (head->x < 0 || head->y < 0 || head->x >= 640/10 || head->y >= 480/10)
    return true;
  
  return false;
}

以上代码段中定义了蛇的结构体和头和尾的指针,记录了蛇的运动方向、当前得分、食物坐标等信息,并实现了游戏初始化、蛇的移动、食物的生成和碰撞检测等功能。

最后我们需要将游戏画面完善,包括画蛇、画食物、显示得分等部分。我们可以使用Windows API中的GDI库来实现画图功能。最终的代码示例如下:

void PaintGame(HDC hdc) {
  MoveSnake();
  if (CheckCollision()) {
    KillTimer(hWnd, 1);
    char s[50];
    sprintf_s(s, "Game Over! The final score is %d", score);
    MessageBox(NULL, s, "Greedy Snake Game", NULL);
    exit(0);
  }
  Rectangle(hdc, food_x * 10, food_y * 10, food_x * 10 + 10, food_y * 10 + 10);
  SnakeNode* node = head;
  while (node) {
    Rectangle(hdc, node->x * 10, node->y * 10, node->x * 10 + 10, node->y * 10 + 10);
    node = node->next;
  }
  char s[20];
  sprintf_s(s, "Score: %d", score);
  TextOut(hdc, 20, 20, s, strlen(s));
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
  PAINTSTRUCT ps;
  HDC hdc;
  switch (message) {
    case WM_PAINT:
      hdc = BeginPaint(hWnd, &ps);
      PaintGame(hdc);
      EndPaint(hWnd, &ps);
      break;
    case WM_DESTROY:
      PostQuitMessage(0);
      break;
    case WM_KEYDOWN:
      switch (wParam) {
        case VK_UP:
          if (direction != 2)
            direction = 1;
          
          break;
        case VK_DOWN:
          if (direction != 1)
            direction = 2;
          
          break;
        case VK_LEFT:
          if (direction != 4)
            direction = 3;
          
          break;
        case VK_RIGHT:
          if (direction != 3)
            direction = 4;
          
          break;
        default:
          break;
      }
      break;
    case WM_TIMER:
      InvalidateRect(hWnd, NULL, TRUE);
      break;
    case WM_CREATE:
      SetTimer(hWnd, 1, 100, NULL);
      StartGame();
      break;
    default:
      return DefWindowProc(hWnd, message, wParam, lParam);
  }
  return 0;
}

最后,我们只需要将以上代码整合到一个完整的C++文件中进行编译和执行,就能够愉快地玩耍我们自己制作的贪吃蛇游戏了。

  
  

评论区