Factory Pattern(intermediate tutorial 3)[SOLVED]

Problems building or running the engine, queries about how to use features etc.
Blender+C++
Gremlin
Posts: 171
Joined: Tue Jan 03, 2012 1:38 am
Location: Brazil
x 3

Factory Pattern(intermediate tutorial 3)[SOLVED]

Post by Blender+C++ »

hi all,
Our program delt with two things, Robots and Ninjas. If we were going to implement a scene editor, we would want to place any number of different object types. Generalize this code to allow the placement of any type of object from a predefined list. Create an overlay with the list of objects you want the editor to have (such as Ninjas, Robots, Knots, Ships, etc), and have the SceneQueries only select that type of object.
2. Since we are using multiple types of objects now, use the Factory Pattern to properly create the SceneNodes and Entities.
i am really willing to create multiple objects in the scene and i also wanted to save the scene ,but lets go by parts...how can i add multiple objects in the scene as mentioned in the intermediate questions above? im pretty new to ogre and c++ so i am not completly independent when it comes to coding..im still taking the baby steps,can someone help me out with this? any reference link dat i can learn from? thx in advance,
Romulo

EDIT: would this be the solution i am looking for? http://www.daniweb.com/software-develop ... eads/18399

btw i couldnt understand well how the code works due to the fact that the code there doesnt show the entire header files and cpp files..so only advanced user would know that and how the concept works..i dont have access to the entire code..so could someone possibly explain me how that works?
any help is greatly appreciated
Last edited by Blender+C++ on Mon Mar 26, 2012 11:50 pm, edited 1 time in total.
User avatar
Mind Calamity
Ogre Magi
Posts: 1255
Joined: Sat Dec 25, 2010 2:55 pm
Location: Macedonia
x 81

Re: Factory Pattern(intermediate tutorial 3)

Post by Mind Calamity »

I think a factory refers to a class which would be able to create and access objects of a given type.

For example, you could understand the scene manager as a factory (among other things), it can create an entity and attach it to a scene node, and then you can get it by doing "mSceneMgr->getEntity/SceneNode("Name");".

So in order to create a for example Ninja Factory, you'd need to define what a ninja should be, for example create a separate ninja class and add it's attributes as member values (ex: health, magic, etc...), now you should create the "Factory" class, which would create these objects and keep track of them to allow you to access any one of them at any given time while your application is running.

This is usually done with std::vector, here's an example (given that your Ninja class is indeed named "Ninja"):
Consider this as a part of the factory class, the part that keeps track of the ninjas.

Code: Select all

std::vector<Ninja*>                   mNinjas; // You create the vector of pointers like this.
Here's an example of Ninja creation function of the NinjaFactory class:

Code: Select all

 Ninja* NinjaFactory::createNinja(Ogre::String& name, Ogre::Vector3& position, Ogre::Quaternion& rotation, Ogre::String& weaponName, AnimationList animList)
 {
  Ninja* ninja = OGRE_NEW Ninja(name, position, rotation, weaponName, animList);
  mNinjas.push_back(ninja);
  return ninja;
 }
The "AnimationList" and "WeaponName" are just placeholders for what you would likely need.

And then you'd have a find and/or findByName function. I'm sure you can figure these out, you just go through all of the members of the vector and compare their names until matched.

You also need a destroy function, so here's one:

Code: Select all

 void NinjaFactory::destroyNinja(Ninja* ninja)
 {
  if (ninja== 0)
   return;
  
  mNinjas.erase(std::find(mNinjas.begin(), mNinjas.end(), ninja));
  OGRE_DELETE ninja; // or just do, depends on how you're creating stuff // delete ninja;
 }
And you could also do a function to destroy every ninja at once:

Code: Select all

 void NinjaFactory::destroyAllNinjas()
 {
  
  for (mNinjas::iterator it = mNinjas.begin(); it != mNinjas.end(); it++)
  {
   OGRE_DELETE (*it);
  }
  
  mNinjas.clear();
 }
BitBucket username changed to iboshkov (from MindCalamity)
Do you need help? What have you tried?
- xavier
---------------------
HkOgre - a Havok Integration for OGRE | Simple SSAO | My Blog | My YouTube | My DeviantArt
User avatar
Waruck
Goblin
Posts: 210
Joined: Mon Dec 12, 2011 12:52 pm
Location: Germany
x 34

Re: Factory Pattern(intermediate tutorial 3)

Post by Waruck »

There are some reasons the use a factory-class to create objects:
- The most importent reason is, that you might not know which concrete object you want to create at compile time. In this example you don't know whether to create a Ninja, or a Robot.
- You need a return-type in a constructor, other than the object itself. This might not be obvious but let's just say you want to create an object of your own ninja-class and want to attach it to a scene node. If a CreateObject() function returns the Ogre::entity that is part of your ninja-class you can do something like:

Code: Select all

pSceneNode->attachObject(pFactory->createObject());
without a factory you'd need something like:

Code: Select all

pNinja = new Ninja;
pSceneNode->attachObject(pNinja->getEntity());
Mind Calamity's example of a NinjaFactory isn't a realy good example for the usage of this pattern, since the function NinjaFactory::createNinja() already implies that you know you want to create a Ninja at compile time and since the return type is the Ninja object, you can do this as well with the object's constructor.

A better usage of this would be a function like Factory::CreateObject(int id) which takes an id to create all kinds of objects you have defined. Let's say 0 for your ninja, and 1 for a robot. You can than use a variable that is changed at run time to create and handle different objects with the same code.

Another variation of this pattern is the abstract factory pattern. In this pattern you derive different sub-classes from you factory-class that overwrite the CreateObject() function to create different Objects instead of using an id. This is usefull if you rarely want to change between sets of objects. For example you could have different levels, that are entirely populated by either ninjas or robots. In this case you could have your level constructor change the used Factory-Class to either a NinjaFactory, or a RobotFactory, but all the rest of your code remains the same, since you only use the abstract Factory::CreateObject() function.


However Design Patterns aren't well suited for beginners in c++. If you are not familliar with all features of c++ they are hard to understand, since they make heavy usage of c++ features and object oriented design, and more importantly it is hard to understand why and when to use them. Learn the basics of c++ first. Make yourself familliar with classes and inheritance and write your own code to practise. You don't need design patterns to achive working code, the patterns only help to make the code more elegant and efficient, but at beginner level this isn't relevant as long as your code is working.
When you have gathered some experience you can look at design patterns and then you'll propably understand why they are usefull and how you can improve your own code with them.
User avatar
Mind Calamity
Ogre Magi
Posts: 1255
Joined: Sat Dec 25, 2010 2:55 pm
Location: Macedonia
x 81

Re: Factory Pattern(intermediate tutorial 3)

Post by Mind Calamity »

@Waruck: I thought it wouldn't be, I haven't really read up on Factory patterns, so I gave an example of how I'd create a similar pattern, which, as you pointed out missed the point of the factory pattern.

Design patterns may not be well-suited for beginners, but they sure help (if you can grasp them properly) a hell of a lot later.
BitBucket username changed to iboshkov (from MindCalamity)
Do you need help? What have you tried?
- xavier
---------------------
HkOgre - a Havok Integration for OGRE | Simple SSAO | My Blog | My YouTube | My DeviantArt
Blender+C++
Gremlin
Posts: 171
Joined: Tue Jan 03, 2012 1:38 am
Location: Brazil
x 3

Re: Factory Pattern(intermediate tutorial 3)

Post by Blender+C++ »

wow thx guys for all the instructions and comments..yeah factory pattern is indeed something advanced and sometimes hard to understand but i understand why they are used and how they work...i studied from tutorials about classes enheritance and stuff...it is very important to me to learn how to create a classes and then sub classes which enherits its properties ,using simple c++ it doesnt seem to be viable for a game design and when u need to create for example object id's for Entities,sceneNodes and as u change the keyboard input it swicthes then to another object id...i understand the concept of the factory pattern but i cant think of it in terms of code structure and how that works if u guys know what i mean...im gonna re read the replies again to see if i understand how it could work for my current code so i can start creating a factory pattern design..i was thinking first to move on with the next tutorials and then in a later time come back tutorials questions and try to solve them...well i really appreciate for all the replies here,it is really good to know that some ppl like to help newbies in this forums!!!!
i didnt read all the replies carefully i just kind of scanned it coz i just got home from the gym but ill defenetly look at it more carefully and see what i can do with it...
thx a lot again guys, and meanwhile if someone else can drop off some code here i dont mind at all..as much code information i have the more i understand how this design works :D
All the best,
Romulo
EDIT: btw Mind Calamity your examples are pretty clear and well explained..i appreciate ur input,it looks really helpfull and complete thx man
EDIT: Waruck i understand ur point and thx for all the explanations they look clear to me too but i think i wont give up on creating a factory pattern design ,i think ill look into it more in depth before moving on to the next tutorials,i think this is a very important step and i dont wanna miss that...the design is pretty much used for everything in a game so considering that i wont skip it but thanks for ur time and explanation ,if u have any aditional input ,feel free to post it :D
User avatar
Waruck
Goblin
Posts: 210
Joined: Mon Dec 12, 2011 12:52 pm
Location: Germany
x 34

Re: Factory Pattern(intermediate tutorial 3)

Post by Waruck »

Well. In Intermediate Tutorial 3 the objects are created in the mousePressed() function with the following code:

Code: Select all

		/*
		This next chunk finds the results of the raycast
		If the mouse is pointing at world geometry we spawn a robot at that position
		*/
		Ogre::RaySceneQueryResult& result = mRayScnQuery->execute();
		Ogre::RaySceneQueryResult::iterator iter = result.begin();
 
		if(iter != result.end() && iter->worldFragment)
		{
			char name[16];
			sprintf(name, "Robot%d", mCount++);
 
			Ogre::Entity* ent = mSceneMgr->createEntity(name, "robot.mesh");
			mCurrentObject = mSceneMgr->getRootSceneNode()->createChildSceneNode(std::string(name) + "Node", iter->worldFragment->singleIntersection);
			mCurrentObject->attachObject(ent);
 
			mCurrentObject->setScale(0.1f, 0.1f, 0.1f);
		}

If you define a mFactory object of a Factory-Class in your IntermediateTutorial3 class and a integer mID that is changeable in run-time (maybe via keyPressed() ) you can do something like this:
(you could also define the createObject() function in the IntermediateTutorial3 class if you wish, but if you want to improve the factory-method later it might be useful to have an own class)

Code: Select all

		/*
		This next chunk finds the results of the raycast
		If the mouse is pointing at world geometry we spawn a robot at that position
		*/
		Ogre::RaySceneQueryResult& result = mRayScnQuery->execute();
		Ogre::RaySceneQueryResult::iterator iter = result.begin();
 
		if(iter != result.end() && iter->worldFragment)
		{
			mCurrentObject = mFactory->createObject(mID, iter->worldFragment->singleIntersection);
		}
the mCurrentObject is a Ogre::SceneNode, so the createObject() function will create an Object at the intersection point of the ray, based on the mID and return the created SceneNode.
I won't give you the createObject() function because you'll learn more, if you write it yourself (for a robot you can almost take the code given before). Only a hint: since you want to do different things based on the ID, a switch(ID) will be quite helpful.
Blender+C++
Gremlin
Posts: 171
Joined: Tue Jan 03, 2012 1:38 am
Location: Brazil
x 3

Re: Factory Pattern(intermediate tutorial 3)

Post by Blender+C++ »

WOW dude thx a lot for ur help..i read this thread yesterday before u post the last post and things got so clear that made me feel really excited about it,ill defenetly try ur method mixed with the Mind Calamity s method and see if i can achieve the desired result which i strongly believe that i will!!
thank u so much for ur attention to my thread, as i already told u guys this step is very important to me coz it will open my mind to create some other kool stuff! thx guys i really appreciate it!
All the best,
Romulo Romero
Blender+C++
Gremlin
Posts: 171
Joined: Tue Jan 03, 2012 1:38 am
Location: Brazil
x 3

Re: Factory Pattern(intermediate tutorial 3)

Post by Blender+C++ »

I tried my best but i couldnt implement the fancy way of creating objects by its ID in a separate class...this is how i did:

Code: Select all

/*
-----------------------------------------------------------------------------
Filename:    IntermediateTutorial2.cpp
-----------------------------------------------------------------------------


This source file is generated by the
   ___                   _              __    __ _                  _ 
  /___\__ _ _ __ ___    /_\  _ __  _ __/ / /\ \ (_)______ _ _ __ __| |
 //  // _` | '__/ _ \  //_\\| '_ \| '_ \ \/  \/ / |_  / _` | '__/ _` |
/ \_// (_| | | |  __/ /  _  \ |_) | |_) \  /\  /| |/ / (_| | | | (_| |
\___/ \__, |_|  \___| \_/ \_/ .__/| .__/ \/  \/ |_/___\__,_|_|  \__,_|
      |___/                 |_|   |_|                                 
      Ogre 1.7.x Application Wizard for VC10 (July 2011)
      http://code.google.com/p/ogreappwizards/
-----------------------------------------------------------------------------
*/

#include "IntermediateTutorial2.h"
#include <CEGUISystem.h>
#include <CEGUISchemeManager.h>
#include <RendererModules/Ogre/CEGUIOgreRenderer.h>

//-------------------------------------------------------------------------------------
IntermediateTutorial2::IntermediateTutorial2(void)
{
	//bRobotMode = true;
}
//-------------------------------------------------------------------------------------
IntermediateTutorial2::~IntermediateTutorial2(void)
{
	mSceneMgr->destroyQuery(mRaySceneQuery);
}

//-------------------------------------------------------------------------------------
void IntermediateTutorial2::createScene(void)
{
	//Set ambient light
	mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
	mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);

	//World geometry
	mSceneMgr->setWorldGeometry("terrain.cfg");

	//Set camera look point
	mCamera->setPosition(40, 100, 580);
	mCamera->pitch(Ogre::Degree(-30));
	mCamera->yaw(Ogre::Degree(-45));
	// CEGUI setup
	mGUIRenderer = &CEGUI::OgreRenderer::bootstrapSystem();
	//Mouse
	CEGUI::SchemeManager::getSingleton().create((CEGUI::utf8*)"TaharezLook.scheme");
	CEGUI::MouseCursor::getSingleton().setImage("TaharezLook", "MouseArrow");
    /*Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh");

    Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    headNode->attachObject(ogreHead);

    // Set ambient light
    mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));

    // Create a light
    Ogre::Light* l = mSceneMgr->createLight("MainLight");
    l->setPosition(20,80,50);*/

}
void IntermediateTutorial2::createFrameListener(void)
{
	BaseApplication::createFrameListener();
	//Setup default variables
	mCount = 0;
	mID = 1;
	mCurrentObject = NULL;
	mLMouseDown = false;
	mRMouseDown = false;

	//Reduce rotate speed
	mRotateSpeed = .1;

	//Create RaySceneQuery
	mRaySceneQuery = mSceneMgr->createRayQuery(Ogre::Ray());
}
void IntermediateTutorial2::chooseSceneManager(void)
{
	mSceneMgr = mRoot->createSceneManager(Ogre::ST_EXTERIOR_CLOSE);
}
bool IntermediateTutorial2::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
	return BaseApplication::frameRenderingQueued(evt);
	//Setup the scene query
	Ogre::Vector3 camPos = mCamera->getPosition();
	Ogre::Ray cameraRay(Ogre::Vector3(camPos.x, 5000.0f, camPos.z), Ogre::Vector3::NEGATIVE_UNIT_Y);
	mRaySceneQuery->setRay(cameraRay);
	mRaySceneQuery->setSortByDistance(false);
	//Perform the scene query
	Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute();
	Ogre::RaySceneQueryResult::iterator itr = result.begin();
	//Get the results , set the camera height
	//if(itr != result.end() && itr->worldFragment)
	for(itr; itr != result.end(); itr++)
	{
		if(itr->worldFragment)
		{
			Ogre::Real terrainHeight = itr->worldFragment->singleIntersection.y;
			if((terrainHeight + 10.0f) > camPos.y)
			{
				mCamera->setPosition(camPos.x, terrainHeight + 10.0f, camPos.z);
			}
			break;
		}//if
	}//for
	return true;
	return false;
}
bool IntermediateTutorial2::mouseMoved(const OIS::MouseEvent& arg)
{
	//Update CEGUI with the mouse motion
	CEGUI::System::getSingleton().injectMouseMove(arg.state.X.rel, arg.state.Y.rel);
	//If we are dragging the left mouse button
	if(mLMouseDown)
	{
		CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition();
		Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x / float(arg.state.width), mousePos.d_y / float(arg.state.height));
		mRaySceneQuery->setRay(mouseRay);
		mRaySceneQuery->setSortByDistance(false);
		Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute();
		Ogre::RaySceneQueryResult::iterator itr = result.begin();
		//if(itr != result.end() && itr->worldFragment)
		for(itr; itr != result.end(); itr++)
		{
			if(itr->worldFragment)
			{
				mCurrentObject->setPosition(itr->worldFragment->singleIntersection);
				break;
			}//if
		}//for
		
	}//if
	//if we are dragging the right mouse button
	else if(mRMouseDown)
	{
		mCamera->yaw(Ogre::Degree(-arg.state.X.rel * mRotateSpeed));
		mCamera->pitch(Ogre::Degree(-arg.state.Y.rel * mRotateSpeed));
	}//else if
	return true;
}
/*bool IntermediateTutorial2::ObjectID(const OIS::KeyEvent& key, Ogre::Entity* ent)
{
	
	switch(key.key)
	{
	case OIS::KC_0:
		mObjectList.push_back(Ogre::Entity::EntitySet("Ninja", "ninja.mesh"));
		
		break;
	case OIS::KC_1:
		mObjectList.push_back(Ogre::Entity::EntitySet("Robot", "robot.mesh"));
		
		break;
	case OIS::KC_2:
		mObjectList.push_back(Ogre::Entity::EntitySet("Knot", "knot.mesh"));
		
		break;

	};
	return true;
}*/
bool IntermediateTutorial2::mousePressed(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
{
	//Left mouse button down
	if(id == OIS::MB_Left)
	{
		if(mCurrentObject)
		{
			//show that the current object has been deselected by removing box visual
			mCurrentObject->showBoundingBox(false);
		}
		//Setup the ray scene query, use CEGUI's mouse position
		CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition();
		Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x / float(arg.state.width), mousePos.d_y / float(arg.state.height));
		mRaySceneQuery->setRay(mouseRay);
		mRaySceneQuery->setSortByDistance(true);
		mRaySceneQuery->setQueryMask(ROBOT_MASK | NINJA_MASK | KNOT_MASK | PENGUIN_MASK);
		//Execute query
		Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute();
		Ogre::RaySceneQueryResult::iterator itr = result.begin();


		//Get results, create a node /entity on the position
		/*if(itr != result.end() && itr->worldFragment)
		{
			
			mFactory->CreateObject(mID),itr->worldFragment->singleIntersection;
	 
			char name[16];
			if(bRobotMode)
			{
				sprintf(name, "Robot%d", mCount++ );
				Ogre::Entity* ent = mSceneMgr->createEntity(name, "robot.mesh");
				mCurrentObject = mSceneMgr->getRootSceneNode()->createChildSceneNode(std::string(name) + "Node", itr->worldFragment->singleIntersection);
				mCurrentObject->attachObject(ent);
				mCurrentObject->setScale(0.1f, 0.1f, 0.1f);
			}
			else
			{
				sprintf(name, "Ninja%d", mCount++);
				Ogre::Entity* entNin = mSceneMgr->createEntity(name, "ninja.mesh");
				mCurrentObject = mSceneMgr->getRootSceneNode()->createChildSceneNode(std::string(name) + "Node", itr->worldFragment->singleIntersection);
				mCurrentObject->attachObject(entNin);
				mCurrentObject->setScale(0.1f, 0.1f, 0.1f);
			}

			}//if*/
		//Get results, create a node/entity on the position
		for(itr; itr != result.end(); itr++)
		{
			if(itr->movable && itr->movable->getName().substr(0, 5) != "tile[")
			{
				mCurrentObject = itr->movable->getParentSceneNode();
				break;
			}//if
			else if(itr->worldFragment)
			{
				//mFactory->mousePressed(arg, id),itr->worldFragment->singleIntersection;
				Ogre::Entity* ent;
				char name[16];
				if(mID == 1)
				{
					//mObjectList.front();
					sprintf(name, "Robot%d", mCount++);
					ent = mSceneMgr->createEntity(name, "robot.mesh");
					ent->setQueryFlags(ROBOT_MASK);
				}//if
				else if(mID == 2)
				{
					sprintf(name, "Ninja%d", mCount++);
					ent = mSceneMgr->createEntity(name, "ninja.mesh");
					ent->setQueryFlags(NINJA_MASK);
				}//else if
				else if(mID == 3)
				{
					sprintf(name, "Knot%d", mCount++);
					ent = mSceneMgr->createEntity(name, "knot.mesh");
					ent->setQueryFlags(KNOT_MASK);
				}
				else 
				{
					sprintf(name, "Penguin%d", mCount++);
					ent = mSceneMgr->createEntity(name, "penguin.mesh");
					ent->setQueryFlags(PENGUIN_MASK);
				}
				mCurrentObject = mSceneMgr->getRootSceneNode()->createChildSceneNode(std::string(name) + "Node", itr->worldFragment->singleIntersection);
				mCurrentObject->attachObject(ent);
				mCurrentObject->setScale(0.1f, 0.1f, 0.1f);
				break;
			}//else if
		}

		mLMouseDown = true;
	}//for
		

	
	//Right mouse button down
	else if(id == OIS::MB_Right)
	{
		CEGUI::MouseCursor::getSingleton().hide();
		mRMouseDown = true;
	}//else if
	if(mCurrentObject)
	{
		mCurrentObject->showBoundingBox(true);
	}
	return true;
}
bool IntermediateTutorial2::mouseReleased(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
{
	//Left mouse button up
	if(id == OIS::MB_Left)
	{
		mLMouseDown = false;
	}
	//Right mouse button up
	else if(id == OIS::MB_Right)
	{
		CEGUI::MouseCursor::getSingleton().show();
		mRMouseDown = false;
	}//else if
	return true;
}
bool IntermediateTutorial2::keyPressed(const OIS::KeyEvent& arg)
{
	//Check and see if the space barf was hit, and this will switch which mesh is spawned
	/*if(arg.key == OIS::KC_SPACE)
	{
		bRobotMode = !bRobotMode;
	}*/
	switch(arg.key)
	{
	case OIS::KC_0:
		mID = 1;
		break;
	case OIS::KC_1:
		mID = 2;
		break;
	case OIS::KC_2:
		mID = 3;
		break;
	case OIS::KC_3:
		mID = 4;
		break;
	}
	// then we return the base app keypressed function so that we get all of the functionality
	//and the return value in one line
	return BaseApplication::keyPressed(arg);
}

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
    INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
    int main(int argc, char *argv[])
#endif
    {
        // Create application object
        IntermediateTutorial2 app;

        try {
            app.go();
        } catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
            MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
            std::cerr << "An exception has occured: " <<
                e.getFullDescription().c_str() << std::endl;
#endif
        }

        return 0;
    }

#ifdef __cplusplus
}
#endif
anymore suggestions on how to create that through a factory pattern method?
thx
User avatar
Waruck
Goblin
Posts: 210
Joined: Mon Dec 12, 2011 12:52 pm
Location: Germany
x 34

Re: Factory Pattern(intermediate tutorial 3)

Post by Waruck »

I haven't tested your code, but if it works, all you have to do is to put the object-creating code into a single function:

Code: Select all

            Ogre::Entity* ent;
            char name[16];
            if(mID == 1)
            {
               //mObjectList.front();
               sprintf(name, "Robot%d", mCount++);
               ent = mSceneMgr->createEntity(name, "robot.mesh");
               ent->setQueryFlags(ROBOT_MASK);
            }//if
            else if(mID == 2)
            {
               sprintf(name, "Ninja%d", mCount++);
               ent = mSceneMgr->createEntity(name, "ninja.mesh");
               ent->setQueryFlags(NINJA_MASK);
            }//else if
            else if(mID == 3)
            {
               sprintf(name, "Knot%d", mCount++);
               ent = mSceneMgr->createEntity(name, "knot.mesh");
               ent->setQueryFlags(KNOT_MASK);
            }
            else 
            {
               sprintf(name, "Penguin%d", mCount++);
               ent = mSceneMgr->createEntity(name, "penguin.mesh");
               ent->setQueryFlags(PENGUIN_MASK);
            }
            mCurrentObject = mSceneMgr->getRootSceneNode()->createChildSceneNode(std::string(name) + "Node", itr->worldFragment->singleIntersection);
            mCurrentObject->attachObject(ent);
            mCurrentObject->setScale(0.1f, 0.1f, 0.1f);
If you don't want to use an additional factory-class you can just define a function createObject() in your IntermediateTutorial2 class. And call this function in the mousePressed() function, instead of having the whole code there.
Why is it better to have a seperated function instead of just writing the whole code in the mousePressed() function? The answer is readability and expandability. If you have a seperated function that is called in mousePressed() anyone will understand what is happening in your code (if you name it properly). Further if you want to add more objects later on, you can find the create-function pretty quick, while it might be troublesome to find the right line if it's written in a different function. Also if you want to create objects at different times, for example in the createScene() function, you can simply call the seperated function there and don't have to copy the code from mousePressed().

Additional comments:
- your mID starts with 1 for robots. Normally one starts to cound at 0, if there is no reason to treat the 0 differently.
- if your mID is not between 1 and 3 you create a Penguin, so a Penguin has no real id. It is better to give every object an id and throw an exeption (error) if a undefined id is used.
- you may want to have a look at the usage of enum and the switch() statement. An enum is a enumeration of objects and a nice way to define the ID's of your objects. A switch() statement is a nice way to write a long if() else if().... chain, if you just compare integer values (like an id)

untested but this should work with your code:

Code: Select all

    bool IntermediateTutorial2::mousePressed(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
    {
       //Left mouse button down
       if(id == OIS::MB_Left)
       {
          if(mCurrentObject)
          {
             //show that the current object has been deselected by removing box visual
             mCurrentObject->showBoundingBox(false);
          }
          //Setup the ray scene query, use CEGUI's mouse position
          CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition();
          Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x / float(arg.state.width), mousePos.d_y / float(arg.state.height));
          mRaySceneQuery->setRay(mouseRay);
          mRaySceneQuery->setSortByDistance(true);
          mRaySceneQuery->setQueryMask(ROBOT_MASK | NINJA_MASK | KNOT_MASK | PENGUIN_MASK);
          //Execute query
          Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute();
          Ogre::RaySceneQueryResult::iterator itr = result.begin();

          //Get results, create a node/entity on the position
          for(itr; itr != result.end(); itr++)
          {
             if(itr->movable && itr->movable->getName().substr(0, 5) != "tile[")
             {
                mCurrentObject = itr->movable->getParentSceneNode();
                break;
             }//if
             else if(itr->worldFragment)
             {
				mCurrentObject = createObject(mID, itr->worldFragment->singleIntersection);
                break;
             }//else if
          }//for

          mLMouseDown = true;
       }//if
          

       
       //Right mouse button down
       else if(id == OIS::MB_Right)
       {
          CEGUI::MouseCursor::getSingleton().hide();
          mRMouseDown = true;
       }//else if
       if(mCurrentObject)
       {
          mCurrentObject->showBoundingBox(true);
       }
       return true;
    }

	
	Ogre::SceneNode* IntermediateTutorial2::createObject(int id, Ogre::Vector3 pos)
	{
		Ogre::Entity* ent;
		char name[16];
		switch(id)
		{
		case 1:
			sprintf(name, "Robot%d", mCount++);
			ent = mSceneMgr->createEntity(name, "robot.mesh");
			ent->setQueryFlags(ROBOT_MASK);
			break;
		case 2:
			sprintf(name, "Ninja%d", mCount++);
			ent = mSceneMgr->createEntity(name, "ninja.mesh");
			ent->setQueryFlags(NINJA_MASK);
			break;
		case 3:
			sprintf(name, "Knot%d", mCount++);
			ent = mSceneMgr->createEntity(name, "knot.mesh");
			ent->setQueryFlags(KNOT_MASK);
			break;
		case 4: 
			sprintf(name, "Penguin%d", mCount++);
			ent = mSceneMgr->createEntity(name, "penguin.mesh");
			ent->setQueryFlags(PENGUIN_MASK);
			break;
		default:
			//unknown id, maybe throw an exeption, for now just return silently
			return 0;
		}
		Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(std::string(name) + "Node", pos);
		node->attachObject(ent);
		node->setScale(0.1f, 0.1f, 0.1f);
		return node;	
	}
Blender+C++
Gremlin
Posts: 171
Joined: Tue Jan 03, 2012 1:38 am
Location: Brazil
x 3

Re: Factory Pattern(intermediate tutorial 3)

Post by Blender+C++ »

Hi Waruck,
thank u so much for ur reply and yeah i have tried something similar to this before u post and it didnt work..so i guess i was close to figure out how the factory pattern method works, and i have also tried ur code and when i add the Ogre::SceneNode* createObject it says Error:Declaration is incompatible with " bool Intermediatetutorial2::createObject etc etc..at line some line of and then the class header line...i guess something is wrong with the function i create in the class...maybe i should add something before the virtual bool and then the function???
i know it might sound stupid but i dont know how to solve this,i actually have created the factory class separately coz i wanna try it in a separate class as it is the desired method..but the same error declaration happens if i create in the intermediatetutorial2 class...can u hook me up again with some ideas dude?
thx in advance and sorry for sounding so stupid but i dont know how to solve that!!
Kind regards,
Romulo Romero
User avatar
Waruck
Goblin
Posts: 210
Joined: Mon Dec 12, 2011 12:52 pm
Location: Germany
x 34

Re: Factory Pattern(intermediate tutorial 3)

Post by Waruck »

Blender+C++ wrote: Error:Declaration is incompatible with " bool Intermediatetutorial2::createObject etc etc..
I defined the function as:

Code: Select all

Ogre::SceneNode* IntermediateTutorial2::createObject(int id, Ogre::Vector3 pos);
so the return type of this function is an Ogre::SceneNode* and not a bool. this is needet for the line:

Code: Select all

mCurrentObject = createObject(mID, itr->worldFragment->singleIntersection);
So you need to change the return type from bool to Ogre::SceneNode* in your header file. You can not have 2 functions that only differ by their return-type in c++.
You also don't need to declare the function virtual. virtual functions only make sense when you derive other classes from your class that want to override some of your functions (this is what you would do, if you want to make an abstract factory)
Blender+C++
Gremlin
Posts: 171
Joined: Tue Jan 03, 2012 1:38 am
Location: Brazil
x 3

Re: Factory Pattern(intermediate tutorial 3)

Post by Blender+C++ »

Hi Waruck,
thx for replying and wow how could i not think about that,in the class before u post here i was trying ,Ogre::SceneNode* virtual bool createObject(int id, Ogre::Vector3 pos) lol i know that looks rediculous but thats what i have tried before u last post here lol!
bro after u posted here now everything works fine except for the separate factory class i created..its not working, i am obviously missing something but i dont know where..im going to post the header file and the .cpp file so u can analyze and see whats wrong with my code...i promise u that as soon as i get it to work i will change the thread status and consider it as solved!
ok so here its the the FactoryClass header file :

Code: Select all

#include "BaseApplication.h"
#ifndef FACTORYCLASS_H
#define FACTORYCLASS_H




class FactoryClass : public BaseApplication
{
public:
	FactoryClass(void);
	virtual~FactoryClass(void);
	enum QueryFlags
	{
		NINJA_MASK = 1<<0,
		ROBOT_MASK = 1<<1,
		KNOT_MASK = 1<<2,
		PENGUIN_MASK = 1<<3
	};
	
	Ogre::SceneNode* createObject(int ObjID, Ogre::Vector3 pos);
protected:	
	
	virtual bool keyPressed(const OIS::KeyEvent& arg);
	int mCount;
	int ObjID;

	
	
	
	

};
#endif
and the FactoryClass implementation file :

Code: Select all

#include "FactoryClass.h"

FactoryClass::FactoryClass(void)
{
	mCount = 0;
	int ObjID = 0;
}
FactoryClass::~FactoryClass(void)
{
}
Ogre::SceneNode*  FactoryClass::createObject(int ObjID, Ogre::Vector3 pos)
{
	Ogre::Entity* ent;
	char name[16];
	switch(ObjID)
	{
	case 1:
		sprintf(name, "Robot%d", mCount++);
		ent = mSceneMgr->createEntity(name, "robot.mesh");
		ent->setQueryFlags(ROBOT_MASK);
		break;
	case 2:
		sprintf(name, "Ninja%d", mCount++);
		ent = mSceneMgr->createEntity(name, "ninja.mesh");
		ent->setQueryFlags(NINJA_MASK);
		break;
	case 3:
		sprintf(name, "Knot%d", mCount++);
		ent = mSceneMgr->createEntity(name, "knot.mesh");
		ent->setQueryFlags(KNOT_MASK);
		break;
	case 4: 
		sprintf(name, "Penguin%d", mCount++);
		ent = mSceneMgr->createEntity(name, "penguin.mesh");
		ent->setQueryFlags(PENGUIN_MASK);
		break;
	default:
		//unknown id, maybe throw an exeption, for now just return silently
		return 0;
	}
	Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(std::string(name) + "Node", pos);
	node->attachObject(ent);
	node->setScale(0.1f, 0.1f, 0.1f);
	return node;
}
bool FactoryClass::keyPressed(const OIS::KeyEvent& arg)
{
		switch(arg.key)
	{
	case OIS::KC_0:
		ObjID = 1;
		break;
	case OIS::KC_1:
		ObjID = 2;
		break;
	case OIS::KC_2:
		ObjID = 3;
		break;
	case OIS::KC_3:
		ObjID = 4;
		break;
	}
	// then we return the base app keypressed function so that we get all of the functionality
	//and the return value in one line
	return BaseApplication::keyPressed(arg);
}
and the intermediateTurtorial implementation:

Code: Select all

/*
-----------------------------------------------------------------------------
Filename:    IntermediateTutorial2.cpp
-----------------------------------------------------------------------------


This source file is generated by the
   ___                   _              __    __ _                  _ 
  /___\__ _ _ __ ___    /_\  _ __  _ __/ / /\ \ (_)______ _ _ __ __| |
 //  // _` | '__/ _ \  //_\\| '_ \| '_ \ \/  \/ / |_  / _` | '__/ _` |
/ \_// (_| | | |  __/ /  _  \ |_) | |_) \  /\  /| |/ / (_| | | | (_| |
\___/ \__, |_|  \___| \_/ \_/ .__/| .__/ \/  \/ |_/___\__,_|_|  \__,_|
      |___/                 |_|   |_|                                 
      Ogre 1.7.x Application Wizard for VC10 (July 2011)
      http://code.google.com/p/ogreappwizards/
-----------------------------------------------------------------------------
*/

#include "IntermediateTutorial2.h"
#include <CEGUISystem.h>
#include <CEGUISchemeManager.h>
#include <RendererModules/Ogre/CEGUIOgreRenderer.h>

//-------------------------------------------------------------------------------------
IntermediateTutorial2::IntermediateTutorial2(void)
{
	//bRobotMode = true;
}
//-------------------------------------------------------------------------------------
IntermediateTutorial2::~IntermediateTutorial2(void)
{
	mSceneMgr->destroyQuery(mRaySceneQuery);
}

//-------------------------------------------------------------------------------------
void IntermediateTutorial2::createScene(void)
{
	//Set ambient light
	mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
	mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);

	//World geometry
	mSceneMgr->setWorldGeometry("terrain.cfg");

	//Set camera look point
	mCamera->setPosition(40, 100, 580);
	mCamera->pitch(Ogre::Degree(-30));
	mCamera->yaw(Ogre::Degree(-45));
	// CEGUI setup
	mGUIRenderer = &CEGUI::OgreRenderer::bootstrapSystem();
	//Mouse
	CEGUI::SchemeManager::getSingleton().create((CEGUI::utf8*)"TaharezLook.scheme");
	CEGUI::MouseCursor::getSingleton().setImage("TaharezLook", "MouseArrow");
    /*Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh");

    Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    headNode->attachObject(ogreHead);

    // Set ambient light
    mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));

    // Create a light
    Ogre::Light* l = mSceneMgr->createLight("MainLight");
    l->setPosition(20,80,50);*/

}
void IntermediateTutorial2::createFrameListener(void)
{
	BaseApplication::createFrameListener();
	//Setup default variables
	//mCount = 0;
	ObjID = 1;
	mCurrentObject = NULL;
	mLMouseDown = false;
	mRMouseDown = false;

	//Reduce rotate speed
	mRotateSpeed = .1;

	//Create RaySceneQuery
	mRaySceneQuery = mSceneMgr->createRayQuery(Ogre::Ray());
}
void IntermediateTutorial2::chooseSceneManager(void)
{
	mSceneMgr = mRoot->createSceneManager(Ogre::ST_EXTERIOR_CLOSE);
}
bool IntermediateTutorial2::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
	return BaseApplication::frameRenderingQueued(evt);
	//Setup the scene query
	Ogre::Vector3 camPos = mCamera->getPosition();
	Ogre::Ray cameraRay(Ogre::Vector3(camPos.x, 5000.0f, camPos.z), Ogre::Vector3::NEGATIVE_UNIT_Y);
	mRaySceneQuery->setRay(cameraRay);
	mRaySceneQuery->setSortByDistance(false);
	//Perform the scene query
	Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute();
	Ogre::RaySceneQueryResult::iterator itr = result.begin();
	//Get the results , set the camera height
	//if(itr != result.end() && itr->worldFragment)
	for(itr; itr != result.end(); itr++)
	{
		if(itr->worldFragment)
		{
			Ogre::Real terrainHeight = itr->worldFragment->singleIntersection.y;
			if((terrainHeight + 10.0f) > camPos.y)
			{
				mCamera->setPosition(camPos.x, terrainHeight + 10.0f, camPos.z);
			}
			break;
		}//if
	}//for
	return true;
	return false;
}
bool IntermediateTutorial2::mouseMoved(const OIS::MouseEvent& arg)
{
	//Update CEGUI with the mouse motion
	CEGUI::System::getSingleton().injectMouseMove(arg.state.X.rel, arg.state.Y.rel);
	//If we are dragging the left mouse button
	if(mLMouseDown)
	{
		CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition();
		Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x / float(arg.state.width), mousePos.d_y / float(arg.state.height));
		mRaySceneQuery->setRay(mouseRay);
		mRaySceneQuery->setSortByDistance(false);
		Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute();
		Ogre::RaySceneQueryResult::iterator itr = result.begin();
		//if(itr != result.end() && itr->worldFragment)
		for(itr; itr != result.end(); itr++)
		{
			if(itr->worldFragment)
			{
				mCurrentObject->setPosition(itr->worldFragment->singleIntersection);
				break;
			}//if
		}//for
		
	}//if
	//if we are dragging the right mouse button
	else if(mRMouseDown)
	{
		mCamera->yaw(Ogre::Degree(-arg.state.X.rel * mRotateSpeed));
		mCamera->pitch(Ogre::Degree(-arg.state.Y.rel * mRotateSpeed));
	}//else if
	return true;
}
/*bool IntermediateTutorial2::ObjectID(const OIS::KeyEvent& key, Ogre::Entity* ent)
{
	
	switch(key.key)
	{
	case OIS::KC_0:
		mObjectList.push_back(Ogre::Entity::EntitySet("Ninja", "ninja.mesh"));
		
		break;
	case OIS::KC_1:
		mObjectList.push_back(Ogre::Entity::EntitySet("Robot", "robot.mesh"));
		
		break;
	case OIS::KC_2:
		mObjectList.push_back(Ogre::Entity::EntitySet("Knot", "knot.mesh"));
		
		break;

	};
	return true;
}*/
bool IntermediateTutorial2::mousePressed(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
{
	//Left mouse button down
	if(id == OIS::MB_Left)
	{
		if(mCurrentObject)
		{
			//show that the current object has been deselected by removing box visual
			mCurrentObject->showBoundingBox(false);
		}
		//Setup the ray scene query, use CEGUI's mouse position
		CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition();
		Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x / float(arg.state.width), mousePos.d_y / float(arg.state.height));
		mRaySceneQuery->setRay(mouseRay);
		mRaySceneQuery->setSortByDistance(true);
		mRaySceneQuery->setQueryMask(ROBOT_MASK | NINJA_MASK | KNOT_MASK | PENGUIN_MASK);
		//Execute query
		Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute();
		Ogre::RaySceneQueryResult::iterator itr = result.begin();


		//Get results, create a node /entity on the position
		/*if(itr != result.end() && itr->worldFragment)
		{
			
			mFactory->CreateObject(mID),itr->worldFragment->singleIntersection;
	 
			char name[16];
			if(bRobotMode)
			{
				sprintf(name, "Robot%d", mCount++ );
				Ogre::Entity* ent = mSceneMgr->createEntity(name, "robot.mesh");
				mCurrentObject = mSceneMgr->getRootSceneNode()->createChildSceneNode(std::string(name) + "Node", itr->worldFragment->singleIntersection);
				mCurrentObject->attachObject(ent);
				mCurrentObject->setScale(0.1f, 0.1f, 0.1f);
			}
			else
			{
				sprintf(name, "Ninja%d", mCount++);
				Ogre::Entity* entNin = mSceneMgr->createEntity(name, "ninja.mesh");
				mCurrentObject = mSceneMgr->getRootSceneNode()->createChildSceneNode(std::string(name) + "Node", itr->worldFragment->singleIntersection);
				mCurrentObject->attachObject(entNin);
				mCurrentObject->setScale(0.1f, 0.1f, 0.1f);
			}

			}//if*/
		//Get results, create a node/entity on the position
		for(itr; itr != result.end(); itr++)
		{
			if(itr->movable && itr->movable->getName().substr(0, 5) != "tile[")
			{
				mCurrentObject = itr->movable->getParentSceneNode();
				break;
			}//if
			else if(itr->worldFragment)
			{
				mCurrentObject = mFactory->createObject(ObjID, itr->worldFragment->singleIntersection);
				/*
				Ogre::Entity* ent;
				char name[16];
				if(mID == 1)
				{
					//mObjectList.front();
					sprintf(name, "Robot%d", mCount++);
					ent = mSceneMgr->createEntity(name, "robot.mesh");
					ent->setQueryFlags(ROBOT_MASK);
				}//if
				else if(mID == 2)
				{
					sprintf(name, "Ninja%d", mCount++);
					ent = mSceneMgr->createEntity(name, "ninja.mesh");
					ent->setQueryFlags(NINJA_MASK);
				}//else if
				else if(mID == 3)
				{
					sprintf(name, "Knot%d", mCount++);
					ent = mSceneMgr->createEntity(name, "knot.mesh");
					ent->setQueryFlags(KNOT_MASK);
				}
				else 
				{
					sprintf(name, "Penguin%d", mCount++);
					ent = mSceneMgr->createEntity(name, "penguin.mesh");
					ent->setQueryFlags(PENGUIN_MASK);
				}
				mCurrentObject = mSceneMgr->getRootSceneNode()->createChildSceneNode(std::string(name) + "Node", itr->worldFragment->singleIntersection);
				mCurrentObject->attachObject(ent);
				mCurrentObject->setScale(0.1f, 0.1f, 0.1f);
				break;*/
			}//else if
		}

		mLMouseDown = true;
	}//for
		

	
	//Right mouse button down
	else if(id == OIS::MB_Right)
	{
		CEGUI::MouseCursor::getSingleton().hide();
		mRMouseDown = true;
	}//else if
	if(mCurrentObject)
	{
		mCurrentObject->showBoundingBox(true);
	}
	return true;
}

bool IntermediateTutorial2::mouseReleased(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
{
	//Left mouse button up
	if(id == OIS::MB_Left)
	{
		mLMouseDown = false;
	}
	//Right mouse button up
	else if(id == OIS::MB_Right)
	{
		CEGUI::MouseCursor::getSingleton().show();
		mRMouseDown = false;
	}//else if
	return true;
}
/*Ogre::SceneNode*  IntermediateTutorial2::createObject(int ObjID, Ogre::Vector3 pos)
{
	Ogre::Entity* ent;
	char name[16];
	switch(ObjID)
	{
	case 1:
		sprintf(name, "Robot%d", mCount++);
		ent = mSceneMgr->createEntity(name, "robot.mesh");
		ent->setQueryFlags(ROBOT_MASK);
		break;
	case 2:
		sprintf(name, "Ninja%d", mCount++);
		ent = mSceneMgr->createEntity(name, "ninja.mesh");
		ent->setQueryFlags(NINJA_MASK);
		break;
	case 3:
		sprintf(name, "Knot%d", mCount++);
		ent = mSceneMgr->createEntity(name, "knot.mesh");
		ent->setQueryFlags(KNOT_MASK);
		break;
	case 4: 
		sprintf(name, "Penguin%d", mCount++);
		ent = mSceneMgr->createEntity(name, "penguin.mesh");
		ent->setQueryFlags(PENGUIN_MASK);
		break;
	default:
		//unknown id, maybe throw an exeption, for now just return silently
		return 0;
	}
	Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(std::string(name) + "Node", pos);
	node->attachObject(ent);
	node->setScale(0.1f, 0.1f, 0.1f);
	return node;
}*/
/*bool IntermediateTutorial2::keyPressed(const OIS::KeyEvent& arg)
{
	//Check and see if the space barf was hit, and this will switch which mesh is spawned
	//if(arg.key == OIS::KC_SPACE)
	//{
	//	bRobotMode = !bRobotMode;
	//}
	switch(arg.key)
	{
	case OIS::KC_0:
		ObjID = 1;
		break;
	case OIS::KC_1:
		ObjID = 2;
		break;
	case OIS::KC_2:
		ObjID = 3;
		break;
	case OIS::KC_3:
		ObjID = 4;
		break;
	}
	// then we return the base app keypressed function so that we get all of the functionality
	//and the return value in one line
	return BaseApplication::keyPressed(arg);
}*/

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
    INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
    int main(int argc, char *argv[])
#endif
    {
        // Create application object
        IntermediateTutorial2 app;

        try {
            app.go();
        } catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
            MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
            std::cerr << "An exception has occured: " <<
                e.getFullDescription().c_str() << std::endl;
#endif
        }

        return 0;
    }

#ifdef __cplusplus
}
#endif
and the IntermediateTutorial class header:

Code: Select all

/*
-----------------------------------------------------------------------------
Filename:    IntermediateTutorial2.h
-----------------------------------------------------------------------------


This source file is generated by the
   ___                   _              __    __ _                  _ 
  /___\__ _ _ __ ___    /_\  _ __  _ __/ / /\ \ (_)______ _ _ __ __| |
 //  // _` | '__/ _ \  //_\\| '_ \| '_ \ \/  \/ / |_  / _` | '__/ _` |
/ \_// (_| | | |  __/ /  _  \ |_) | |_) \  /\  /| |/ / (_| | | | (_| |
\___/ \__, |_|  \___| \_/ \_/ .__/| .__/ \/  \/ |_/___\__,_|_|  \__,_|
      |___/                 |_|   |_|                                 
      Ogre 1.7.x Application Wizard for VC10 (July 2011)
      http://code.google.com/p/ogreappwizards/
-----------------------------------------------------------------------------
*/
#ifndef __IntermediateTutorial2_h_
#define __IntermediateTutorial2_h_

#include "BaseApplication.h"
#include <CEGUI.h>
#include <RendererModules\Ogre\CEGUIOgreRenderer.h>
#include "FactoryClass.h"


#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#include "../res/resource.h"
#endif


class IntermediateTutorial2 : public BaseApplication
{
public:
    IntermediateTutorial2(void);
    virtual ~IntermediateTutorial2(void);
	enum QueryFlags
	{
		NINJA_MASK = 1<<0,
		ROBOT_MASK = 1<<1,
		KNOT_MASK = 1<<2,
		PENGUIN_MASK = 1<<3
	};

protected:
    virtual void createScene(void);
	virtual void chooseSceneManager(void);
	virtual void createFrameListener(void);
	//virtual void CreateObjectID(int ID);
	//frame listener
	virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt);
	//mouse listener
	virtual bool mouseMoved(const OIS::MouseEvent& arg);
	virtual bool mousePressed(const OIS::MouseEvent& arg, OIS::MouseButtonID id);
	virtual bool mouseReleased(const OIS::MouseEvent& arg, OIS::MouseButtonID id);
	//Ogre::SceneNode* createObject(int ObjID, Ogre::Vector3 pos);
	//virtual bool keyPressed(const OIS::KeyEvent& arg);
	//virtual bool createObject(int ObjID, Ogre::Vector3 pos);
	//virtual bool ObjectID(const OIS::KeyEvent& arg, Ogre::Entity* ent);

	Ogre::RaySceneQuery* mRaySceneQuery;// The Ray scene query pointer
	bool mLMouseDown, mRMouseDown; //True if the mouse buttons are down
	//int mCount; //the number of robots on the screen
	Ogre::SceneNode* mCurrentObject; // The newly created object
	CEGUI::Renderer *mGUIRenderer; //CEGUI renderer
	float mRotateSpeed;
	//bool bRobotMode; //The current state
	//std::deque<Ogre::Entity::EntitySet> mObjectList;
	//std::pair<Ogre::SceneManager, Ogre::SceneNode> mList;
	//std::vector<FactoryClass*> mFactory;
	FactoryClass* mFactory;
	//int mID;
	int ObjID;

};

#endif // #ifndef __IntermediateTutorial2_h_
i hope ur patient enough to teach me one more lesson before i move on with the other intermediate tutorials!
thx a lot for everything you have showed me so far and i hope to get it solved soon !
Kind regards,
Romulo Romero
EDIT: something seems to be wrong with the mCount name incrementation in the factoryclass .cpp file
User avatar
Waruck
Goblin
Posts: 210
Joined: Mon Dec 12, 2011 12:52 pm
Location: Germany
x 34

Re: Factory Pattern(intermediate tutorial 3)

Post by Waruck »

Got the code to run correctly. I deleted all previous comments and added new comments for every change I made. You should try to understand every single change and why I made it to understand how the code works.

FactoryClass.h :

Code: Select all

#ifndef FACTORYCLASS_H
#define FACTORYCLASS_H
#include "BaseApplication.h"		//no big difference, but put nothing above the include guard (the #ifndef)


class FactoryClass					//the FactoryClass is an independent class. there's no need to inherit any other class
{
public:
	FactoryClass(void);
	~FactoryClass(void);			//since we don't inherit anything there's no need to declare the destructor virtual

	/*enum QueryFlags				//no need to redefine this here since the enum is public in intermediateTutorial2
	{
		NINJA_MASK = 1<<0,
		ROBOT_MASK = 1<<1,
		KNOT_MASK = 1<<2,
		PENGUIN_MASK = 1<<3
	};*/
	Ogre::SceneNode* createObject(int ObjID, Ogre::Vector3 pos, Ogre::SceneManager* SceneMngr);		//added the scene-manager as a parameter since we're no longer in the intermediate tutorial class and don't have direct access to it. you may get trouble here since you named the function parameter ObjID exactly like you named the class-member
private:						//since there's no inheritance you can mark this section as private instead of protected. this is no difference though.

	//virtual bool keyPressed(const OIS::KeyEvent& arg);			//we don't need the keyPressed function in the factory-class. the factoryclass is not suppost to get any key-input. the input is handeled elsewhere and only the createObject() function is called with the id as one of the function's parameters.
	int mCount;
	//int ObjID;													//we don't need this class-member. the function variable is enough do specify which object to create. Also you need to be carefull not to mix up names. it is a good habbit to begin the name of class-members with a little 'm' to indicate they are class-members and not to accidentally name 2 variables the same.
};
#endif
FactoryClass.cpp:

Code: Select all

#include "FactoryClass.h"
#include "IntermediateTutorial2.h"	//include this to use the mask-enum, don't include this in FactoryClass.h to avoid circle-inclusion

FactoryClass::FactoryClass(void)
{
	mCount = 0;
	//int ObjID = 0;				//don't need this as a classmember... anyway the initialisation with 'int' would define it as a local variable that is lost after the constructer finished...
}
FactoryClass::~FactoryClass(void)
{
}
Ogre::SceneNode*  FactoryClass::createObject(int ObjID, Ogre::Vector3 pos, Ogre::SceneManager* sceneMgr)
{
	Ogre::Entity* ent;
	char name[16];
	switch(ObjID)
	{
	case 1:
		sprintf(name, "Robot%d", mCount++);
		ent = sceneMgr->createEntity(name, "robot.mesh");			//renamed mSceneMgr to sceneMgr (function parameter)
		ent->setQueryFlags(IntermediateTutorial2::ROBOT_MASK);		//use intermediaateTutorial2 enum
		break;
	case 2:
		sprintf(name, "Ninja%d", mCount++);
		ent = sceneMgr->createEntity(name, "ninja.mesh");			//renamed mSceneMgr to sceneMgr (function parameter)
		ent->setQueryFlags(IntermediateTutorial2::NINJA_MASK);		//use intermediaateTutorial2 enum
		break;
	case 3:
		sprintf(name, "Knot%d", mCount++);
		ent = sceneMgr->createEntity(name, "knot.mesh");			//renamed mSceneMgr to sceneMgr (function parameter)
		ent->setQueryFlags(IntermediateTutorial2::KNOT_MASK);		//use intermediaateTutorial2 enum
		break;
	case 4: 
		sprintf(name, "Penguin%d", mCount++);
		ent = sceneMgr->createEntity(name, "penguin.mesh");			//renamed mSceneMgr to sceneMgr (function parameter)
		ent->setQueryFlags(IntermediateTutorial2::PENGUIN_MASK);	//use intermediaateTutorial2 enum
		break;
	default:
		return 0;
	}
	Ogre::SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(std::string(name) + "Node", pos);		//renamed mSceneMgr to sceneMgr (function parameter)
	node->attachObject(ent);
	node->setScale(0.1f, 0.1f, 0.1f);
	return node;
}

/* we don't need this function
bool FactoryClass::keyPressed(const OIS::KeyEvent& arg)
{
	switch(arg.key)
	{
	case OIS::KC_0:
		ObjID = 1;
		break;
	case OIS::KC_1:
		ObjID = 2;
		break;
	case OIS::KC_2:
		ObjID = 3;
		break;
	case OIS::KC_3:
		ObjID = 4;
		break;
	}
	return BaseApplication::keyPressed(arg);
}*/
IntermediateTutorial2.h:

Code: Select all

/*
-----------------------------------------------------------------------------
Filename:    IntermediateTutorial2.h
-----------------------------------------------------------------------------


This source file is generated by the
   ___                   _              __    __ _                  _ 
  /___\__ _ _ __ ___    /_\  _ __  _ __/ / /\ \ (_)______ _ _ __ __| |
 //  // _` | '__/ _ \  //_\\| '_ \| '_ \ \/  \/ / |_  / _` | '__/ _` |
/ \_// (_| | | |  __/ /  _  \ |_) | |_) \  /\  /| |/ / (_| | | | (_| |
\___/ \__, |_|  \___| \_/ \_/ .__/| .__/ \/  \/ |_/___\__,_|_|  \__,_|
      |___/                 |_|   |_|                                 
      Ogre 1.7.x Application Wizard for VC10 (July 2011)
      http://code.google.com/p/ogreappwizards/
-----------------------------------------------------------------------------
*/
#ifndef __IntermediateTutorial2_h_
#define __IntermediateTutorial2_h_

#include "BaseApplication.h"
#include <CEGUI.h>
#include <RendererModules\Ogre\CEGUIOgreRenderer.h>
#include "FactoryClass.h"


#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#include "../res/resource.h"
#endif


class IntermediateTutorial2 : public BaseApplication
{
public:
	IntermediateTutorial2(void);
	virtual ~IntermediateTutorial2(void);
	enum QueryFlags
	{
		NINJA_MASK = 1<<0,
		ROBOT_MASK = 1<<1,
		KNOT_MASK = 1<<2,
		PENGUIN_MASK = 1<<3
	};

protected:
	virtual void createScene(void);
	virtual void chooseSceneManager(void);
	virtual void createFrameListener(void);
	virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt);
	virtual bool mouseMoved(const OIS::MouseEvent& arg);
	virtual bool mousePressed(const OIS::MouseEvent& arg, OIS::MouseButtonID id);
	virtual bool mouseReleased(const OIS::MouseEvent& arg, OIS::MouseButtonID id);
	virtual bool keyPressed(const OIS::KeyEvent& arg);								//since this class is still the keylisteneder we need this function

	Ogre::RaySceneQuery* mRaySceneQuery;
	bool mLMouseDown, mRMouseDown;
	Ogre::SceneNode* mCurrentObject;
	CEGUI::Renderer *mGUIRenderer;
	float mRotateSpeed;
	FactoryClass* mFactory;
	int mObjID;						//renamed to avoid confusion
};

#endif // #ifndef __IntermediateTutorial2_h_
IntermediateTutorial2.cpp:

Code: Select all

/*
-----------------------------------------------------------------------------
Filename:    IntermediateTutorial2.cpp
-----------------------------------------------------------------------------


This source file is generated by the
   ___                   _              __    __ _                  _ 
  /___\__ _ _ __ ___    /_\  _ __  _ __/ / /\ \ (_)______ _ _ __ __| |
 //  // _` | '__/ _ \  //_\\| '_ \| '_ \ \/  \/ / |_  / _` | '__/ _` |
/ \_// (_| | | |  __/ /  _  \ |_) | |_) \  /\  /| |/ / (_| | | | (_| |
\___/ \__, |_|  \___| \_/ \_/ .__/| .__/ \/  \/ |_/___\__,_|_|  \__,_|
      |___/                 |_|   |_|                                 
      Ogre 1.7.x Application Wizard for VC10 (July 2011)
      http://code.google.com/p/ogreappwizards/
-----------------------------------------------------------------------------
*/

#include "IntermediateTutorial2.h"
/*#include <CEGUISystem.h>								//we don't need to include these files since IntermediateTutorial2.h allready includes them
#include <CEGUISchemeManager.h>
#include <RendererModules/Ogre/CEGUIOgreRenderer.h>*/

//-------------------------------------------------------------------------------------
IntermediateTutorial2::IntermediateTutorial2(void)
{
}
//-------------------------------------------------------------------------------------
IntermediateTutorial2::~IntermediateTutorial2(void)
{
	mSceneMgr->destroyQuery(mRaySceneQuery);
	if(mFactory) delete mFactory;			//clean up the allocated memory
}

//-------------------------------------------------------------------------------------
void IntermediateTutorial2::createScene(void)
{
	mFactory = new FactoryClass;			//since mFactory is only a pointer we need to initialize it at some point before we can use it!

	mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
	mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);

	mSceneMgr->setWorldGeometry("terrain.cfg");

	mCamera->setPosition(40, 100, 580);
	mCamera->pitch(Ogre::Degree(-30));
	mCamera->yaw(Ogre::Degree(-45));
	mGUIRenderer = &CEGUI::OgreRenderer::bootstrapSystem();
	CEGUI::SchemeManager::getSingleton().create((CEGUI::utf8*)"TaharezLook.scheme");
	CEGUI::MouseCursor::getSingleton().setImage("TaharezLook", "MouseArrow");
}

void IntermediateTutorial2::createFrameListener(void)
{
	BaseApplication::createFrameListener();
	mObjID = 1;
	mCurrentObject = NULL;
	mLMouseDown = false;
	mRMouseDown = false;

	mRotateSpeed = .1;

	mRaySceneQuery = mSceneMgr->createRayQuery(Ogre::Ray());
}

void IntermediateTutorial2::chooseSceneManager(void)
{
	mSceneMgr = mRoot->createSceneManager(Ogre::ST_EXTERIOR_CLOSE);
}

bool IntermediateTutorial2::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
	//return BaseApplication::frameRenderingQueued(evt);		//this line is wrong (check the tutorial page!) a return statement, regardless of what is returned, ends the function, so everything below would never be executed!
	
	if(!BaseApplication::frameRenderingQueued(evt))				//the correct line from the tutorial. this only executes the return statement if the value is false, so if it's right we continue with this function
	{
		return false;
	}

	Ogre::Vector3 camPos = mCamera->getPosition();
	Ogre::Ray cameraRay(Ogre::Vector3(camPos.x, 5000.0f, camPos.z), Ogre::Vector3::NEGATIVE_UNIT_Y);
	mRaySceneQuery->setRay(cameraRay);
	mRaySceneQuery->setSortByDistance(false);
	Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute();
	Ogre::RaySceneQueryResult::iterator itr = result.begin();
	for(itr; itr != result.end(); itr++)
	{
		if(itr->worldFragment)
		{
			Ogre::Real terrainHeight = itr->worldFragment->singleIntersection.y;
			if((terrainHeight + 10.0f) > camPos.y)
			{
				mCamera->setPosition(camPos.x, terrainHeight + 10.0f, camPos.z);
			}
			break;
		}
	}
	return true;
	//return false;				2 return statements in a row?? doesn't make any sense....
}

bool IntermediateTutorial2::mouseMoved(const OIS::MouseEvent& arg)
{
	if(!mRMouseDown)								//small addition form me. if we press the right mouse to look around I prefer if the cursor doesn't move and reappears at the same position it disapperd from
		CEGUI::System::getSingleton().injectMouseMove(arg.state.X.rel, arg.state.Y.rel);
	if(mLMouseDown)
	{
		CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition();
		Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x / float(arg.state.width), mousePos.d_y / float(arg.state.height));
		mRaySceneQuery->setRay(mouseRay);
		mRaySceneQuery->setSortByDistance(false);
		Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute();
		Ogre::RaySceneQueryResult::iterator itr = result.begin();
		for(itr; itr != result.end(); itr++)
		{
			if(itr->worldFragment)
			{
				mCurrentObject->setPosition(itr->worldFragment->singleIntersection);
				break;
			}
		}
	}
	else if(mRMouseDown)
	{
		mCamera->yaw(Ogre::Degree(-arg.state.X.rel * mRotateSpeed));
		mCamera->pitch(Ogre::Degree(-arg.state.Y.rel * mRotateSpeed));
	}
	return true;
}


bool IntermediateTutorial2::mousePressed(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
{
	if(id == OIS::MB_Left)
	{
		if(mCurrentObject)
		{
			mCurrentObject->showBoundingBox(false);
		}
		CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition();
		Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x / float(arg.state.width), mousePos.d_y / float(arg.state.height));
		mRaySceneQuery->setRay(mouseRay);
		mRaySceneQuery->setSortByDistance(true);
		mRaySceneQuery->setQueryMask(ROBOT_MASK | NINJA_MASK | KNOT_MASK | PENGUIN_MASK);
		Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute();
		Ogre::RaySceneQueryResult::iterator itr = result.begin();

		for(itr; itr != result.end(); itr++)
		{
			if(itr->movable && itr->movable->getName().substr(0, 5) != "tile[")
			{
				mCurrentObject = itr->movable->getParentSceneNode();
				break;
			}
			else if(itr->worldFragment)
			{
				mCurrentObject = mFactory->createObject(mObjID, itr->worldFragment->singleIntersection, mSceneMgr);	//renamed ObjID to mObjID and added SceneManager as parameter so the factory class can use it to create the scene node.
			}
		}

		mLMouseDown = true;
	}
    
	else if(id == OIS::MB_Right)
	{
		CEGUI::MouseCursor::getSingleton().hide();
		mRMouseDown = true;
	}
	if(mCurrentObject)
	{
		mCurrentObject->showBoundingBox(true);
	}
	return true;
}

bool IntermediateTutorial2::mouseReleased(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
{
	
	if(id == OIS::MB_Left)
	{
		mLMouseDown = false;
	}
	else if(id == OIS::MB_Right)
	{
		CEGUI::MouseCursor::getSingleton().show();
		mRMouseDown = false;
	}
	return true;
}

bool IntermediateTutorial2::keyPressed(const OIS::KeyEvent& arg)		//we need this function since this is the keylistener
    {
       switch(arg.key)
       {
       case OIS::KC_0:
          mObjID = 1;			//renamed
          break;
       case OIS::KC_1:
          mObjID = 2;			//renamed
          break;
       case OIS::KC_2:
          mObjID = 3;			//renamed
          break;
       case OIS::KC_3:
          mObjID = 4;			//renamed
          break;
	   default:					//added default
		   break;
       }
       return BaseApplication::keyPressed(arg);
    }

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
    INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
	int main(int argc, char *argv[])
#endif
	{
		// Create application object
		IntermediateTutorial2 app;

		try {
			app.go();
		} catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
		MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
		std::cerr << "An exception has occured: " <<
			e.getFullDescription().c_str() << std::endl;
#endif
		}

		return 0;
	}

#ifdef __cplusplus
}
#endif
Blender+C++
Gremlin
Posts: 171
Joined: Tue Jan 03, 2012 1:38 am
Location: Brazil
x 3

Re: Factory Pattern(intermediate tutorial 3)

Post by Blender+C++ »

Waruck wrote:Got the code to run correctly. I deleted all previous comments and added new comments for every change I made. You should try to understand every single change and why I made it to understand how the code works.

FactoryClass.h :

Code: Select all

#ifndef FACTORYCLASS_H
#define FACTORYCLASS_H
#include "BaseApplication.h"		//no big difference, but put nothing above the include guard (the #ifndef)


class FactoryClass					//the FactoryClass is an independent class. there's no need to inherit any other class
{
public:
	FactoryClass(void);
	~FactoryClass(void);			//since we don't inherit anything there's no need to declare the destructor virtual

	/*enum QueryFlags				//no need to redefine this here since the enum is public in intermediateTutorial2
	{
		NINJA_MASK = 1<<0,
		ROBOT_MASK = 1<<1,
		KNOT_MASK = 1<<2,
		PENGUIN_MASK = 1<<3
	};*/
	Ogre::SceneNode* createObject(int ObjID, Ogre::Vector3 pos, Ogre::SceneManager* SceneMngr);		//added the scene-manager as a parameter since we're no longer in the intermediate tutorial class and don't have direct access to it. you may get trouble here since you named the function parameter ObjID exactly like you named the class-member
private:						//since there's no inheritance you can mark this section as private instead of protected. this is no difference though.

	//virtual bool keyPressed(const OIS::KeyEvent& arg);			//we don't need the keyPressed function in the factory-class. the factoryclass is not suppost to get any key-input. the input is handeled elsewhere and only the createObject() function is called with the id as one of the function's parameters.
	int mCount;
	//int ObjID;													//we don't need this class-member. the function variable is enough do specify which object to create. Also you need to be carefull not to mix up names. it is a good habbit to begin the name of class-members with a little 'm' to indicate they are class-members and not to accidentally name 2 variables the same.
};
#endif
FactoryClass.cpp:

Code: Select all

#include "FactoryClass.h"
#include "IntermediateTutorial2.h"	//include this to use the mask-enum, don't include this in FactoryClass.h to avoid circle-inclusion

FactoryClass::FactoryClass(void)
{
	mCount = 0;
	//int ObjID = 0;				//don't need this as a classmember... anyway the initialisation with 'int' would define it as a local variable that is lost after the constructer finished...
}
FactoryClass::~FactoryClass(void)
{
}
Ogre::SceneNode*  FactoryClass::createObject(int ObjID, Ogre::Vector3 pos, Ogre::SceneManager* sceneMgr)
{
	Ogre::Entity* ent;
	char name[16];
	switch(ObjID)
	{
	case 1:
		sprintf(name, "Robot%d", mCount++);
		ent = sceneMgr->createEntity(name, "robot.mesh");			//renamed mSceneMgr to sceneMgr (function parameter)
		ent->setQueryFlags(IntermediateTutorial2::ROBOT_MASK);		//use intermediaateTutorial2 enum
		break;
	case 2:
		sprintf(name, "Ninja%d", mCount++);
		ent = sceneMgr->createEntity(name, "ninja.mesh");			//renamed mSceneMgr to sceneMgr (function parameter)
		ent->setQueryFlags(IntermediateTutorial2::NINJA_MASK);		//use intermediaateTutorial2 enum
		break;
	case 3:
		sprintf(name, "Knot%d", mCount++);
		ent = sceneMgr->createEntity(name, "knot.mesh");			//renamed mSceneMgr to sceneMgr (function parameter)
		ent->setQueryFlags(IntermediateTutorial2::KNOT_MASK);		//use intermediaateTutorial2 enum
		break;
	case 4: 
		sprintf(name, "Penguin%d", mCount++);
		ent = sceneMgr->createEntity(name, "penguin.mesh");			//renamed mSceneMgr to sceneMgr (function parameter)
		ent->setQueryFlags(IntermediateTutorial2::PENGUIN_MASK);	//use intermediaateTutorial2 enum
		break;
	default:
		return 0;
	}
	Ogre::SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(std::string(name) + "Node", pos);		//renamed mSceneMgr to sceneMgr (function parameter)
	node->attachObject(ent);
	node->setScale(0.1f, 0.1f, 0.1f);
	return node;
}

/* we don't need this function
bool FactoryClass::keyPressed(const OIS::KeyEvent& arg)
{
	switch(arg.key)
	{
	case OIS::KC_0:
		ObjID = 1;
		break;
	case OIS::KC_1:
		ObjID = 2;
		break;
	case OIS::KC_2:
		ObjID = 3;
		break;
	case OIS::KC_3:
		ObjID = 4;
		break;
	}
	return BaseApplication::keyPressed(arg);
}*/
IntermediateTutorial2.h:

Code: Select all

/*
-----------------------------------------------------------------------------
Filename:    IntermediateTutorial2.h
-----------------------------------------------------------------------------


This source file is generated by the
   ___                   _              __    __ _                  _ 
  /___\__ _ _ __ ___    /_\  _ __  _ __/ / /\ \ (_)______ _ _ __ __| |
 //  // _` | '__/ _ \  //_\\| '_ \| '_ \ \/  \/ / |_  / _` | '__/ _` |
/ \_// (_| | | |  __/ /  _  \ |_) | |_) \  /\  /| |/ / (_| | | | (_| |
\___/ \__, |_|  \___| \_/ \_/ .__/| .__/ \/  \/ |_/___\__,_|_|  \__,_|
      |___/                 |_|   |_|                                 
      Ogre 1.7.x Application Wizard for VC10 (July 2011)
      http://code.google.com/p/ogreappwizards/
-----------------------------------------------------------------------------
*/
#ifndef __IntermediateTutorial2_h_
#define __IntermediateTutorial2_h_

#include "BaseApplication.h"
#include <CEGUI.h>
#include <RendererModules\Ogre\CEGUIOgreRenderer.h>
#include "FactoryClass.h"


#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#include "../res/resource.h"
#endif


class IntermediateTutorial2 : public BaseApplication
{
public:
	IntermediateTutorial2(void);
	virtual ~IntermediateTutorial2(void);
	enum QueryFlags
	{
		NINJA_MASK = 1<<0,
		ROBOT_MASK = 1<<1,
		KNOT_MASK = 1<<2,
		PENGUIN_MASK = 1<<3
	};

protected:
	virtual void createScene(void);
	virtual void chooseSceneManager(void);
	virtual void createFrameListener(void);
	virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt);
	virtual bool mouseMoved(const OIS::MouseEvent& arg);
	virtual bool mousePressed(const OIS::MouseEvent& arg, OIS::MouseButtonID id);
	virtual bool mouseReleased(const OIS::MouseEvent& arg, OIS::MouseButtonID id);
	virtual bool keyPressed(const OIS::KeyEvent& arg);								//since this class is still the keylisteneder we need this function

	Ogre::RaySceneQuery* mRaySceneQuery;
	bool mLMouseDown, mRMouseDown;
	Ogre::SceneNode* mCurrentObject;
	CEGUI::Renderer *mGUIRenderer;
	float mRotateSpeed;
	FactoryClass* mFactory;
	int mObjID;						//renamed to avoid confusion
};

#endif // #ifndef __IntermediateTutorial2_h_
IntermediateTutorial2.cpp:

Code: Select all

/*
-----------------------------------------------------------------------------
Filename:    IntermediateTutorial2.cpp
-----------------------------------------------------------------------------


This source file is generated by the
   ___                   _              __    __ _                  _ 
  /___\__ _ _ __ ___    /_\  _ __  _ __/ / /\ \ (_)______ _ _ __ __| |
 //  // _` | '__/ _ \  //_\\| '_ \| '_ \ \/  \/ / |_  / _` | '__/ _` |
/ \_// (_| | | |  __/ /  _  \ |_) | |_) \  /\  /| |/ / (_| | | | (_| |
\___/ \__, |_|  \___| \_/ \_/ .__/| .__/ \/  \/ |_/___\__,_|_|  \__,_|
      |___/                 |_|   |_|                                 
      Ogre 1.7.x Application Wizard for VC10 (July 2011)
      http://code.google.com/p/ogreappwizards/
-----------------------------------------------------------------------------
*/

#include "IntermediateTutorial2.h"
/*#include <CEGUISystem.h>								//we don't need to include these files since IntermediateTutorial2.h allready includes them
#include <CEGUISchemeManager.h>
#include <RendererModules/Ogre/CEGUIOgreRenderer.h>*/

//-------------------------------------------------------------------------------------
IntermediateTutorial2::IntermediateTutorial2(void)
{
}
//-------------------------------------------------------------------------------------
IntermediateTutorial2::~IntermediateTutorial2(void)
{
	mSceneMgr->destroyQuery(mRaySceneQuery);
	if(mFactory) delete mFactory;			//clean up the allocated memory
}

//-------------------------------------------------------------------------------------
void IntermediateTutorial2::createScene(void)
{
	mFactory = new FactoryClass;			//since mFactory is only a pointer we need to initialize it at some point before we can use it!

	mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
	mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);

	mSceneMgr->setWorldGeometry("terrain.cfg");

	mCamera->setPosition(40, 100, 580);
	mCamera->pitch(Ogre::Degree(-30));
	mCamera->yaw(Ogre::Degree(-45));
	mGUIRenderer = &CEGUI::OgreRenderer::bootstrapSystem();
	CEGUI::SchemeManager::getSingleton().create((CEGUI::utf8*)"TaharezLook.scheme");
	CEGUI::MouseCursor::getSingleton().setImage("TaharezLook", "MouseArrow");
}

void IntermediateTutorial2::createFrameListener(void)
{
	BaseApplication::createFrameListener();
	mObjID = 1;
	mCurrentObject = NULL;
	mLMouseDown = false;
	mRMouseDown = false;

	mRotateSpeed = .1;

	mRaySceneQuery = mSceneMgr->createRayQuery(Ogre::Ray());
}

void IntermediateTutorial2::chooseSceneManager(void)
{
	mSceneMgr = mRoot->createSceneManager(Ogre::ST_EXTERIOR_CLOSE);
}

bool IntermediateTutorial2::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
	//return BaseApplication::frameRenderingQueued(evt);		//this line is wrong (check the tutorial page!) a return statement, regardless of what is returned, ends the function, so everything below would never be executed!
	
	if(!BaseApplication::frameRenderingQueued(evt))				//the correct line from the tutorial. this only executes the return statement if the value is false, so if it's right we continue with this function
	{
		return false;
	}

	Ogre::Vector3 camPos = mCamera->getPosition();
	Ogre::Ray cameraRay(Ogre::Vector3(camPos.x, 5000.0f, camPos.z), Ogre::Vector3::NEGATIVE_UNIT_Y);
	mRaySceneQuery->setRay(cameraRay);
	mRaySceneQuery->setSortByDistance(false);
	Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute();
	Ogre::RaySceneQueryResult::iterator itr = result.begin();
	for(itr; itr != result.end(); itr++)
	{
		if(itr->worldFragment)
		{
			Ogre::Real terrainHeight = itr->worldFragment->singleIntersection.y;
			if((terrainHeight + 10.0f) > camPos.y)
			{
				mCamera->setPosition(camPos.x, terrainHeight + 10.0f, camPos.z);
			}
			break;
		}
	}
	return true;
	//return false;				2 return statements in a row?? doesn't make any sense....
}

bool IntermediateTutorial2::mouseMoved(const OIS::MouseEvent& arg)
{
	if(!mRMouseDown)								//small addition form me. if we press the right mouse to look around I prefer if the cursor doesn't move and reappears at the same position it disapperd from
		CEGUI::System::getSingleton().injectMouseMove(arg.state.X.rel, arg.state.Y.rel);
	if(mLMouseDown)
	{
		CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition();
		Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x / float(arg.state.width), mousePos.d_y / float(arg.state.height));
		mRaySceneQuery->setRay(mouseRay);
		mRaySceneQuery->setSortByDistance(false);
		Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute();
		Ogre::RaySceneQueryResult::iterator itr = result.begin();
		for(itr; itr != result.end(); itr++)
		{
			if(itr->worldFragment)
			{
				mCurrentObject->setPosition(itr->worldFragment->singleIntersection);
				break;
			}
		}
	}
	else if(mRMouseDown)
	{
		mCamera->yaw(Ogre::Degree(-arg.state.X.rel * mRotateSpeed));
		mCamera->pitch(Ogre::Degree(-arg.state.Y.rel * mRotateSpeed));
	}
	return true;
}


bool IntermediateTutorial2::mousePressed(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
{
	if(id == OIS::MB_Left)
	{
		if(mCurrentObject)
		{
			mCurrentObject->showBoundingBox(false);
		}
		CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition();
		Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x / float(arg.state.width), mousePos.d_y / float(arg.state.height));
		mRaySceneQuery->setRay(mouseRay);
		mRaySceneQuery->setSortByDistance(true);
		mRaySceneQuery->setQueryMask(ROBOT_MASK | NINJA_MASK | KNOT_MASK | PENGUIN_MASK);
		Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute();
		Ogre::RaySceneQueryResult::iterator itr = result.begin();

		for(itr; itr != result.end(); itr++)
		{
			if(itr->movable && itr->movable->getName().substr(0, 5) != "tile[")
			{
				mCurrentObject = itr->movable->getParentSceneNode();
				break;
			}
			else if(itr->worldFragment)
			{
				mCurrentObject = mFactory->createObject(mObjID, itr->worldFragment->singleIntersection, mSceneMgr);	//renamed ObjID to mObjID and added SceneManager as parameter so the factory class can use it to create the scene node.
			}
		}

		mLMouseDown = true;
	}
    
	else if(id == OIS::MB_Right)
	{
		CEGUI::MouseCursor::getSingleton().hide();
		mRMouseDown = true;
	}
	if(mCurrentObject)
	{
		mCurrentObject->showBoundingBox(true);
	}
	return true;
}

bool IntermediateTutorial2::mouseReleased(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
{
	
	if(id == OIS::MB_Left)
	{
		mLMouseDown = false;
	}
	else if(id == OIS::MB_Right)
	{
		CEGUI::MouseCursor::getSingleton().show();
		mRMouseDown = false;
	}
	return true;
}

bool IntermediateTutorial2::keyPressed(const OIS::KeyEvent& arg)		//we need this function since this is the keylistener
    {
       switch(arg.key)
       {
       case OIS::KC_0:
          mObjID = 1;			//renamed
          break;
       case OIS::KC_1:
          mObjID = 2;			//renamed
          break;
       case OIS::KC_2:
          mObjID = 3;			//renamed
          break;
       case OIS::KC_3:
          mObjID = 4;			//renamed
          break;
	   default:					//added default
		   break;
       }
       return BaseApplication::keyPressed(arg);
    }

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
    INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
	int main(int argc, char *argv[])
#endif
	{
		// Create application object
		IntermediateTutorial2 app;

		try {
			app.go();
		} catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
		MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
		std::cerr << "An exception has occured: " <<
			e.getFullDescription().c_str() << std::endl;
#endif
		}

		return 0;
	}

#ifdef __cplusplus
}
#endif
WOW Waruck,
first of all thank u so much for all the effort and help and for dedicating ur time to help others and what a help btw that was just a class,more than a tutorial,i really really appreciate it,no words would express how thankful i feel for u!!!
u are a rare type of person 4 real!!!!
the comments uve put in every line they were reaaallly helpful and made me understand a whole lot,and all the confusion i made in some parts is due to the changes i made throughout my attempts to make it work and sometimes i forget to erase some stuff or reorganise it...
what im really impressed is for ur patience in trying to help me out(a newbie),again i gotta say it again ,i feel really greatful,i know that this is not a social networking forums ,but i feel like i should somehow thank u for alll the help here!
finally ill leave this thread wiser and knowing a bit more about how ogre works!
wish me good luck in my jorney to become a game developer,btw in June ill be going to Boston to study in a game design school(college)..i need good luck for all that :D
thanks thanks thanks...Thread finally solved,thanks to u brotha!
All the best,
Romulo Romero