my game design flaw

Post your questions, suggestions and experiences regarding game design, integration of external libraries here. For irrEdit, irrXML and irrKlang, see the
ambiera forums
Post Reply
thatdudeoverthere
Posts: 28
Joined: Fri Apr 24, 2009 2:43 pm
Location: over there...

my game design flaw

Post by thatdudeoverthere »

I have a node called entity_node from my class game_entity that is locally initialized in the function init_entity.

Code: Select all

void game_entity::init_entity(game_manager* entity_game_manager, vector3df entity_position)
{
	e_health = 100;
	entity_selector = 0;
	entity_mesh = entity_game_manager->getSceneMgr()->getMesh("media/dwarf.x");
	if(entity_mesh)
	{
	entity_node = entity_game_manager->getSceneMgr()->addAnimatedMeshSceneNode(entity_mesh);
	entity_node->setPosition(entity_position);

....
}

Now that i want to move the entity with the IEventReceiver from part of the game manager class(not included here yet ) with a keyboard event, but since entity was initialized within the function everytime i try to access the entity_node i get an access violation (which is to be expected) since it was declared within a function. I guess my question is how can i get access to entity_node without making entity_node a global variable or having to define it in the game_entity.h file since i'm trying to avoid global variables and dirty code. I see four options:

1. Create my own IAnimatedMeshSceneNode class with event receiving builtin (time consuming for just moving a node)
2. Go back to FPS camera (since it has its own eventreceiver, not what i really want)
3. Declared entity_node on a global scope
4. Ask to see what everyone else would do. :)

I could make entity_node a parameter of init_entity(), but then i would have to declared another node somewhere else to get it to work.
//Personal code

bool sarcasm;

void set_sarcastic()
{
sarcasm = true;
}
[img]
http://imgs.xkcd.com/comics/goto.png
[/img]
Frank Dodd
Posts: 208
Joined: Sun Apr 02, 2006 9:20 pm

Post by Frank Dodd »

Its hard to know as you don't show the actual declaration, but if its declared as public in the game_entity class I don't see why can't you couldn't access it directly elsewhere with my_entity->entity_node ?
xDan
Competition winner
Posts: 673
Joined: Thu Mar 30, 2006 1:23 pm
Location: UK
Contact:

Post by xDan »

I'm not sure I understand exactly what you are doing to get an access violation. Are you saying you try to access entity_node from your event receiver before you have called init_entity()? In which case the obvious solution is to call init_entity before any events are handled...

Maybe you want to let your EventReceiver have a pointer to the game_entity class, and then the event reciever calls methods like game_entity.MoveLeft() or whatever.
thatdudeoverthere
Posts: 28
Joined: Fri Apr 24, 2009 2:43 pm
Location: over there...

Post by thatdudeoverthere »

I'm not sure I understand exactly what you are doing to get an access violation. Are you saying you try to access entity_node from your event receiver before you have called init_entity()? In which case the obvious solution is to call init_entity before any events are handled...
it seems that way.. i make a call to init_entity() when the game_manager is initialized.. i.e.

Code: Select all

void game_manager::init()
{
	gm_player = new game_entity;
	gm_player->init_entity(this, vector3df(0,0,0));
	gm_state->load_map(this, gm_player,"media/20kdm2.bsp",vector3df(-1500,-300,-800));
	gDevice->getCursorControl()->setVisible(false);
}

bool game_manager::OnEvent(const SEvent &event)
{
	   if (event.EventType == EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown) 
   { 
      switch (event.KeyInput.Key) 
      { 
	  case irr::KEY_ESCAPE: 
		  gDevice->closeDevice(); 
		  break;
	  case irr::KEY_KEY_0:
		  gDevice->closeDevice();
		  break;
	  case irr::KEY_KEY_1:
		  gDevice->closeDevice();
		 break;
         default: 
            break; 
      } 
   } 
	   else
	   {
		   keys[event.KeyInput.Key] = event.KeyInput.PressedDown;
		   gm_player->KeyboardEvent(this, gm_player->get_entity_node());
	   }

	if (event.EventType == EET_MOUSE_INPUT_EVENT)
    {
        // Pass input down to the specific game state mouse handler
        cMouse = event.MouseInput.Event;
    }
   return false; 
}
but it still crashes! :?
//Personal code

bool sarcasm;

void set_sarcastic()
{
sarcasm = true;
}
[img]
http://imgs.xkcd.com/comics/goto.png
[/img]
xDan
Competition winner
Posts: 673
Joined: Thu Mar 30, 2006 1:23 pm
Location: UK
Contact:

Post by xDan »

Where are you setting your custom event receiver? Try moving that into game_manager::init() , and AFTER the call to init_entity(), that way no events can possibly be handled until your entity has been initialised.

Also I think you've got your event handling wrong. How you are doing it, gm_player->KeyboardEvent will get called with *ANY* event that is not an EET_KEY_INPUT_EVENT.

So should be:

Code: Select all

bool game_manager::OnEvent(const SEvent &event)
{
      if (event.EventType == EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
   {
      switch (event.KeyInput.Key)
      {
     case irr::KEY_ESCAPE:
        gDevice->closeDevice();
        break;
     case irr::KEY_KEY_0:
        gDevice->closeDevice();
        break;
     case irr::KEY_KEY_1:
        gDevice->closeDevice();
       break;
         default:
            break;
      }
   }
      // need to check EventType again here
      else if (event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
      {
         keys[event.KeyInput.Key] = event.KeyInput.PressedDown;
         gm_player->KeyboardEvent(this, gm_player->get_entity_node());
      }

   if (event.EventType == EET_MOUSE_INPUT_EVENT)
    {
        // Pass input down to the specific game state mouse handler
        cMouse = event.MouseInput.Event;
    }
   return false;
} 
and also, it seems illogical to pass gm_player its *own* node when calling gm_player->KeyboardEvent. surely gm_player can access its own node?!
thatdudeoverthere
Posts: 28
Joined: Fri Apr 24, 2009 2:43 pm
Location: over there...

Post by thatdudeoverthere »

:D it works for the most part except it seems to create more than one dwarf and it only works once and it doesn't matter which key is pressed it moves once. i'm going to do alittle work and see what i can come up with
:?
//Personal code

bool sarcasm;

void set_sarcastic()
{
sarcasm = true;
}
[img]
http://imgs.xkcd.com/comics/goto.png
[/img]
thatdudeoverthere
Posts: 28
Joined: Fri Apr 24, 2009 2:43 pm
Location: over there...

Post by thatdudeoverthere »

http://www.imagecabin.com/index.php?vie ... 41e8ad0cd5

i just need to update it or something??
//Personal code

bool sarcasm;

void set_sarcastic()
{
sarcasm = true;
}
[img]
http://imgs.xkcd.com/comics/goto.png
[/img]
xDan
Competition winner
Posts: 673
Joined: Thu Mar 30, 2006 1:23 pm
Location: UK
Contact:

Post by xDan »

Does indeed look like there are two dwarves :wink: Are you adding the scene node twice? Creating two entities? We can't really help much without seeing more code.
thatdudeoverthere
Posts: 28
Joined: Fri Apr 24, 2009 2:43 pm
Location: over there...

Post by thatdudeoverthere »

Does indeed look like there are two dwarves Are you adding the scene node twice? Creating two entities? We can't really help much without seeing more code.
you're the boss :)

b.t.w it only responses once with any key moving forward (seems to be the way i created the KeyboardEvent)

game_entity.h

Code: Select all

#include <irrlicht.h>

using namespace irr;
using namespace scene;
using namespace video;
using namespace gui;
using namespace core;

class game_manager;
class game_weapon;

class game_entity
{
public:
	game_entity();
	virtual ~game_entity();
	s32 set_e_id(s32 s_id); //set entity id
	s32 get_e_id(); //return  entity id
	s32 e_health;
	s32 set_phealth(s32 player_health);
	s32 get_phealth();
	IAnimatedMeshSceneNode* get_entity_node();
	void init_entity(game_manager* entity_game_manager, vector3df entity_position);
	void MouseEvent(game_manager* entity_game_manager);
	void KeyboardEvent(game_manager* entity_game_manager);

private:
	s32 e_id;
	s32 global_id;
	//s32 e_heatlh;
	s32 fatigue;
	game_weapon* weapons[2];
	IAnimatedMesh* entity_mesh;
	IAnimatedMeshSceneNode* entity_node;
	ICameraSceneNode* entity_camera;
	ITriangleSelector* entity_selector;

};

game_entity.cpp

Code: Select all

#include "game_entity.h"
#include "game_manager.h"
#include "game_weapons.h"

game_entity::game_entity()
{
// inits game_entity a.k.a constructor
}

game_entity::~game_entity()
{
// closes game_entity a.k.a destructor
}

s32 game_entity::set_e_id(s32 s_id)
{
	 e_id = s_id;
	 return e_id;
}

s32 game_entity::get_e_id()
{
	return e_id;
}

s32 game_entity::set_phealth(irr::s32 player_health) //set the player's new health and then returns the new value
{
	e_health = player_health;
	return e_health;
}

s32 game_entity::get_phealth() //returns the player's health value at the time of the calling of this function
{
	return e_health;
}

void game_entity::init_entity(game_manager* entity_game_manager, vector3df entity_position)
{
	e_health = 100;
	entity_selector = 0;
	entity_mesh = entity_game_manager->getSceneMgr()->getMesh("media/dwarf.x");
	if(entity_mesh)
	{
	entity_node = entity_game_manager->getSceneMgr()->addAnimatedMeshSceneNode(entity_mesh);
	entity_node->setPosition(entity_position);
	entity_node->setRotation(vector3df(0,180,0));
	entity_node->setAnimationSpeed(0);
	//entity_node->setDebugDataVisible(true); //just for testing
	entity_selector = entity_game_manager->getSceneMgr()->createTriangleSelectorFromBoundingBox(entity_node);
	entity_camera = entity_game_manager->getSceneMgr()->addCameraSceneNode(entity_node, vector3df(-20,70,40));
	weapons[0] = new game_weapon;
	weapons[0]->init_assault_rifle(100, entity_game_manager, entity_node);
	}

}

IAnimatedMeshSceneNode* game_entity::get_entity_node()
{
	return entity_node;
}

void game_entity::MouseEvent(game_manager* entity_game_manager)
{
	switch(entity_game_manager->getMouse())
	{
	case EMIE_LMOUSE_PRESSED_DOWN:
		weapons[0]->init_shoot(entity_game_manager, entity_camera);
		break;
		
	case EMIE_RMOUSE_PRESSED_DOWN:
		weapons[0]->init_shoot(entity_game_manager, entity_camera);
		break;
	}
}

void game_entity::KeyboardEvent(game_manager* entity_game_manager)
{
	vector3df pos;
	if(entity_game_manager->getKey(KEY_KEY_W))
	{ 
		pos.Z = pos.Z - 2;
		entity_node->setPosition(pos);
		entity_node->updateAbsolutePosition();
	}
	else if(entity_game_manager->getKey(KEY_KEY_S))
	{
		pos.Z = pos.Z + 2;
		this->get_entity_node()->setPosition(pos);
		entity_node->updateAbsolutePosition();
	}
}

game.cpp

Code: Select all

#include "game.h"

game::game()
{
//default constructor
}

game::~game()
{
//close the game
}

bool game::gamerun()
{ 
	
// Keep running game loop if device exists 
   while(the_manager.getDevice()->run()) 
      { 
      the_manager.getVideo()->beginScene(true,true, SColor(255, 100, 101, 140)); 
      the_manager.getSceneMgr()->drawAll(); 
      the_manager.getGUIEnv()->drawAll();
      the_manager.getVideo()->endScene(); 
    } 
    
   the_manager.getDevice()->drop(); 
   return 0;
  
}

//Personal code

bool sarcasm;

void set_sarcastic()
{
sarcasm = true;
}
[img]
http://imgs.xkcd.com/comics/goto.png
[/img]
xDan
Competition winner
Posts: 673
Joined: Thu Mar 30, 2006 1:23 pm
Location: UK
Contact:

Post by xDan »

Well, in that code shown you only create one dwarf... so maybe check elsewhere that you are not creating two instances of game_entity, or calling init_entity twice... or that game_weapon is not using the wrong model...

You should walk through the flow of the code in your mind and it should be obvious where you are going wrong...

About key movement, I've commented in the code:

Code: Select all

void game_entity::KeyboardEvent(game_manager* entity_game_manager)
{
   // this will be initialised with a default position of {0,0,0}
   vector3df pos;
   
   if(entity_game_manager->getKey(KEY_KEY_W))
   {
      // You now subtract 2 from the Z component, giving a position of {0,0,-2}
      pos.Z = pos.Z - 2;
      
      // So what you are actually doing is setting the position to
      // {0,0,-2} each key press.
      // Obviously you don't want to do that, you want to add 2 to the
      // *current* position
      entity_node->setPosition(pos);
      entity_node->updateAbsolutePosition();
   }
   else if(entity_game_manager->getKey(KEY_KEY_S))
   {
      pos.Z = pos.Z + 2;
      this->get_entity_node()->setPosition(pos);
      entity_node->updateAbsolutePosition();
   }
} 
so a version that might work:

Code: Select all

void game_entity::KeyboardEvent(game_manager* entity_game_manager)
{
   // Now we start with the *current* position of the entity node
   // So when 2 is added to it below it has actually moved relative
   // to its last position
   vector3df pos = entity_node->getPosition();
   
   if(entity_game_manager->getKey(KEY_KEY_W))
   {
      pos.Z = pos.Z - 2;
      entity_node->setPosition(pos);
      entity_node->updateAbsolutePosition();
   }
   else if(entity_game_manager->getKey(KEY_KEY_S))
   {
      pos.Z = pos.Z + 2;
      this->get_entity_node()->setPosition(pos);
      entity_node->updateAbsolutePosition();
   }
}
But still, what you have here will only move your node in the Z axis, and also not relative to the direction the camera is looking, and will only move a single step each time you press a key. If you search the forum I am sure there are examples of how to do better movement... (or look in the source for how the irrlicht FPS camera works..)

also remember you should delete everything created with new...

you might want a destroy_entity method where you delete weapons[0];

and you might also want a good book on C++ :)
Post Reply