Welcome, Guest. Please login or register. Did you miss your activation email?

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - PeterWelzien

Pages: [1]
1
SFML projects / Lightning
« on: September 13, 2010, 09:50:30 pm »
I'm going to need a force field in future project and since I suck at making graphics, I decided to make a simple class that draws lightning (not a lightning rod  :))

I thought I'd share the code incase someone else need some lightning.

Code: [Select]
#include <SFML/Graphics.hpp>
#include <vector>

class Lightning : public sf::Drawable
{
  public:
               Lightning(unsigned long noSegments, float thickness = 1.0f, sf::Color fadeColor = sf::Color(0, 0, 0))
                 : noSegments(noSegments), thickness(thickness), fadeColor(fadeColor)                                {segments.reserve(noSegments);}
  void         generate ();
  void         setSize  (float width, float height)                                                                  {size.x = width; size.y = height;}
  virtual void Render   (sf::RenderTarget& target, sf::Renderer& renderer) const;

  private:
  unsigned long      noSegments;
  float              thickness;
  sf::Color          fadeColor; // Outer color of the lightning
  std::vector<float> segments;  // Contains the x-position of each segment (-1.0 - +1.0), multiply with width to get final position
  sf::Vector2f       size;      // Size of the lightning
};

void Lightning::generate()
{
  sf::Vector2f start;
  sf::Vector2f end(0.0f, 0.0f);

  segments.clear();

  segments.push_back(0.0f); // The start point of the lightning is centered

  for(unsigned long c = 1; c < noSegments - 1; ++c)
    segments.push_back(sf::Randomizer::Random(-1.0f, 1.0f));

  segments.push_back(0.0f); // The end point of the lightning is also centered
}

void Lightning::Render(sf::RenderTarget& target, sf::Renderer& renderer) const
{
  sf::Vector2f start, end;
  sf::Color color, colorDifference, colorStep;

  // If the thickness is 1.0 then draw using only the main color. Otherwise calculate the amount to fade the fade color each iteration
  if(thickness == 1.0f)
    color = GetColor();
  else
  {
    color = fadeColor;
 
    // sf::Color doesn't provide the minus or division operators, so we'll have to make the calculations component by component
    colorDifference = sf::Color(GetColor().r - fadeColor.r,
                                GetColor().g - fadeColor.g,
                                GetColor().b - fadeColor.b,
                                GetColor().a - fadeColor.a);
    colorStep = sf::Color(colorDifference.r / static_cast<sf::Uint8> (thickness - 1.0f),
                          colorDifference.g / static_cast<sf::Uint8> (thickness - 1.0f),
                          colorDifference.b / static_cast<sf::Uint8> (thickness - 1.0f),
                          colorDifference.a / static_cast<sf::Uint8> (thickness - 1.0f)); // Increase the fade color by this each iteration.
  }

  float segmentHeight = size.y / (noSegments - 1.0f);
  float halfWidth = size.x / 2;
  float halfThickness = thickness / 2;

  // Draw multiple lightnings, decreasing the thinkness by 1.0 until we reach thickness 1.0 (or less)
  for(float t = thickness; t >= 1.0f; --t, color += colorStep)
    for(unsigned long c = 0; c < noSegments - 1; ++c)
    {
      start.x = segments[c]     * (halfWidth - halfThickness) + halfWidth ; start.y = segmentHeight * c;
        end.x = segments[c + 1] * (halfWidth - halfThickness)  + halfWidth;   end.y = segmentHeight * (c + 1);
      sf::Shape line = sf::Shape::Line(start, end, t, color);
      target.Draw(line);
    }
}

int main()
{
  sf::RenderWindow window(sf::VideoMode(800, 600), "Lightning test");
  sf::Event evnt;
  bool paused=false;
  Lightning lightning(15, 3.0f, sf::Color::Blue);
  lightning.SetPosition(0.0f, 0.0f);
  lightning.setSize(15.0f, 150.0f);
  lightning.SetColor(sf::Color::White);

  while(window.IsOpened())
  {
    while(window.GetEvent(evnt))
    {
      if(evnt.Type == sf::Event::Closed)
        window.Close();
      if(evnt.Type == sf::Event::KeyPressed && evnt.Key.Code == sf::Key::Escape)
        window.Close();
      if(evnt.Type == sf::Event::KeyPressed && evnt.Key.Code == sf::Key::Space)
        paused=true;
      if(evnt.Type == sf::Event::KeyReleased && evnt.Key.Code == sf::Key::Space)
        paused=false;
    }

    if(!paused)
    {
      window.Clear();

      lightning.generate();
      window.Draw(lightning);

      window.Display();
    }
  }
 
  return EXIT_SUCCESS;
}


I've included a simple main() to test it. Hold SPACE to pause, ESCAPE to quit.

The corners don't look good if the size and/or thinkness gets to large. The start and end points of the lightning are fixed. But it shouldn't be too hard to change that if you need eg. a lightning gun.

I've only tried it with SFML2.

edit: Fixed a small bug when calculating segmentHeight.

Pages: [1]