2021-04-16

俄罗斯方块代码阅读

总结的知识点

知识点一 SFML的固定窗口

在阅读别人源码的时候发现放大后会拉伸,效果不好
自己修改为固定窗口大小

sf::RenderWindow window(sf::VideoMode(320, 480), "the Game", sf::Style::Close);//固定窗口

//window(VideoMode, title, [style, graphics settings]),创建一个窗口,style为枚举,在等于close时是固定大小,具有标题栏、最小化按钮,关闭按钮。

知识点二 SFML的坐标系

采用了左上角为坐标原点,像素为单位的坐标系。

知识点三 各种图形的表示

采用了直观的表示,在后面通过计算确定坐标

//对应两行四列(0~7)的生成7种图形,+(VS用※才能对齐)作为旋转的中心点!d

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, 
};

知识点四 在UGUI坐标系的旋转


(x,y)绕原点顺时针旋转α°,有:
在这里插入图片描述本例向右旋转90°,有:
在这里插入图片描述
以选中的中心点为原点,相对坐标旋转后加上中心点坐标即为原坐标系的旋转后的坐标点。

全部代码

#include <SFML/Graphics.hpp>
#include <time.h>
using namespace sf;

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

//整个游戏的领域
int field[M][N] = { 0 };

//存图形的4个点
struct Point
{
    int x, y;
} a[4], b[4];

//对应两行四列(0~7)的生成7种图形,※作为旋转的中心点
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));

    sf::RenderWindow window(sf::VideoMode(320, 480), "the Game", sf::Style::Close);//固定窗口

    Texture t1, t2, t3;
    t1.loadFromFile("images/tiles.png");
    t2.loadFromFile("images/background.png");
    t3.loadFromFile("images/frame.png");

    Sprite s(t1), background(t2), frame(t3);

    //初始位置,是否旋转,颜色
    int dx = 0; bool rotate = 0; int colorNum = 1;
    float timer = 0, 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)
                //↑键,将rotate标志置为1;
                if (e.key.code == Keyboard::Up) rotate = true;
                //←键,向左平移一个单位(18像素)
                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;
                //计算图形的点位,ui坐标系
                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 = 0; 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); //offset
                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); //offset
            window.draw(s);
        }

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

    return 0;
}

运行截图

在这里插入图片描述

待改进的地方

  1. 没有封装成类,所有的逻辑都在主函数中完成
  2. 没有死亡检测,仅仅是转换和下降判断是否合法
  3. 没有计分机制和下个图形预测
  4. 直接在左上角4行2列绘制图形,在足够高度时会直接改变已经存在的图形,也就是上面说的没有死亡检测和生成检测

阅读体会

更加深刻的了解了编译练接运行的步骤,分别测试了静态和动态DLL,记录了一个特别坑的点——自己用的VS在调试时的生成的exe运行环境是项目目录而不是exe存放目录,需要更改调试运行环境

能够体会到一个程序的完整编写过程,把自己前几章学的大概都用了一下

明白了学习的三角变化和矩阵运算的一个实际运用方向,而不是仅仅调用Rotate函数

定个小目标

用更c++风格改写这个小demo,~~ 加上第二章学习的AssetManager类实现资源的自动管理(好像整个程序过程都用了3个Texture,不能释放) ~~
争取加上死亡判定,大概思路,在最上面单独设立一个生成区,省去生成合法判定,在最上一行检测是否存在物体,有即死亡

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值