Let's make 16 games in C++(二):Tetris

1、准备游戏所需要的背景文件。

①方块的颜色样式,每一种颜色代表的是一种形状。

②游戏刷新范围

③游戏背景图

2、这是一个经典的俄罗斯方块的游戏,首先先建立一个320x480的游戏屏幕。然后设置游戏的主循环事件。

#include<SFML/Graphics.hpp>
#include<time.h>

using namespace sf;

int main()
{
	RenderWindow window(VideoMode(320, 480), "The Game!");

	while (window.isOpen())
	{
		Event e;
		while (window.pollEvent(e))
		{
			if (e.type == Event::Closed)
			{
				window.close();
			}
		}

		window.clear(Color::White);
		window.display();
	}

	return 0;
}

 

3、把样式图片通过纹理渲染在界面上。

#include<SFML/Graphics.hpp>
#include<time.h>

using namespace sf;

int main()
{
	RenderWindow window(VideoMode(320, 480), "The Game!");

	Texture t;//++++++++++++++++++++++++
	t.loadFromFile("./Resources/images/tiles.png");//++++++++++++++++++++++++
	Sprite s(t);//++++++++++++++++++++++++
	s.setTextureRect(IntRect(0, 0, 18, 18));//++++++++++++++++++++++++

	while (window.isOpen())
	{
		Event e;
		while (window.pollEvent(e))
		{
			if (e.type == Event::Closed)
			{
				window.close();
			}
		}

		window.clear(Color::White);
		window.draw(s);//++++++++++++++++++++++++
		window.display();
	}

	return 0;
}

4、定义方框的样式(7种)

先定义一个8格的2x4矩形,然后根据编号定义形状。每个形状都是有四个小方块组成。

以及定义移动的范围区域

const int M = 20;
const int N = 10;

int field[M][N] = { 0 };


int figures[7][4] =
{
	1, 3, 5, 7,
	2, 4, 5, 7,
	3, 5, 4, 6,
	3, 5, 4, 7,
	2, 3, 5, 7,
	3, 5, 7, 6,
	2, 3, 4, 5,
};

5、将一维中的位置信息{3, 5, 4, 7}转化为Point的二维结构{{1,1}, {2, 1}, {2,0}, {3,1}}并存进a[4]数组

struct Point
{
	int x,y;
} a[4], b[4];



...
...


int n = 3;
for (int i = 0; i < 4; i++)
{
	a[i].x = figures[n][i] % 2;
	a[i].y = figures[n][i] / 2;
}

window.clear(Color::White);
for (int i = 0; i < 4; i++)
{
        s.setPosition(a[i].x * 18, a[i].y * 18);
        window.draw(s);
}

6、设置按键实现平移和旋转,旋转中心为任意形状的第二个小方格。

int dx = 0;
bool rotate = 0;
int colorNum = 1;


...
...

if (e.type == Event::KeyPressed)
{
    if (e.key.code == Keyboard::Up)
    {
        rotate = true;
    }else if(e.key.code == Keyboard::Left){
        dx = -1;
    }else if(e.key.code == Keyboard::Right){
        dx = 1;
    }
}


...
...

//Move
for (int i = 0; i < 4; i++)
{
    a[i].x += dx;
}

//Rotate
if (rotate)
{
    Point p = a[1]; //center of rotation
    for (int i = 0; i < 4; i++)
    {
        int x = a[i].y - p.y;
        int y = a[i].x - p.x;
        a[i].x = p.x - x;
        a[i].y = p.y + y;
    }
}

7、修改渲染的a[]的坐标,并将dx和rotate清零。

if (a[0].x == 0)
{
    for (int i = 0; i < 4; i++)
    {
        a[i].x = figures[n][i] % 2;
        a[i].y = figures[n][i] / 2;
    }
}

dx = 0;
rotate = false;

8、加入时钟,模拟自由下路过程。

float timer = 0;
float delay = 0.3;
Clock clock;



...
...
float time = clock.getElapsedTime().asSeconds();
clock.restart();
timer += time;

...

//Tick
if (timer > delay)
{

    for (int i = 0; i < 4; i++)
    {
        a[i].y += 1;
    }
    timer = 0;
}

9、移动的边缘检测以及绘制已经落下的方块

bool check()
{
	for (int i = 0; i < 4; i++)
	{
		if (a[i].x < 0 || a[i].x >= N || a[i].y >= M)
		{
			return 0;
		}
		else if (field[a[i].y][a[i].x])
		{
			return 0;
		}
	}
	return 1;
}


...
...

for (int i = 0; i < M; i++)
{
    for (int j = 0; j < N; j++)
    {
        if (field[i][j] == 0)
    {
        continue;
    }
    s.setPosition(j * 18, i * 18);
    window.draw(s);
    }
}

10、消除满行

//check lines
int k = M - 1;
for (int i = M -1; i > 0 ; i--)
{
    int count = 0;
    for (int j = 0; j < N; j++)
    {
        if (field[i][j])
        {
        count++;
        }
        field[k][j] = field[i][j];
    }
    if (count<N)
    {
        k--;
    }
}

11、最后添加背景:

#include<SFML/Graphics.hpp>
#include<time.h>

using namespace sf;


const int M = 20;
const int N = 10;

int field[M][N] = { 0 };

struct Point
{
	int x,y;
} a[4], b[4];

int figures[7][4] =
{
	1, 3, 5, 7,
	2, 4, 5, 7,
	3, 5, 4, 6,
	3, 5, 4, 7,
	2, 3, 5, 7,
	3, 5, 7, 6,
	2, 3, 4, 5,
};


bool check()
{
	for (int i = 0; i < 4; i++)
	{
		if (a[i].x < 0 || a[i].x >= N || a[i].y >= M)
		{
			return 0;
		}
		else if (field[a[i].y][a[i].x])
		{
			return 0;
		}
	}
	return 1;
}

int main()
{
	srand(time(0));
	RenderWindow window(VideoMode(320, 480), "The Game!");

	Texture t1, t2, t3;
	t1.loadFromFile("./Resources/images/tiles.png");
	t2.loadFromFile("./Resources/images/background.png");
	t3.loadFromFile("./Resources/images/frame.png");
	Sprite s(t1), background(t2), frame(t3);
	//s.setTextureRect(IntRect(0, 0, 18, 18));

	int dx = 0;
	bool rotate = 0;
	int colorNum = 1;

	float timer = 0;
	float delay = 0.3;
	Clock clock;

	while (window.isOpen())
	{
		float time = clock.getElapsedTime().asSeconds();
		clock.restart();
		timer += time;

		Event e;
		while (window.pollEvent(e))
		{
			if(e.type == Event::Closed)
			{
				window.close();
			}
			if (e.type == Event::KeyPressed)
			{
				if (e.key.code == Keyboard::Up)
				{
					rotate = true;
				}
				else if(e.key.code == Keyboard::Left){
					dx = -1;
				}
				else if(e.key.code == Keyboard::Right)
				{
					dx = 1;
				}
			}
		}

		if (Keyboard::isKeyPressed(Keyboard::Down))
		{
			delay = 0.05;
		}

		//Move
		for (int i = 0; i < 4; i++)
		{
			b[i] = a[i];
			a[i].x += dx;
		}

		if (!check())
		{
			for (int i = 0; i < 4; i++)
			{
				a[i] = b[i];
			}
		}

		//Rotate
		if (rotate)
		{
			Point p = a[1]; //center of rotation
			for (int i = 0; i < 4; i++)
			{
				int x = a[i].y - p.y;
				int y = a[i].x - p.x;
				a[i].x = p.x - x;
				a[i].y = p.y + y;
			}
			if (!check())
			{
				for (int i = 0; i < 4; i++)
				{
					a[i] = b[i];
				}
			}
		}

		//Tick
		if (timer > delay)
		{
			for (int i = 0; i < 4; i++)
			{
				b[i] = a[i];
				a[i].y += 1;
			}

			if (!check())
			{
				for (int i = 0; i < 4; i++)
				{
					field[b[i].y][b[i].x] = colorNum;
				}
				colorNum = 1 + rand() % 7;
				int n = rand() % 7;
				for (int i = 0; i < 4; i++)
				{
					a[i].x = figures[n][i] % 2;
					a[i].y = figures[n][i] / 2;
				}
			}

			timer = 0;
		}

		//check lines
		int k = M - 1;
		for (int i = M -1; i > 0 ; i--)
		{
			int count = 0;
			for (int j = 0; j < N; j++)
			{
				if (field[i][j])
				{
					count++;
				}
				field[k][j] = field[i][j];
			}
			if (count<N)
			{
				k--;
			}

		}
	

		dx = 0;
		rotate = false;
		delay = 0.3;


		//draw
		window.clear(Color::White);
		window.draw(background);

		for (int i = 0; i < M; i++)
		{
			for (int j = 0; j < N; j++)
			{
				if (field[i][j] == 0)
				{
					continue;
				}
				s.setTextureRect(IntRect(field[i][j] * 18, 0, 18, 18));
				s.setPosition(j * 18, i * 18);
				s.move(28, 31);
				window.draw(s);
			}
		}

		for (int i = 0; i < 4; i++)
		{
			s.setTextureRect(IntRect(colorNum * 18, 0, 18, 18));
			s.setPosition(a[i].x * 18, a[i].y * 18);
			s.move(28, 31);
			window.draw(s);

		}
		window.draw(frame);
		window.display();
	}

	return 0;
}

结果图:

==================================================

总结:只是实现了主要逻辑,很多功能没有实现,暂停,计分等。而且游戏最开始是一个方块。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值