(更新中……)
參考部落格:
https://blog.csdn.net/qq_39151563/article/details/104283217
https://blog.csdn.net/qq_39151563/article/details/104342530
由于放在一篇會導緻篇幅太長,是以分成了幾篇。(可能有個10篇吧=.=)
目前寫完的:
- 2048遊戲系列—總覽篇
- 2048遊戲系列—功能子產品第一稿【矩陣操作】
- 2048遊戲系列—功能子產品第二稿【鍵盤輸入】
- 2048遊戲系列—功能子產品第三稿【添加新數】
- 2048遊戲系列—功能子產品第四稿【結束檢測】
本篇介紹如何把數字轉化為圖檔輸出。
相關圖檔資源下載下傳:2048圖檔 提取碼:u0h3
一、圖檔的命名
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI2EzX4xSZz91ZsAzNfRHLGZkRGZkRfJ3bs92YsAjMfVmepNHLlZDT2YTcMVjRXBXN1dVW1I2QaVTQClGVF5UMR9Fd4VGdsATNfd3bkFGazxycykFaKdkYzZUbapXNXlleSdVY2pESa9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zRQpkL4gjYmFTN4AzYmdTO4AjZhRjZjRTNjV2YxUTOxMjNxI2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
2的1次方 到 2的17次方,本篇用到背景圖、格子圖和
gameOver
圖, 共19張圖。
二、圖檔加載
-
格式化字元串sprintf
#include <iostream>
#include "graphics.h"
using namespace std;
int main()
{
char imgAdress[40];
//PIMAGE BlockImgs[18];//EGE圖檔形式
for(int i=1,num=2; i<18; i++,num*=2)
{
sprintf(imgAdress,"image\\block_%d.png",num);
cout << imgAdress << endl;
}
return 0;
}
運作結果是圖檔的相對路徑:
-
圖檔操作EGE
- 擷取圖像
getimage()
參考部落格裡寫了很多,這裡這用
第一個參數是getimage(BlockImgs[i], imgAdress);
PIMAGE
對象,第二個參數是圖檔位址(建議用相對路徑,這樣友善移動檔案夾)
要把圖檔檔案夾放在于
main.cpp
同一目錄下
将
位址的圖檔”賦 給“imgAddress
對象,這樣我們就可以在程式中進行引用了。BlockImgs[i]
- 繪制圖像
putimage()
最常用的,
本篇用的:putimage(x, y, pimg);
putimage_withalpha(NULL,pimg,x,y)
void EGEAPI putimage ( int dstX, int dstY, //目标位置(X,Y) const PIMAGE pSrcImg, //源圖像 DWORD dwRop = SRCCOPY //最後一個參數是三元光栅操作碼,不用管它,不寫就行, //因為它有預設參數SRCCOPY (預設參數就是如果不寫,就傳入預設的值)。 ); int putimage_withalpha( PIMAGE imgdest, // 目标圖像 PIMAGE imgsrc, // 源圖像 int dstX, // 目标圖像左上角x坐标 int dstY, // 目标圖像左上角y坐标 int srcX = 0, // 源圖像左上角x坐标 int srcY = 0, // 源圖像左上角y坐标 int srcWidth = 0, // 原圖像混合區域寬度 int srcHeight = 0 // 源圖像混合區域高度 );
- 擷取圖像
三、圖檔的尺寸
- 背景圖檔尺寸:500*500
【C++】2048遊戲系列---優化子產品第一稿【加載圖檔】一、圖檔的命名二、圖檔加載三、圖檔的尺寸四、圖檔的釋放五、所有的代碼六、運作結果 - Block圖檔尺寸:106*106
【C++】2048遊戲系列---優化子產品第一稿【加載圖檔】一、圖檔的命名二、圖檔加載三、圖檔的尺寸四、圖檔的釋放五、所有的代碼六、運作結果 - 尺寸計算:
圖中紅色的點
(x,y)
就是我們要放照片函數
putimage_withalpha(NULL,pimg,x,y)
裡面的參數
- 周遊紅點放照片
運作結果:const int DEVIDE = 15; const int GRID_WIDTH = 106; void Draw() { putimage_withalpha(NULL,BlockImgs[0],0,0);//放背景 for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { int x = (j+1)*DEVIDE + j*GRID_WIDTH; int y = (i+1)*DEVIDE + i*GRID_WIDTH; //cout << "(x,y) = " << "(" << x << ","<< y << ")" << endl; if(grid[i][j]!=0) { putimage_withalpha(NULL,BlockImgs[grid[i][j]],x,y); } } } }
【C++】2048遊戲系列---優化子產品第一稿【加載圖檔】一、圖檔的命名二、圖檔加載三、圖檔的尺寸四、圖檔的釋放五、所有的代碼六、運作結果
四、圖檔的釋放
在圖檔無用後或遊戲結束後,應該釋放圖檔記憶體空間
對應的函數:
delimage(pimg);
void ReleaseImgs()
{
for(int i=0; i<18; i++)
{
delimage(BlockImgs[i]);
}
delimage(GameOverImg);
}
五、所有的代碼
#include <iostream>
#include "graphics.h"
using namespace std;
//測試矩陣
int grid[4][4] = {0
// {1,2,3,4},
// {4,5,6,7},
// {7,8,9,10},
// {1,1,1,0}
};
int EmptyBlock = 4 ; //空格數
int dir = -1; // 0-左,1-上,2-右,3-下
//列印函數
void PrintGrid()
{
for(int i=0; i<4; i++)
{
for(int j=0; j<4; j++)
cout << grid[i][j] << " ";
cout << endl;
}
cout << endl;
}
//計算空格函數
int CalculateEmpty()
{
int cnt = 0;
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
if(grid[i][j]==0) cnt++;
return cnt;
}
//顯示資訊
void ShowInfo()
{
cout << "dir = " << dir << endl;
cout<< "EmptyBlock = " << CalculateEmpty() << endl;
cout << "grid[4][4] = " << endl;
PrintGrid();
}
//移動函數
static int x0[4] = {0, 0, 3, 0};
static int y0[4] = {0, 0, 0, 3};
static int firstOffset[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
static int secondOffset[4][2] = {{0,1},{1,0},{0,1} ,{1,0}};
void Move(int dir)
{
//bool moved = false;
if(dir==-1) return;
int tx, ty;
int t1x, t1y;
int t2x, t2y;
for(int i=0; i<4; i++)
{
tx = x0[dir] + i*secondOffset[dir][0];
ty = y0[dir] + i*secondOffset[dir][1];
//cout << "(" << tx << ", " << ty << ")" << endl;
t1x = tx;
t1y = ty;
t2x = tx + firstOffset[dir][0];
t2y = ty + firstOffset[dir][1];
for( ;t2x>=0&&t2x<=3&&t2y>=0&&t2y<=3; t2x+=firstOffset[dir][0],t2y+=firstOffset[dir][1])
{
if(grid[t2y][t2x]!=0)
{
if(grid[t1y][t1x]==0)
{
grid[t1y][t1x] = grid[t2y][t2x];
grid[t2y][t2x] = 0;
// moved = true;
}
else if(grid[t1y][t1x]==grid[t2y][t2x])
{
grid[t1y][t1x]++;
grid[t2y][t2x] = 0;
t1x += firstOffset[dir][0];
t1y += firstOffset[dir][1];
// moved = true;
}
else if(t1x+firstOffset[dir][0]!=t2x||t1y+firstOffset[dir][1]!=t2y)
{
grid[t1y+firstOffset[dir][1]][t1x+firstOffset[dir][0]] = grid[t2y][t2x];
grid[t2y][t2x] = 0;
t1x += firstOffset[dir][0];
t1y += firstOffset[dir][1];
//cout << "Move Test" << endl;
// moved = true;
}
else
{
t1x += firstOffset[dir][0];
t1y += firstOffset[dir][1];
}
}
}
}
//return moved;
}
//添加新數
void Addnum(int n)
{
while(n--)//添加n個
{
EmptyBlock = CalculateEmpty();
if(EmptyBlock<=0)
{
//cout << "addnum EmptyBlock = " << EmptyBlock << endl;
//cout << "addnum Test1" << endl;
return;
}
int cnt = random(EmptyBlock)+1;//随機得到一個空格數以内的數
//cout << "找到第" << cnt << "個空位" << endl;
//cout << "cnt = " << cnt << endl;
int *p = &grid[0][0]-1;//記錄矩陣首位址前一個 ,因為後面的 p 在找到時還會 ++
//cout << "n = "<< n <<endl;
for(int i=0; i<4&&cnt; i++)
for(int j=0; j<4&&cnt; j++)
{
if(grid[i][j]==0 && cnt)//如果有空格并且cnt有效
{
//cout << "cnt = " << cnt << endl;
cnt--;//找到一個劃一個
}
p++;//p 指向下一個再進行判斷
}
//循環結束時 p 指向我們之前随機指定的空格
*p = (random(10)==0)?2:1;// 0.1 的機率為2,0.9 的機率為1
//cout << "插入成功" << endl;
//*p = (random(10)==0)+1;//這樣寫也可以
EmptyBlock--;
}
}
PIMAGE BlockImgs[18];//EGE圖檔形式
PIMAGE GameOverImg;
//加載圖檔
void LoadImgs()
{
char imgAdress[40];
for(int i=1,num=2; i<18; i++,num*=2)
{
sprintf(imgAdress,"image\\block_%d.png",num);
BlockImgs[i] = newimage();
getimage(BlockImgs[i], imgAdress);
//cout << imgAdress << endl;
}
BlockImgs[0] = newimage();
GameOverImg = newimage();
getimage(BlockImgs[0],"image\\background.png");
getimage(GameOverImg,"image\\gameOver.png");
cout<< "讀取圖檔成功" << endl;
}
//釋放圖檔
void ReleaseImgs()
{
for(int i=0; i<18; i++)
{
delimage(BlockImgs[i]);
}
delimage(GameOverImg);
}
const int DEVIDE = 15;
const int GRID_WIDTH = 106;
void Draw()
{
cleardevice();
putimage_withalpha(NULL,BlockImgs[0],0,0);
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
int x = (j+1)*DEVIDE + j*GRID_WIDTH;
int y = (i+1)*DEVIDE + i*GRID_WIDTH;
//cout << "(x,y) = " << "(" << x << ","<< y << ")" << endl;
if(grid[i][j]!=0)
{
putimage_withalpha(NULL,BlockImgs[grid[i][j]],x,y);
}
}
}
}
bool gameOver()
{
EmptyBlock = CalculateEmpty();
if(EmptyBlock>0) return false;
for(int i=0;i<4;i++)
{
int t1=0,t2=1;
while(t2<=3)
{
if(grid[i][t1]==grid[i][t2] || grid[t1][i]==grid[t2][i])// 橫 ||縱
{
return false;
}
else
{
t1++;
t2++;
}
}
}
return true;
}
int main()
{
initgraph(500, 500);
setbkcolor(WHITE);
Addnum(2); //在随機2個位置添加新數
ShowInfo();
LoadImgs();
Draw();
for ( ; is_run(); delay_fps(60) )
{
//cleardevice();
// todo: 邏輯更新(資料更新)
//按鍵檢測
while(kbmsg())
{
key_msg keyMsg = getkey();
if(keyMsg.msg == key_msg_down)
{
switch(keyMsg.key)
{
case 'A':case key_left : dir = 0; break;//左
case 'W':case key_up : dir = 1; break;//上
case 'D':case key_right : dir = 2; break;//右
case 'S':case key_down : dir = 3; break;//下
}
}
}
// todo: 圖形更新
if(dir!=-1)
{
system("cls");
switch(dir)
{
case 0: cout << "按下了 A/左 鍵" << endl; break;//左
case 1: cout << "按下了 W/上 鍵" << endl; break;//上
case 2: cout << "按下了 D/右 鍵" << endl; break;//右
case 3: cout << "按下了 S/下 鍵" << endl; break;//下
}
bool flag = false; //移動标志位
int tempGrid[4][4]; //暫存數組
int i,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
tempGrid[i][j] = grid[i][j];
Move(dir);
//比較
for(i=0; i<4; i++)
for(j=0; j<4; j++)
if(grid[i][j]!=tempGrid[i][j])
{
flag = true;
break;
}
if(flag)
{
cout << "有效移動" << endl;
Addnum(1);
}
else cout << "無效移動" << endl;
ShowInfo();
cout << "gameover: " << (gameOver()?"是":"否") << endl;
Draw();
dir = -1;//将 dir 置為無效,否則控制台會一直重新整理
}
if(gameOver())
{
cout << "Game Over!" << endl;
//putimage(150,150,GameOver);
putimage_withalpha(NULL,GameOverImg,120,200);
break;
}
}
ReleaseImgs();
getch();
closegraph();
return 0;
}
六、運作結果
本篇就結束了,介紹了加載圖檔的原理和操作,不過是不是感覺有點單調呢?那是因為我們沒有計分,沒有“正向回報”,缺少了遊戲的樂趣,下一部分的優化,就是加入計分子產品,加油!