Adding a BeamNode
From IrrWizard
This article will show you how to add cdbarrett's Beam SceneNode. The original post can be found on the Irrlicht forum [here]
Code
// Just a simple wrapper :D
struct IrrQuad {
video::S3DVertex verts[4];
};
class CBeamNode : public scene::ISceneNode {
private:
// The beam material.
video::SMaterial material;
// Start/End Points
core::vector3df vStart;
core::vector3df vEnd;
// Bounding Box
core::aabbox3d<f32> Box;
// Size of the beam
float flScale;
// Beam color
video::SColor beamColor;
void DrawQuad( IrrQuad& quad ) {
u16 indices[] = { 0,2,3, 2,1,3, 1,0,3, 2,0,1 };
video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setMaterial(material);
driver->drawIndexedTriangleList( &quad.verts[0], 4, &indices[0], 4 );
}
// Thanks to whoever wrote this little function :)
core::vector3df getTargetAngle( core::vector3df v, core::vector3df r) {
//v -current node position
//r -target node position
core::vector3df angle;
float x,y,z;
x = r.X - v.X;
y = r.Y - v.Y;
z = r.Z - v.Z;
//angle in X-Z plane
angle.Y = atan2 (x, z);
angle.Y *= (180 / 3.14); //converting from rad to degrees
//just making sure angle is somewhere between 0-360 degrees
if(angle.Y < 0) angle.Y += 360;
if(angle.Y >= 360) angle.Y -= 360;
//angle in Y-Z plane while Z and X axes are already rotated around Y
float z1 = sqrt(x*x + z*z);
angle.X = atan2 (z1, y);
angle.X *= (180 / 3.14); //converting from rad to degrees
angle.X -= 90;
//just making sure angle is somewhere between 0-360 degrees
if(angle.X < 0) angle.X += 360;
if(angle.X >= 360) angle.X -= 360;
return angle;
}
public:
CBeamNode( scene::ISceneNode* parent,
scene::ISceneManager *mgr, s32 id, char* szBeam ) : scene::ISceneNode( parent, mgr, id ) {
// Setup the beam material
material.Wireframe = false;
material.Lighting = false;
material.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
material.Texture1 = mgr->getVideoDriver( )->getTexture( szBeam );
// Default to 32 units for the scale
flScale = 32.0;
// Default to white
beamColor.set( 255, 255, 255, 255 );
}
virtual void OnPreRender( ) {
if( IsVisible ) {
SceneManager->registerNodeForRendering( this );
}
}
virtual void render( ) {
SceneManager->getVideoDriver()->
setTransform(irr::video::ETS_WORLD, AbsoluteTransformation);
// Figure out quads based on start/end points.
core::matrix4 m;
m.setRotationDegrees( getTargetAngle( vStart, vEnd ) );
core::vector3df vUp( 0, 1, 0 );
core::vector3df vRight( -1, 0, 0 );
m.transformVect( vRight );
m.transformVect( vUp );
// Draw the first cross
IrrQuad beam;
beam.verts[0] = video::S3DVertex( vStart + vUp * flScale,
core::vector3df( 1, 1, 0 ), beamColor, core::vector2df( 0, 1 ) );
beam.verts[1] = video::S3DVertex( vStart + vUp * -flScale,
core::vector3df( 1, 0, 0 ), beamColor, core::vector2df( 1, 1 ) );
beam.verts[2] = video::S3DVertex( vEnd + vUp * -flScale,
core::vector3df( 0, 1, 1 ), beamColor, core::vector2df( 1, 0 ) );
beam.verts[3] = video::S3DVertex( vEnd + vUp * flScale,
core::vector3df( 0, 0, 1 ), beamColor, core::vector2df( 0, 0 ) );
DrawQuad( beam );
// Draw the second cross.
beam.verts[0] = video::S3DVertex( vStart + vRight * flScale,
core::vector3df( 1, 1, 0 ), beamColor, core::vector2df( 0, 1 ) );
beam.verts[1] = video::S3DVertex( vStart + vRight * -flScale,
core::vector3df( 1, 0, 0 ), beamColor, core::vector2df( 1, 1 ) );
beam.verts[2] = video::S3DVertex( vEnd + vRight * -flScale,
core::vector3df( 0, 1, 1 ), beamColor, core::vector2df( 1, 0 ) );
beam.verts[3] = video::S3DVertex( vEnd + vRight * flScale,
core::vector3df( 0, 0, 1 ), beamColor, core::vector2df( 0, 0 ) );
DrawQuad( beam );
}
virtual const core::aabbox3d<f32>& getBoundingBox() const {
return Box;
}
virtual s32 getMaterialCount() {
return 1;
}
virtual video::SMaterial& getMaterial(s32 i) {
return material;
}
void SetStartPoint( core::vector3df pos ) {
vStart = pos;
}
void SetEndPoint( core::vector3df pos ) {
vEnd = pos;
}
void SetBeamScale( float size ) {
flScale = size;
}
void SetBeamColor( video::SColor color ) {
beamColor = color;
}
};
Copy and paste the code above into a file and call it BeamNode.h
Dont worry too much about the content of the code, as all that needs to be done is including it in the GamePlayState.cpp or CGameStateLevelxx.cpp.
If the BeamNode is required for any or all game levels, then the CGamePlayState header file is the best place to put it as it's common to all GamePlayStates.
Implemenation
Place BeamNode.h in the 'Game' folder and add it to the project. Then add the following code to the CGamePlayState header file.
GamePlayState.h:
... #include "BeamNode.h"
Now add the following code to the Init() function of the game level, in this case game level 01.
GameLevelState01.cpp:
//! Initialisation, loads data required for level
void CGameLevelState01::Init(CGameManager* pManager)
{
...
CBeamNode* beam = new CBeamNode( pManager->getSceneManager()->getRootSceneNode( ), pManager->getSceneManager(), 200, "caleb.pcx" );
beam->SetStartPoint( core::vector3df( -500, 200, 0 ) );
beam->SetEndPoint( core::vector3df( 500, 0, 50 ) );
beam->SetBeamColor( video::SColor( 255, 0, 255, 0 ) );
...
}
The 'caleb.pcx' image file has been used just because it already exists in the IrrWizard distribution, other images can be used to produce a
narrower laser sight type beam. Compile and run
