How to retrieve user data from NxOgre objects?

Night Elf

27-08-2007 17:01:33

How can I retrieve custom data from triggers, characters, actors and bodies? (For example in a trigger callback).

betajaen

27-08-2007 17:06:41

Do you mean the NxActor's UserData?

Night Elf

27-08-2007 17:12:27

No, I mean my custom user data. (I tried to use NxActor userData, but then noticed you used that internally in NxOgre).

betajaen

27-08-2007 17:36:47

Yeah we do. What you want to do? Some sort of Custom GameObject that is an actor?

Night Elf

27-08-2007 17:43:27

For example, when I get onEnter called for a trigger, I need to identify and retrieve my game objects associated with the trigger and the character so that I can perform the appropriate actions.

A simple void* member, while ugly, seems like the simplest way to achieve that...

I thought about subclassing NxOgre's classes to add my custom data, but as those must created by Scene::createXXXX() methods instead of directly using new, I believe that approach wouldn't work...

betajaen

27-08-2007 17:56:22

You can subclass Actor and use it in your own application, and even use new and delete but obviously not any Scene creator/destroyer functions. However you must handle the pointers yourself, and delete them before the Scene they are in is destroyed.

The Body class a great example of this, and you can copy and paste it into your own application (change the name of course), and use that as your physics game object.

I recommend anyone who is seriously using NxOgre to have there own "Inherited Actor" class in their game engine or application.

I'll walk you through it if you like.

Night Elf

27-08-2007 18:39:47

The Body class a great example of this, and you can copy and paste it into your own application (change the name of course), and use that as your physics game object.
OK, but Bodies are still created by the Scene. Is it OK to create it from outside?

I looked inside the createBody function:

Body* body = new Body(identifier, this, firstShapeDescription, pose, params);
mActors.lock(body->getName(), true);
return body;


What does the mActors bit do? What should I do about it if I create a Body from outside the Scene?

Also, can I directly subclass Body instead of Actor?

Can I do the same with Characters? Looking at the createCharacter funcion, it seems subclassing a Character would be a bit more involved...

betajaen

27-08-2007 18:48:42

Alright, here is a copy and paste of the "How to create your own Actor class with NxOgre" comment block in NxOgreActor.h '35.

Using your own Actor class with NxOgre:

The Header of "IActor", the inherited Actor.

class NxExport IActor : public Actor {

public:

// Constructors similar to. Used for creating a NxActor by hand through a blueprint,
// or the NxuStream tool
IActor(const NxString& name, Scene*);

// Constructors similar to. Normal Everyday Constructor.
// Name, Scene, ShapeBlueprint, Pose, ActorParams are required by Actor, so they
// must be part of your constructor.
IActor(const NxString& name, Scene*, ShapeBlueprint*, const Pose&, ActorParams = "");

// Destructor.
virtual ~IActor();

// Your IActor may have some visualisation.
virtual bool hasVisualisation() const {return true;}

// to call ShapeSimulate
void simulate(float);

// to call ShapeRender, and to render your visualisation.
void render(float);

// Save any custom data related to your Inherited Actor to a StringPairList
StringPairList saveCustom();

// Restore any custom data to your Inherited Actor.
void restoreCustom(StringPairList);

};



The code side of the IActor:

IActor::IActor(const NxString& name, Scene* scene) : Actor(name, scene) {
// Do nothing. Not even your own visualisation. RestoreCustom will kick in soon to handle that.
}

IActor::IActor(const NxString& identifier, Scene* scene, ShapeBlueprint *firstShapeDescription, const Pose& pose, ActorParams params)
: Actor(identifier, scene, firstShapeDescription, pose, params) {
// Setup visualisation stuff here.
// You can access the SceneManager from mOwner->getSceneMgr()
}

IActor::~IActor {
// Clean up your visualisation here. The destructor in Actor will clean up the NxActor stuff.
}


void IActor::simulate(float dT) {
// Required...
if (mActor) {
shapeSimulate(dT);
}
}

void IActor::render(float dT) {
// You can get the Position and Orientation of the NxActor using:
// getGlobalPosition();
// getGlobalOrientation();
//
// If you have NX_UNSTABLE_USE_SCENE_ACTIVE_TRANSFORM on, render will only be called
// if the NxActor has moved.
}


StringPairList IActor::saveCustom() {

// Required...
StringPairList l;
l.insert("ActorType", "IActor"); // IActor or the name of your class; *Not* Actor or Body.
l.insert("Key", "Value");
// You can have multiple keys with the same name.
}

void IActor::restoreCustom(StringPairList spl) {

for (StringPairList::StringPair sp = spl.begin();spl.hasNext();) {
sp = spl.next();

NxString key = sp.first;
NxString value = sp.second;
Ogre::StringUtil::toLowerCase(key);

if (key == "x") {
mY = value;
}
}


Using a NxOgre Container to store your IActor.

class SomeGameManagerClass {

typedef NxOgre::Container<NxString, IActor*> IActors;

IActors mActors;

};


Creating an IActor and storing the pointer.

// Create a new IActor.
IActor* iactor = new IActor("name", mScene, new CubeShape(1), Vector3::ZERO, "mass: 10");

// Store the pointer in IActors.
mIActors.insert(iactor->getName(), iactor);

// A copy of the IActor has been placed in mScene::mActors. NxOgre does not "own" the class we do. So we are responsible for deleting it.

// To own the IActor, we must "lock" it.
IActors.lock(iactor->getName(), true);


When the time is right, we must delete the IActor before the destruction of the Scene.

mIActors.destroyAllOwned();
mWorld->destroyScene(mScene->getName());


or:

mIActors.destroyAllOwned();
delete mWorld;




You wouldn't want to inherit your class from Body, because Body is also an inherited Actor. It's really easy once you get your head around it. 95% of everything is handled for you anyway.


With Characters sadly not, but Characters have names don't they? A quick loop up in a stl map would help. ;)

frier

27-08-2007 18:50:29

Sorry to hi-jack but this caught my eye.

I recommend anyone who is seriously using NxOgre to have there own "Inherited Actor" class in their game engine or application.

I'll walk you through it if you like.


1)why
2)how/example?

edit: ok you beat me. yeah i tried to inherit actor class but it didnt like it. ill read the example now
-FrieR

betajaen

27-08-2007 18:53:08

How: See Above.

Why: Well for one thing GamePhysics objects aren't just about Physics and the visualisation; You may want some sort of sound emitter attached to it for it to emit sounds if it hits something or perhaps some sort of AI code (say if it was a turret) or many other things.

Caphalor

27-08-2007 19:09:38

I use a big container class for every type of Object. You can initialize it using string params or a char array (for loading from file). The class provides some functions likes setPosition, setOrientation, setParent, setName etc. so that you don't have to cope with the fact that you have a node, a body, a sound, a light or a particlesystem. I don't know whether it's a good solution, but it seemed to be suitable for my editor.

Night Elf

27-08-2007 19:11:52

Thanks for the very detailed answer, betajaen!

What about triggers? Should I follow the same steps to make an ITrigger?

frier

27-08-2007 19:22:54

So i could create.. say a iCarActor class.

i can then implement my own methods that do the following:

- Lock Y axis on the actor if its in mid air(not colliding with anything) and do a sound while your at it.

- It also will know how to create a common basic vehicle for my project using other inherited nxOgre classes(like the one i just make for AllWheelDrive) as members.

i Guess these things would warrant a inherited Actor class?

betajaen

27-08-2007 19:25:45

No, Triggers are quite specific. The TriggerCallback system is quite extensive as it is, I'm sure you can adapt to it. ;)

betajaen

27-08-2007 19:26:31

So i could create.. say a iCarActor class.

i can then implement my own methods that do the following:

- Lock Y axis on the actor if its in mid air(not colliding with anything) and do a sound while your at it.

- It also will know how to create a common basic vehicle for my project using other inherited nxOgre classes(like the one i just make for AllWheelDrive) as members?


Yep. You could do that; It would be almost like a Body and a WheelSet in one.

Night Elf

27-08-2007 19:54:40

No, Triggers are quite specific. The TriggerCallback system is quite extensive as it is, I'm sure you can adapt to it. ;)

Mmmh... OK, I'll see what I can do.

I still think a simple void* customData member in Actors, Characters and Triggers would be the simplest solution to something like this. Maybe not very OO-like, but effective. (It wouldn't even need to be a void*, you could have an empty CustomData class which users can freely subclass to suit their needs. Then Actors, Characters and Triggers would have a CustomData* member they can just ignore as it would only be used by the client application).

frier

27-08-2007 20:03:45

I just quickly implemented an inherited Actor Class betajaen.

i fixed all the errors i was getting. This is one of them:

Error 1 error C2555: 'BugActor::saveCustom': overriding virtual function return type differs and is not covariant from 'NxOgre::Actor::saveCustom' c:\dev\nxogre\tutorials\compiler\source\bugactor.h 36

Im just worried about all these warnings:

Warning 1 warning C4273: 'BugActor::BugActor' : inconsistent dll linkage c:\dev\nxogre\tutorials\compiler\source\bugactor.cpp 3

betajaen

27-08-2007 20:38:22

@Night Elf
Ogre doesn't have anything like that, it just expects to you to get along with SceneNodes as it is. I would like it to be the same with Actor. Can't you use the name of the Actor as some sort of, I dunno an identifier. ;)

At least then you can use it to look up the IActor, in GameManagerObject::IActors.

@Frier
Try removing the "NxExport" part from the class.

Night Elf

27-08-2007 20:57:45

@Night Elf
Ogre doesn't have anything like that, it just expects to you to get along with SceneNodes as it is. I would like it to be the same with Actor.


Yes, that's true, but Ogre doesn't use callbacks (at least, not the portion of Ogre I've used so far), so something like this isn't necessary. The problem in this case are callbacks, where most of the time you need access to your data to be able to do anything useful.

Can't you use the name of the Actor as some sort of, I dunno an identifier. ;)

At least then you can use it to look up the IActor, in GameManagerObject::IActors.

Yes, I could do something like that, though it'd be quite a bit slower than just having the pointer right there, and surely much less convenient

frier

31-08-2007 03:08:54

OK been a bit busy lately but I'm getting back to business now.

I don't really understand what the following functions do? some sort of customer actor attribute saver/restore?

NxString iActor::saveCustom()

void iActor::restoreCustom(StringPairList spl)


also the :
StringPairList iActor::saveCustom();

function has a different return type to the actors saveCustomer function.

virtual NxString NxOgreActor::saveCustom()

i changed the iActor saveCustomer to return a NxString though.

Edit: i was reading how the body inherits and uses the actor class. i need most of the body attributes so ill just copy all of its attributes and functions over.

betajaen

31-08-2007 10:55:29

saveCustom and restoreCustom are for the serialiser it's required and they both need to be using the "StringPairList" and not the NxString. It's a required virtual function of Actor.

If you do copy body code over, your application will be under the same licence as NxOgre GPL/LGPL. Can't you just follow the tutorial I wrote?, I think I made it pretty clear.

luis

31-08-2007 11:59:26

is it possible to just tell to the Actor to hold a reference to some user data?
that user data could be something 'ligther' than inheriting from Actor and in that way you dont have to hold a reference and then delete it....

Just like Ogre do with MovableObject class:
http://www.ogre3d.org/docs/api/html/cla ... dingBoxa34



then the UserDefinedObject class acts like an "adaptor" class ;)
http://www.ogre3d.org/docs/api/html/cla ... bject.html
Detailed Description
This class is designed to be subclassed by OGRE users, to allow them to associate their own application objects with MovableObject instances in the engine.

Remarks:
It's always been suggested that an OGRE application would likley comprise a number of game objects which would keep pointers to OGRE objects in order to maintain the link. However, in some cases it would be very useful to be able to navigate directly from an OGRE instance back to a custom application object. This abstract class exists for this purpose; MovableObjects hold a pointer to a UserDefinedObject instance, which application writers subclass in order to include their own attributes. Your game objects themselves may be subclasses of this class, or your subclasses may merely be a link between them.

Because OGRE never uses instances of this object itself, there is very little definition to this class; the application is expected to add all the detail it wants. However, as a hint, and for debugging purposes, this class does define a 'type id', which it is recommended you use to differentiate between your subclasses, if you have more than one type.

luis

31-08-2007 13:07:20

ok, forget wat i said..... after chating with betajaen i realize that there is no need to have it in the Actor class....

NxOgre users (we) have either an Actor without visual representation (without MovableObject/Entity) and in that case he/she should inherit from Actor class or an Actor with a body and in that case you could use the Ogre way of adding your own UserObject ;)

frier

31-08-2007 14:12:47

Yup, i've finished with all the inheriting of the Actor class and seems to be fine. yes those examples you posted work greatebetajaen

Um also it crashes when i try to select my Inherited Actor in CAKE? any ideas why?


Need to do garbage collection now, which is mentioned above. :)

betajaen

31-08-2007 14:18:15

It's casting it as an Body. Which obviously it isn't, hence the crash.

frier

31-08-2007 14:23:49

ah that makes sense.

Night Elf

31-08-2007 15:39:38

I understand that subclassing Actor works ok, but I still think it's too much work for something quite simple. Plus, it doesn't work for triggers or characters, which I need.

I ended up modifying NxOgre to work like I wanted it to... I added a very simple CustomData class (very much like the UserDefinedObject in Ogre, which I didn't know till I read Luis' post, perhaps I could have used that instead) and a public mCustomData member in Actor, Character and Trigger. As NxOgre doesn't need to manage it, it doesn't break any interfaces and it's just up to the client to use it or not.

Here's a patch file for revision 34 in case anyone finds it useful:

Index: NxOgre/include/NxOgreActor.h
===================================================================
--- NxOgre/include/NxOgreActor.h (revision 34)
+++ NxOgre/include/NxOgreActor.h (working copy)
@@ -536,6 +536,8 @@

private:

+ public:
+ CustomData* mCustomData;

};// End of Actor Class

Index: NxOgre/include/NxOgreCharacter.h
===================================================================
--- NxOgre/include/NxOgreCharacter.h (revision 34)
+++ NxOgre/include/NxOgreCharacter.h (working copy)
@@ -148,6 +148,8 @@

private:

+ public:
+ CustomData* mCustomData;
};


Index: NxOgre/include/NxOgrePrerequisites.h
===================================================================
--- NxOgre/include/NxOgrePrerequisites.h (revision 34)
+++ NxOgre/include/NxOgrePrerequisites.h (working copy)
@@ -333,6 +333,11 @@

////////////////////////////////////////////////////////

+ // Used to store custom user data in Actors, Characters and Triggers.
+ // User can freely subclass to their own needs.
+ class CustomData
+ {
+ };
};

#endif
Index: NxOgre/include/NxOgreTrigger.h
===================================================================
--- NxOgre/include/NxOgreTrigger.h (revision 34)
+++ NxOgre/include/NxOgreTrigger.h (working copy)
@@ -257,6 +257,8 @@
TriggerCallback* mCallback;
bool mCallbackOwned;

+ public:
+ CustomData* mCustomData;
};

//////////////////////////////////////////////////////////
Index: NxOgre/source/NxOgreActor.cpp
===================================================================
--- NxOgre/source/NxOgreActor.cpp (revision 34)
+++ NxOgre/source/NxOgreActor.cpp (working copy)
@@ -167,7 +167,7 @@

//////////////////////////////////////////////////////////

-Actor::Actor(const NxString& Identifier, Scene* scene, bool isActorBased) : mName(Identifier), mOwner(scene) {
+Actor::Actor(const NxString& Identifier, Scene* scene, bool isActorBased) : mName(Identifier), mOwner(scene), mCustomData(0) {
mActor = 0;
if (isActorBased)
mOwner->_registerActor(mName, this);
@@ -175,7 +175,7 @@

//////////////////////////////////////////////////////////

-Actor::Actor(const NxString& name, Scene* scene, ShapeBlueprint *shape, const Pose& pose, ActorParams params) : mName(name), mOwner(scene) {
+Actor::Actor(const NxString& name, Scene* scene, ShapeBlueprint *shape, const Pose& pose, ActorParams params) : mName(name), mOwner(scene), mCustomData(0) {

if (scene->getActors()->has(name)) {

Index: NxOgre/source/NxOgreCharacter.cpp
===================================================================
--- NxOgre/source/NxOgreCharacter.cpp (revision 34)
+++ NxOgre/source/NxOgreCharacter.cpp (working copy)
@@ -37,7 +37,7 @@
////////////////////////////////////////////////////////////////////////////////////////////////

Character::Character(const NxString &name, Scene* scene, CharacterController* cc, Pose p , CharacterParams cp)
-: mName(name), mScene(scene), mCharacterController(cc), mNode(0), mEntity(0) {
+: mName(name), mScene(scene), mCharacterController(cc), mNode(0), mEntity(0), mCustomData(0) {

mMoveVectorController = mCharacterController;
mCharacterController->_registerCharacter(mName, this);
Index: NxOgre/source/NxOgreTrigger.cpp
===================================================================
--- NxOgre/source/NxOgreTrigger.cpp (revision 34)
+++ NxOgre/source/NxOgreTrigger.cpp (working copy)
@@ -32,7 +32,7 @@

//////////////////////////////////////////////////////////////////////

-Trigger::Trigger(const NxString& identifier, Scene* scene, ShapeBlueprint* shape, const Pose& pose, ActorParams params) : Actor(identifier, scene, false) {
+Trigger::Trigger(const NxString& identifier, Scene* scene, ShapeBlueprint* shape, const Pose& pose, ActorParams params) : Actor(identifier, scene, false), mCustomData(0) {
_createActor(shape, pose, params);
mOwner->_registerTrigger(mName, this);
}

betajaen

31-08-2007 16:11:57

You can subclass Character and there is no point sub-classing triggers, because all of the action is handled in the callback.

betajaen

31-08-2007 16:27:43

Yep; just tried it and it works fine:

class myCharacter : public Character {

public:

myCharacter(NxString id, Scene* scene, CharacterController* cc, NxOgre::Pose pose, CharacterParams params) : Character(id, scene,cc, pose, params) {

createNode();
attachMesh("cube.1m.mesh");
mNode->scale(toVector3(params.mDimensions));
}


~myCharacter() {

}
};



mCharacter = new myCharacter("Woo", mScene, mWorld->getCharacterController(), Vector3(0, 10,5), "type: box, dimensions: 1 2 1");

frier

31-08-2007 16:29:13

OK cool, i like seeing different ways of doing things.

I understand how Night Elf implemented it is that you inherit the CustomData class and fill it with attributes and members, then passes it to, Actor, and assigns it to the local member mCustomData pointer, but which class does the "delete mCustomData" or you dont need to?

betajaen

31-08-2007 16:35:23

Well it's your data, you delete it when you want to. It's not the character or triggers responsibility.

I would still prefer you guys to use the inherited system for the Character, like with Actor. Nobody would really use it as a main class to represent a character in your game, I wouldn't.

Night Elf

31-08-2007 16:57:12

I would still prefer you guys to use the inherited system for the Character, like with Actor. Nobody would really use it as a main class to represent a character in your game, I wouldn't.
I wouldn't either. It's just that I prefer to have the NxOgre::Character as a member of my own character (composition) instead of inheriting from it. I prefer not to inherit from classes in the libs I use (unless it's a simple interface that's only meant to be subclassed like CustomData in this case or Ogre::FrameListener).

I use the custom data to store a pointer to my own character class for whenever I have to trace it from an NxOgre::Character. Not the other way around (like having, let's say, a CustomCharacterData stored inside the NxOgre::Character and using NxOgre::Character as my main character class).

but which class does the "delete mCustomData" or you dont need to?
As I use the custom data just to have a way to trace back to my own character class, this is not a problem. The NxOgre::Character doesn't "own" the pointed data, its just a reference. My Level object handles deletion of my own characters just the same as before, there's no special delete nxCharacter->mCustomData. (Of course, you have to delete the NxOgre::Character together with my character or set mCustomData to NULL to prevent inconsistencies).

betajaen

31-08-2007 17:06:39

I fully agree.

With a few comments; Inheritance is quite useful if you want a "low" wrapper class, with a low amount of features and some control over the character. Where as you can add tons of features with composition and have complete control over it. However it needs quite a bit of wrapping done, and a tiny bit slower.

I suppose it's a bit of a trade off really.

luis

31-08-2007 18:32:26

i'm using composition too.... the problem i see with inheritance from libs is the code dependency and if the "base" class is too big it polutes all your 'scope'/context in your class....

@Night Elf
That is the idea ! but i'll add some spice to your recipe:

class CustomData
{
public:
// default constructor
CustomData(void) {;}
// virtual destructor to prevent leaks
virtual ~CustomData(void){;}
// disallow direct intances of this class, also ints cast very well to enums ;)
virtual int getId(void) const = 0;
};


i was looking at this post:
http://www.ogre3d.org/phpBB2addons/view ... 7130#27130

and since you can make a group of collisions that could be 'interesting' to you, you could downcast the actors here to a Body for example:

class myCallback : public GroupCallback::InheritedCallback {
public:
void onStartTouch(Actor* A , Actor*B) {
Body *C = static_cast<Body*>(A);
}
....


Since you know if it is a body or not (since *you* added it to the group)... then with that body you could access to Ogre::UserDefinedObject with its entity. Perhaps this is not too elegant, but should work...

In that way there is no need to hack NxOgre. But the idea of using that customdata isn't that bad...

TMT

10-10-2007 19:53:34

I want to make an appeal to betajaen to add a custom data pointer down in Actor (and maybe some others) for us. I know we could modify it ourselves, but it sure seems like several people prefer that method rather than the subclassing (me included).

My personal reasons:
- I want Actor and anything derived from Actor (i.e. Body) to have that custom pointer available
- What good is batch creation in Scene if it can't batch create my derived class??

I'm just voting. But even if you still don't like it, how about a #define at least to control whether it exists or not. That way I won't have to keep merging my changes in when new revisions come out.

Thanks for the wonderful NxOgre.

betajaen

10-10-2007 20:11:15

Nope. For the reasons I explained in this thread. You should a class that inherits actor, it's much faster, neater and you won't have to keep casting that void pointer every time you want to use it.

I've have some idea on how to support custom actors directly with the scene factory methods, including the batching functions. As well as Garbage collection like with Body and a non-subclassed Actor. It involves function and method pointers.

kungfoomasta

10-10-2007 21:27:16

Why not imitate ParticleSystems, Materials, and other ogre objects by provinding a "getOrigin" and "setOrigin" set of functions?

Ogre::String mOrigin;

Set the Origin to the name of your character class that owns the nxCharacter.

Inheritance is a nice feature, but realistically everybody will be working with a composition design. Try making an Entity class that inherits from Ogre::Entity and you will see how painful it will be to create your class, and how bloated your class will become. Only wrap functions that you need. (specific to your project) My suggestion anyway. :)