0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

C語言零基礎(chǔ)項目:俄羅斯方塊游戲!詳細(xì)思路+源碼分享

C語言編程學(xué)習(xí)基地 ? 來源:C語言編程學(xué)習(xí)基地 ? 作者:C語言編程學(xué)習(xí)基地 ? 2022-12-19 14:52 ? 次閱讀

每天一個C語言小項目,提升你的編程能力!

俄羅斯方塊是童年的經(jīng)典游戲~~

由小方塊組成的不同形狀的板塊陸續(xù)從屏幕上方落下來,玩家通過調(diào)整板塊的位置和方向,使它們在屏幕底部拼出完整的一條或幾條。這些完整的橫條會隨即消失,給新落下來的板塊騰出空間,與此同時,玩家得到分?jǐn)?shù)獎勵。沒有被消除掉的方塊不斷堆積起來,一旦堆到屏幕頂端,玩家便告輸,游戲結(jié)束。

本次用C語言來實現(xiàn)!這個程序在界面上沒有做額外的修飾,重點放在游戲手感和消息處理過程。游戲手感上做了一些細(xì)節(jié)處理,仔細(xì)體驗感受一下。

效果如圖:

56009552-7d2d-11ed-8abf-dac502259ad0.png

其中也是加入了按鍵操作功能:"A"左移一格;"D"右移一格;"W"旋轉(zhuǎn)方塊;S 下移一格;空格鍵讓方塊下落到底),"ESC"健退出游戲,用戶還可以自己根據(jù)自定義習(xí)慣的按鍵來操作游戲。

編譯環(huán)境:Visual Studio 2019/2022,EasyX插件

代碼展示:

#include 
#include 
#include 
#include 






/////////////////////////////////////////////
// 定義常量、枚舉量、結(jié)構(gòu)體、全局變量
/////////////////////////////////////////////


#define  WIDTH  10    // 游戲區(qū)寬度
#define  HEIGHT  22    // 游戲區(qū)高度
#define  UNIT  20    // 每個游戲區(qū)單位的實際像素


// 定義操作類型
enum CMD
{
  CMD_ROTATE,            // 方塊旋轉(zhuǎn)
  CMD_LEFT, CMD_RIGHT, CMD_DOWN,  // 方塊左、右、下移動
  CMD_SINK,            // 方塊沉底
  CMD_QUIT            // 退出游戲
};


// 定義繪制方塊的方法
enum DRAW
{
  SHOW,  // 顯示方塊
  CLEAR,  // 擦除方塊
  FIX    // 固定方塊
};


// 定義七種俄羅斯方塊
struct BLOCK
{
  WORD dir[4];  // 方塊的四個旋轉(zhuǎn)狀態(tài)
  COLORREF color;  // 方塊的顏色
};
BLOCK g_Blocks[7] = {  {0x0F00, 0x4444, 0x0F00, 0x4444, RED},    // I
            {0x0660, 0x0660, 0x0660, 0x0660, BLUE},    // 口
            {0x4460, 0x02E0, 0x0622, 0x0740, MAGENTA},  // L
            {0x2260, 0x0E20, 0x0644, 0x0470, YELLOW},  // 反 L
            {0x0C60, 0x2640, 0x0C60, 0x2640, CYAN},    // Z
            {0x0360, 0x4620, 0x0360, 0x4620, GREEN},  // 反 Z
            {0x4E00, 0x4C40, 0x0E40, 0x4640, BROWN}};  // T


// 定義當(dāng)前方塊、下一個方塊的信息
struct BLOCKINFO
{
  byte id;  // 方塊 ID
  char x, y;  // 方塊在游戲區(qū)中的坐標(biāo)
  byte dir:2;  // 方向
}  g_CurBlock, g_NextBlock;


// 定義游戲區(qū)
BYTE g_World[WIDTH][HEIGHT] = {0};






/////////////////////////////////////////////
// 函數(shù)聲明
/////////////////////////////////////////////


void Init();                      // 初始化游戲
void Quit();                      // 退出游戲
void NewGame();                      // 開始新游戲
void GameOver();                    // 結(jié)束游戲
CMD GetCmd();                      // 獲取控制命令
void DispatchCmd(CMD _cmd);                // 分發(fā)控制命令
void NewBlock();                    // 生成新的方塊
bool CheckBlock(BLOCKINFO _block);            // 檢測指定方塊是否可以放下
void DrawUnit(int x, int y, COLORREF c, DRAW _draw);  // 畫單元方塊
void DrawBlock(BLOCKINFO _block, DRAW _draw = SHOW);  // 畫方塊
void OnRotate();                    // 旋轉(zhuǎn)方塊
void OnLeft();                      // 左移方塊
void OnRight();                      // 右移方塊
void OnDown();                      // 下移方塊
void OnSink();                      // 沉底方塊






/////////////////////////////////////////////
// 函數(shù)定義
/////////////////////////////////////////////


// 主函數(shù)
void main()
{
  Init();


  CMD c;
  while(true)
  {
    c = GetCmd();
    DispatchCmd(c);


    // 按退出時,顯示對話框咨詢用戶是否退出
    if (c == CMD_QUIT)
    {
      HWND wnd = GetHWnd();
      if (MessageBox(wnd, _T("您要退出游戲嗎?"), _T("提醒"), MB_OKCANCEL | MB_ICONQUESTION) == IDOK)
        Quit();
    }
  }
}




// 初始化游戲
void Init()
{
  initgraph(640, 480);
  srand((unsigned)time(NULL));
  setbkmode(TRANSPARENT);      // 設(shè)置圖案填充的背景色為透明


  // 顯示操作說明
  settextstyle(14, 0, _T("宋體"));
  outtextxy(20, 330, _T("操作說明"));
  outtextxy(20, 350, _T("上:旋轉(zhuǎn)"));
  outtextxy(20, 370, _T("左:左移"));
  outtextxy(20, 390, _T("右:右移"));
  outtextxy(20, 410, _T("下:下移"));
  outtextxy(20, 430, _T("空格:沉底"));
  outtextxy(20, 450, _T("ESC:退出"));


  // 設(shè)置坐標(biāo)原點
  setorigin(220, 20);


  // 繪制游戲區(qū)邊界
  rectangle(-1, -1, WIDTH * UNIT, HEIGHT * UNIT);
  rectangle((WIDTH + 1) * UNIT - 1, -1, (WIDTH + 5) * UNIT, 4 * UNIT);


  // 開始新游戲
  NewGame();
}




// 退出游戲
void Quit()
{
  closegraph();
  exit(0);
}




// 開始新游戲
void NewGame()
{
  // 清空游戲區(qū)
  setfillcolor(BLACK);
  solidrectangle(0, 0, WIDTH * UNIT - 1, HEIGHT * UNIT - 1);
  ZeroMemory(g_World, WIDTH * HEIGHT);


  // 生成下一個方塊
  g_NextBlock.id = rand() % 7;
  g_NextBlock.dir = rand() % 4;
  g_NextBlock.x = WIDTH + 1;
  g_NextBlock.y = HEIGHT - 1;


  // 獲取新方塊
  NewBlock();
}




// 結(jié)束游戲
void GameOver()
{
  HWND wnd = GetHWnd();
  if (MessageBox(wnd, _T("游戲結(jié)束。
您想重新來一局嗎?"), _T("游戲結(jié)束"), MB_YESNO | MB_ICONQUESTION) == IDYES)
    NewGame();
  else
    Quit();
}




// 獲取控制命令
DWORD m_oldtime;
CMD GetCmd()
{
  // 獲取控制值
  while(true)
  {
    // 如果超時,自動下落一格
    DWORD newtime = GetTickCount();
    if (newtime - m_oldtime >= 500)
    {
      m_oldtime = newtime;
      return CMD_DOWN;
    }


    // 如果有按鍵,返回按鍵對應(yīng)的功能
    if (_kbhit())
    {
      switch(_getch())
      {
        case 'w':
        case 'W':  return CMD_ROTATE;
        case 'a':
        case 'A':  return CMD_LEFT;
        case 'd':
        case 'D':  return CMD_RIGHT;
        case 's':
        case 'S':  return CMD_DOWN;
        case 27:  return CMD_QUIT;
        case ' ':  return CMD_SINK;
        case 0:
        case 0xE0:
          switch(_getch())
          {
            case 72:  return CMD_ROTATE;
            case 75:  return CMD_LEFT;
            case 77:  return CMD_RIGHT;
            case 80:  return CMD_DOWN;
          }
      }
    }


    // 延時 (降低 CPU 占用率)
    Sleep(20);
  }
}




// 分發(fā)控制命令
void DispatchCmd(CMD _cmd)
{
  switch(_cmd)
  {
    case CMD_ROTATE:  OnRotate();    break;
    case CMD_LEFT:    OnLeft();    break;
    case CMD_RIGHT:    OnRight();    break;
    case CMD_DOWN:    OnDown();    break;
    case CMD_SINK:    OnSink();    break;
    case CMD_QUIT:    break;
  }
}




// 生成新的方塊
void NewBlock()
{
  g_CurBlock.id = g_NextBlock.id,    g_NextBlock.id = rand() % 7;
  g_CurBlock.dir = g_NextBlock.dir,  g_NextBlock.dir = rand() % 4;
  g_CurBlock.x = (WIDTH - 4) / 2;
  g_CurBlock.y = HEIGHT + 2;


  // 下移新方塊直到有局部顯示
  WORD c = g_Blocks[g_CurBlock.id].dir[g_CurBlock.dir];
  while((c & 0xF) == 0)
  {
    g_CurBlock.y--;
    c >>= 4;
  }


  // 繪制新方塊
  DrawBlock(g_CurBlock);


  // 繪制下一個方塊
  setfillcolor(BLACK);
  solidrectangle((WIDTH + 1) * UNIT, 0, (WIDTH + 5) * UNIT - 1, 4 * UNIT - 1);
  DrawBlock(g_NextBlock);


  // 設(shè)置計時器,用于判斷自動下落
  m_oldtime = GetTickCount();
}




// 畫單元方塊
void DrawUnit(int x, int y, COLORREF c, DRAW _draw)
{
  // 計算單元方塊對應(yīng)的屏幕坐標(biāo)
  int left = x * UNIT;
  int top = (HEIGHT - y - 1) * UNIT;
  int right = (x + 1) * UNIT - 1;
  int bottom = (HEIGHT - y) * UNIT - 1;


  // 畫單元方塊
  switch(_draw)
  {
    case SHOW:
      // 畫普通方塊
      setlinecolor(0x006060);
      roundrect(left + 1, top + 1, right - 1, bottom - 1, 5, 5);
      setlinecolor(0x003030);
      roundrect(left, top, right, bottom, 8, 8);
      setfillcolor(c);
      setlinecolor(LIGHTGRAY);
      fillrectangle(left + 2, top + 2, right - 2, bottom - 2);
      break;


    case FIX:
      // 畫固定的方塊
      setfillcolor(RGB(GetRValue(c) * 2 / 3, GetGValue(c) * 2 / 3, GetBValue(c) * 2 / 3));
      setlinecolor(DARKGRAY);
      fillrectangle(left + 1, top + 1, right - 1, bottom - 1);
      break;


    case CLEAR:
      // 擦除方塊
      setfillcolor(BLACK);
      solidrectangle(x * UNIT, (HEIGHT - y - 1) * UNIT, (x + 1) * UNIT - 1, (HEIGHT - y) * UNIT - 1);
      break;
  }
}




// 畫方塊
void DrawBlock(BLOCKINFO _block, DRAW _draw)
{
  WORD b = g_Blocks[_block.id].dir[_block.dir];
  int x, y;


  for(int i = 0; i < 16; i++, b <<= 1)
    if (b & 0x8000)
    {
      x = _block.x + i % 4;
      y = _block.y - i / 4;
      if (y < HEIGHT)
        DrawUnit(x, y, g_Blocks[_block.id].color, _draw);
    }
}




// 檢測指定方塊是否可以放下
bool CheckBlock(BLOCKINFO _block)
{
  WORD b = g_Blocks[_block.id].dir[_block.dir];
  int x, y;


  for(int i = 0; i < 16; i++, b <<= 1)
    if (b & 0x8000)
    {
      x = _block.x + i % 4;
      y = _block.y - i / 4;
      if ((x < 0) || (x >= WIDTH) || (y < 0))
        return false;


      if ((y < HEIGHT) && (g_World[x][y]))
        return false;
    }


  return true;
}




// 旋轉(zhuǎn)方塊
void OnRotate()
{
  // 獲取可以旋轉(zhuǎn)的 x 偏移量
  int dx;
  BLOCKINFO tmp = g_CurBlock;
  tmp.dir++;          if (CheckBlock(tmp))  {  dx = 0;    goto rotate;  }
  tmp.x = g_CurBlock.x - 1;  if (CheckBlock(tmp))  {  dx = -1;  goto rotate;  }
  tmp.x = g_CurBlock.x + 1;  if (CheckBlock(tmp))  {  dx = 1;    goto rotate;  }
  tmp.x = g_CurBlock.x - 2;  if (CheckBlock(tmp))  {  dx = -2;  goto rotate;  }
  tmp.x = g_CurBlock.x + 2;  if (CheckBlock(tmp))  {  dx = 2;    goto rotate;  }
  return;


rotate:
  // 旋轉(zhuǎn)
  DrawBlock(g_CurBlock, CLEAR);
  g_CurBlock.dir++;
  g_CurBlock.x += dx;
  DrawBlock(g_CurBlock);
}




// 左移方塊
void OnLeft()
{
  BLOCKINFO tmp = g_CurBlock;
  tmp.x--;
  if (CheckBlock(tmp))
  {
    DrawBlock(g_CurBlock, CLEAR);
    g_CurBlock.x--;
    DrawBlock(g_CurBlock);
  }
}




// 右移方塊
void OnRight()
{
  BLOCKINFO tmp = g_CurBlock;
  tmp.x++;
  if (CheckBlock(tmp))
  {
    DrawBlock(g_CurBlock, CLEAR);
    g_CurBlock.x++;
    DrawBlock(g_CurBlock);
  }
}




// 下移方塊
void OnDown()
{
  BLOCKINFO tmp = g_CurBlock;
  tmp.y--;
  if (CheckBlock(tmp))
  {
    DrawBlock(g_CurBlock, CLEAR);
    g_CurBlock.y--;
    DrawBlock(g_CurBlock);
  }
  else
    OnSink();  // 不可下移時,執(zhí)行“沉底方塊”操作
}




// 沉底方塊
void OnSink()
{
  int i, x, y;


  // 連續(xù)下移方塊
  DrawBlock(g_CurBlock, CLEAR);
  BLOCKINFO tmp = g_CurBlock;
  tmp.y--;
  while (CheckBlock(tmp))
  {
    g_CurBlock.y--;
    tmp.y--;
  }
  DrawBlock(g_CurBlock, FIX);


  // 固定方塊在游戲區(qū)
  WORD b = g_Blocks[g_CurBlock.id].dir[g_CurBlock.dir];
  for(i = 0; i < 16; i++, b <<= 1)
    if (b & 0x8000)
    {
      if (g_CurBlock.y - i / 4 >= HEIGHT)
      {  // 如果方塊的固定位置超出高度,結(jié)束游戲
        GameOver();
        return;
      }
      else
        g_World[g_CurBlock.x + i % 4][g_CurBlock.y - i / 4] = 1;
    }


  // 檢查是否需要消掉行,并標(biāo)記
  BYTE remove = 0;  // 低 4 位用來標(biāo)記方塊涉及的 4 行是否有消除行為
  for(y = g_CurBlock.y; y >= max(g_CurBlock.y - 3, 0); y--)
  {
    i = 0;
    for(x = 0; x < WIDTH; x++)
      if (g_World[x][y] == 1)
        i++;


    if (i == WIDTH)
    {
      remove |= (1 << (g_CurBlock.y - y));
      setfillcolor(LIGHTGREEN);
      setlinecolor(LIGHTGREEN);
      setfillstyle(BS_HATCHED, HS_DIAGCROSS);
      fillrectangle(0, (HEIGHT - y - 1) * UNIT + UNIT / 2 - 5, WIDTH * UNIT - 1, (HEIGHT - y - 1) * UNIT + UNIT / 2 + 5);
      setfillstyle(BS_SOLID);
    }
  }


  if (remove)  // 如果產(chǎn)生整行消除
  {
    // 延時 300 毫秒
    Sleep(300);


    // 擦掉剛才標(biāo)記的行
    IMAGE img;
    for(i = 0; i < 4; i++, remove >>= 1)
    {
      if (remove & 1)
      {
        for(y = g_CurBlock.y - i + 1; y < HEIGHT; y++)
          for(x = 0; x < WIDTH; x++)
          {
            g_World[x][y - 1] = g_World[x][y];
            g_World[x][y] = 0;
          }


        getimage(&img, 0, 0, WIDTH * UNIT, (HEIGHT - (g_CurBlock.y - i + 1)) * UNIT);
        putimage(0, UNIT, &img);
      }
    }
  }


  // 產(chǎn)生新方塊
  NewBlock();
}

大家趕緊去動手試試吧!

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 游戲
    +關(guān)注

    關(guān)注

    2

    文章

    733

    瀏覽量

    26261
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7594

    瀏覽量

    135857
  • 源碼
    +關(guān)注

    關(guān)注

    8

    文章

    632

    瀏覽量

    29110

原文標(biāo)題:C語言零基礎(chǔ)項目:俄羅斯方塊游戲!詳細(xì)思路+源碼分享

文章出處:【微信號:cyuyanxuexi,微信公眾號:C語言編程學(xué)習(xí)基地】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    俄羅斯方塊游戲實例

    一個很完善的俄羅斯方塊游戲
    發(fā)表于 01-10 17:45

    俄羅斯方塊

    單片機(jī)做的俄羅斯方塊游戲
    發(fā)表于 07-31 19:56

    好玩的俄羅斯方塊游戲仿真

    好玩的俄羅斯方塊游戲仿真,學(xué)protues看到的,很好玩,分享下
    發(fā)表于 10-21 20:31

    c語言版的俄羅斯方塊

    c語言版的俄羅斯方塊自己寫的,一時高興和大家分享
    發(fā)表于 12-03 18:09

    游戲手柄俄羅斯方塊

    本帖最后由 依然Dirk 于 2015-1-21 15:52 編輯 游戲手柄俄羅斯方塊
    發(fā)表于 01-21 15:27

    誰有俄羅斯方塊游戲機(jī)的源碼

    如題,誰有俄羅斯方塊游戲機(jī)的源碼
    發(fā)表于 10-24 18:02

    帶AI的俄羅斯方塊

    本帖最后由 shi_dongyu 于 2017-2-11 08:05 編輯 這周花了幾天時間研究了下俄羅斯方塊,并寫了一個帶AI的俄羅斯方塊游戲。我想這個游戲對每個人都很熟悉,很
    發(fā)表于 02-10 20:08

    采用單片機(jī)來實現(xiàn)的智能俄羅斯方塊游戲

    游戲,該設(shè)計選用的處理器型號為AT89C51的單片機(jī)。重點從軟件工程角度論述了俄羅斯方塊模型構(gòu)造,圖形旋轉(zhuǎn),坐標(biāo)變換,雙人游戲中多任務(wù)實時操作的設(shè)計方法與實現(xiàn)。2.硬件設(shè)計總體電路圖硬
    發(fā)表于 11-19 08:26

    俄羅斯方塊源碼(帶煙花版)

    俄羅斯方塊源碼(帶煙花版)游戲簡介經(jīng)典游戲,俄羅斯方塊源碼公布。我爭取簡化功能,使結(jié)構(gòu)清晰、框
    發(fā)表于 08-02 09:55 ?0次下載

    基于c#的游戲設(shè)計_俄羅斯方塊論文終結(jié)版

    基于c#的游戲設(shè)計——俄羅斯方塊,內(nèi)容包括源代碼的詳細(xì)介紹,源代碼,功能以及怎么實現(xiàn)等。
    發(fā)表于 11-25 14:34 ?0次下載

    俄羅斯方塊游戲設(shè)計原理

    俄羅斯方塊游戲是VHDL 應(yīng)用于復(fù)雜數(shù)字系統(tǒng)的一個經(jīng)典設(shè)計,本章將詳細(xì)介紹該游戲的設(shè)計原理和設(shè)計方法。其中包括系統(tǒng)構(gòu)成、系統(tǒng)設(shè)計原理和系統(tǒng)各個模塊的實現(xiàn)方法。
    發(fā)表于 09-01 17:24 ?0次下載

    使用STM32系列單片機(jī)設(shè)計的俄羅斯方塊游戲的程序免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是使用STM32系列單片機(jī)設(shè)計的俄羅斯方塊游戲的程序免費(fèi)下載。可以使用STM32F系列通過該例程程序通過TFT屏幕顯示俄羅斯方塊
    發(fā)表于 05-13 08:00 ?25次下載
    使用STM32系列單片機(jī)設(shè)計的<b class='flag-5'>俄羅斯方塊</b><b class='flag-5'>游戲</b>的程序免費(fèi)下載

    使用labview進(jìn)行俄羅斯方塊游戲程序

    本文檔的主要內(nèi)容詳細(xì)介紹的是使用labview進(jìn)行俄羅斯方塊游戲程序。
    發(fā)表于 05-21 08:00 ?97次下載
    使用labview進(jìn)行<b class='flag-5'>俄羅斯方塊</b>的<b class='flag-5'>游戲</b>程序

    使用C語言C++編寫俄羅斯方塊的資料和源代碼免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是使用C語言C++編寫俄羅斯方塊的資料和源代碼免費(fèi)下載。
    發(fā)表于 06-10 08:00 ?4次下載
    使用<b class='flag-5'>C</b><b class='flag-5'>語言</b>和<b class='flag-5'>C</b>++編寫<b class='flag-5'>俄羅斯方塊</b>的資料和源代碼免費(fèi)下載

    基于51單片機(jī)的俄羅斯方塊游戲

    俄羅斯方塊游戲,該設(shè)計選用的處理器型號為AT89C51的單片機(jī)。重點從軟件工程角度論述了俄羅斯方塊模型構(gòu)造,圖形旋轉(zhuǎn),坐標(biāo)變換,雙人游戲中多
    發(fā)表于 11-13 10:21 ?57次下載
    基于51單片機(jī)的<b class='flag-5'>俄羅斯方塊</b><b class='flag-5'>游戲</b>