The power comes from Components. ​ Components can (but don't have to) render, think, and process input.

-

Ok, time to just cannon-ball into the pool and show you what this stuff can do. The important thing to realize ​is we're just using entities ​and components ​to do everything.

+

They way they accomplish this is by connecting a component function (say, Render) ​to a function object called "​OnRender"​ (or any name) of their parent, ​and when that is triggered, the component function (and any others functions connected ​to it) is called.

-

If you say a weird function, like, BobEntity(),​ realize that it'​s ​just a helper function from EntityUtils.cpp and is components to manipulate things to make any entity "​bob"​. These helpers are not that complicated and just save on repetitive code, so dig in and look at them.

+

There is no looping through the entities to do things, Entities don't even need to be in the same hierarchy or in a list to work. But it's a good idea as the hierarchy makes rendering/​thinking order clear.

-

My philosophy is if it's a simple one line of code to add a fade, zoom, or bob to a visual, you are that much more likely to do it.

+

====Test drive=====

+

+

Ok, time to just cannon-ball into the pool and show you some stuff. ​ The important thing to realize is we're just using entities and components to do everything.

+

+

If you see a weird function, like, BobEntity(),​ realize that it's just a helper function from **EntityUtils.cpp** and is using components to manipulate things to make any entity "​bob"​. These helpers are not that complicated and just save on repetitive code, so dig in and look at them. Most of them can operate on any kind of entity, without knowing anything about it. If they try to read "​pos2d"​ but the entity doesn'​t have it set, it will be created with 0,0 instead of crash. ​ If they call a function object that no components have connected to (like, "​OnRender"​ or something) the effect is nothing happens, not an error.

+

+

There are a TON of tiny helper functions in **EntityUtils.cpp**,​ check the h sometime. ​My philosophy is if it's a simple one line of code to add a fade, zoom, or bob to a visual, you are that much more likely to do it.

If you'd like to work along with me, open the RTSimpleApp project now!

If you'd like to work along with me, open the RTSimpleApp project now!

Line 61:

Line 67:

{{:​entity_1.png?​|}}

{{:​entity_1.png?​|}}

-

Well, we see the logo there. ​ If you looked inside of CreateOverlayEntity,​ you'd see it creates an Entity, and adds a RenderOverlay component to it and sets some properties. (All of which are storied ​in either entity'​s VariantDB (like pos2d, color, scale2d, etc) or the components ​VariantDB if it is specific to the component. (properties like fileName, and framex, framey)

+

Well, we see the logo there. ​ If you looked inside of CreateOverlayEntity,​ you'd see it creates an Entity, and adds a RenderOverlay component to it and sets some properties. (All of which are stored ​in either entity'​s VariantDB (like pos2d, color, scale2d, etc) or the component'​s ​VariantDB if it is specific to the component. (properties like fileName, and framex, framey)

Add a few more lines of code:

Add a few more lines of code:

Line 79:

Line 85:

So now the ball sort of jerks around the screen. ​ Any variable can be "​scheduled"​ to be set in this way. If the entity is destroyed, any pending messages are also destroyed.

So now the ball sort of jerks around the screen. ​ Any variable can be "​scheduled"​ to be set in this way. If the entity is destroyed, any pending messages are also destroyed.

-

Instead of jerkily moving, we can use an InterpolateComponent to smoothly change one variant value to another. ​ This works numbers, vectors, colors, etc. I don't think it works for strings though, although that does seem possible.

+

Instead of jerkily moving, we can use an InterpolateComponent to smoothly change one variant value to another. ​ This works numbers, vectors, colors, etc.

Instead of adding InterpolateComponent directly, we'll use some helper functions that apply it to pos2d, but just keep in mind we can do this for any variable.

Instead of adding InterpolateComponent directly, we'll use some helper functions that apply it to pos2d, but just keep in mind we can do this for any variable.

Line 106:

Line 112:

The logo now fades in, smoothly zooms around the screen a bit, then fades out. (and kills the entity completely)

The logo now fades in, smoothly zooms around the screen a bit, then fades out. (and kills the entity completely)

-

Let's add a cool "shadow" ​effect.

+

Notice that most things work by time in milliseconds. ​ This allows very exact sequencing and movement of events. ​ Internally, ZoomToPositionEntityMulti is using the MessageManager to schedule things to happen, most helper functions allow you to control the "start time"​. ​ In this way, they sort of act like a scripting language.

+

+

Let's add a graphic trail effect to our moving logo.

+

+

<code cpp>

+

//​MainMenuCreate(pGUIEnt);​

+

AddFocusIfNeeded(pGUIEnt);​ //so it will render, update, and draw. Really it just adds a few components.

By simply adding the TrailRenderComponent we can add a "​trail"​ to any kind of moving visual, including buttons, text rendering, despite not knowing a thing about them.

+

+

In fact, this will even work with visuals not invented yet because the method TrailRenderComponent is using is just recording specific variables such as "​pos2d",​ "​scale2d",​ "​rotation",​ connecting itself to the "​OnRender"​ function object of the parent and calling OnRender() multiple times while controlling those variables. ​ It puts them back to normal when done. This is something only possible with a loosely coupled system.

+

+

We accepted TrailRender'​s default properties but what if we wanted a fancier trail?

+

+

First, take a look at TrailRenderComponent::​OnAdd. ​ This is where components register the properties/​functions they will allow the outside world to read and set.

The first big chunk setting up pointers to variables that the parent has (or doesn'​t have). ​ You can see defaults are set in many cases, this kicks in if they don't exist yet.

+

+

Look near the bottom, it's not using the GetParent() prefix, it's using variables from its own VariantDB. ​ A uint32 named "​frames"​ with a default of 5, and a "​timeBetweenFramesMS"​ with a default of 50.

+

+

(It means every 50 ms it takes a "​snapshot"​ and it only keeps track of the last 5 frames when drawing the trail)

+

+

So those are the two properties we can change!

+

+

Add this code somewhere after the TrailRenderComponent is added:

+

+

<code cpp>

+

pComp->​GetVar("​frames"​)->​Set(uint32(20));​

+

pComp->​GetVar("​timeBetweenFramesMS"​)->​Set(uint32(20));​

+

</​code>​

+

+

Then compile and you'll get this:

+

+

{{:​entity_3.png?​|}}

+

+

Whee!

+

+

Let's say you want the image to be clickable, and when clicked, it changes to a random tint color. ​ To do this we'll need to add a TouchHandlerComponent. ​ These will call function objects on parent called "​OnTouchStart",​ "​OnOverStart",​ "​OnOverEnd",​ "​OnTouchEnd"​. ​ It's up to us to connect them to a function to do something. (yep, sigslots again)

+

+

Here is the new code:

+

<code cpp>

+

//first add this anywhere above the App::​Update(),​ it will get called when we "​touch"​ the logo

And now you get a bundle of crazy logos bouncing around. ​ Tapping them changes color. ​ Hmm, make them explode and you've almost got a crappy game here!

+

So now you probably can sort of see the concept of "​wiring functions to things and calling them later" - we have only barely touched on what is possible!

+

Well written components respond to property changes at any time - for instance, if you were to change the "​fileName"​ property of the OverlayRenderComponent to a new image to display, it would understand and the touch rectangle and such would all just work. (It connects to the "on changed"​ signal of the fileName Variant) This technique can be used for cheapo anims.