Best way to switch between children?

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
NoodlePowa
Posts: 32
Joined: Sun Jul 15, 2007 1:02 pm
Location: California

Best way to switch between children?

Post by NoodlePowa »

I'm trying to make an equip system, and I've decided to do a very simple way: removing and adding children to a parent.

However, I get an error when I try to do this...

Code: Select all

if (isHelmet00)
{
    head_Head->removeAll();
    head_Head->addChild(helmet01);
    isHelmet00 = false;
}
else if (!isHelmet00)
{
    head_Head->removeAll();
    head_Head->addChild(helmet00);
    isHelmet00 = true;
}
The first if works, and then it crashes at the second if...


Thanks in advance for any help. ^^
"Be not ashamed of mistakes and thus make them crimes."
-Confucius
FyShu^
Posts: 6
Joined: Sun May 27, 2007 12:57 pm

Post by FyShu^ »

Hey.

I can't see any problems, but I just looking, I thought it was redundant to include the condition ( ! isHelmet00 ) with the else-if block.

Probably better to put a comment there instead. Otherwise you'd be wasting CPU cycles where you're doing logic checks on the obvious: What isn't isHelmet00 is going to be ! isHelmet00 anyway.

And, what exact line does it stop on?
What is the error?
Catprog
Posts: 164
Joined: Wed Jan 31, 2007 9:07 am
Contact:

Post by Catprog »

With no data i'm guessing helmet00 is not loaded.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

The removeAll() call causes head_Head to drop all of its children. When this happens, the memory is freed back to the system, buy you still have a pointer to it [helmet01 and helmet00]. The next time through the loop the pointer gets dereferenced. You need to grab() scene nodes that you want to keep around after they've been removed from the scene graph. You might try something like this...

Code: Select all

// this stuff is probably in some player class
core::array<scene::ISceneNode*> Helmets;
s32 Helmet; // init to -1

void addHelmet(scene::ISceneNode* helmet)
{
    s32 found = Helmets.linear_search(helmet);
    if (found != -1)
        return;

    Helmets.push_back(helmet);
    helmet->grab();
}

void removeHelmet(scene::ISceneNode* helmet)
{
    s32 found = Helmets.linear_search(helmet);
    if (found == -1)
        return;

   Helmets.erase(found);
   helmet->drop();
}

void removeAllHelmets()
{
    u32 n;
    for (n = 0; n < Helmets.size(); ++n)
        Helmets[n]->drop();

    Helmets.clear();

    // user still has active helmet, you need to call pickNextHelmet
    // so it will dissapear
}

void pickNextHelmet()
{
    // remove selected helmet from head
    if (Helmet != -1)
      Helmets[Helmet]->remove();

    // no helmets to choose from
    if (Helmets.empty())
        return;

    // select a new one
    Helmet = (Helmet + 1) % Helmets.size();

    // put new one on head
    Helmets[Helmet]->setParent(head_Head);
}
Travis
Last edited by vitek on Thu Aug 16, 2007 4:53 pm, edited 1 time in total.
koller202
Posts: 143
Joined: Tue May 08, 2007 4:53 am
Location: Thailand

Post by koller202 »

cool vitek
________
Honda S360 history
Last edited by koller202 on Thu Feb 17, 2011 1:14 am, edited 1 time in total.
NoodlePowa
Posts: 32
Joined: Sun Jul 15, 2007 1:02 pm
Location: California

Post by NoodlePowa »

Thanks a bunch, vitek, I'll try it out. :)

There doesn't seem to be an operator+ for array<ISceneNode*> :?
Was it meant to be Helmet instead of Helmets?
"Be not ashamed of mistakes and thus make them crimes."
-Confucius
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Yeah. I had a typo or two in there. It should work now.
NoodlePowa
Posts: 32
Joined: Sun Jul 15, 2007 1:02 pm
Location: California

Post by NoodlePowa »

It crashes when I call pickNextHelmet()

I debugged and hovered over Helmet. It showed that it had the value
-858993460
O_O

Is there a specific way I'm supposed to call these?


My console says:
Assertion failed: !(index)=used), file d:\irrlicht-1.3.1\include\irrarray.h, line 270

Thanks again.
"Be not ashamed of mistakes and thus make them crimes."
-Confucius
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Did you see the comment next to the declaration of Helmet? You need to set it to -1. I didn't do it myself because I don't know exactly how you are going to use the code. I would expect that you'd make Helmet and Helmets a member of a class and init them in the ctor, but you aren't doing that...
NoodlePowa
Posts: 32
Joined: Sun Jul 15, 2007 1:02 pm
Location: California

Post by NoodlePowa »

I am doing that.

PlayerEquips.h

Code: Select all

#ifndef _PLAYEREQUIPS_H_
#define _PLAYEREQUIPS_H_

#include <irrlicht.h>

using namespace irr;
using namespace core;
using namespace scene;

class CPlayerEquips
{
private:
	array<ISceneNode*> Helmets;
	s32 Helmet; // init to -1 in constructors
	ISceneNode* head_Head;
public:
	CPlayerEquips();
	CPlayerEquips(ISceneNode* head);
	void addHelmet(scene::ISceneNode* helmet);
	void removeHelmet(scene::ISceneNode* helmet);
	void removeAllHelmets();
	void pickNextHelmet();
};

#endif
PlayerEquips.cpp

Code: Select all

#include "PlayerEquips.h"

CPlayerEquips::CPlayerEquips()
{
	Helmet = -1;
	head_Head = 0;
}
CPlayerEquips::CPlayerEquips(ISceneNode* head)
{
	Helmet = -1;
	head_Head = head;
}
void CPlayerEquips::addHelmet(scene::ISceneNode* helmet)
{
	...
}
void CPlayerEquips::removeHelmet(scene::ISceneNode* helmet)
{
	...
}
void CPlayerEquips::removeAllHelmets()
{
	...
}
void CPlayerEquips::pickNextHelmet()
{
	...
}
"Be not ashamed of mistakes and thus make them crimes."
-Confucius
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Works fine for me. You have a ctor that initialized head_Head to NULL, and then you have no way to set it to something valid. That could cause a crash. Also, you need a destructor that calls removeAllHelmets() so that they won't leak at program exit.

Code: Select all

class MyEventReceiver : public IEventReceiver
{
public:
  MyEventReceiver(CPlayerEquips* equips)
    : Equips(equips)
  {
  }

  virtual bool OnEvent(SEvent event)
  {
    if (event.KeyInput.Key == irr::KEY_F1 && event.KeyInput.PressedDown)
    {
      Equips->pickNextHelmet();
      return true;
    }

    return false;
  }

  CPlayerEquips* Equips;
};

int main() 
{ 
  // ask user for driver 
  video::E_DRIVER_TYPE driverType = 
    video::EDT_DIRECT3D8;

  // create device and exit if creation failed 
  IrrlichtDevice *device = createDevice(driverType, core::dimension2d<s32>(1280, 800), 32, false, false, false); 
  if (device == 0) 
    return 1; // could not create selected driver. 

  video::IVideoDriver* driver = device->getVideoDriver(); 
  scene::ISceneManager* smgr = device->getSceneManager(); 

  // load the scene
  smgr->setAmbientLight(video::SColorf(.1f, .1f, .1f, 1.f));

  // add camera 
  smgr->addCameraSceneNodeFPS(0, 50, 50);

  scene::IAnimatedMeshSceneNode* dwarf = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/dwarf.x"));
  scene::ISceneNode* head = dwarf->getXJointNode("head");

  CPlayerEquips equips(head);

  MyEventReceiver receiver(&equips);
  device->setEventReceiver(&receiver);

  scene::ISceneNode* hat1 = smgr->addCubeSceneNode(20);
  equips.addHelmet(hat1);
  hat1->remove();

  scene::ISceneNode* hat2 = smgr->addSphereSceneNode(10);
  equips.addHelmet(hat2);
  hat2->remove();

  while(device->run()) 
  { 
    // window is active, so render scene 
    if (driver->beginScene(true, true, video::SColor(100, 50, 50, 50))) 
    {
      smgr->drawAll(); 

      driver->endScene(); 
    } 
  }

  device->drop(); 

  return 0; 
}
Travis
NoodlePowa
Posts: 32
Joined: Sun Jul 15, 2007 1:02 pm
Location: California

Post by NoodlePowa »

Thanks a bunch, vitek!

You rock. :wink: Thanks for the reminder for the destructor, heh.
"Be not ashamed of mistakes and thus make them crimes."
-Confucius
Post Reply