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

Author Topic: SOLVED [SFML Book] Z-Ordering Between The parent and his children  (Read 3929 times)

0 Members and 3 Guests are viewing this topic.

OualidH38

  • Newbie
  • *
  • Posts: 46
    • View Profile
    • Email
Hi everyone!  ;D

I'm currently programming a little zelda like for fun with the SFML Game Dev book, and I have a little problem with z-ordering. I'm using the scenenode book architecture.
Actually, I'm able to sort children between them like this:
//Inside the update function
std::sort(mChildren.begin(), mChildren.end(), [] (Ptr& lchild, Ptr& rchild) {
                return lchild->getWorldPosition().y < rchild->getWorldPosition().y;
        });
 

But the draw function always draws the Parent before his children:
void SceneNode::draw(sf::RenderTarget& target, sf::RenderStates states) const {

        states.transform *= getTransform();

        drawCurrent(target, states);
        drawChildren(target, states);
}
 

The problem is that I need sometimes to draw the entity after his children.
Imagine that I want to implement some weapons entity.
I use the attachChild function to attach the weapon with the player.
I want to draw the weapon after the player when he uses the weapon at his left, right or bottom. But I want to draw the weapon before the player when he throws a hit at his top.


How could I sort (in the same way I sort children between them) the Parent with his children according to the book architecture?
I was looking for an answer on google, and I found nothing relevant.

I feel like the book architecture doesn't fit with what I look for.

I don't think this is a good solution:

Compare the the position between the parent and all his children individually

if(parent.position().y < child.position().y)
{
   -> draw child
   -> then draw parent
}
else
{
   -> draw parent
   -> draw child
}
 


Any idea will help.
Thank you in advance!  :D
« Last Edit: March 13, 2016, 06:28:30 pm by OualidH38 »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
AW: [SFML Book] Z-Ordering Between The parent and his children
« Reply #1 on: March 12, 2016, 09:02:44 pm »
And why do you think it's not a good solution?

To make it a bit nicer you could add a property to the entity and check that.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

OualidH38

  • Newbie
  • *
  • Posts: 46
    • View Profile
    • Email
Re: AW: [SFML Book] Z-Ordering Between The parent and his children
« Reply #2 on: March 13, 2016, 12:08:35 am »
And why do you think it's not a good solution?

To make it a bit nicer you could add a property to the entity and check that.

I think it's not a good solution because I would have to change the drawChildren function, and add a parameter like a child, and then draw only one child by one.
The drawChildren will become a drawChild.
Inside the draw function I compare the position in the y axis between children and the parent, then I draw the parent and the current child like this:


Inside the draw() function
Compare the the position between the parent and all his children individually

for(auto child : mChildren){

if(parent.position().y < child.position().y)
{
   drawChild(child)
   drawCurrent()
}
else
{
   drawCurrent()
   drawChild(child)
}
}
 

However, with this solution I draw the parent x times depending on how many children it has.
Let's say that we have a parent, with 5 children.
The parent will be drawn 5 times, because for each child we draw.
There's a way to do, but I only have words to explain it, don't know how to implement it.


The solution looks like this for me :


two child containers :
std::vector<std::unique_ptr<SceneNode>> mFrontChildren
std::vector<std::unique_ptr<SceneNode>> mBackChildren

two drawChildren function:
drawFrontChildren(...)
drawBackChildren(...)

Inside the update function:

for(auto child : mChildren){

if(parent.position().y < child.position().y)
{
   mBackChildren.push_back(std::move(child));
}
else
{
   mFrontChildren.push_back(std::move(child));
}
}


Inside the draw function

drawBackChildren(...)
drawCurrent(...)
drawFrontChildren(...)

 

I need two separate functions for front and back children, the problem is, how to dynamically switch children from front and behind?
With the example of the weapon, sometimes it's in front of the player, sometimes it's behind him.

I don't really know how to implement this kind of logique.
« Last Edit: March 13, 2016, 12:21:50 am by OualidH38 »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: [SFML Book] Z-Ordering Between The parent and his children
« Reply #3 on: March 13, 2016, 09:15:23 am »
If you already sort your children back to front, then all the children that must be drawn before their parent are at the beginning of the array, and the children that must be drawn after the parent are at the end. Then all you need to find is where to "split" the array to insert the drawing of the parent, between back and front children.

// condition: children are sorted back to front

// find the first child that is in front of the parent
auto split = std::find_if(mChildren.begin(), mChildren.end(), [this](Ptr& child) {return child->getWorldPosition().y >= this->getWorldPosition().y;});

// draw children that are behind parent
for (auto it = mChildren.begin(); it != split; ++it)
    // draw *it

// draw current

// draw children that are in front of parent
for (auto it = split; it != mChildren.end(); ++it)
    // draw *it
Laurent Gomila - SFML developer

OualidH38

  • Newbie
  • *
  • Posts: 46
    • View Profile
    • Email
Re: [SFML Book] Z-Ordering Between The parent and his children
« Reply #4 on: March 13, 2016, 10:42:47 am »
That is exactly what I was looking for thank you!  ;)

This is what I've done :
//two function for drawing the children

virtual void drawBackChildren(sf::RenderTarget& target, sf::RenderStates states, Ptr child) const;
virtual void drawFrontChildren(sf::RenderTarget& target, sf::RenderStates states, Ptr child) const;

//Inside the draw function

states.transform *= getTransform();

auto split = std::find_if(mChildren.begin(), mChildren.end(), [this](Ptr& child) {return child->getWorldPosition().y >= this->getWorldPosition().y; });

        // draw children that are behind parent
        for (auto it = mChildren.begin(); it != split; ++it)
                drawBackChildren(target, states, *it);

        drawCurrent(target, states);

                // draw children that are in front of parent
                for (auto it = split; it != mChildren.end(); ++it)
                        drawFrontChildren(target, states, *it);

//the drawFrontChildren and drawBackChildren look as follow

child->draw(target, states);
 

But I have an issue with the child param, how could I get the child from the iterator "it" and pass it as an argument?
"it" is a unique_ptr iterator pointing to a child how I am suppose to access to the child?

With this code an error says:
"Impossible to do a reference to a function "std::unqiue_ptr<_Ty, _Dx>::unqiue_ptr....."

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: [SFML Book] Z-Ordering Between The parent and his children
« Reply #5 on: March 13, 2016, 12:19:47 pm »
You must dereference twice, once for the iterator and once for the unique_ptr.
**it
Laurent Gomila - SFML developer

OualidH38

  • Newbie
  • *
  • Posts: 46
    • View Profile
    • Email
Re: [SFML Book] Z-Ordering Between The parent and his children
« Reply #6 on: March 13, 2016, 04:04:43 pm »
You must dereference twice, once for the iterator and once for the unique_ptr.
**it

I tried but it says that there's no conversion between SceneNode and SceneNode::Ptr defined.
The problem is perphaps my child argument in the functions drawBack and Front.

I'm not used to multiple dereferencing  :-[

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: [SFML Book] Z-Ordering Between The parent and his children
« Reply #7 on: March 13, 2016, 04:13:00 pm »
Yes, don't use Ptr as a parameter type. It's a typedef to std::unique_ptr<SceneNode> and thus owns the scene node. Passing unique pointers by value means transferring ownership to the function.

Instead, simply use a reference, possibly to a const object.

Why are drawBackChildren() and drawFrontChildren() virtual?
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

OualidH38

  • Newbie
  • *
  • Posts: 46
    • View Profile
    • Email
Re: [SFML Book] Z-Ordering Between The parent and his children
« Reply #8 on: March 13, 2016, 04:23:12 pm »
Yes, don't use Ptr as a parameter type. It's a typedef to std::unique_ptr<SceneNode> and thus owns the scene node. Passing unique pointers by value means transferring ownership to the function.

Instead, simply use a reference, possibly to a const object.

Why are drawBackChildren() and drawFrontChildren() virtual?

Oh I didn't notice that, it was an error  ;D

Ok so I changed the argument from Ptr to const SceneNode&, dereferenced twice the iterator, and I have a weird error that says:

Error    C2664  'bool SceneElement::draw::<lambda_cc8223163d3d6fd2ab5ca905407b6710>::operator ()(SceneNode::Ptr &) const' : impossible to convert argument 1 from 'const std::unique_ptr<SceneNode,std::default_delete<_Ty>>' to 'SceneNode::Ptr &'

2DGameSFML      g:\programmes\visual studio\vc\include\algorithm        43     

 


There's still a conversion issue  :-\

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: [SFML Book] Z-Ordering Between The parent and his children
« Reply #9 on: March 13, 2016, 05:33:49 pm »
You're trying to pass a const type to a lambda that takes a non-const argument. If it's the find_if lambda, it can (and must) take a const Ptr&.
Laurent Gomila - SFML developer

OualidH38

  • Newbie
  • *
  • Posts: 46
    • View Profile
    • Email
Re: [SFML Book] Z-Ordering Between The parent and his children
« Reply #10 on: March 13, 2016, 06:28:14 pm »
You're trying to pass a const type to a lambda that takes a non-const argument. If it's the find_if lambda, it can (and must) take a const Ptr&.

It works, you were right!  :D

Actually this is what I have :

//The two draw functions
void drawBackChildren(sf::RenderTarget& target, sf::RenderStates states, const Ptr& child) const;
void drawFrontChildren(sf::RenderTarget& target, sf::RenderStates states, const Ptr& child) const;

//Inside the draw function

states.transform *= getTransform();

        auto split = std::find_if(mChildren.begin(), mChildren.end(), [this](const Ptr& child) {return child->getWorldPosition().y >= this->getWorldPosition().y; });

        // draw children that are behind parent
        for (auto it = mChildren.begin(); it != split; ++it)
                drawBackChildren(target, states, *it);// It needs only one dereferencing

        drawCurrent(target, states);

                // draw children that are in front of parent
                for (auto it = split; it != mChildren.end(); ++it)
                        drawFrontChildren(target, states, *it);

 

Thank you all for your help  ;D

Fixed!