Hi there, I'm developing a submarine simulator, and have got a little question.
For the moment, I'm just creating a submarine and a target ship
I've created the scene node for the sub, so that I have a mesh, in the location that I want, etc, however, I obviously also want a submarine class to hold data such as maxSpeed, health_points, etc, as well as member functions to raise and lower the periscope etc (because I want to time how long it's raised for)
I wasn't quite sure the best way of going about doing this.
Would the following work?
create a Submarine class, which holds a pointer to a scene node as a data member. Use a setSceneNode member function to set the pointer to the previously created submarine scene node.
Then use a getSceneNode member function, which simply returns the stored pointer to the scene node...
so I can use commands like sub->getSceneNode->getPosition to get the position of the sub scene node which is pointed to by the data member of my sub object (of class Sub)
would that be possible?
Or could the actual sub object identifier be a pointer to the sub scene node, so I can do sub->getPosition?
Any advice would be very welcome.
Thanks a lot.
Scene node contained in object
-
Kencho
- OGRE Retired Moderator

- Posts: 4011
- Joined: Fri Sep 19, 2003 6:28 pm
- Location: Burgos, Spain
- x 2
The second is not desirable in my opinion. Designing/finding classes is a matter of classifying responsibilities. A scene node is just an anchor, where you can attach a movable object into the scene itself. Your submarine class is instead a game logic entity. It stores and takes responsibility of anything submarine-related (or mostly anything). So you should keep a pointer of the scene node in the submarine class. Also, I suggest you to create and destroy the scene node, entity and such from inside the submarine class, as it's its responsibility. That's what composition relationships mean (that scene node is part of the submarine itself, in terms of game logic).
Hope that helps
Hope that helps
-
Protagonist
- Goblin
- Posts: 214
- Joined: Tue Nov 21, 2006 11:11 pm
Thanks for such a fast reply 
I really need to get this implemented tonight.
Cool, I agree....
however, I'm a bit lost as to how to implement that now.
I tried having the following data member:
SceneNode *ptrNode = 0;
and these member functions:
void setSceneNode( SceneNode value )
{
ptrNode = value;
}
SceneNode getSceneNode ()
{
return ptrNode;
}
so I can do this in the createScene(void) function:
sub.getSceneNode( nodeSub );
sub.getSceneNode()->setPosition( 0, -30, 0 );
where nodeSub is the scene node to which the sub mesh is attached,
and where sub is an object of type Submarine in which the getSceneNode function etc are defined
However, that's not legal...
Do you have any suggestions for how to implement it correctly?
Thanks very much
I really need to get this implemented tonight.
Cool, I agree....
however, I'm a bit lost as to how to implement that now.
I tried having the following data member:
SceneNode *ptrNode = 0;
and these member functions:
void setSceneNode( SceneNode value )
{
ptrNode = value;
}
SceneNode getSceneNode ()
{
return ptrNode;
}
so I can do this in the createScene(void) function:
sub.getSceneNode( nodeSub );
sub.getSceneNode()->setPosition( 0, -30, 0 );
where nodeSub is the scene node to which the sub mesh is attached,
and where sub is an object of type Submarine in which the getSceneNode function etc are defined
However, that's not legal...
Do you have any suggestions for how to implement it correctly?
Thanks very much
-
Kencho
- OGRE Retired Moderator

- Posts: 4011
- Joined: Fri Sep 19, 2003 6:28 pm
- Location: Burgos, Spain
- x 2
Pass the scene manager as a parameter to the submarine's constructor, and create the scene node and entity yourself. And of course, destroy both in the destructor 
You might also consider providing "façade" methods to the submarine, to only play with things such as set position, set yaw/pitch... instead of letting access to the whole scene node operations
You might also consider providing "façade" methods to the submarine, to only play with things such as set position, set yaw/pitch... instead of letting access to the whole scene node operations
-
Protagonist
- Goblin
- Posts: 214
- Joined: Tue Nov 21, 2006 11:11 pm
-
Kencho
- OGRE Retired Moderator

- Posts: 4011
- Joined: Fri Sep 19, 2003 6:28 pm
- Location: Burgos, Spain
- x 2
Splitted this topic in two. The new branch is here: http://www.ogre3d.org/phpBB2/viewtopic. ... 837#191837
Try not to change the overall topic. Open a new thread if you need to solve a different problem.
Try not to change the overall topic. Open a new thread if you need to solve a different problem.
-
Protagonist
- Goblin
- Posts: 214
- Joined: Tue Nov 21, 2006 11:11 pm
Hey, that was a great idea! It's really coming together I think. Thanks a lot.Kencho wrote:Pass the scene manager as a parameter to the submarine's constructor, and create the scene node and entity yourself. And of course, destroy both in the destructor
You might also consider providing "façade" methods to the submarine, to only play with things such as set position, set yaw/pitch... instead of letting access to the whole scene node operations
I've got a problem though... I think it's just a C++ misunderstanding of mine...
I get an error that the constructor of my derived class Sub from base class Watercraft cannot have a default constructor.
I'll post an accurate error message if that makes no sense (can't compile it where I am)
The code is as follows:
Code: Select all
#include <iostream>
#include <ctime>
#include <cmath>
using namespace std;
#ifndef __Simulator_H__ //1
#define __Simulator_H__
#include "Ogre.h"
#include "OgreConfigFile.h"
#include "ExampleFrameListener.h"
using namespace Ogre;
class Watercraft
{
public:
Watercraft( String &entityName, String ptype, SceneManager *mSceneMgr,
int healthValue, int maxSpeedValue, int typicalSpeedValue )
{
initialiseObject( entityName, ptype, mSceneMgr );
setHealth( healthValue );
setMaxSpeed( maxSpeedValue );
setTypicalSpeed( typicalSpeedValue );
}
~Watercraft()
{
}
void setHealth( int value )
{
health = value;
}
void setMaxSpeed( int value )
{
maxSpeed = value;
}
void setTypicalSpeed( int value )
{
typicalSpeed = value;
}
int getHealth()
{
return health;
}
int getMaxSpeed()
{
return maxSpeed;
}
int getTypicalSpeed()
{
return typicalSpeed;
}
//setPosition facade method
void setPosition( Real x, Real y, Real z )
{
node->setPosition( x, y, z );
}
const Vector3& getPosition()
{
return node->getPosition();
}
void faceTarget( Watercraft *target )
{
//get position of target
Vector3 targetPosition = target->getPosition();
//node->setFixedYawAxis( true ); //Vector3::UNIT_Y
//make the watercraft face the target
this->lookAt( targetPosition, Node::TS_PARENT );
//TS - transform space, relative to parent
//3rd param = The vector which normally describes
//the natural direction of the node, optional
}
void lookAt( const Vector3 &targetPoint, Ogre::Node::TransformSpace relativeTo,
const Vector3 &locationDirectionVector = Vector3::NEGATIVE_UNIT_Z )
{
lookAt( targetPoint, relativeTo, locationDirectionVector );
}
//roll facade method
void roll( const Radian &angle,
enum Ogre::Node::TransformSpace relativeTo = Ogre::Node::TS_LOCAL )
{
node->roll( angle, relativeTo );
}
//rotate facade method
void rotate( const Vector3 &axis, const Radian &angle,
enum Ogre::Node::TransformSpace relativeTo = Ogre::Node::TS_LOCAL )
{
node->rotate( axis, angle, relativeTo );
}
//yaw facade method
void yaw( const Ogre::Radian& degrees, Ogre::Node::TransformSpace relativeTo = Ogre::Node::TS_LOCAL )
{
node->yaw( degrees, relativeTo );
}
//setVisible facade method
void setVisible( bool visible, bool cascade = true )
{
node->setVisible( visible, cascade );
}
void setRandPos()
{
//seed random number generator
srand( time(0));
Vector3 pos = this->getPosition();
//normally 1 + rand() % value
int valueX = ( 1000 - rand() % 2000 );
//use existing value, as simply wish to yaw the node
int valueY = pos.y;
int valueZ = ( 1000 - rand() % 2000 );
this->setPosition( valueX, valueY, valueZ );
}
void setRandPosAway ( Watercraft *vessel, int distanceThresh = 200 )
{
double distance = 0;
//repeat while distance is too small
while ( distance < distanceThresh )
{
this->setRandPos();
//get distance, for condition test
distance = this->getRange( vessel );
}
//far enough random position set
}
//function to calculate distance between node of calling object and node of target
double getRange( Watercraft *vessel )
{
//vessel type, as then can reuse to allign ships to each other
//as well as test range between sub and ship
Vector3 pos1 = this->getPosition();
Vector3 pos2 = vessel->getPosition();
//euclidian distance, using x and z,
//as y is vertical in this coordinate system
double range = sqrt( pow((pos1.x - pos2.x), 2) + pow((pos1.z - pos2.z), 2));
//return the calculated range
return range;
}
protected:
int maxSpeed;
int typicalSpeed;
int health;
SceneNode* node;
Entity* ent;
//internal methods, only used by constructor:
virtual void initialiseObject( String &entityName, String ptype, SceneManager *mSceneMgr )
{
//don't have watercraft object
//replace code in derived classes
}
}; //end base class Watercraft
class Sub : public Watercraft
{
public:
Sub()
{
}
~Sub()
{
}
double getPeriscopeAngle( double rangeValue, double heightValue )
{
//local constant v, virtual image conversation value
const float v = 1.15;
//reverse ranging equation to obtain angle at periscope
double angle = ( ( heightValue * v * 1000 ) / rangeValue );
return angle;
}
private:
int diveDeepDepth;
int periscopeDepth;
SceneNode* nodePeriscope;
Entity* entPeriscope;
void initialiseObject( String &entityName, String ptype, SceneManager *mSceneMgr )
{
/////////////////////Create Submarine
ent = mSceneMgr->createEntity( entityName, ptype );
node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); //no name required
node->attachObject( ent );
////////////////////End creating Submarine
////////////////////Manipulate Submarine visual properties
//double the size of the sub, as model too small
node->scale(2, 2, 2 );
//lower position of submarine, so submerged
node->setPosition( 0, -30, 0 ); //x, y, z
//yaw (rotate about x axis) the sub
node->yaw( Degree(-90));
////////////////////End Manipulating Submarine visual properties
/////////////////////Create Periscope as child of sub
entPeriscope = mSceneMgr->createEntity( "Periscope", "attack_periscope.mesh" );
//make periscope child of submarine (also means no need to reposition,
//as position is relative). Also no need to scale
nodePeriscope = node->createChildSceneNode();
nodePeriscope->attachObject( entPeriscope );
//create camera node - child of periscope
//put camera in camera node
//create 2nd camera node
}
}; //end derived class sub
class Ship : public Watercraft
{
public:
Ship()
{
}
~Ship()
{
}
private:
void initialiseObject( String &entityName, String ptype, SceneManager *mSceneMgr )
{
/////////////////////Create Ship
ent = mSceneMgr->createEntity( entityName, ptype );
node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
node->attachObject( ent );
////////////////////End creating Ship
//place the ship in a random position (range -1000 to 1000 )
this->setRandPosAway( submarine, 200 );
}
}; //end derived class Ship
//Core class of the trainer
class Simulator
{
public:
/// Standard constructor
Simulator()
{
mFrameListener = 0;
mRoot = 0;
}
/// Standard destructor
~Simulator()
{
if (mFrameListener)
delete mFrameListener;
if (mRoot)
delete mRoot;
}
/// Start the example
void go(void)
{
if (!setup())
return;
mRoot->startRendering();
// clean up
destroyScene();
}
protected:
Root *mRoot;
Camera* mCamera;
SceneManager* mSceneMgr;
ExampleFrameListener* mFrameListener;
RenderWindow* mWindow;
// These internal methods package up the stages in the startup process
// Sets up the application - returns false if the user chooses to
//abandon configuration.
bool setup(void)
{
mRoot = new Root();
setupResources();
bool carryOn = configure();
if (!carryOn) return false;
chooseSceneManager();
createCamera();
createViewports();
// Set default mipmap level (NB some APIs ignore this)
TextureManager::getSingleton().setDefaultNumMipmaps(5);
// Create any resource listeners (for loading screens)
createResourceListener();
// Load resources
loadResources();
// Create the scene
createScene();
createFrameListener();
return true;
}
// Configures the application - returns false if the user chooses to
//abandon configuration.
bool configure(void)
{
//Show the configuration dialog and initialise the system
//You can skip this and use root.restoreConfig() to load configuration
//settings if you were sure there are valid ones saved in ogre.cfg
if(mRoot->showConfigDialog())
{
//If returned true, user clicked OK so initialise
//Here we choose to let the system create a default
//rendering window by passing 'true'
mWindow = mRoot->initialise(true, "Periscope Ranging Simulator");
return true;
}
else
{
return false;
}
}
void chooseSceneManager(void)
{
// Create the SceneManager exterior far
// See: http://www.ogre3d.org/wiki/index.php/SceneManagersFAQ
mSceneMgr = mRoot->createSceneManager( ST_EXTERIOR_FAR );
}
void createCamera(void)
{
// Create the camera
mCamera = mSceneMgr->createCamera("PlayerCam");
// Position it at scene origin
mCamera->setPosition(Vector3(0,0,0)); //x,y,z
// Look back along -Z
//mCamera->lookAt(Vector3(0,0,-300));
mCamera->setNearClipDistance(5);
}
void createFrameListener(void)
{
mFrameListener= new ExampleFrameListener(mWindow, mCamera);
mFrameListener->showDebugOverlay(false);
mRoot->addFrameListener(mFrameListener);
}
void createScene(void)
{
/////////////////////////Create Lights
Light *light;
mSceneMgr->setAmbientLight( ColourValue( .2, .2, .2)); //everything is slightly illuminated
//create basic point light, no direction required. - so can see objects
light = mSceneMgr->createLight( "Light1" );
light->setType( Light::LT_POINT );
light->setPosition( Vector3(0, 150, 250) );
////////////////////////End creating lights
//Create Skybox
mSceneMgr->setSkyBox( true, "Examples/MorningSkyBox" );
/////////////////////////Create ocean
Ogre::Plane oceanSurface;
oceanSurface.normal = Ogre::Vector3::UNIT_Y;
oceanSurface.d = 20;
Ogre::MeshManager::getSingleton().createPlane("OceanSurface",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
oceanSurface,
10000, 10000, 50, 50, true, 1, 1, 1, Ogre::Vector3::UNIT_Z);
Entity* mOceanSurfaceEnt = mSceneMgr->createEntity( "OceanSurface", "OceanSurface" );
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(mOceanSurfaceEnt);
mOceanSurfaceEnt->setMaterialName("Ocean2_HLSL_GLSL");
////////////////////////End making ocean
////////////////////////Create sub and ships, and setup positions
Sub submarine( "Sub", "submarine5.mesh", mSceneMgr, 100, 35, 20 );
Ship ship1( "Ship", "battle_ship2.mesh", mSceneMgr, 100, 45, 30 );
//set position of ship
ship1.setPosition( 0, -30, -1000 );
//pass the scene manager as a parameter to the submarine's constructor,
//and create the scene node and entity yourself
//-destroy both in destructor
//create 'facade' methods, methods in submarine that call
//the methodso of scenenode that are required
}
void destroyScene(void){} // Optional to override this
void createViewports(void)
{
// Create one viewport, entire window
Viewport* vp = mWindow->addViewport(mCamera);
vp->setBackgroundColour(ColourValue(0,0,0));
// Alter the camera aspect ratio to match the viewport
mCamera->setAspectRatio(
Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
}
/// Method which will define the source of resources (other than current folder)
void setupResources(void)
{
// Load resource paths from config file
ConfigFile cf;
cf.load("resources.cfg");
// Go through all sections & settings in the file
ConfigFile::SectionIterator seci = cf.getSectionIterator();
String secName, typeName, archName;
while (seci.hasMoreElements())
{
secName = seci.peekNextKey();
ConfigFile::SettingsMultiMap *settings = seci.getNext();
ConfigFile::SettingsMultiMap::iterator i;
for (i = settings->begin(); i != settings->end(); ++i)
{
typeName = i->first;
archName = i->second;
ResourceGroupManager::getSingleton().addResourceLocation(
archName, typeName, secName);
}
}
}
/// Optional override method where you can create resource listeners (e.g. for loading screens)
void createResourceListener(void)
{
}
/// Optional override method where you can perform resource group loading
/// Must at least do ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
void loadResources(void)
{
// Initialise, parse scripts etc
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}
};
#endif //1
#if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
// Create application object
Simulator app;
try {
app.go();
} catch( Exception& e ) {
#if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
fprintf(stderr, "An exception has occured: %s\n",
e.getFullDescription().c_str());
#endif
}
return 0;
}Code: Select all
class Ship : public Watercraft
{
public:
Ship()
{
}
~Ship()
{
}
private:
But I get the error that there is no suitable default constructor.
Putting all the same parameters in as the Watercraft constructor causes the same error.
Sorry, this is probably rather noobish.
If you can help that'd be great!
Thanks!
-
Protagonist
- Goblin
- Posts: 214
- Joined: Tue Nov 21, 2006 11:11 pm
-
Kencho
- OGRE Retired Moderator

- Posts: 4011
- Joined: Fri Sep 19, 2003 6:28 pm
- Location: Burgos, Spain
- x 2
Hmmm, I think I found the problem. When you define a constructor, default constructors aren't added. So the base class doesn't have a default constructor. Okay with this? Fine
So when you define a derived class, you need to use the same constructor as the base class. And not only that: You should define your constructor in the form:
I won't bet about this as my head is a mix of P-Codes, Java, C++ and Bison at this moment
But that's probably the error.
Code: Select all
MyConstructor (params) : MyBaseClassConstructor (params) {
...
}-
Protagonist
- Goblin
- Posts: 214
- Joined: Tue Nov 21, 2006 11:11 pm
