Hi,
I'm working on an entity factory which reads in information about entities from an XML file and sets them up in the world. So, I step through the XML file, find an entity, get its name as a string, and use its factory method to create a new entity of the right type and call an initialisation function on it (which sets up the scene node and some other stuff). Later on in the XML parsing, I grab a position vector for where this object should go, and set the scene node to that position.
Which doesn't work.
The entities all end up at the origin of the world, which happens to be inside a bit of collision. If I set their initial positions (in the initialise function when I'm setting up the scene node) to somewhere where there isn't any collision, and then let the parser update their position to where they're supposed to be, it seems to work. But it seems to be a pretty horrible work-around, and I'd rather find out why just setting their position once doesn't work.
Any ideas? Has anyone had something like this before? I can post the parsing and initialisation code if it helps.
Cheers
setPosition strangeness
Is it possible that the collision code detects that the node is in collision and then prevents the setPosition() call from taking effect?
I would imagine that the collision system would assume that if a node is at position A for tick t and position B at tick t+1, then the node has moved from A to B in the elapsed time. If, in the course of moving from A to B, the object collided with something, then the collision system would prevent the object from moving.
If that is the case then maybe you should disable collisions until all obect positions are final, or you should set the object to the correct position when it is created, but before the collision system has been notified of the new object.
Travis
I would imagine that the collision system would assume that if a node is at position A for tick t and position B at tick t+1, then the node has moved from A to B in the elapsed time. If, in the course of moving from A to B, the object collided with something, then the collision system would prevent the object from moving.
If that is the case then maybe you should disable collisions until all obect positions are final, or you should set the object to the correct position when it is created, but before the collision system has been notified of the new object.
Travis
I don't know if this is exactly what you mean, but maybe it helps:
I had to update the position of sceneNodes which had irrlicht collision detection with the level enabled (big square with Boxes on it).
If collision was active, the sceneNodes collided with the boxes and were dangling at the first box on their way.
The solution was:
1. Disable collision detection for this node
2. use setPosition to move the node
3. enable collision detection for this node.
Maybe it helps!
andreas
I had to update the position of sceneNodes which had irrlicht collision detection with the level enabled (big square with Boxes on it).
If collision was active, the sceneNodes collided with the boxes and were dangling at the first box on their way.
The solution was:
1. Disable collision detection for this node
2. use setPosition to move the node
3. enable collision detection for this node.
Maybe it helps!
andreas
-
ElectroDruid
- Posts: 23
- Joined: Thu Oct 21, 2004 3:55 pm
Hi, thanks for the replies. I played about a bit, thinking about your suggestions, and I did indeed find that the problem seems to occur because I add the collision response animator when I set up the cube (i.e before I've had a chance to position it properly, meaning it's initialised to be at the origin, where it intersects with collision). But from looking through Irrlicht, I can't see how it could get stuck in collision - my code is happening at initialisation time, i.e. before entering the Irrlicht main update loop. There must be something in my setup code which is causing the entities to get stuck in collision even before I've had a chance to place them properly.
Here's my parsing code (with some error checking and irrelevant stuff taken out to make it easier to read):
Create entity just creates a new subclass of cGameEntity, depending on what string is passed into it from the XML file. I'm currently making a subclass call cEntityTestCube. The init function which gets called for this test class is as follows, again with some error checking taken out for clarity:
So, as I said, if I don't add the collision animator in the init function, but instead wait until after I've parsed and set the initial position from the XML, it works. But (A) It's a messy way of doing things, and (B) I'd like to know where in Irrlicht it stops me from changing the position of things before I've even hit the main loop (before I've even finished parsing the data files and creating objects, in fact). Because I don't like it when code does stuff (or won't let me do stuff) behind my back when I don't know how or why.
Any ideas?
Here's my parsing code (with some error checking and irrelevant stuff taken out to make it easier to read):
Code: Select all
bool cEntityMgr::Load(const char* szFileName)
{
io::IrrXMLReader* xml = io::createIrrXMLReader(szFileName);
const char* szEntityType = NULL;
Vec3f pos(0,0,0);
Vec3f rot(0,0,0);
cGameEntity* pNewEnt = NULL;
while(xml->read())
{
io::EXML_NODE nodeType = xml->getNodeType();
switch (nodeType)
{
case(io::EXN_ELEMENT):
{
irr::core::stringc nodeName = xml->getNodeName();
if (nodeName == "Entity")
{
szEntityType = xml->getAttributeValue("Type");
pNewEnt = CreateEntity(szEntityType);
pNewEnt->Init(); // See below
}
else if (nodeName == "Position")
{
const char* szPosX = xml->getAttributeValue("x");
const char* szPosY = xml->getAttributeValue("y");
const char* szPosZ = xml->getAttributeValue("z");
pNewEnt->mpSceneNode->setPosition(Vec3f(static_cast<float>(atof(szPosX)),
static_cast<float>(atof(szPosY)),
static_cast<float>(atof(szPosZ))));
}
}
break;
case(io::EXN_ELEMENT_END):
{
irr::core::stringc nodeName = xml->getNodeName();
if (nodeName == "Entity")
{
// Register this entity with my entity manager
Register(pNewEnt);
pNewEnt = NULL;
}
}
default:
break;
}
}
delete xml;
return true;
}Code: Select all
void cEntityTestCube::Init()
{
mpMesh = gpSceneManager->getMesh("models/cube.3ds");
if (mpMesh)
{
mpSceneNode = gpSceneManager->addAnimatedMeshSceneNode(mpMesh);
mpSceneNode->setMaterialTexture(0, gpVideoDriver->getTexture("textures/red.jpg"));
// This is line I don't want to have to put in
mpSceneNode->setPosition(Vec3f(0.0f,50.0f,0.0f));
mpSceneNode->setScale(Vec3f(1.0f,1.0f,1.0f));
for (int i = 0; i < mpSceneNode->getMaterialCount(); ++i)
{
mpSceneNode->getMaterial(i).SpecularColor.set(255,255,255,255);
mpSceneNode->getMaterial(i).AmbientColor.set(255,255,255,255);
mpSceneNode->getMaterial(i).DiffuseColor.set(255,255,255,255);
mpSceneNode->getMaterial(i).Shininess = 1.0f;
}
// Add this to my own collision manager, which just keeps track of things
CollisionMgr()->AddToEntityCollision(mpMesh,mpSceneNode);
}
core::aabbox3d<f32> cubebox = mpSceneNode->getBoundingBox();
Vec3f cuberadius = cubebox.MaxEdge - cubebox.getCenter();
scene::ISceneNodeAnimator* pCubeAnim = gpSceneManager->createCollisionResponseAnimator(
CollisionMgr()->GetLevelCollision(), mpSceneNode,
cuberadius,
Vec3f(0,-0.5,0),
Vec3f(0,0,0), 100.0f);
mpSceneNode->addAnimator(pCubeAnim);
pCubeAnim->drop();
}Any ideas?
I don't understand why you are not looking at the source code or at the very least setting a breakpoint in CSceneNodeAnimatorCollisionResponse::animateNode(). You would get the answer a lot quicker than asking on the forums, and you'd learn about how the Irrlicht collision system works.
When the collision response animator is created, the following lines are executed...
This caches the object position at the time the animator is created. As you already know the value of LastPosition is going to be (0, 0, 0). Then in the animateNode() function, the following line is executed...
Here the animator figures out how far the object has travelled since the last tick. Since LastPosition was (0, 0, 0) and the object new position is somewhere else completely different, the vector is rather large. This vector is later used to do collision testing, and wow, guess what, your node collides with stuff.
Travis
When the collision response animator is created, the following lines are executed...
Code: Select all
if (Object)
LastPosition = Object->getPosition();
Code: Select all
core::vector3df pos = Object->getPosition();
core::vector3df vel = pos - LastPosition;
Travis
-
ElectroDruid
- Posts: 23
- Joined: Thu Oct 21, 2004 3:55 pm
*sound of penny dropping*
Right, now it makes sense
Thanks for illuminating me.
So, I will have to move the bit that creates the collision response animator out into another function, to be called only when everything else about the object has been set up. So, the Init() function sets up the scene node, mesh, default position etc, the XML dictates any optional over-rides to position, rotation, etc, and then when the tag closes and we know all the information is complete (ie, somewhere just before I call my Register() function), call a new method on my entity, called SetupCollisionAnimator() or whatever.
*shrug* it's not exactly how I wanted to do things, but I can see now that there's a good reason for doing things that way. Thanks again!
Right, now it makes sense
So, I will have to move the bit that creates the collision response animator out into another function, to be called only when everything else about the object has been set up. So, the Init() function sets up the scene node, mesh, default position etc, the XML dictates any optional over-rides to position, rotation, etc, and then when the tag closes and we know all the information is complete (ie, somewhere just before I call my Register() function), call a new method on my entity, called SetupCollisionAnimator() or whatever.
*shrug* it's not exactly how I wanted to do things, but I can see now that there's a good reason for doing things that way. Thanks again!