Game Development Community

dev|Pro Game Development Curriculum

afxWeaponLight

by Gibby · 01/23/2014 (7:51 am) · 9 comments

Greets all, in response to Brian M's post here's my weapon light/sight effectron;

Create a new file, lights.cs or something to that effect, in your datablocks folder and be sure to add it to datablockExec.cs

//****************************************************************
// Gibby's Uber-Duper Weapon sight/Light script...
//****************************************************************

datablock afxXM_MountedImageNodeData(Weapon_MuzzlePoint_XM)
{
   imageSlot = 0;
   nodeName = "muzzlepoint";
};

datablock afxXM_MountedImageNodeData(Weapon_Light0_XM)
{
   imageSlot = 0;
   nodeName = "light0";
};

datablock afxXM_MountedImageNodeData(Weapon_Light1_XM)
{
   imageSlot = 0;
   nodeName = "light1";
};

datablock afxT3DSpotLightData(Weapon_WeaponLight_CE)
{
  range = 40;
  color = "1.0 1.0 1.0";
  cookie = "art/gui/light.png";
  flareType = "LightFlareExample1";  
  brightness = 3.0;
  castShadows = false;
  localRenderViz = false;
};

datablock afxT3DSpotLightData(Weapon_WeaponSight_CE)
{
   range = "50"; 
   
   innerAngle = 0;
   outerAngle = 1;
   
   brightness = "10";
   
   color = "1 0 0 1"; // red?
   
   cookie = "art/gui/laser.png"; // Basic Lighting will not render this.

   // Lens Flare will need a good mount and will need the mountOffset of the Flashlight 
   // to be modified for your specific application.
   flareType = "LightFlareExample2";
   castShadows = false;
   localRenderViz = false;
};

datablock afxEffectWrapperData(Weapon_MuzzleLight_EW)
{
  effect = Weapon_WeaponLight_CE; // some effect to mount
  constraint = "caster";
  xfmModifiers[0] = Weapon_MuzzlePoint_XM;
};

datablock afxEffectWrapperData(Weapon_WeaponLight_EW)
{
  effect = Weapon_WeaponLight_CE; // some effect to mount
  constraint = "caster";
  xfmModifiers[0] = Weapon_Light0_XM;
};

datablock afxEffectWrapperData(Weapon_MuzzleSight_EW)
{
  effect = Weapon_WeaponSight_CE; // some effect to mount
  constraint = "caster";
  xfmModifiers[0] = Weapon_MuzzlePoint_XM;
};

datablock afxEffectWrapperData(Weapon_WeaponSight_EW)
{
  effect = Weapon_WeaponSight_CE; // some effect to mount
  constraint = "caster";
  xfmModifiers[0] = Weapon_Light1_XM;
};

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
//  Muzzle Spotlight EFFECTRON
//
datablock afxEffectronData(Weapon_MuzzleLight_Effectron)
{
  echoPacketUsage = 20;
  duration = -1;
  numLoops = 1;
  execOnNewClients = true;
  
    // mine zodiacs //
  addEffect = Weapon_MuzzleLight_EW;

};

datablock afxEffectronData(Weapon_WeaponLight_Effectron)
{
  echoPacketUsage = 20;
  duration = -1;
  numLoops = 1;
  execOnNewClients = true;
  
    // mine zodiacs //
  addEffect = Weapon_WeaponLight_EW;

};

datablock afxEffectronData(Weapon_WeaponSight_Effectron)
{
  echoPacketUsage = 20;
  duration = -1;
  numLoops = 1;
  execOnNewClients = true;
  
    // mine zodiacs //
  addEffect = Weapon_WeaponSight_EW;

};

Now in server/player.cs add this to the bottom of the file:

//----------------------------------------------------------------------------
// Enable/Disable Player Weapon Lights
//----------------------------------------------------------------------------
function Player::MuzzleLightEnable(%this)
{      
   // delete existing lights
   if(isObject(%this.light))
      %this.light.interrupt();
   
   echo("Player::MuzzleLightEnable -> CALLED BY: "@%this);
   
      // spotlight
   %effectron = new afxEffectron() 
   {
      datablock = Weapon_MuzzleLight_Effectron;
   };
   
   %effectron.addConstraint(%this, "caster");
   %this.light = %effectron;
}

function Player::MuzzleLightDisable(%this)
{
      // delete lights
      if(isObject(%this.light))
         %this.light.interrupt();
}

function Player::WeaponLightEnable(%this)
{      
   // delete existing lights
   if(isObject(%this.light))
      %this.light.interrupt();
   
   echo("Player::WeaponLightEnable -> CALLED BY: "@%this);
   
      // spotlight
   %effectron = new afxEffectron() 
   {
      datablock = Weapon_WeaponLight_Effectron;
   };
   
   %effectron.addConstraint(%this, "caster");
   %this.light = %effectron;
}

function Player::WeaponLightDisable(%this)
{
      // delete lights
      if(isObject(%this.light))
         %this.light.interrupt();
}


function Player::WeaponSightEnable(%this)
{
   // delete existing lights
   if(isObject(%this.light))
      %this.light.interrupt();
      
   
   echo("Player::WeaponSightEnable -> CALLED BY: "@%this);
   
      // spotSight
   %effectron = new afxEffectron() 
   {
      datablock = Weapon_WeaponSight_Effectron;
   };
   
   %effectron.addConstraint(%this, "caster");
   %this.light = %effectron;
}

function Player::WeaponSightDisable(%this)
{
      // delete lights
      if(isObject(%this.light))
         %this.light.interrupt();
}

Next, in server/commands

//------------------------------------------------------------------------------
// Light Controls
//------------------------------------------------------------------------------

function serverCmdEnableMuzzleLight(%client)
{
   %player = %client.player;
   
   echo("serverCmdEnableMuzzleLight( -> CALLED BY: "@%client@" player: "@%player);
   %player.MuzzleLightEnable();
}

function serverCmdDisableMuzzleLight(%client)
{
   %player = %client.player;
   %player.MuzzleLightDisable();
}


function serverCmdEnableWeaponLight(%client)
{
   %player = %client.player;
   
   echo("serverCmdEnableWeaponLight( -> CALLED BY: "@%client@" player: "@%player);
   %player.WeaponLightEnable();
}

function serverCmdDisableWeaponLight(%client)
{
   %player = %client.player;
   %player.WeaponLightDisable();
}
function serverCmdEnableWeaponSight(%client)
{
   %player = %client.player;
   
   echo("serverCmdEnableWeaponSight( -> CALLED BY: "@%client@" player: "@%player);
   %player.WeaponSightEnable();
}

function serverCmdDisableWeaponSight(%client)
{
   %player = %client.player;
   %player.WeaponSightDisable();
}

finally, depending on whether you're using the Full template or afxDemo, change client/default.bind.cs or client/afx/default.bind_AFX.cs:

$MuzzleLightVar = "1";
function toggleMuzzleLight(%val)
{
   if (%val)
   {
      if($MuzzleLightVar)
      {
         $MuzzleLightVar = "0";
         commandToServer('EnableMuzzleLight');
      }
      else
      {
         $MuzzleLightVar = "1";
         commandToServer('DisableMuzzleLight'); 
      }
   }
}

$WeaponLightVar = "1";
function toggleWeaponLight(%val)
{
   if (%val)
   {
      if($WeaponLightVar)
      {
         $WeaponLightVar = "0";
         commandToServer('EnableWeaponLight');
      }
      else
      {
         $WeaponLightVar = "1";
         commandToServer('DisableWeaponLight'); 
      }
   }
}

$WeaponSightVar = "1";
function toggleWeaponSight(%val)
{
   if (%val)
   {
      if($WeaponSightVar)
      {
         $WeaponSightVar = "0";
         commandToServer('EnableWeaponSight');
      }
      else
      {
         $WeaponSightVar = "1";
         commandToServer('DisableWeaponSight'); 
      }
   }
}

moveMap.bind( keyboard, "alt f", toggleMuzzleLight );
moveMap.bind( keyboard, "l", toggleWeaponLight );
moveMap.bind( keyboard, "alt l", toggleWeaponSight );

Note:

I rig my weapons with extra nodes light0 and light1. You'll need to do the same or use shape editor to add them. I then setup constraints for each node using afxXM_MountedImageNodeData, then a light using afxT3DSpotLightData. These are then enclosed within the corresponding afxEffectWrapperData and afxEffectronData. The scripts then simply launch/delete the effectron as needed.

Disfruten!

#1
01/23/2014 (8:08 am)
Additional notes:

I setup a default in my game where the sight/light uses the muzzlepoint in case it wasn't rigged for nodes for the lights.

Note that the laser sight is a bit off from the crosshair. I'm using this in a TPS so I've not dealt with the math to fix this issue, if anyone resolves it please share...
#2
01/23/2014 (10:34 am)
Confirmed as working great in AFX 2.0 with T3D MIT 3.0

Thanks so much, this is perfect!

Renders great in the Oculus Rift too, we're going to use the laser sight as a sort of selection cursor for selectable objects in the world... Can't use a normal 2D mouse cursor with the Rift so have to come up with creative solutions for user input :)

Will work on fine tuning the laser sight and post any solutions we find.

Cheers
#3
01/23/2014 (3:27 pm)
Great to see a possible solution for you Brian :)
#4
01/23/2014 (9:36 pm)
@Brian: I found this resource useful:

"TGEA - Select objects with FPS HUD with Arcane FX"

http://www.garagegames.com/community/resources/view/18183

I seem to recall it working with T3D 3.0 without any issues...
#5
01/27/2014 (7:31 am)
@Gibby: Thanks for that, never seen that one before...

Does exactly what we figured out already, but in a different way - we just piggybacked off the Awesomium raycast, checking for selectable objects at the same time as we check for Awesomium web shapes.

If a player is looking at a selectable object, then in the background it sets that as the AFX preselected object. Then when you right-click, it actions whatever object has been preselected.

If you are not using the Oculus Rift, then the AFX highlighting works when looking at an object, as well as when you mouse over it in standard AFX gui mode. When using the Rift, we disable the AFX highlight because it does not stereo render correctly.

So, in this case we are already there... But for anyone who doesn't have Awesomium integrated, that solution would certainly achieve the same result, good find!
#6
01/27/2014 (7:38 am)
Oh, and FYI, here is a quick and dirty hack to get the laser pointer to match the center of the crosshair.

All we did was open our weapons in the shape editor, and move the light-mount nodes up and to the left, until they line up with the player's eye.

Makes for a dead-on accurate laser sight, that when using the Rift can pinpoint even the tiniest of clickable buttons even if there are several close together. Then right-click on what the laser is pointing at and it performs the selection just as if you'd clicked with the mouse in non-Rift mode.

Not sure if this is portable code or not, may be specific to our weapons, but these co-ordinates worked on all of our weapons to get the laser sight centered in the crosshair.

In art/shapes/weapons/Phaser (substitute your weapon folder name), there is a .cs file corresponding to the weapon shape, in our case this is Phaser.cs... Here are the contents after adding and moving the light nodes:

singleton TSShapeConstructor(PhaserDts)
{
baseShape = "./Phaser.dts";
};

function PhaserDts::onLoad(%this)
{
%this.setNodeTransform("light0", "-0.452485 0.617027 0.500264 1 0 0 0", "1");
%this.addNode("light1", "", "-0.452485 0.617027 0.500264 1 0 0 0", "1");
}

Moving existing nodes in the Shape editor does not alter the original model, and in fact the original model does not even need the extra node points on it, they will be added on the fly with this script.

Anyhow, give it a shot if you like, see if it works for you.

Cheers
#7
01/27/2014 (8:53 am)
@Brian:

I think you can also implement the offset with afx - I'll try this and post the result...
#8
01/27/2014 (8:42 pm)
Thank you for posting this, very helpful to me for even unrelated areas.
#9
02/18/2014 (9:54 am)
awesome,good post~~