c++ - 带有 SFML 的动态光照程序,1.6 到 2.x 转换

标签 c++ line sfml lighting vertex-array

我找到了这个 sfml tutorial写于 2009 年,我正在尝试将其转换为 2.4。

我无法转换这两行:

win.draw(sf::Shape::Rectangle(le.Blocks[0].fRect, sf::Color(255, 0, 0)));

rt.draw(sf::Shape(sf::Shape::Line(l.position, end, 1, l.color)));

我一直在尝试按照 SFML 论坛上的建议使用 sf::RectangleShape 进行转换,但我只是找不到合适的参数。以下是转换为 2.x 的完整代码(除了这两行之外)。

如果有人愿意“完成”转换,我将非常感激,并且我相信本教程对其他人会有帮助。

主要:

#include <SFML/Graphics.hpp>
#include <iostream>
#include "LightEngine.h"

int main()
{
    sf::RenderWindow win(sf::VideoMode(800, 600), "Light Tutorial");
    sf::Event event;

    LightEngine le;

    Light light;
    light.radius = 600;
    light.angleSpread = 100;
    light.position = sf::Vector2f(100, 150);
    le.Lights.push_back(light);

    Block block;
    block.fRect = sf::FloatRect(0, 0, 50, 50);
    le.Blocks.push_back(block);


    while (win.isOpen())
    {
        while (win.pollEvent(event))
        {
            if (event.type == sf::Event::Closed) win.close();
        }

        win.clear();

        le.Blocks[0].fRect.left = sf::Mouse::getPosition(win).x;
        le.Blocks[0].fRect.top = sf::Mouse::getPosition(win).y;
        /*HERE*/ win.draw(sf::Shape::Rectangle(le.Blocks[0].fRect, sf::Color(255, 0, 0)));
        le.Step(win);

        win.display();
    }
}

LightEngine.h

#pragma once//don't allow this header to be included more than once
#include "Light.hpp"
#include "Block.hpp"
#include <vector>
#include <SFML/Graphics/RenderTarget.hpp> //Place to draw on
#include <SFML/Graphics/Shape.hpp> //SFML programmable Shapes

class LightEngine
{
public:
    void Step(sf::RenderTarget &rt);

    std::vector <Light> Lights; //Container for Lights

    std::vector <Block> Blocks; //Container for Blocks
private:

    void ShineLight(Light &lig, sf::RenderTarget &rt);

    static const float Distance(const sf::Vector2f &p1, const sf::Vector2f &p2);
    static const sf::Vector2f GetCenter(const sf::FloatRect &fr); //Get the center of a rectangle


    struct FindDistance //if a light's radius manages to intersect multiple blocks, we need to find the sortest distance to shorten the light
    {
        FindDistance();
        float shortest;
        bool LightHitsBlock(Light &l, Block &b, const float cur_ang, float &reflength);
        bool start; //to get the first distance to refer off of
    };

    FindDistance findDis;
};

LightEngine.cpp

#include "LightEngine.h"


LightEngine::FindDistance::FindDistance()
{
    start = false;
    shortest = 0;
}

const sf::Vector2f LightEngine::GetCenter(const sf::FloatRect &fr)
{
    return sf::Vector2f(fr.left + (fr.width / 2), fr.top + (fr.height / 2));
}

const float LightEngine::Distance(const sf::Vector2f &p1, const sf::Vector2f &p2)
{
    //We need to look at this as a triangle

    /*
    /|p1.y
    / |
    /  |
    /   |
    /    |
    /     |b
    /      |
    /       |
    /        |
    /         |
    -----------
    a     p2.y
    p1.x           p2.x

    */

    float a = p2.x - p1.x;  //width length
    float b = p2.y - p1.y; //height length
    float c = sqrt((a * a) + (b * b)); //Pythagorean Theorem. (c² = a² + b²). c = squareroot(a² + b²)

    return c;
}

void LightEngine::Step(sf::RenderTarget &rt)
{
    for (unsigned i = 0; i < Lights.size(); i++)
    {
        ShineLight(Lights[i], rt); //Shine all lights
    }
}

void LightEngine::ShineLight(Light &l, sf::RenderTarget &rt)
{
    /*
    remember back in the Light class, we had something called 'angleSpread' ?
    that's to create a tunnel, or arc shaped light. Like this:
    /)
    /  )
    /    )
    /      )
    <       )
    \      )
    \    )
    \  )
    \)

    Obviously it'll look better than an ascii drawing
    */

    float current_angle = l.angle - (l.angleSpread / 2); //This will rotate the angle back far enough to get a desired arc

                                                         /*
                                                         Lights Angle (if it was at 0):

                                                         -------------

                                                         Current_Angle:
                                                         /
                                                         /
                                                         /
                                                         (slanted)

                                                         */

    float dyn_len = l.radius; //dynamic length of the light. This will be changed in the function LightHitsBlock()

    float addto = 1.f / l.radius;
    for (current_angle; current_angle < l.angle + (l.angleSpread / 2); current_angle += addto * (180.f / 3.14f)) //we need to add to the current angle, until it reaches the end of the arc. we divide 1.f by radius for a more solid shape. Otherwize you could see lines seperating
    {
        dyn_len = l.radius; //Reset the length
        findDis.start = true; //Start of finding a light, we need to reset
        findDis.shortest = 0; //Reset the shortest.



        if (l.dynamic) //can this change?
        {
            for (unsigned i = 0; i < Blocks.size(); i++)
            {
                findDis.LightHitsBlock(l, Blocks[i], current_angle, dyn_len);
            }
        }


        float radians = current_angle * (3.14f / 180); //Convert to radians for trig functions

        sf::Vector2f end = l.position;
        end.x += cos(radians) * dyn_len;
        end.y += sin(radians) * dyn_len;
        /*HERE*/rt.draw(sf::Shape(sf::Shape::Line(l.position, end, 1, l.color)));
    }
}

bool LightEngine::FindDistance::LightHitsBlock(Light &l, Block &b, float cur_ang, float &refleng)
{
    if (b.allowBlock) //can this even block?
    {
        float distance = Distance(l.position, GetCenter(b.fRect));

        if (l.radius >= distance) //check if it's radius is even long enough to hit a block
        {
            float radians = cur_ang * (3.14f / 180); //convert cur_ang to radians for trig functions
            sf::Vector2f pointpos = l.position;

            pointpos.x += cos(radians) * distance;
            pointpos.y += sin(radians) * distance;
            //By doing this, we check if the angle is in the direciton of the block.

            if (b.fRect.contains(pointpos)) //If it was, than the point would be intersecting the rectangle of the block
            {
                if (start || distance < shortest) //If this is the first block, or it has a shorter distance
                {
                    start = false; //definately not the start so other blocks can't automatically set the distance
                    shortest = distance; //shortest is set to this
                    refleng = distance; //This is where the dynamic comes in, it changes the length of the reference towhere it's going to stop after it hits the distance from the point to the block
                }
                return true;
            }
        }
    }
    return false;
}

block .hpp

#pragma once//don't allow this header to be included more than once
#include <SFML/Graphics/Rect.hpp>

class Block
{
public:
    Block()
    {
        allowBlock = true;
        fRect = sf::FloatRect(0, 0, 0, 0);
    }
    /* Like the light class, you can do this in an initializer list, whatever works for you

    Block()
    : fRect(0,0,0,0), allowBlock(false)
    {
    }
    */

    sf::FloatRect fRect; //Area that will be blocking light
    bool allowBlock; //Sometimes we want to keep a block, but don't want it to actually block until a certain point
};

最佳答案

win.draw(sf::Shape::Rectangle(le.Blocks[0].fRect, sf::Color(255, 0, 0)));

将是:

sf::RectangleShape rshape;

rshape.setSize(sf::Vector2f(le.Blocks[0].fRect.width, le.Blocks[0].fRect.height));
rshape.setPosition(le.Blocks[0].fRect.left, le.Blocks[0].fRect.top);
rshape.setFillColor(sf::Color(255, 0, 0));

win.draw(rshape);

因此:

rt.draw(sf::Shape::Line(l.position, end, 1, l.color));

因为不再有线条形状:

sf::Vertex line[] =
{
    sf::Vertex(l.position, l.color),
    sf::Vertex(end, l.color)
};

rt.draw(line, 2, sf::Lines);

关于c++ - 带有 SFML 的动态光照程序,1.6 到 2.x 转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44620031/

相关文章:

c++ - GNU 递归 make - 如何捕获 make 变量以执行嵌套的 makefile

html - 整个网页的行间距

php - 如何从 PHP 中的文本文件中读取特定行

c++ - 为什么这个整数会无限下降?

c++ - ( boolean/SFML)如何创建一个检查碰撞的 boolean 值?

c++ - 如何从我的 Mac 上的终端窗口运行 g++

c++ - 适用于 Windows 的类似 distcc 的框架

c++ - ptrdiff_t 太小?

line - 萨普伊5水平线

c++ - 缺少类型说明符 - 假定为 int。注意 : C++ does not support default-int on function in ..h 文件