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.


Messages - JayhawkZombie

Pages: 1 [2] 3 4 ... 6
16
General / Re: Need Help
« on: April 15, 2017, 10:52:43 pm »
This probably belongs in https://en.sfml-dev.org/forums/index.php?board=4.0

But in any case, how are you defining "getGlobalBounds" for your classes?

17
General / Re: How does this work?
« on: April 12, 2017, 05:20:25 am »
The creep class is being updated in this call on line 68 of main.cpp
c.update(t,w);
and the function
call_creep(c)
is called on line 135 of main.cpp

Yes, you need to call update from within the game loop.  But you can use other functions to do that, like that code does.  It called "call_creep" every frame within the game loop and passes a "creep" by reference. That function in turn calls "update" on the creep object.

18
SFML projects / Procedural Lightning Effect Startup Animation
« on: April 12, 2017, 03:47:47 am »
Hey, all. 

I feel this just sort of looks cool, so I'll show it off to see what you think.
Here our engine is spelling out the letters "SFENGINE" by outlining the letters in lightning.  4 lightning bolts will strike 4 corners of the letters every frame, and then multiple lightning bolts will travel across the letters.  The 4 corner bolts will strike every 750ms until every letter has been hit, at which time it'll just go to the main menu.

While our engine is still in a baby state, we did recently add procedural lightning generation and lightning "storms" (really just probabilistic lightning bolt generation). 

The lightning will look similar every run (as it should), but the actual bolts are generated at runtime every time this is run so the bolts will never be identical.

After that we added a class to handle time-sequenced events with custom callbacks, a pretty simple group of 2 classes. 

  class SequenceNode
  {
  public:
    SequenceNode() = default;
    SequenceNode(const SequenceNode &Copy);
    SequenceNode(std::initializer_list<SequenceNode> Seq);
    SequenceNode(double delta,
                 std::function<void(void)> start,
                 std::function<void(void)> end);

    ~SequenceNode() = default;

    void TickUpdate(const double &delta);
    bool IsDone() const;

    void Start();
    void End();

  protected:

    double m_Duration;
    double m_CurrentDuration = 0.0;
    bool   m_IsDone = false;
   
    std::function<void(void)> m_StartCallBack = []() {};
    std::function<void(void)> m_EndCallBack   = []() {};
  };

and, of course, the class that actually queues up the nodes 

  class TimedSequence
  {
  public:
    TimedSequence() = default;
    ~TimedSequence() = default;

    void AddSequence(
      double Duration,
      std::function<void(void)> StartCB,
      std::function<void(void)> EndCB
    );

    void AddSequences(
      std::function<void(void)> Start,
      std::function<void(void)> End,
      std::initializer_list<SequenceNode> Nodes
    );

    void Start();
    void TickUpdate(const double &delta);
  protected:

    bool m_IsTiming = false;
    std::queue<SequenceNode> m_Nodes;
    std::function<void(void)> m_StartCallBack = []() {};
    std::function<void(void)> m_EndCallBack   = []() {};
  };

Whenever a sequence is started, a callback is called (if one was registered for that sequence node), and one is also called whenever that sequence node's duration has expired.  Here we are just using the m_StartCallBack function pointer, and for the second we just pass an empty lambda.

Then we can do this to create the sequence of callbacks, as well as the durations between them: 

  m_LightningSequence.AddSequences(
    [this]() {this->LightningSequenceStarted(); }, //CB for the lightning sequence starting
    [this]() {this->LightningSequenceEnded(); },   //CB for the lightning sequence ending
    {
      { 750.0, [this]() { this->LightningSequenceCB(0,  1,  2,  3, "S");  }, []() {} }, // 4 bolts strike the 'S' character
      { 750.0, [this]() { this->LightningSequenceCB(4,  5,  6,  7, "SF");  }, []() {} }, // 4 botls strike the 'F' character
      { 750.0, [this]() { this->LightningSequenceCB(8,  9,  10, 11, "SFE"); }, []() {} }, // 4 botls strike the 'F' character
      { 750.0, [this]() { this->LightningSequenceCB(12, 13, 14, 15, "SFEN"); }, []() {} }, // 4 botls strike the 'F' character
      { 750.0, [this]() { this->LightningSequenceCB(16, 17, 18, 19, "SFENG"); }, []() {} }, // 4 botls strike the 'F' character
      { 750.0, [this]() { this->LightningSequenceCB(20, 21, 22, 23, "SFENGI"); }, []() {} }, // 4 botls strike the 'F' character
      { 750.0, [this]() { this->LightningSequenceCB(24, 25, 26, 27, "SFENGIN"); }, []() {} }, // 4 botls strike the 'F' character
      { 750.0, [this]() { this->LightningSequenceCB(28, 29, 30, 31, "SFENGINE"); }, []() {} }, // 4 botls strike the 'F' character
    }
  );

After that, it's just a matter of telling the bolts that travel across the letters to start off and walk, so the "LightningSequenceCB" function is only a few lines long

void Level1::LightningSequenceCB(int Bolt1, int Bolt2, int Bolt3, int Bolt4, std::string ltext)
{
  m_LightningText.setString(ltext);
  m_BoltTopLeft.Spark(    { 0.f,    0.f },   m_BoltStrikePositions[Bolt1]);
  m_BoltTopRight.Spark(   { 1700.f, 0.f },   m_BoltStrikePositions[Bolt2]);
  m_BoltBottomLeft.Spark( { 0.f,    900.f }, m_BoltStrikePositions[Bolt3]);
  m_BoltBottomRight.Spark({ 1700.f, 900.f }, m_BoltStrikePositions[Bolt4]);

  m_CrawlBolts[Bolt1].Spark(m_LightningTraces[Bolt1]);
  m_CrawlBolts[Bolt2].Spark(m_LightningTraces[Bolt2]);
  m_CrawlBolts[Bolt3].Spark(m_LightningTraces[Bolt3]);
  m_CrawlBolts[Bolt4].Spark(m_LightningTraces[Bolt4]);
}

m_BoltStrikePositions is where the 4 bolts coming from the corners strike, which is just 4 chosen corners of the letters. 
m_LightningTraces contains the sequence of positions for the corners of the letters that we want each bolt to travel along. 

To update the sequence, all we have to do is call
m_LightningSequence.TickUpdate(delta);

The bolts themselves keep track of their lifetime, so we can call render on them even if they're supposed to be dead and they just won't draw.

The result is this (the word "SFENGINE" doesn't get rendered, but we're fixing that):


19
General / Re: How to make a textbox
« on: April 04, 2017, 12:29:03 am »
You can try TGUI: https://tgui.eu/
My team is using it exclusively for our engine's in-game UI (shh, texus doesn't know yet).

You can also check out SFGUI: http://sfgui.sfml-dev.de/
And ImGUI: https://github.com/ocornut/imgui

20
General discussions / Re: SFML Game Development review
« on: April 03, 2017, 07:20:37 pm »
If you're curious about expanding your knowledge beyond what the book may teach you, you can check out https://www.gamedev.net/.  They don't do SFML-specific stuff, but they shouldn't, since SFML is just an API.  What gamedev covers is applicable using any graphics API.

21
To expand on what they said, sf::Event is a union.  It is undefined behavior to access a union whose fields have not been set. See: http://en.cppreference.com/w/cpp/language/union

22
SFML projects / Re: First SFML/C++ project - Need feedback
« on: March 27, 2017, 09:27:21 pm »
Then there is one quirk that I couldn't get my head around. When I created a class, and I added a constructor with arguments, omitting the argless one, the compilation failed   :-\

Ah, I feel your frustration.  If you define any constructor, your compiler will no longer generate a no-arg/default one for you unless explicitly instructed to do so.  If you want one, you'll have to define it yourself.
You can either define it completely yourself or explicitly tell the compiler to make one for you.
If you want it to make it for you, even if you have defined other constructors, use the "default" syntax,
class MyClass
{
  MyClass() = default; //Tells compiler to make default one for you
  MyClass(args...); //Some other constructor that isn't the no-arg one
  ...
};
The "default" keyword has been here since forever for switch statements, but C++11 added it as an explicit function declaration for special class member functions (see http://en.cppreference.com/w/cpp/language/member_functions#Special_member_functions). 
You can also "delete" them, if you want to completely disable to use of a specific constructor.  I "delete" some copy constructors in my classes, for example, to control how objects are copied.
You can, of course, have a class that does not have a default constructor if that is what you want to enforce.

23
SFML projects / Re: First SFML/C++ project - Need feedback
« on: March 27, 2017, 07:26:06 pm »
It doesn't technically matter which order in the class are public sections and private sections but doesn't it make more sense to provide the public interface at the top?
Surprisingly, I've seen a lot of source code with the public interface defined at the bottom of the class.  It seems odd, but maybe there's a new habit going around?

Technically, the constructor is called whenever an object is created or copied (and some other instances).  You'll invoke a copy constructor if you do something like
myClass obj = someOtherObject;
"obj" will be a copy of "someOtherObject".  If you don't define a copy constructor, your compiler will try to generate one for you.  If you use that new object, you may not get the behavior you were expecting.
You generally want to avoid copying as much as possible.
If you just create an object, like
myClass myObject;
a default constructor will be used, if one exists.  If one does not exist, you'll get a compiler error.  The compiler will generate a default constructor for you provided you do not define any constructors yourself, or you declare it as "default" (ie "myClass() = default;" in the class declaration).

One last thing, "this" is a pointer to the calling object.  It is analogous to the one in Java.
You can use whatever naming convention you like, but your code should operate the same with and without the "this".

24
Have you considered mapping your tiles to a letter and having the algorithms generate the letters? Then render your tiles based on whatever characters it generated.

25
SFML development / Re: SFML concurrency vs C++ standard
« on: March 17, 2017, 04:38:41 pm »
I think it's pretty obvious. sf::Thread, sf::Mutex, sf::Lock, sf::ThreadLocal, sf::ThreadLocalPtr and sf::sleep should all go away.

Agreed.  The C++ interface is just as clean, and code would more cleanly tie in with the rest of the C++ threading libraries.
http://en.cppreference.com/w/cpp/thread
(I think cppreference isn't always easy to follow, and I prefer cplusplus.com - http://www.cplusplus.com/reference/multithreading/)

This particular example will/is supported in C++17 if I'm correct.
Correct, std::lock is variadic, and from what I can tell should already be supported in C++11 (so long as your compiler supports it): http://www.cplusplus.com/reference/mutex/lock/ 
If C++ implements a helper, I don't see any reason for SFML to wrap/re-implement it.  If not, perhaps SFML could provide a list of helpers for things, but there are libraries out there, like Hiura said, that are meant for exactly that.

26
SFML development / Re: sf::Time & sf::Clock vs C++11 chrono
« on: March 13, 2017, 03:31:07 pm »
If my input is of any use:

We all use std::chrono for our internal timing, but it's not far off from sf::Clock.
Sort of like:

CurrFrameStart = std::chrono::high_resolution_clock::now();
TickDelta = std::chrono::duration<double, std::milli>(CurrFrameStart - LastFrameStart).count();

I'd argue that SFML's timing libraries are easier to use, and certainly less verbose, but I see no reason SFML couldn't wrap the C++11 implementation.  It would allow, like Laurent said, conversion between representations, and you'd have access to the system's highest resolution clock if needed.
It would also strip off some more platform-dependent code (and remove that oh-so-beautiful "isWindowsXpOrOlder" check), at least for compilers that support the C++11 standard chrono addition (though I've yet to encounter one that doesn't).

27
True, thanks for pointing that out. I'm not sure what you mean by "orthogonal", but I think I understand what you were getting at.

Sure, I could make it so that one could choose between them, but right now that would be on a per-light-system basis. The only real difference between them is one line in their respective fragment shader

Multiplcative:
color.rgb = color.rgb + color.rgb * maskColor.rgb * lightIntensity;

Additive:
color.rgb = color.rgb + color.rgb + maskColor.rgb * lightIntensity;

It wouldn't  bee to hard to change it so that every light could independently choose how to illuminate the region around it.

Maybe the multiplicative one, with the "mist-like/grungy-like effect" as you said, would be good for eerie/dark/thematic scenes.
I guess what throws me off with the additive one is that it doesn't seem to brighten the scenery. It sort of slaps a translucent sheet on top of it.  The multiplicative one amplifies scenery colors (if I move the lights into a darker area, they are much less apparent, since there isn't anything to actually make brighter, which isn't the case for the additive one).

28
Feature requests / Re: Vulkan Support
« on: March 11, 2017, 07:14:15 am »
There is a lot that SFML is doing behind the scenes for you with sf::RenderWindow.  I don't imagine we should expect a really high FPS unless the devs designed it to use Vulkan.
There's a lot more work involved in using the Vulkan API.  The Vulkan implementation of SFML would probably be much larger since it expects us to do more of the heavy work.  It might be faster, but it will be more complex.  I for one very much like the simplicity of SFML's wrapper.  Vulkan does less error checking than OpenGL, so it would be easier to cause a crash.  One can use validation layers, but they can have an impact on performance.  Would SFML force the use of validation layers internally or make the programmer use them manually?

29
SFML projects / Additive v. Multiplicative Light and Shadow Blending
« on: March 11, 2017, 05:12:30 am »
I've been working on a new lighting system (wayyyyyyy more efficient than the raycasting one I posted a couple months ago).

Buuuuuuut, now I'm at a fork.  I need to choose between using a multiplicative algorithm for the lights/shadow blending and an additive method.  There is no performance difference, since the change is only in a couple fragment shaders.

Using a multiplicative method seems to make it appear as though the light is actually brightening the area around it, but the lights themselves are much less prominent (and this require some visual emphasis)

I have a system with 2 shadow casters (the two largest light sources) and 12 non shadow casing light sources.
This is what it looks like using a multiplicative algorithm:



This is what it looks like using an additive algorithm:


The big purple light moved a bit between the two, but that light follows the mouse. All the others are static.

I could go on for far too long about why I like one more than the other, but I want to hear what you think.

As far as 360-400fps for 14 lights goes in terms of performance, it's meh, but I'll optimize it later.

30
Feature requests / Re: Sprite batching
« on: March 02, 2017, 04:53:30 am »
You can query the max texture size yourself if you want to check:

https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGet.xhtml

eg
GLint mxSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mxSize);

Current OpenGL specification indicates this must be at least 1024, but older versions will specify a different size.  For example, a 2.1 compatibility context specifies this must be at least 64 (yeesh).
If you have even a halfway decent GPU, you should be able to load large textures.
My NVidia 980M, for example, gives 16384.

Pages: 1 [2] 3 4 ... 6
anything