User Tools

Site Tools


This is an old revision of the document!

The Problem

“Update and Render functions? Where we're going we don't need hardcoded Update and Render functions”

First of all, a disclaimer: You don't really *HAVE* to use the Proton Entity System to use the framework. If you already have a system you like, or are porting existing code, you can safely ignore most of this section.

I've made a lot of engines and a lot of game frameworks and for some reason I'm constantly trying new methods, mostly because it keeps things fun and interesting.

Here are some past methods I've tried when creating games:

  • Not knowing what I'm doing and hacking everything (see, Dink source)
  • Create a giant entity class hierarchy where each kind of thing gets its own class. A bird might be derived like: Object→Visual→MovingObject→NPC→Bird or something ridiculous like that. End up using virtuals everywhere.
    • VERDICT: Slow to add new things, too difficult to refactor, maintenance is a hassle.
  • Create one SUPER HUGE Entity class that does everything, possibly having it initialize sub objects. It ends up with 200 functions and bloated beyond belief. (See Novashell's entity class)
    • VERDICT: Probably the most productive and easy to work with, but becomes a horrible ball of twine eventually where every entity is like a 20KB object when initialized.

Using all of these, this is how it went:

(Ladies, look at your game programming development cycle)

(Now look at mine)

What if we could trade some initial complexity in the beginning for a more sane experience over all?

The Proton Entity System

Aka, “my interpretation of how Unity internals sort of work after I used it for a few hours”.

If you take a look at Entity.h you'll see some functions but nothing about thinking/updating or drawing. So what can an entity do?

Well, not much, alone. It's fairly lightweight at about 200 bytes.

Instantiate an entity

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.

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.

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!

//Open App.cpp.  Find MainMenuCreate(pGUIEnt) in App::Update(), comment it out and add two lines so you have this:
AddFocusIfNeeded(pGUIEnt); //so it will render, update, and draw.  Really it just adds a few components.
Entity *pEnt = CreateOverlayEntity(pGUIEnt, "logo", "interface/proton.rttex", 0,0);

Instead of the menu as before, you should see the proton logo rendered. (I've set my screen output to iPhone size in main.cpp btw)

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)

Add a few more lines of code:

AddFocusIfNeeded(pGUIEnt); //so it will render, update, and draw.  Really it just adds a few components.
Entity *pEnt = CreateOverlayEntity(pGUIEnt, "logo", "interface/proton.rttex", 0,0);
//Instead of drawing at 0,0, let's set the pos2d variable to 100,100 so it draws there instead.
//let's move to 200,200 1000ms (one second) later.
GetMessageManager()->SetEntityVariable(pEnt, 1000, "pos2d", CL_Vec2f(200,200));
//and, move back to 0,0 a second after that.
GetMessageManager()->SetEntityVariable(pEnt, 2000, "pos2d", CL_Vec2f(0,0));

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 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.

Replace with this code:

AddFocusIfNeeded(pGUIEnt); //so it will render, update, and draw.  Really it just adds a few components.
Entity *pEnt = CreateOverlayEntity(pGUIEnt, "logo", "interface/proton.rttex", 0,0);
CL_Vec2f imageSize = pEnt->GetVar("size2d")->GetVector2();
FadeInEntity(pEnt, true, 1000);
//zoom to bottom right, take 1000 ms to get there, initiate it in 1000 ms.
ZoomToPositionEntityMulti(pEnt, GetScreenSize()-imageSize, 1000, INTERPOLATE_SMOOTHSTEP, 1000);
//zoom back to start
ZoomToPositionEntityMulti(pEnt, CL_Vec2f(0,0), 1000, INTERPOLATE_SMOOTHSTEP, 2000);
//zoom to bottom right again
ZoomToPositionEntityMulti(pEnt, GetScreenSize()-imageSize, 1000, INTERPOLATE_SMOOTHSTEP, 3000);
FadeOutAndKillEntity(pEnt, true, 1000, 4000)

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.

proton_entity.1288093056.txt.gz · Last modified: 2010/10/26 11:37 by seth