SimpleCG小游戏开发系列(3)--俄罗斯方块(方法2)

一、前言

        在之前一篇文章中,我们介绍了俄罗斯方块的其中一种数组点阵方阵算法,在本篇我们尝试换一种坐标算法来写同样的程序。所以预览效果也跟之前的没什么不同,就沿用之前的预览图了。

二、算法逻辑

        其中大体逻辑跟上一篇大体一致,我们可以直接沿用之前的代码,只在方块数据表示及相关运算需要更改。

数据结构如下

struct _tagTetris
{
	POINT ptBlock[4];
};

其中POINT结构是windows的系统结构,成员分别是int x 和int y。

四个数组成员代表了小方块的相对坐标,其中第一个数组成员(0,0)是当前方块中心点。所以之前的7个方块形状

可表示如下

//积木形状
tagTeris g_TetrsTemplate[] = {
	{
		{0,0,
		-1,0,			//****
		1,0,
		2,0}  },
	{					//***
		{0,0,			//*
		1,0,
		2,0,
		0,1} },
	{
		{0,0,
		-1,0,			//***
		1,0,			// *
		0,1} },
	{
		{0,0,
		-2,0,			//***
		-1,0,         //  *
		0,1} },
	{
		{0,0,
		1,0,			//**
		0,1,			//**
		1,1} },
	{
		{0,0,
		-1,0,			//**
		0,1,			// **
		1,1} },
	{
		{0,0,
		1,0,			// **
		0,1,			//**
		-1,1}}
};

旋转算法则相对简单了,可以直接用旋转公式旋转90度来计算。

转左边

for(i=0;i<C_BLOCK_CNT;++i)
	{
		temp.ptBlock[i].x=g_TetrsRunning.ptBlock[i].y;
		temp.ptBlock[i].y=-g_TetrsRunning.ptBlock[i].x;
	}

转右边

for(i=0;i<C_BLOCK_CNT;++i)
	{
		temp.ptBlock[i].x=-g_TetrsRunning.ptBlock[i].y;
		temp.ptBlock[i].y=g_TetrsRunning.ptBlock[i].x;
	}

三、游戏主逻辑全部代码

游戏逻辑都在Tetris.h和Tetris.cpp文件中

Tetris.h

#ifndef _TETRIS_H
#define _TETRIS_H

#include "../import/include/SimpleCG.h"
#define C_IMAGE_BLOCK			20
#define C_MAP_WIDTH				10
#define C_MAP_HEIGHT			20
#define C_BLOCK_CNT				4
struct _tagTetris
{
	POINT ptBlock[C_BLOCK_CNT];
};
typedef struct _tagTetris tagTeris;
int GetSpeed();
//初始化
void NewBlock();
//绘制单个方块
void DrawBlock( int nX, int nY, COLORREF nColor );
//绘制背景
void DrawMapBack( );
//绘制界面
void RenderBack();
//绘制内容
void DrawMap( );
//绘制移动中方块
void DrawMovinggBlock( );
//转动左边
void TurnLeft();
//转动右边
void TurnRight();
//移动左边
void MoveLeft();
//移动右边
void MoveRight();
//获取方块最左最右位置
void GetCurLeftRight(tagTeris *pTest, int *pLeft, int *pRight);
//是否可以往左右移动
bool CanMovHor(int nStepX);
//是否可以往下移动
bool IsExisted(tagTeris *pTest);
//往下移动
bool MovingDown();
//清除
void ClearBlock();
//清除
void ClearLine(int nY);
#endif

Tetris.cpsip

#include "Tetris.h"
enum ENUM_MAPTYPE
{
	  enumMAPTYPE_NULL
	, enumMAPTYPE_FIXBLOCK
	, enumMAPTYPE_DEADBLOCK
};
int g_nMap[ C_MAP_WIDTH * C_MAP_HEIGHT] = {0};
int g_nXMapPos = 100;
int g_nYMapPos = 50;
//积木形状
tagTeris g_TetrsTemplate[] = {
	{
		{0,0,
		-1,0,			//****
		1,0,
		2,0}  },
	{					//***
		{0,0,			//*
		1,0,
		2,0,
		0,1} },
	{
		{0,0,
		-1,0,			//***
		1,0,			// *
		0,1} },
	{
		{0,0,
		-2,0,			//***
		-1,0,         //  *
		0,1} },
	{
		{0,0,
		1,0,			//**
		0,1,			//**
		1,1} },
	{
		{0,0,
		-1,0,			//**
		0,1,			// **
		1,1} },
	{
		{0,0,
		1,0,			// **
		0,1,			//**
		-1,1}}
};


tagTeris g_TetrsRunning = {0};
int g_nMovingX = 0;
int g_nMovingY = 0;
tagTeris g_Next=g_TetrsTemplate[1];
int g_nColorBlockNext = RGB(rand()%255,rand()%255,rand()%255);
int g_nColorBlock = g_nColorBlockNext;
int g_nSpeed = 9;
int g_nScore = 0;
int GetSpeed()
{
	return g_nSpeed;
}
//创建新的方块
void NewBlock()
{
	g_TetrsRunning = g_Next;
	int nCount = sizeof(g_TetrsTemplate)/sizeof(g_TetrsTemplate[0]);
	g_Next = g_TetrsTemplate[rand()%nCount];
	g_nColorBlock = g_nColorBlockNext;

	g_nMovingY = 0;
	g_nMovingX = 4;
	g_nColorBlockNext = RGB(rand()%255,rand()%255,rand()%255);
	g_nScore += 10;
}
//绘制单个方块,绝对坐标
void DrawBlockPos( int nX, int nY, COLORREF nColor )
{
	setlinewidth(3);
	setfillcolor(nColor);
	setlinecolor(SCGSubColor(nColor,100));
	fillrectangle( nX, nY, nX + C_IMAGE_BLOCK-3, nY + C_IMAGE_BLOCK-3);

	setlinecolor(SCGAddColor(nColor,100));
	line(nX, nY, nX + C_IMAGE_BLOCK-5,nY);
	line(nX, nY, nX,nY + C_IMAGE_BLOCK-5);
}
//绘制单个方块,地图坐标
void DrawBlock( int nX, int nY, COLORREF nColor )
{
	int nXPos = g_nXMapPos + nX*C_IMAGE_BLOCK + 2;
	int nYPos = g_nYMapPos + nY*C_IMAGE_BLOCK;
	DrawBlockPos(nXPos, nYPos,nColor);
}
//绘制形状方块,地图坐标
void DrawTerisBlock( tagTeris *pTetris, int nX, int nY, COLORREF nColor )
{
	int i=0;
	for(i=0;i<C_BLOCK_CNT;++i)
	{
		DrawBlock( nX + pTetris->ptBlock[i].x, pTetris->ptBlock[i].y + nY, nColor );
	}
}
//绘制背景
void DrawMapBack(  )
{
	int i=0;
	int x=0;
	int y=0;
	
	clearrectangle(g_nXMapPos+1,g_nYMapPos-1,g_nXMapPos+1+C_IMAGE_BLOCK*C_MAP_WIDTH, g_nYMapPos+C_IMAGE_BLOCK*C_MAP_HEIGHT);
	clearrectangle(301,90,350+C_IMAGE_BLOCK*4, 240);
	RenderBack();
	
	DrawTerisBlock(&g_Next, 12, 3, g_nColorBlockNext);
	outtextXY(350,80,_T("下一个"));
	outtextXY(320,180,_T("当前级别"));
	outtextXY(320,220,_T("当前分数"));
	printfXY( 400, 220, _T("%d"), g_nScore );
	printfXY( 400, 180, _T("%d"), 10 - g_nSpeed);
}
//绘制界面
void RenderBack()
{
	setline(0,	1, 0);
	line(g_nXMapPos,g_nYMapPos,g_nXMapPos,g_nYMapPos+C_IMAGE_BLOCK*C_MAP_HEIGHT);
	line(g_nXMapPos+C_IMAGE_BLOCK*C_MAP_WIDTH,g_nYMapPos,g_nXMapPos+C_IMAGE_BLOCK*C_MAP_WIDTH,g_nYMapPos+C_IMAGE_BLOCK*C_MAP_HEIGHT);
	line(g_nXMapPos,g_nYMapPos+C_IMAGE_BLOCK*C_MAP_HEIGHT,g_nXMapPos+C_IMAGE_BLOCK*C_MAP_WIDTH,g_nYMapPos+C_IMAGE_BLOCK*C_MAP_HEIGHT);

}
//绘制内容
void DrawMap(  )
{
	int i=0;
	int j=0;
	for(j=0;j<C_MAP_HEIGHT;++j)
	{
		for(i=0;i<C_MAP_WIDTH;++i)
		{
			switch( g_nMap[j*C_MAP_WIDTH+i] )
			{
			case enumMAPTYPE_FIXBLOCK:
				DrawBlock( i, j, RGB(30,60,235) );
				break;
			case enumMAPTYPE_DEADBLOCK:
				break;
			}
			
		}
	}
}
//绘制移动中方块
void DrawMovinggBlock(  )
{
	DrawTerisBlock(&g_TetrsRunning, g_nMovingX, g_nMovingY, g_nColorBlock);
}
//转动左边
void TurnLeft()
{
	tagTeris temp;
	int i=0;
	for(i=0;i<C_BLOCK_CNT;++i)
	{
		temp.ptBlock[i].x=g_TetrsRunning.ptBlock[i].y;
		temp.ptBlock[i].y=-g_TetrsRunning.ptBlock[i].x;
	}
	if(!IsExisted(&temp))
		return;
	int nLeft = 0;
	int nRight = 0;
	GetCurLeftRight(&temp, &nLeft, &nRight);
	if( nLeft<0 )
	{
		g_nMovingX -= nLeft;
	}
	if( nRight>=C_MAP_WIDTH )
	{
		g_nMovingX -= nRight - C_MAP_WIDTH + 1;
	}
	g_TetrsRunning = temp;
}
//转动右边
void TurnRight()
{
	tagTeris temp;
	int i=0;
	for(i=0;i<C_BLOCK_CNT;++i)
	{
		temp.ptBlock[i].x=-g_TetrsRunning.ptBlock[i].y;
		temp.ptBlock[i].y=g_TetrsRunning.ptBlock[i].x;
	}
	if(!IsExisted(&temp))
		return;
	int nLeft = 0;
	int nRight = 0;
	GetCurLeftRight(&temp, &nLeft, &nRight);
	if( nLeft<0 )
	{
		g_nMovingX -= nLeft;
	}
	if( nRight>=C_MAP_WIDTH )
	{
		g_nMovingX -= nRight - C_MAP_WIDTH + 1;
	}
	g_TetrsRunning = temp;
}
//移动左边
void MoveLeft()
{
	if(CanMovHor(-1))
		--g_nMovingX;
}
//移动右边
void MoveRight()
{
	if(CanMovHor(1))
		++g_nMovingX;
}
//获取方块最左位置
void GetCurLeftRight(tagTeris *pTest, int *pLeft, int *pRight)
{
	int i=0;
	int j=0;
	*pLeft = 99;
	*pRight = -1;
	for(i=0;i<C_BLOCK_CNT;++i)
	{
		if( *pLeft>pTest->ptBlock[i].x + g_nMovingX )
			*pLeft = pTest->ptBlock[i].x + g_nMovingX;
		if( *pRight<pTest->ptBlock[i].x + g_nMovingX )
			*pRight = pTest->ptBlock[i].x + g_nMovingX;
	}
}
//是否可以往左右移动
bool CanMovHor(int nStepX)
{
	int i=0;
	int j=0;
	for(i=0;i<C_BLOCK_CNT;++i)
	{
		int nX=g_TetrsRunning.ptBlock[i].x + g_nMovingX + nStepX;
		int nY=g_TetrsRunning.ptBlock[i].y + g_nMovingY;
		if(nX<0 || nX>=C_MAP_WIDTH )
			return false;
		if( g_nMap[nY*C_MAP_WIDTH+nX] != enumMAPTYPE_NULL )
			return false;
	};
	return true;
}
//是否与原来方块冲突
bool IsExisted(tagTeris *pTest)
{
	int i=0;
	int j=0;
	for(i=0;i<C_BLOCK_CNT;++i)
	{
		int nY=pTest->ptBlock[i].y + g_nMovingY + 1;
		if( nY>=C_MAP_HEIGHT )
			return false;
		if( g_nMap[nY*C_MAP_WIDTH+pTest->ptBlock[i].x+g_nMovingX] )
			return false;
	}
	return true;
}
//往下移动
bool MovingDown()
{
	if(!IsExisted(&g_TetrsRunning))
	{
		int i=0;
		int j=0;
		for(i=0;i<C_BLOCK_CNT;++i)
		{
			int nY=g_TetrsRunning.ptBlock[i].y + g_nMovingY;
			g_nMap[nY*C_MAP_WIDTH+g_TetrsRunning.ptBlock[i].x+g_nMovingX] = enumMAPTYPE_FIXBLOCK;
			//测试是否结束
			if(nY<=0)
			{
				outtextXY(200,20,_T("游戏结束"));
				return false;
			}
		}
		g_nMap[g_nMovingY*C_MAP_WIDTH+g_nMovingX] = enumMAPTYPE_FIXBLOCK;

		NewBlock();
		return false;
	}
	++g_nMovingY;
	return true;
}
//清除
void ClearBlock()
{
	int i=0;
	int j=0;
	bool bIsClear=true;
	for(j=C_MAP_HEIGHT-1;j>=0;--j)
	{
		bIsClear=true;
		for(i=0;i<C_MAP_WIDTH;++i)
		{
			if( g_nMap[j*C_MAP_WIDTH+i]==enumMAPTYPE_NULL )
			{
				bIsClear = false;
				break;
			}
			
		}
		if(bIsClear)
		{
			ClearLine(j);
			g_nScore += 100;
			if(g_nScore>=(10-g_nSpeed)*1000 && g_nSpeed>0)
				--g_nSpeed;
			++j;
		}
	}
}
//清除
void ClearLine(int nY)
{
	int i=0;
	int j=0;
	for(j=nY;j>0;--j)
	{
		for(i=0;i<C_MAP_WIDTH;++i)
		{
			g_nMap[j*C_MAP_WIDTH+i]=g_nMap[(j-1)*C_MAP_WIDTH+i];
		}
	}
}

四、全部源代码

源码下载

GameRussiaTetris2 · master · b2b160 / SimpleCG_Demo · GitCode

 编译此程序需安装SimpleCG库,安装方法如下: 

SimpleCG库安装方法

上一篇: 俄罗斯方块教程--方法一

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

b2b160

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值