最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

TETRIS—基于現(xiàn)代官方規(guī)則俄羅斯方塊實(shí)現(xiàn)案例(c/c++,EasyX,附完整代碼)

2023-02-18 10:06 作者:墨奕白_  | 我要投稿

簡介:

作為方塊圈的玩家,和剛接觸 EasyX 的萌新。我希望大家能夠重新認(rèn)識一下這款經(jīng)久不衰的游戲。

官方規(guī)則是基于俄羅斯方塊公司(The Tetris Company,TTC)公司授權(quán)的方塊游戲規(guī)則。如俄羅斯方塊效應(yīng),噗喲噗喲VS俄羅斯方塊等游戲采用的規(guī)則。

大部分人對方塊的印象大多還停留在上個(gè)世紀(jì)的? ”消消樂“ 吧?我將一邊科普現(xiàn)代方塊規(guī)則, 一邊介紹個(gè)人的實(shí)現(xiàn)思路,而不是隨隨便便寫一個(gè)消消樂。

也希望大家可以去體驗(yàn)一下方塊的魅力 !

先來介紹一下現(xiàn)代方塊界面吧

噗喲噗喲 VS 俄羅斯方塊 2 游戲界面。

介紹 / 規(guī)則
標(biāo)準(zhǔn)場地是 10 X 20 個(gè)小方塊場地,共有 7 個(gè)方塊,一般也都采用固定 7 種顏色。比如我看到黃色就知道是正方形來了。

來認(rèn)識一下各個(gè)方塊,現(xiàn)代方塊以 “ T ” 方塊為尊(紫色),“ I ” 方塊居其次(棍子/長條),紅色 Z 綠色 S,一個(gè)正方形 O 和 JL。

七個(gè)字母對應(yīng)形狀,方塊也是有名字的,TIOZSJL 每個(gè)方塊都由 4 個(gè)小方塊組成,場地里填滿一行就會消除,然后相愛相殺!

HOLD:儲存一個(gè)方塊,可與當(dāng)前操作的方塊交換一下。(是從上面重新下來的不是直接和當(dāng)前位置交換,每次鎖定前只能交換一次)

NEXT:這個(gè)好理解看見下一個(gè)方塊是什么。(官方的好像沒有超過 5next 的)

GHOST:影子,可以看見當(dāng)前方塊落下后的樣子。(游戲里都是可以選擇開啟/關(guān)閉的)

7bg:七巡,方塊的出塊規(guī)則。隨機(jī)排列這 7 個(gè)不同方塊為一包,一包一包出方塊。

操作:軟降(加速下落)/硬降(當(dāng)前方塊直接下落到最底部鎖定)左移動(dòng)/右移動(dòng)/軟/順時(shí)針旋轉(zhuǎn)/逆時(shí)針旋轉(zhuǎn)/ HOLD(暫存按鍵)。標(biāo)準(zhǔn)七個(gè)按鍵。

方塊落到最下面不會鎖定,還可以旋轉(zhuǎn)和移動(dòng)如果 1.5 秒(大約)不操作才會鎖定,硬降就是直接落下鎖定。

對戰(zhàn)傷害系統(tǒng)就先不提了,可以來看看下面的視頻鏈接。(與人斗其樂無窮!)

【國區(qū)最強(qiáng)噗喲噗喲俄羅斯方塊2比賽(上)】

代碼思路解析(個(gè)人理解)
場地:想必大家也都理解要用二維數(shù)組儲存場地?cái)?shù)據(jù),xy 坐標(biāo)和 ij 數(shù)組下標(biāo)方便后面功能判斷。

#define Column 10 // 10 列

#define RowNum 22 // 22 行,現(xiàn)代方塊場地理論上應(yīng)該更高

const int Radius = 20; // 方塊大小

// 枚舉每一個(gè)小方塊的填充和未填充狀態(tài)

enum T_STATE {NoBlock, IsBlock};

// 表示方向

enum DIRECTION {Up1, Right2, Down3, left4};

// 表示當(dāng)前方塊種類

enum TKIND {T, I, O, S, Z, L, J};

// 創(chuàng)建單個(gè)方塊結(jié)構(gòu)體

class A_TETRIS

{

public:

int x, y; // 儲存小方塊的中心 X Y 坐標(biāo)

int i, j; // 儲存小方塊的在地圖數(shù)組下標(biāo) i j

T_STATE T_state; // 每一個(gè)小方塊的狀態(tài),存在和不存在

IMAGE T_im; // 一個(gè)小方塊的皮膚

}

// 打包的 4 個(gè)方塊都有一個(gè)旋轉(zhuǎn)中心點(diǎn)

struct FOUR_TETRIS

{

A_TETRIS TheFourT[4]; // 打包 4 個(gè)為一個(gè)

int centerX, centerY; // 儲存旋轉(zhuǎn)中心位置

float centeri, centerj; // 儲存旋轉(zhuǎn)中心 ij 下標(biāo),為什么是 float 呢,特殊方塊中心點(diǎn)不規(guī)則

DIRECTION Direction = Up1;

TKIND Kind; // 方塊種類

}

// 定義地圖數(shù)據(jù)結(jié)構(gòu)體

class TETRIS_MAP

{

public:

A_TETRIS Map_T[RowNum][Column]; // 地圖二維數(shù)組

}

由每一個(gè)小方塊的數(shù)據(jù)構(gòu)成一個(gè)地圖數(shù)據(jù),然后畫出來。3 個(gè)枚舉也好理解,地圖里就用一個(gè)是否有方塊狀態(tài),有就顯示圖片沒有就不顯示。

你也可以直接使用簡單的填充矩形,后期隨變改皮膚。數(shù)組構(gòu)成一個(gè)地圖,每個(gè)方塊由 4 個(gè)小方塊組成。

那么我再定義一個(gè)結(jié)構(gòu)體,里面由包含 4 個(gè)小方塊數(shù)據(jù)的一維數(shù)組組成。

我直接寫進(jìn)去 4 個(gè)元素?cái)?shù)據(jù),就組成了我要的任意形狀方塊。

方塊一個(gè)一個(gè)按順序出來。那么我定義一個(gè)類,表示序列。


class SEVEN_BG// 創(chuàng)建七循相關(guān)結(jié)構(gòu)體

{

public:

FOUR_TETRIS Four_T; // 用于初始化加載的方塊

vector<FOUR_TETRIS> SevenList; // 儲存初始化的 7 個(gè)方塊鏈表

vector<FOUR_TETRIS> PutSevenT; // 用來存放固定的 7 個(gè)方塊

vector<FOUR_TETRIS> NextList; // 存放 NEXT 序列

}

序列存放方塊數(shù)據(jù),我想到的就是鏈表,#include <vector> //矢量模板也是鏈表,我用的這個(gè)。

這里用了 3 個(gè)鏈表儲存單個(gè)方塊信息,第一個(gè)里只有 7 個(gè)方塊數(shù)據(jù),我直接暴力寫入 7 個(gè)方塊數(shù)據(jù),存到這鏈表里

void initialize() // 簡單粗暴的直接寫入 7bg 初始數(shù)據(jù)

{ // 加載順序 T I O S Z L J 超出邊界的方塊手動(dòng)計(jì)算賦值一下

Four_T.TheFourT[0] = MapDate.Map_T[1][4];

Four_T.TheFourT[1] = MapDate.Map_T[2][3];

Four_T.TheFourT[2] = MapDate.Map_T[2][4];

Four_T.TheFourT[3] = MapDate.Map_T[2][5];

for (int i =0; i<4; i++)

{

Four_T.TheFourT[i].T_state = IsBlock; // 也就第一次要加載這個(gè)

loadimage(&Four_T.TheFourT[i].T_im, _T("image / T.png"));

}

Four_T.centerX = Four_T.TheFourT[2].x; // T 的中心點(diǎn)

Four_T.centerY = Four_T.TheFourT[2].y;

Four_T.centeri = Four_T.TheFourT[2].i; // 記錄下標(biāo)

Four_T.centerj = Four_T.TheFourT[2].j;

Four_T.Kind = T;

SevenList.push_back(Four_T); // 將一個(gè) T 方塊信息儲存到了 7BG 鏈表

}

手寫七·個(gè)方塊數(shù)據(jù)到第一個(gè)鏈表里,這里省略。

第二個(gè)鏈表復(fù)制一遍第一個(gè)鏈表,然后寫一個(gè)簡單的隨機(jī)取出鏈表里的函數(shù)

int Rand7BG(int Max)// 生成兩個(gè)數(shù)之間的隨機(jī)數(shù)。就是選擇下一個(gè)方塊

{ // max 不能為 0。思考一下取 0 的余是啥?

????int num =int(rand()%Max);

????return num;

}

7 個(gè)方塊嘛,循環(huán) 7 次不就全取完了,隨機(jī)取 7 次,取一次 Max 減一。就得到隨機(jī)方塊順序,然后存到 第三個(gè)序列鏈表里。

取完了再第二鏈表再復(fù)制一遍第一個(gè)鏈表,再隨機(jī)取出給第三個(gè)序列鏈表,這就是出塊規(guī)則了。

當(dāng)前操作的方塊就等于第三個(gè)鏈表里的第一個(gè)數(shù)據(jù),我定義了一個(gè)當(dāng)前方塊類,依然引用 4 個(gè)單個(gè)方塊構(gòu)成的一個(gè)方塊結(jié)構(gòu)體。

class NOW_TETRIS// 創(chuàng)建當(dāng)前方塊結(jié)構(gòu)體

{

public:

int EraseRow[4]; // 要消除的行的 i 標(biāo)

int whatRL = 0; // 右旋轉(zhuǎn)為 1,左旋轉(zhuǎn)為-1

FOUR_TETRIS Now_FourT; // 當(dāng)前方塊信息

FOUR_TETRIS Ghost_FourT; // 存放影子信息

FOUR_TETRIS Rotate_FourT; // 用來計(jì)算旋轉(zhuǎn)是否成立

FOUR_TETRIS SeekSpin_FourT; // 正常旋轉(zhuǎn)不行就來計(jì)算偏移

}

當(dāng)前方塊信息算一個(gè),影子算一個(gè),也就等于鏈表里的第一個(gè)數(shù)據(jù)。鎖定后刪除鏈表第一個(gè)數(shù)據(jù)然后再復(fù)制第一個(gè)數(shù)據(jù),源源不斷的生成。

void OnceDown() // 一次下落執(zhí)行的數(shù)據(jù)

{ y + = 2 * Radius;

i + = 1; }

單個(gè)方塊結(jié)構(gòu)體的移動(dòng)

void OnceUp() // 一個(gè)整體方塊的一次向上移動(dòng)

{

for (int i =0; i<4; i++)

TheFourT[i].OnceUp();

centeri - = 1;

centerY - = 2 * Radius;

}

移動(dòng)簡單,下落還是移動(dòng)都是這種一格一格的,調(diào)用然后放到循環(huán)里更新就好了。判斷能不能移動(dòng)和下落稍微麻煩一點(diǎn)點(diǎn)而已。


int InspectDown(A_TETRIS &Now, A_TETRIS &Next) // 檢查下一個(gè)下降位置是否有沖突

{

if (Now.i > = RowNum - 1 || Next.T_state ! = NoBlock)

return 1;

else return 0;

}

int JudgeWhetherDown() // 判斷是否可以下落

{

for (int i = 0; i<4; i++)

{ // 下面這串是檢查當(dāng)前方塊下路是否和地圖里的有沖突

if (InspectDown(Now_FourT.TheFourT[i], MapDate.Map_T[Now_FourT.TheFourT[i].i + 1][Now_FourT.TheFourT[i].j]))

return 0;

}

return 1;

}

每一個(gè)小方塊里都有一個(gè)枚舉表示當(dāng)前是否有方塊,也有數(shù)組下標(biāo)數(shù)據(jù),提前判斷一下它移動(dòng)后的位置有沒有存在方塊,和邊界判斷,如上。

我這里旋轉(zhuǎn)也是提前將旋轉(zhuǎn)過后的數(shù)據(jù)存一個(gè)然后和地圖數(shù)據(jù)比對。

旋轉(zhuǎn)在現(xiàn)代方塊規(guī)則里是非常重要的!繞旋轉(zhuǎn)中心點(diǎn)旋轉(zhuǎn),旋轉(zhuǎn)中心各位可以運(yùn)行后面源文件里程序觀看,如下。

旋轉(zhuǎn)中心每個(gè)方塊都不一樣,這個(gè)數(shù)據(jù)也在一開始鏈表里寫數(shù)據(jù)的直接寫了,在 4 個(gè)小方塊結(jié)構(gòu)體里也定義了中心點(diǎn)數(shù)據(jù)。以這個(gè)點(diǎn)是以為官方標(biāo)準(zhǔn),旋轉(zhuǎn)系統(tǒng)稱為 SRS 系統(tǒng)。

如何通過旋轉(zhuǎn)中心坐標(biāo)計(jì)算旋轉(zhuǎn)后 4 個(gè)小方塊的坐標(biāo)。下面這個(gè)可是我打了不少草稿發(fā)現(xiàn)規(guī)律簡化的!


A_TETRIS LoadRspin(A_TETRIS &oneT) // 載入右旋轉(zhuǎn),輸入一個(gè)單方塊用來計(jì)算他旋轉(zhuǎn)后的坐標(biāo)位置

{

float xd = centerX - oneT.x;

float yd = centerY - oneT.y;

float jd = centerj - oneT.j;

float id = centeri - oneT.i;

oneT.x = centerX + yd;

oneT.j = centerj + id;

oneT.y = centerY - xd;

oneT.i = centeri - jd;

return oneT;

}

A_TETRIS LoadLspin(A_TETRIS &oneT) // 載入左旋轉(zhuǎn),輸入一個(gè)單方塊用來計(jì)算他旋轉(zhuǎn)后的坐標(biāo)位置

{

float xd = centerX - oneT.x;

float yd = centerY - oneT.y;

float jd = centerj - oneT.j;

float id = centeri - oneT.i;

oneT.x = centerX - yd;

oneT.j = centerj - id;

oneT.y = centerY + xd;

oneT.i = centeri + jd;

return oneT;

}

上面就是如何通過旋轉(zhuǎn)中心坐標(biāo)計(jì)算旋轉(zhuǎn)后 4 個(gè)小方塊的坐標(biāo)。這個(gè)可是我打了不少草稿發(fā)現(xiàn)規(guī)律簡化的!

得到旋轉(zhuǎn)過后的數(shù)據(jù)了,要和地圖里的數(shù)據(jù)比較。防止重疊嘛,但是當(dāng)方塊移動(dòng)到邊上后,旋轉(zhuǎn)過后的樣子肯定超出邊界了。

此外還有特殊旋轉(zhuǎn),你可能會覺得下面這個(gè)有點(diǎn)離譜。但這都是真的,當(dāng)然也是有條件的,也有別的奇怪旋轉(zhuǎn)。

這里就要用到官方設(shè)定偏移表了。(千萬不要研究什么旋轉(zhuǎn)規(guī)律!我痛苦的回憶!)

以下面 i 塊為例子,我也會在壓縮包里放上完整偏移表。


i 的偏移最特殊,雖然它只有橫豎兩個(gè)狀態(tài),注意看旋轉(zhuǎn)中心位置,它是不一樣的。

來看看消除


int JudgeErase(int &row) // 判斷當(dāng)前行是否消除

{

int clear = 0; // 判斷是否清除。滿足 10 行就清除

for (int i = 0; i< Column; i ++)

{

if(Map_T[row][i].T_state == IsBlock)

clear ++;

}

if (clear == 10)

return row;

else return - 1;

}

void eraseline(int &row) // 獲取到要消除的行,執(zhí)行消行后需要做的

{

for (int j = 0; j<Column; j ++) // 首先刪除當(dāng)前行的方塊

Map_T[row][j].T_state = NoBlock;

for (int T = row - 1; T>=0; T--) // 當(dāng)前要消除的上一行開始遍歷

for (int j = 0; j<Column; j ++) // 列

{ // 要消除的肯定得是不是方塊狀態(tài)

if (Map_T[T][j].T_state == IsBlock) // 只有遍歷到存在方塊的數(shù)據(jù)才開始執(zhí)行下落

{ // 降消除后落下的方塊的信息修改正確

Map_T[T + 1][j].T_im = Map_T[T][j].T_im;

Map_T[T + 1][j].T_state = IsBlock;

Map_T[T][j].T_state = NoBlock; // 當(dāng)前方塊給下面后刪除

}

}

}

我這里是每次落下方塊,獲取當(dāng)前落下方塊的 4 個(gè)小方塊的 i?坐標(biāo),對應(yīng)地圖里那一行有沒有滿足 10 個(gè),滿足就代表這一行要消除,讓當(dāng)前行消失,狀態(tài)為 noblock 沒有方塊。上面的方塊往下移動(dòng)一格,從當(dāng)前 i 行便利走最上面第 22 行,對應(yīng) i 下標(biāo)為 0。

HOLD 交換功能就是和當(dāng)前方塊交換一下嘛,然后顯示在右上角就好了。下落就寫個(gè)時(shí)間觸發(fā)移動(dòng)一下,不能移動(dòng)后過 1 秒不操作就鎖定,數(shù)據(jù)寫到地圖里。

GOHST 影子數(shù)據(jù)一開始肯定和當(dāng)前方塊一樣位置也一樣,直接判斷影子方塊能不能往下移動(dòng)一格,這個(gè)判斷放到 while 里,可以下落就繼續(xù)下落,直到不能下落才是影子位置的數(shù)據(jù)。

寫一個(gè)找到影子位置的函數(shù),只在方塊左右移動(dòng)的時(shí)候調(diào)用一下,別的操作不要調(diào)用。移動(dòng)還有 das 什么操作要求啥的,等我下次把別的功能做好再來更新吧。目前我寫的這個(gè)操作起來還不錯(cuò),我就是玩方塊的玩起來手感還行哦。

好就寫到這吧,源代碼都有注釋應(yīng)該容易理解,比較詳細(xì)。(有些注釋自己寫著玩的請見諒)

http://farter.cn/t/?塊圈群主“屁大爺”的屁塊?。ㄍ诰蚰J胶苡幸馑己苌项^)

http://tetr.io? ?目前圈里很火的在線對戰(zhàn)方塊

墨白的源碼 :https://pan.baidu.com/s/1FmIBp5sobAqZb-h870BWWw?pwd=gi68?

提取碼:gi68?


調(diào)試環(huán)境 VS200 (沒有EasyX庫的可以去官網(wǎng)看一下https://easyx.cn/)








TETRIS—基于現(xiàn)代官方規(guī)則俄羅斯方塊實(shí)現(xiàn)案例(c/c++,EasyX,附完整代碼)的評論 (共 條)

分享到微博請遵守國家法律
天气| 邵阳市| 房山区| 布拖县| 方城县| 沙田区| 墨玉县| 宜宾县| 桃江县| 来安县| 平原县| 蕉岭县| 石河子市| 锡林浩特市| 闽清县| 安康市| 荣昌县| 兖州市| 恩平市| 修文县| 昌都县| 百色市| 伊川县| 开原市| 洛扎县| 当涂县| 平昌县| 达孜县| 武汉市| 新蔡县| 平陆县| 商城县| 赞皇县| 平和县| 左贡县| 鄂州市| 安溪县| 鹿泉市| 杂多县| 雅江县| 信丰县|