Character controller class - v.0.9

Aquatix

31-10-2007 22:16:53

Well, better late than never, right? :wink:
So, as a foreword:
this is a base class (in other words you will need to make sure your top-level classes (e.g. Player, NPC, Creature, whatever else...) inherit it). The class is called Actor. It provides the physical "cage" for the character, as well as a convinient way to control it. It has one dependency - GamePhysicsManager (which is again a base class, which deals with CollisionListening, etc.) The code for both is below:

-EDIT- : a few minor fixes

Actor.h

#ifndef Actor_H
#define Actor_H

#include <GamePhysicsManager.h>

class Actor {
public:
~Actor(void);
Actor ();
void actor_init (const Ogre::String &actorName, const Ogre::String &actorMesh, const Ogre::Real &actorHeight,
const Ogre::Real &actorWidth, const Ogre::Real &actorFootH, const Ogre::Real &actorMaxAng);
//Actor physics model
OgreOde::SimpleSpace *pSpace;
OgreOde::Body *pBody;
OgreOde::Geometry *pCapsuleBase;
OgreOde::TransformGeometry *pCapsule;
OgreOde::RayGeometry *pWalkRay;
//Actor physics body parts
OgreOde::Geometry *pHeadBase;
OgreOde::TransformGeometry *pHead;
OgreOde::Geometry *pTorsoBase;
OgreOde::TransformGeometry *pTorso;
OgreOde::Geometry *pArmLeftBase;
OgreOde::TransformGeometry *pArmLeft;
OgreOde::Geometry *pArmRightBase;
OgreOde::TransformGeometry *pArmRight;

//Visual representation
Ogre::SceneManager *SceneMgr;
Ogre::SceneNode *pNode;
Ogre::SceneNode *mNode;
Ogre::Entity *mModel;

//Resulting external Actor parameters
Ogre::Real rSpeedWalk, rSpeedRunMult, rJumpHeight;

//Params for total control
Ogre::Real _actorHeight, _actorWidth, _actorFoot, _max_angle; //for char control
int walk_fwd, walk_str;
bool _on_ground;
//Control vars
bool _req_jump;

//Here go the functions
virtual void update (const Ogre::Real &timeGone);

//Actions low-level
void act_walk (void);
void act_jump (void);
void act_crouch (void);

//Actions high-level
void walk (int walkF, int walkS);
void run (void);
void jump (void);

protected:

};
#endif


Actor.cpp

#include <Actor.h>

using namespace Ogre;

Actor::~Actor(void) {

}

Actor::Actor() {

}

void Actor::actor_init(const String &actorName, const String &actorMesh, const Real &actorHeight,
const Real &actorWidth, const Real &actorFootH, const Real &actorMaxAng)
{
SceneMgr = Root::getSingletonPtr()->getSceneManager("Game_Scene_Manager");
GamePhysicsManager *mGamePhysMgr = GamePhysicsManager::getSingletonPtr();

//Main body init
pSpace = new OgreOde::SimpleSpace (mGamePhysMgr->World, mGamePhysMgr->Space);
pSpace->setInternalCollisions (false);
pBody = new OgreOde::Body (mGamePhysMgr->World, actorName);
pBody->setMass (OgreOde::CapsuleMass (75, actorWidth/2, ::Vector3::UNIT_Y, actorHeight));
pBody->setAutoSleep (false);
pWalkRay = new OgreOde::RayGeometry (actorHeight/2,mGamePhysMgr->World, pSpace);
pCapsuleBase = new OgreOde::CapsuleGeometry (actorWidth/2, actorHeight-actorWidth-actorFootH, mGamePhysMgr->World, pSpace);
pCapsule = new OgreOde::TransformGeometry (mGamePhysMgr->World, pSpace);
pCapsuleBase->setPosition(Vector3(0, actorFootH/2, 0));
pCapsuleBase->setOrientation(Quaternion(Degree(90),Vector3::UNIT_X));
pCapsule->setEncapsulatedGeometry(pCapsuleBase);
pCapsule->setBody(pBody);
//Visual
mModel = SceneMgr->createEntity(actorName,actorMesh);
pNode = SceneMgr->getRootSceneNode()->createChildSceneNode(actorName);
mNode = pNode->createChildSceneNode(Vector3(0,-actorHeight/2,0));
mNode->attachObject(mModel);
pNode->attachObject(pBody);

//Body parts init

//save Vars
_actorHeight = actorHeight;
_actorWidth = actorWidth;
_actorFoot = actorFootH;
_max_angle = actorMaxAng;
walk_fwd=0; walk_str=0; rSpeedRunMult=1;
_req_jump=false;
}

void Actor::update(const Real &timeGone) {

}

void Actor::act_jump(void) {
/*if (_on_ground && _req_jump) {
pBody->setLinearVelocity(Vector3(pBody->getLinearVelocity().x,rJumpHeight,pBody->getLinearVelocity().z));
_req_jump = false;
}*/
}

void Actor::act_walk(void) {
/*Vector3 walkVect;
if (_on_ground) {
walkVect = Vector3(rSpeedWalk*walk_str*rSpeedRunMult, 0, rSpeedWalk*walk_fwd*rSpeedRunMult);
pBody->setLinearVelocity(pBody->getOrientation()*walkVect);
}
else {
walkVect = Vector3(rSpeedWalk*walk_str*0.3,0,rSpeedWalk*walk_fwd*0.3);
pBody->setLinearVelocity(pBody->getLinearVelocity()+pBody->getOrientation()*walkVect);
}*/
}

void Actor::act_crouch(void) {
/*GamePhysicsManager *mGamePhysMgr = GamePhysicsManager::getSingletonPtr();

pWalkRay->setLength(_actorHeight/4);
pCapsule->setEncapsulatedGeometry(0);
pCapsuleBase->~Geometry();
pCapsuleBase = new OgreOde::CapsuleGeometry (_actorWidth/2, _actorHeight/2-_actorWidth-_actorFoot,mGamePhysMgr->World,pSpace);
pCapsuleBase->setOrientation(Quaternion(Degree(90),Vector3::UNIT_X));
pCapsule->setEncapsulatedGeometry(pCapsuleBase);*/
}

///////--------------============================External-driven actions=======================-----------------\\\\\\\\\\

void Actor::walk(int walkF, int walkS) {
/*walk_fwd = walkF;
walk_str = walkS;*/
}

void Actor::jump(void) {
//_req_jump = true;
}


GamePhysicsManager.h

#ifndef GamePhysicsManager_H
#define GamePhysicsManager_H

#include <OgreRoot.h>
#include <OgreRenderWindow.h>
#include <OgreStringConverter.h>

#include <OgreOde_Core.h>

//#include "WalkableObject.h"

class GamePhysicsManager: public OgreOde::CollisionListener, public OgreOde::TriangleMeshCollisionListener {
public:
~GamePhysicsManager();
GamePhysicsManager ();

OgreOde::World *World;
OgreOde::Space *Space;
OgreOde::StepHandler *Stepper;
OgreOde::Contact *Contact;

virtual bool collision (OgreOde::Contact *contact);
static GamePhysicsManager* getSingletonPtr( void );

protected:
GamePhysicsManager( const GamePhysicsManager& ) { }
GamePhysicsManager & operator = ( const GamePhysicsManager& );
static GamePhysicsManager *mGamePhysicsManager;
};
#endif


GamePhysicsManager.cpp

#include <GamePhysicsManager.h>

using namespace Ogre;

GamePhysicsManager* GamePhysicsManager::mGamePhysicsManager;

GamePhysicsManager::~GamePhysicsManager() {

}

GamePhysicsManager::GamePhysicsManager() {
World = new OgreOde::World(Root::getSingletonPtr()->getSceneManager("Game_Scene_Manager"));
World->setCollisionListener(this);
Space = World->getDefaultSpace();
//Stepper = new OgreOde::ForwardFixedStepHandler(World,OgreOde::StepHandler::QuickStep,1/30,1/4,1.0);
Stepper = new OgreOde::ForwardFixedInterpolatedStepHandler(World,OgreOde::StepHandler::QuickStep,0.01,1/60,1/4,1.7);
//Stepper->setAutomatic(OgreOde::StepHandler::AutoMode_NotAutomatic,Ogre::Root::getSingletonPtr());
World->setAutoSleep(true);
World->setGravity(Ogre::Vector3(0,-9.83665,0));
World->setERP(0.8);
World->setCFM(10e-5);
World->setAutoSleepAngularThreshold(0.1);
World->setAutoSleepLinearThreshold(0.1);
World->setAutoSleepSteps(10);
World->setContactCorrectionVelocity(2);
Ogre::Root::getSingletonPtr()->setFrameSmoothingPeriod(5); //Seems to have no effect really...
}

bool GamePhysicsManager::collision(OgreOde::Contact *contact) {
return true;
}

GamePhysicsManager* GamePhysicsManager::getSingletonPtr( void ) {
if( !mGamePhysicsManager ) {
mGamePhysicsManager = new GamePhysicsManager();
}

return mGamePhysicsManager;
}


Now, that all is complete, apart from the Actor::update, which needs to be called every frame, passing the frameTime in milliseconds. This method is empty in the base class. Why? Well, it is not convinient for it to be there, instead you would put it in each of your top-level classes and modify according to your needs. But the template is the same everywhere. Here we go:
Actor::update (in a top-level class)

GameObjectManager *mGameObjMgr = GameObjectManager::getSingletonPtr();
_on_ground = false;
bool ray_col = false;
OgreOde::Contact *ray_cont;
std::map<std::string, TerrainObject*>::iterator itTerrains;
std::map<std::string, TerrainObject*>::iterator itTerrainsEnd;
itTerrains = mGameObjMgr->mTerrainObjects.begin();
itTerrainsEnd = mGameObjMgr->mTerrainObjects.end();

pWalkRay->setDefinition(pBody->getPosition(),Vector3::NEGATIVE_UNIT_Y);
for (; itTerrains != itTerrainsEnd; ++itTerrains) {
if (pWalkRay->collide(itTerrains->second->TerrainGeom,mGameObjMgr)) { ray_col = true;}
}
if (ray_col) {
ray_cont = mGameObjMgr->Contact;
pBody->setPosition(ray_cont->getPosition()+Vector3(0,_actorHeight/2,0));
pBody->setLinearVelocity(Vector3::ZERO);
_on_ground = true;
}

pBody->setAngularVelocity(Vector3::ZERO);
pBody->setOrientation(Quaternion(pBody->getOrientation().xAxis(),Vector3::UNIT_Y,pBody->getOrientation().zAxis()));
//Possible actions
if (walk_str != 0 || walk_fwd != 0) act_walk();
act_jump();

The only scary thing here is GameObjectManager - basially this is just you class, which inherits GamePhysicsManager, but also keeps a list of your in-game objects. Terrain object is nothing other than an object, which hold a mesh (simple one, only for physics, not for rendering) and a body. I can upload it as well, if you want.

Well, that's it for now, all should be working. Please try to import this into your project and tell me what do you think about it. I will keep updating it over the next few days. And soon I will post a demo to see, what it should be like. For now it is a class, which fulfill the standarts of games like Unreal, Oblivion, etc.

Hope you will find it usefull,
Best wishes,
Aquatix.

P.S. Please don't forget, that I do not guarantee for this to work, and even if the code blows up your entire system, it's not my fault! :wink:

kungfoomasta

31-10-2007 23:12:47

Wow I'm getting some big time slow downs at Ogre3d.org right now.. :(

THANK YOU!!

Your work will greatly help me out. Tonight I will finish up my small TODO list and tomorrow I will start working with your code. Due to my Component Based Design I will probably try to split up your code into segments:

CCapsuleShape
CCapsuleMass

And probably update one of my current components, CMovement. Also thanks for posting up the PhysicsManager portion, I haven't used ODE in a while. I was looking at the Landscape demo, but I'll probably just stick with what you have. I remember mention of various time stepping, so I don't want to venture out until I've got something working.

If you could share your terrain code that would be great also. (By the way, are you using default TSM, or something like ETM?) Are the terrain geometry shapes created via heightmap, or are vertices/indices needed? I already figured out how to get ETM's vertex/index data when I used OgreOpcode, so if this is needed, it shouldn't be hard to revisit and plugin to ODE. (heightmap would be a breeze, I imagine. Although I think Tuan mentioned heightmap shape isn't working)

I'll probably need to revisit the code used to actually move the character forward, but I remember where its at so that's ok.

I'll keep you posted with any ideas/comments/questions/etc.

Thanks again! :D

rewb0rn

01-11-2007 21:57:17

thx, i will have a look at it as soon as i finished networking. did you think of putting it to the ogreode wiki section?

Aquatix

02-11-2007 04:14:54

Surely I will, but need to finish debugging first. Don't want to see beginners using the code, which is not yet fully polished :D Plus I'm a bit in doubt in as to how abstract should I keep it. For instance, IMO the way prefabs are done is not exatly the best way since you lose too much flexibility, and more importantly they are ever hard to debug... So, maybe instead make a "basic" class, and then an FPS adopted class and a RPG adopted or something?

kungfoomasta

02-11-2007 07:00:34

You mean there are differences in functionality, depending on whether its RPG/FPS/Basic?

For me personally, I would be going for the RPG style, as the game we're really developing is an RTS, but with a lot of interaction with the environment. Also in the case of units moving into each other, they shouldn't stick or anything.

Due to my component design I'll break it into parts like this:

Mass
Shape
Movement
SlidingCollisionHandler (?)

I don't see in your code where is handles sliding along objects. Is it feasible to have GameObjects handle their own Collisions? Not sure how I will design this, but the way the collisions are handled will be based on the GameObject properties. Two actors should slide, but say an actor goes into water, or walks into a plant, the collision handling should be different.

rewb0rn

02-11-2007 08:02:38

i do this by calling a collide method of the objects in my collision listener. therefor all objects that are in the scene have user objects that are derived from a collidingobject class. in that method you can specify what fraction is to be used, what bouncyness etc. basically i do something like this:

contact->setBouncyness(1.0);

Obj1->collide(contact);
Obj2->collide(contact);

where Obj1->collide() might do something like

contact->setBouncyness(contact->getBouncyness() * myBouncynessFactor);

Thats why I added getters to the contact class, I posted it in the forums once but I think it has never been added to cvs.

Aquatix

02-11-2007 14:03:25

Hey, rewb0rn, that's a very interesting thing you are talking about there! Can you please expand on it a little? The reason I'm asking, is that the currect method of setting friction, bouncyness, etc. for me goes in my GameObjectManager class (which kinda creates/destroys all objects and their physics counterparts, but more importantly it is a derivative of a OgreOde::CollisionListener class). So, then I have a
bool GameObjectManager::collision (OgreOde::Contact *contact) {...}
and in this method I just iterate through all the game objects trying to find which one has collided, i.e. check their Geometry->getID() with contact->FirstGeometry->getID() or contact->SecondGeometry->getID(). And then I just set contact->setBouncyness(whatever), return true;
This is what is used in the character controller class above. Aber personally I think this is damn ineffecient.
And just one more thing - can you give a pointer, as to where you added getters to the contact class?

@kungfoomasta:
The differences in functionality are mainly how easy it is for a character to perform a certain action (e.g. basic just moves, FPS moves, but checks if its running or walking, RPG would also check if the character is tired and cannot run, for example). So, in these terms, if you have an RTS, I doubt you would need such things, like stamina, etc. (the RPG thingies)
As for the water, ground, plant, etc, then indeed these can be handled differently. Now, I'm just in doubt about what rewb0rn has said, since his way can be used to improve things here.

tuan kuranes

02-11-2007 16:04:08

rewb0rn: patch are really welcome, but please use Ogre sourceforge patch tracker interface so that I can see it, remind it and apply asap.

kungfoomasta

02-11-2007 22:33:48

Aquatix, I'm curious. What is your design for your game objects? Do you have an entity hierarchy, or use composition to create functional units? You're obviously ahead of where I'm at in terms of development, so just want to know what works.

Aquatix

03-11-2007 10:05:43

Heh, I doubt I'm much ahead of anything, considering all those bugs still around! :wink: Maybe in a week or so the system would be more or less stable. All I can say for sure, is that every object is basically a physics body with a few in-game parameters and an entity (or two, or three...). What is good about Ode here is that is enables a very easy direct control over bodies at any given point in time - if you need something, you just directly set the body's position and orientation, or you disable it for a while, or enable again, change velocity (not just apply a force), and so on and so forth.
As for the hierarchy, than there hardly is one. This is also due to the fact, that I'm trying to have quite a number of objects at the same time (say, have walking characters, flying machines, driving cars and flying ships).
At the top there's a game objects manager class. Its responsible for creating/destroing/iterating through all the objects out there. Most objects have their own class, and similar ones are always based on the same base class, so that they can be linked if necessary (e.g. Player and NPC classes both are based on the Actor class). But in generic terms, every class is self sufficient. They don't call for any shared functions or anything. This helps avoid the hassle of any possible incompatibility. I read what use said before about the component design you use. I must admit, I did try to use something similar at start, but they dropped due to the simple reason, that if I have to change anything, then it was a really great pain, and switched to just having independent class. Now, if anything needs to change, then its done like a charm, as never before seen classes can be just added, and then linked to whatever situations necessary.

rewb0rn

03-11-2007 13:53:38

Hi,

as you are so interested in it, I think I'm gonna write a tutorial on it and add it to the wiki, like how to handle collisions well.. But I'm a little lazy right now, so that might take some days, also for the patch.

Aquatix

03-11-2007 19:39:14

Great idea! More tutorials we have, better it is. Especially for the people, who only begin using OgreOde.

kungfoomasta

05-11-2007 19:51:20

I skimmed the source, looking at the steppers, since I'm getting ready to add OgreODE to my project.

Stepper = new OgreOde::ForwardFixedInterpolatedStepHandler(World,OgreOde::StepHandler::QuickStep,0.01,1/60,1/4,1.7);

I would assume that steppers add themselves as FrameListeners, but the only function I see that does this is StepHandler::setAutomatic, and I don't see this in your code. (Aquatix)

:?: Can I assume the stepper is being called for every frame that Ogre renders?

In my situation, each Window has a SceneManager, and a World object. So I will need to create a stepper for each World, and make sure the physics are being stepped every frame. My Window class is the equivalent to the PhysicsManager.

Aquatix

05-11-2007 21:30:39

@ kungfoomasta:
Actually, you are right, I forgot to mention - there's a function, which goes in your main loop:
Stepper->step(frameTime);
World->synchronise();
One I'll be over with my org problems, I'll update the code as well as post a working demo source.

@tuan:
Hey, tuan, could you please shed some light on the recent (well, a week ago or something) update of the Stepper class? AFAIK the last update was done by cloud, where he added a few things to the Geoms, right? So, who exactly did the code change for the stepper, and what is it meant to do? The reason for asking, is that after the change, I seem to be getting the weirdest behavior ever. Even if I try a completely blank project, still, only the use of Interpolated Stepper allows to overcome the trouble (which is basically the stepper not doing any steps, or doing them wrongly or sometimes simply crashing.
Thnx in advance!

kungfoomasta

06-11-2007 18:13:06

Right before I went to sleep last night I plugged in the code to create a world and stepper. I didn't register my class as a collision listener,

World->setCollisionListener(this);

which I plan to do tonight. But the main problem was that I got some strange crash when creating the stepper. Is it mandatory I have a collision listener before I create the stepper?

I will work on this more tonight, and hopefully get more useful information.

kungfoomasta

07-11-2007 07:49:12

I found the problem, lol.

In your code sample, you have values like "1/4", which actually results to the integer value of 0.

Stepper = new OgreOde::ForwardFixedInterpolatedStepHandler(World,OgreOde::StepHandler::QuickStep,0.01,1/60,1/4,1.7);

assert((max_interval > 0)&&("max interval must be greater than zero"));

Just to be explicit, the solution is to do something like "1.0/4.0", if anybody else gets this.

My next move is to make shapes and objects. Although if I do this, the entities will fall forever downward, won't they? If you have any time, can you post a little snippet on how Terrain can be converted into a shape?

kungfoomasta

07-11-2007 18:55:33

This is the TerrainGeometry constructor:


TerrainGeometry(World *world,
Space* space,
const Ogre::Vector3 &scale,
int nodes_per_sideX,
int nodes_per_sideY,
Ogre::Real worldSizeX,
Ogre::Real worldSizeZ,
bool centered,
Ogre::Real thickness = 10.0f);


Nowhere in this entire class do I see it asking for information regarding a specific terrain. How can it build the geometry without knowing the vertices, indices, or heightmap? Does this class even work?

The TriangleMeshGeometry class looks like it would work, since it asks for the data. Or a HeightmapGeometry would make things easier..

[edit]
Wow, I understand it now. The OgreODE TerrainGeometry class assumes standard ray queries will work, and uses that transparently for collisions. lol.

I wonder if making the ETM terrain into a trimesh would badly hurt performance. I may have to implement my own class, that overrides the getHeight function. If you fire OgreODE::RayGeometry objects it will correctly collide with terrain?
[/edit]

Aquatix

07-11-2007 20:03:50

Hi! and sorry for not responding, was damn busy :D
Well, first of all, ->setListener() should be before creating the stepper, otherwise it creates some relly bad behaviour (or like in your case it never starts).
About 1/4 - thnx for spotting that, it is indeed meant to be 1.0/4.0, or use 2 vars, and declare them as 1.0f and 4.0f. Thnx for spotting!
About the terrain, I've tested the Heighfield method for several months with a few other ppl, but the only conclusion we came up with was: use it for graphics (with some PagedTerrain SceneManager or whatever), but use simple meshes for physics (and it is better to have 1 bigger mesh than 2 smaller ones, that is in terms of speed). One way to do it is simple: use your 3d package (I use Max) to generate the terrain (you can use some sculpting tool too, like Zbrush or Mudbox), then save it as a heightfield map (use some plugin, like OgreMax), and then use the mesh, do an "optimize" to it, and plug it in for ODE physics.

A little snapshot of the terrain code is dead simple:

TerrainEnt->setCastShadows(false);
TerrainEnt->setVisible(false);
TerrainNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(terrainPos);
TerrainNode->attachObject(TerrainEnt);
TerrainEI = new OgreOde::EntityInformer(TerrainEnt,TerrainNode->_getFullTransform());
TerrainGeom = TerrainEI->createStaticTriangleMesh(mWorld,mSpace);

//Where:
TerrainEnt - Ogre::Entity,
terrainPos - Ogre::Vector3, you location
TerrainEI - OgreOde::EntityInformer
TerrainGeom - OgreOde::TriangleMeshGeometry

So, its something along those lines. I'll post some more in a more readable form, when I'll have time (hope it'll be soon :))
Ye, and hope the above helps in any way.

kungfoomasta

07-11-2007 20:20:41

Awesome, thanks for the information. I will try to use ETM to make an ODE::TriangleMeshGeometry object, instead of making the terrain into a mesh. One reason is because ETM supports real time deformation, which is a requirement we have. So I'll have to refit the triangle mesh at times, hopefully this doesn't take a lot from performance. It's really awesome that OgreODE lets you give an Ogre::Entity and creates a triangle mesh, very convenient.

kungfoomasta

15-11-2007 22:36:10

Just a heads up. I haven't forgotten about this, I'm quickly trying to get to this state so I can bug you about the character controller, but I'm doing some work on QuickGUI at the moment. :twisted:

kungfoomasta

27-11-2007 19:41:03

This is probably a dumb question, but Terrain doesn't need a Mass object right? Mass is what allows objects to be affected by gravity and interact with other bodies, so is terrain a body?

rewb0rn

27-11-2007 20:22:25

No, according to Aquatix' code its a normal Geometry. You could create a body with a mass for it to make it move, but thats probably a case that doesnt make sense.

Aquatix

27-11-2007 21:55:11

Unless you have a world with huge floating islands... but then again, it doesn't make much sense to give the body a mass, maybe just recreate it every now and then.
BTW, in has anyone looked into the time necessary for different ODE functions? I mean, I found that setRayDefinition (or whatever is the proper wording) takes really a long time.

kungfoomasta

28-11-2007 23:35:40

Sorry if this is a really dumb question, but can you show debug shapes with OgreODE? I hope to start and finish my CTerrainShape component, which converts ETM into a Ode trimesh shape. By finish, I mean that it should work. I might need to change things later on, but it would be nice to be able to see if the collision shape actually represents the terrain.

Also, my first test model is a dog. Assuming by default he points in the Ogre Z direction (out of the screen), should this be the direction of the capsule used to represent him? What would be a good density and mass, I have no idea...

If its relevant, 1 ogre unit = 1 meter

rewb0rn

29-11-2007 11:02:37

That would be Geometry->setDebug(true)?

kungfoomasta

29-11-2007 17:56:19

Yah I was reading the source, and figured the debug object is coded to show the geometry shapes. (I only had the header files from Aquatix) Aquatix, did you end up breaking the Terrain Shape into Tile Trimesh objects? Any noticeable performance gains?

Harvest

01-12-2007 00:52:25

Can I use this class to realize a fighting game with different reactions, if, for exampe one character kicks another one in the head or in the balls?

Can I switch between animations pre-made in a modeling program like blender and rag-doll animations? So that a movement like a kick is animated by a modeller, but a collapse & dying animation is done by a ragdoll system?

Aquatix

01-12-2007 18:48:13

Yep, but not with the code I posted here. What you've described is something I'm using myself. I will release the code as soon as it is stable enough. sorry for delays, but I am just to overwhelmed these days (have you seen a coder having to deal with art?)

Aquatix

01-12-2007 19:03:47

Yeah, almost forgot, Kungfoomasta, I did get this whole thing working. What it does now is it keeps graphics side separately from the physics side. Basically, physics break it all into islands, each one with it's own world. If there is noone on that island, then the world is just switched off. What this means is that on a 2km by 2km terrain I was able to get up to 300 little guys running around with decent FPS (that is ~40-50 and above with hires and antialising). When I'll get back to my PC (hopefully mon-tue) I'll post up the code, so that you an try it out, if it's of any use.

Harvest

01-12-2007 19:38:48

Yep, but not with the code I posted here. What you've described is something I'm using myself. I will release the code as soon as it is stable enough.

You will? Cool! Take your time, I hate dealing with art problems myself, especially graphics^^
I'm pretty excited to see that piece of code :)

kungfoomasta

01-12-2007 19:48:18

islands, or tiles? :? I'm interested in seeing this code! If each section of land is its own world, what happens when one object move from one section to another? Are you using real islands, or is that a term to describe a section of land?

Aquatix

01-12-2007 19:54:34

It's just my term. What you see is a normal game. The "transition" is nothing more than a reassigment to a different world. This is used in different areas, last time, I've seen it, it was in Gothic 3. (well, and PCZCM /crap, hate spelling it/ uses a similar approach).
But it works really well, allowing for crazy optimisations.

kungfoomasta

01-12-2007 20:08:04

sweet. If your planning on sharing, I'll want to dissect the code when possible, so I can figure out how to incorporate it into my Component Design. :twisted:

Aquatix

01-12-2007 20:18:25

Surely, no point in keeping it secret :lol: (unless I could somehow use that code to control a few nukes here and there :twisted: ). The only delay is that atm I'm off my main place, fixing some art here, so once I'll get back next week, I'll spit out all this code
Ahh, your component design... something similar I wanted to use, but then after banging my head a few times, used quite the opposite :)

kungfoomasta

10-12-2007 17:50:33

Some questions:

1. What's the difference between transform geometry and capsule geometry? I see both being used together.

2. Do I need to attach shapes to scene nodes? Normally I associate the shape with a body, and attach the body to a scene node, but it seems like a terrain TriMesh object doesn't require a body? Or does it? (We've established it doesn't need a mass)

3. Any sample code for using the OgreOde::TriangleMeshGeometry class? :)

rewb0rn

10-12-2007 19:26:48

as far as i got into this, i think transform geometries are used to set some offset between the scenenode the geometry is attached to and the geometry itself, because although there is a method on the geometry that is called setOffset or something similar, it has no effect. i worked with it a few times but i can not guarantee that my explanation is right, maybe i missed something.

kungfoomasta

10-12-2007 19:49:16

Guess I'll have to look into the code if I want a better answer, thanks for the information!

I would have found out more last night, but my version of QuickGUI disabled me from getting to the correct game state. :lol: In time I'll get there, and probably have more questions.

I think Aquatix disappeared and went to become a jedi under Yoda. Good thing there is some code to use as a guideline! :twisted:

kungfoomasta

13-12-2007 05:12:32

Hmm, the Terrain TriMesh shape isn't showing up. I should be able to see the shape if I create the Debug object, right?


void CTerrainShape::_createODETriMeshShape()
{
OgreOde::World* world = mOwner->mComponentManager->getWorld();
OgreOde::Space* space = world->getDefaultSpace();

mTriangleMeshGeometry = new OgreOde::TriangleMeshGeometry(mTerrainComponent->getVertices(),mTerrainComponent->getVertexCount(),mTerrainComponent->getIndices(),mTerrainComponent->getIndexCount(),world,space);
mTriangleMeshGeometry->createDebugObject();
}


I also call this every frame:


mStepper->step(1.0/60.0);
mWorld->synchronise();


What else is needed? What am I missing?

Thanks for any help.

rewb0rn

13-12-2007 17:37:59

Here a code snipped how I create my triangleMeshGeos:

OgreOde::EntityInformer* EntityInformer = new OgreOde::EntityInformer(Entity, Node->_getFullTransform());
Geometry = EntityInformer->createStaticTriangleMesh(World, Space);


//Geometry->setDebug(true);
delete EntityInformer;


if you uncomment that line you should see the debug object.

kungfoomasta

13-12-2007 18:06:30

rewb0rn, thanks a lot for posting! I'm sincerely greatful for the help. I'm a bit worried that the OgreODE forum seems dead. Hopefully I can set everything up and never have to worry about it again. :lol:

I will try this when I get home, if it works for static trangle mesh it should work for the regular triangle mesh. Hopefully i setup the verticese and indices correctly. If I still don't see anything I'll work on making my Capsule components and seeing if I can get those.

Thanks again!

cloud9

27-03-2008 15:11:25

Hi all.
I've been using the code here as a model for my own character controller and I found a pretty good solution to a problem I was having, where some animated characters move off from where the ode body is, an example is jaiqua in some of the ogre examples... and I just thought I'd share it.

Since it needs to move the capsule geometry with the Bone of the character, pick a Bone e.g. the pelvis bone. I created a TagPoint on the entity to use to get a world space position more easily. Then in the update code, in mine its a preStep() callback just add


Vector3 offset = mTagPoint->_getDerivedPosition() - mBody->getPosition();
offset = mBody->getOrientation().UnitInverse() * offset;

if(offset.y < 0.0)
offset.y = 0.0;

mCapsuleBase->setOffsetPosition(offset);


As in aquatix's code
mBody is the body representing the actor
mCapsuleBase is the capusle for colliding with the enviroment

Also this does away with any need for the TransformGeometry. I know this seems very simple but I tried, failed and made a mess several times before I came up with this, hope it helps someone else.

dement

21-07-2008 05:54:02

I have added the following code:
OgreOde::EntityInformer* EntityInformer = new OgreOde::EntityInformer(Entity, Node->_getFullTransform());
Geometry = EntityInformer->createStaticTriangleMesh(World, Space);

//Geometry->setDebug(true);
delete EntityInformer;

but appeared the error:

ODE INTERNAL ERROR 2

GeomTransform encapsulated object must not be in a space (..\ode\ode\src\collision_transform.cpp:133)


if I changed the sentence:
Geometry = EntityInformer->createStaticTriangleMesh(World, Space);
by
Geometry = EntityInformer->createStaticTriangleMesh(World);
not appear error, but no exist simulation

rewb0rn

21-07-2008 09:00:54

That message normally appears i you use a TransformGeo and try to set an encapsulated object that already is in a space. Do you?

dement

21-07-2008 15:40:25

the code is as follows

Entity* escenario_ent = mSceneMgr->createEntity("Escenario", "landscape.mesh");
SceneNode* escenario_sn = mSceneMgr->getRootSceneNode()->createChildSceneNode();
escenario_sn->attachObject(escenario_ent);
escenario_sn->setPosition(0,-50,0);
escenario_sn->scale(Vector3(50,10,50));
OgreOde::EntityInformer* escenario_ei = new OgreOde::EntityInformer(escenario_ent,escenario_sn->_getFullTransform());
OgreOde::TriangleMeshGeometry *escenario_geo = escenario_ei->createStaticTriangleMesh(_world,_space);


the application runs until the collision occurs and appear the error

dement

22-07-2008 07:33:55

testing found the following way to run the application correctly:

in the function Actor::actor_init, changed the next line:

pCapsuleBase = new OgreOde::CapsuleGeometry (actorWidth/2, actorHeight-actorWidth-actorFootH, mGamePhysMgr->World, pSpace);


by

pCapsuleBase = new OgreOde::CapsuleGeometry (actorWidth/2, actorHeight-actorWidth-actorFootH, mGamePhysMgr->World);

all runs right, but i do not know which implications carries this change
:shock: