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;
}
结果图:
==================================================
总结:只是实现了主要逻辑,很多功能没有实现,暂停,计分等。而且游戏最开始是一个方块。