Adding a BeamNode

From IrrWizard

Jump to: navigation, search

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

beam01.jpg

Personal tools