NxOgre.org

Index

Actors and dead bodies.

shortguide

This document is still being written. Anything in here is likely to change.

Like a play, Actors are needed to make everything interesting and fun else without them you’d be staring at the scenery for the next two hours, get bored then die. Unlike Actors in a play NxOgre actors don’t generally move about on there own, perform stage fighting or generally talk.

NxOgre Actors are individual units of mass within a Scene; such as a pencil, a bucket or a skyscraper. They are made up of three or four things; A pose; where it is and what it’s looking at, a Collision Model; A rough idea of how it collides with other Actors, also called Shapes, a unique Name and most of the time some Mass.

Based on an Actors mass, it can be decided if it’s Static or Dynamic. Static Actors have no mass what so ever, so they never move around and used for buildings, pieces of terrain or impenetrable fortresses. Dynamic Actors, used for guns, flying pieces of rock and pencil cases do have mass and they move around – a lot.

Actors do not have any form of representation such as a Ogre Mesh, a Billboard or even a sound, in fact it doesn’t even hint at a possibility, in all sense and purposes Actors are invisible. However let’s not worry about that for now, and just learn Actors.

Actors are owned by a Scene, since they are owned, and Scenes are very stingy, they cannot be moved to another.

Actor* mActor = mScene->createActor("Spot", new Cube(1.0f), Vector3(0, 2, 0), "mass: 10");

Let’s go through each portion of the actor, we’ve just created into existance.

  • The name (or an identifier) must be unique, but it is doubtful there will be another actor named “Spot” in an empty Scene. But NxOgre is kind and will try to resolve conflicts in naming. In the case of an Spot, our Spot will be called Spot2.
  • The Collision Model of the Actor is a 1m 3 cube, meaning it’s generic shape is well…a cube. If you look around the room you are in right now, many of the things can be physically represented by primitives. Your computer; a cube, a football; a sphere, and so on. If nothing matches, or is complicated then it can be repsenteded quite accurately with a Convex or a Triangle mesh. For lush scenic lands can be represtened by a Terrain loaded usually from a greyscale image. Shapes will be discussed later in the guide.
  • The pose of myActor is 2 metres above from center of the world. All poses of things are specified by the NxOgre Pose class; a location and a orientation. The Pose class is quite flexible, and can use the PhysX (and Ogre) Vector and Quaternion classes interchangeably. Vector3(9, -3, 0) , Quaternion(Degree(90), Vector3::UNIT_Z) or Pose(Vector3(9, -3, 0), Quaternion(Degree(90), Vector3::UNIT_Z))
  • Finally we have the ActorParams. As this is a dynamic Actor we’ve added some mass of 10 kilograms. Without it, the Actor would still be dynamic as the default mass is 10. So it doesn’t matter. However perhaps I want it static "static: yes", or perhaps I want the mass calculated via the volume of the shape "density: 1.0", or sometimes I want my Actors to have a bit of a kick when they are created "mass: 10, linear-velocity: 10 0 0". I think you get the idea.


h3. More Actors

Let’s add more actors. Lets say ooh…26 of them.

for(i=0;i<26;i++)
Actor* mActor = mScene->createActor("Rocky", new Cube(1.0f), Vector3(0,i,0), "mass: 10");

Now hopefully at this point you know enough about C++, Ogre and NxOgre to notice when something will explode it will. Look at that piece of code again, and tell me what explodes and why. Go on I can wait.

Got an answer? Hilight below, to check if your right.

They are all called Rocky!

Did you get it? It all 26 of them are called Rocky, that would make anyone explode.

However, NxOgre the creator and destroyer of worlds isn’t a completely evil little monster. In this case of name collisions, NxOgre will rename the new Rocky to Rocky1, then another Rocky will be called Rocky 2 and soon after that you have 26 Actors all named from Rocky to Rocky 25.

You’ll find as you use NxOgre, it will try it’s best not to crash and come up with a solution for events like this, and many others.

Rock on Rocky

Since we have a nice stack of Rockies, it would be nice if we could move them around, Ground is waiting to meet them after all.

First let’s get one rocky4 = mScene->getActor("Rocky4") then place it somewhere rocky4->setGlobalPosition(10, 10, 10), but as with all teleportation your bound to end up in a wall sometime in the future. So how about adding bit of force rocky4->addForce(1000, 0, 0) and nudge it out of the stack instead? Or perhaps taking it for a rocky4->addTorque(1000, 0, 1000) spin? I know let’s just tell it where we rougly where we want it to go rocky4->moveTo(10, 10, 10) to, and hope it gets there?

Tony Rocky Horror

At this point now, I should introduce you to the concept to the Betajaen SharedList and SharedMap classes.

In this case, let’s get a bunch of Actors which is a typedef of Betajaen::SharedMap<NxString, Actor>. Nearly every class has a container in the plural form; Scenes, ShapeGroups, Materials, and so on. In this case; “NxString” is the identifier and Actor is the class we want to hold.

All of those Actors, ShapeGroups, Scenes, Materials and so on have have cousins, Constant cousins; ConstActors, ConstShapeGroups, ConstScenes. There are differences and rules between these two sets of families which may be clear. Let’s ignore the cousins for now and just invite our immediate family to our party.

Actors the_rockies;
Actor* NotRocky = mScene->createActor("Not Rocky", new CubeShape(1), Vector3(2,4,0), "mass: 15");
actors.Insert(NotRocky->getName(), actor);
actors.Insert("Rocky5", mScene->getActor("Rocky5"));
Actor* Rocky5 = actors.Get("Rocky5");
actors.Remove("Rocky5);
mScene->destroyActor("Rocky5");

Seems simple enough? What about if the Rockies, break the law and go on the lamb to avoid being arrested? Can’t go around being called Rocky now can we?

Actors the_jeffersons = the_rockies;
Actor* jefferson4 = the_jeffersons.Get("Rocky4");

We can confirm it’s really Rocky4 via:

the_jeffersons.Get("Rocky4") == the_rockies.Get("Rocky4");

That’s obvious, but this will blow your mind. When you can interchange between the Jeffersons and Rockies

mScene->destroyActor("Rocky4");
Actor* is_it_rocky4 = the_rockies.Get("Rocky4");

Rocky4 should be Null right? How about Jefferson4/Rocky4?

Actor* is_it_rocky4 = the_jefferson.Get("Rocky4");

Rocky4 is Null too. Anything you do to one SharedMap, will affect another other SharedMap that it has been copied from. the_rockies and the_jeffersons are more or less the same thing.

Party list

SharedList’s are another handy little class to work with, if you’ve ever worked with the STL library. It is very similar to the vector class. Let’s build an invitation list.

SharedList<Actor> invitations;

As will all Betajaen Container classes, there is no need to put a * on the class name. It’s assumed to be a pointer.

invitations.Insert(Rocky3);
invitations.Insert(betajaen); // Obviously.
invitations.Insert(Rocky7);
invitations.Insert(Rocky9);
invitations.Insert(Rocky2);
invitations.Insert(Rocky);

The Party is at 54, 0, 43. So let’s move the party guests over there. We can use the inbuilt Actor function Actor::moveTowards to get there.

invitations.Each<Vector3>(&Actor::moveTowards, Vector3(54, 0, 43));

Did I just blow your mind then? We don’t need no stinking for loops when it comes to containers. As long as you want to use a function belonging to the class; you can use the Each function to iterate through every stored class in that list. This works for SharedMap too.

Sometimes you would want to work with other classes, or perform the famous “Welsh guest stacking trick“, that the Welsh people are famous for, so you would want a stinking loop.

Vector3 party_trick_position = Vector3(54, 0.5, 43);
for (Actor* party_guest = invitations.Begin(); party_guest = invitations.Next(); ) {
   party_guest->setGlobalPosition(party_trick_position);
   party_trick_position.y += 1.0f;
}

Problem is with this method, that Begin() / Next() use an internal iterator which makes nesting not possible. Not impossible though; SharedList::Iterator, SharedMap::Iterator can help.

SharedList::Iterator iterator = invitations.getIterator;
for (Actor* party_guest = iterator.Begin(); party_guest = iterator.Next();) {
  SharedList::Iterator dance_iterator = invitations.getIterator();
  for (Actor* other_party_guest = dance_iterator.Begin(); other_party_guest = invitations.Next(); ) [
     other_party_guest->moveTowards(party_guest->getGlobalPosition());
  }
}

That should start them dancing.