Tutorial 5: Nodes

In this tutorial you will learn about scene nodes.

Before starting this tutorial be sure to setup an empty project with the Setup Tutorial.

 

what are we going to get?

at the end of this tutorial we will have this code:

That's it. :)

Now that you have basic understanding of nodes, time to go deeper about sprites and entities!
 
continue to next tutorial -->

#include <NessEngine.h>

 

int _tmain(int argc, _TCHAR* argv[])

{

    Ness::init();

    Ness::Renderer renderer("new project", Ness::Sizei(800,600));

 

    Ness::ScenePtr scene = renderer.create_scene();

 

    Ness::NodePtr green_node = scene->create_node();

    green_node->set_color(Ness::Color::GREEN);

    green_node->set_position(Ness::Point(100, 100));

    for (int i = 0; i < 10; i++)

    {

        Ness::SpritePtr sprite = green_node->create_sprite("ness-engine/resources/gfx/meteor.png");

        sprite->set_anchor(Ness::Point::HALF);

        sprite->set_blend_mode(Ness::BLEND_MODE_BLEND);

        sprite->set_position(Ness::Pointi(rand() % 200, rand() % 200));

    }

 

    

    Ness::NodePtr red_node = scene->create_node();

    red_node->set_color(Ness::Color::RED);

    red_node->set_position(Ness::Pointi(400, 100));

    for (int i = 0; i < 10; i++)

    {

        Ness::SpritePtr sprite = red_node->create_sprite("ness-engine/resources/gfx/meteor.png");

        sprite->set_anchor(Ness::Point::HALF);

        sprite->set_blend_mode(Ness::BLEND_MODE_BLEND);

        sprite->set_position(Ness::Pointi(rand() % 200, rand() % 200));

    }

 

    Ness::Utils::EventsPoller EventsPoller;

    Ness::Utils::ApplicationEvents app;

    EventsPoller.add_handler(app);

 

    while( !app.got_quit() )

    {

        EventsPoller.poll_events();

 

        renderer.start_frame();

        scene->render();

        renderer.end_frame();

    }

}

Ness::NodePtr green_node = scene->create_node();

green_node->set_color(Ness::Color::GREEN);

green_node->set_position(Ness::Point(100, 100));

    for (int i = 0; i < 10; i++)

    {

        Ness::SpritePtr sprite = green_node->create_sprite("ness-engine/resources/gfx/meteor.png");

        sprite->set_anchor(Ness::Point::HALF);

        sprite->set_blend_mode(Ness::BLEND_MODE_BLEND);

        sprite->set_position(Ness::Pointi(rand() % 200, rand() % 200));

    }

    Ness::NodePtr red_node = scene->create_node();

    red_node->set_color(Ness::Color::RED);

    red_node->set_position(Ness::Pointi(400, 100));

    for (int i = 0; i < 10; i++)

    {

        Ness::SpritePtr sprite = red_node->create_sprite("ness-engine/resources/gfx/meteor.png");

        sprite->set_anchor(Ness::Point::HALF);

        sprite->set_blend_mode(Ness::BLEND_MODE_BLEND);

        sprite->set_position(Ness::Pointi(rand() % 200, rand() % 200));

    }

green_node->set_position(Ness::Pointi(400, 100));

green_node->set_rotation(90);

scene->remove(green_node);

red_node->add(green_node);

green_node->set_position(Ness::Pointi(0, 0));

which will produce the following window:

We will now go over the code and explain what we just did.

 
What are scene nodes?

A scene node is a container of entities and nodes, which you can create and render. you can set nodes to contain other nodes and go deeper as many levels as you like. remember the scene object we always create and render? the 'Scene' itself is actually just a type of node.

 

Remember: Your scene is not a list of entities, it's a tree of entities and nodes.

 

Transformations inheritance

As you should know from this tutorial, every sprite has it's own transformation properties: rotation, scale, position, etc..

 

A scene node has the same type of transformations as well. when you put an entity under a node, the entity will be rendered with transformations that are combination of the entity and his parents, all the way up to the root node (which is the Scene).

 

for example, if you have node1 containing node2 containing entity1, node1 has scale of 2, node2 has scale of 3 and entity has scale of 1, what will be the final scale? answer: 2 * 3 * 1 = 6.

 

You can read more about nodes and inheritance in this doc.

 

 

Creating the nodes

Creating a node is very simple and similar to creating a sprite:

and now we can set the node transformations just as we would a sprite:

first we set the color of this node to green, so everything under this node will have its rendering color multiplied with the green color. question: if we put an object with red color transformation, what will we get? answer: black color. this is because green is (0.0f, 1.0f, 0.0f) and red is (1.0f, 0.0f, 0.0f), so multiplying them gives: (0.0f*1.0f, 1.0f*0.0f, 0.0f*0.0f) = (0.0f, 0.0f, 0.0f).

 

after setting the color we set position. position is a transformation that doesn't multiply, but sum up.  so everything under this node will origin from point (100, 100) instead of (0, 0). 

 

now let's add some random entities to this node:

just like adding sprites to a scene.

time to create our next node and add some entities to it:

this node we color in red, and move 400 pixels to the right.

note that both the nodes are under the scene object. so rendering the scene renders both the nodes.

 

the result, as seen above, should be something like this:

Playing with the nodes

Let's play with the nodes a little, the get the grasp of the concept. first, let's move the green node on the red node:

notice how all the red sprites are above the green sprites? technically all the red sprites were created after the green ones, but even if you add a new green sprite (sprite under the green node), it will still be below. why? because nodes also have rendering order. if we first created the green node and then the red node, it means that all the entities in green node will be rendered before all entities in red node, even if they were added later.

 

now what will happen if we rotate the node?

when setting rotation to a node it means that all entities under the node get that rotation. so now all the green sprites got rotation of 0 + 90 = 90 degrees.

 

every sprite will rotate around it's own anchor, and the result will look like this:

if you need to rotate all the sprites around a single axis and as a single body, there's also a technique for that, which is covered in later tutorials.

 

now what will happen if we remove the green node from the scene and add it as a son of the red node?

Ooops, where did all the green sprites go?

if you followed this tutorial and got this result it's because in previous step we set the position of the green node to (400, 100). so now that the green node is son of the red node, it's position is red + green, which is (400, 100) + (400, 100) = (800, 200), which means all the green sprites are out of screen.

let's reset green's position:

and now we got this:

Why are they black? since the green node is now under the red node, the final color that every sprite gets is red * green, which is actually black: (1, 0, 0) * (0, 1, 0) = (0, 0, 0).

 

Why are the black sprites above the red ones? since we just pushed the entire green node into the red node's rendering queue, the green node is now rendered after all the sprites that were already in the queue. if we add new entities to the red node, whey will be rendered above the black entities.

Help ness-engine grow!