Plastic Gem #29: Zapper Lightning
by Paul Dana · 07/19/2008 (11:15 am) · 0 comments
Download Code File

Plastic Gem # 29: Zapper Lightning
Difficulty: Intermediate
Before following this gem, you must follow the instructions in Gem #20, Gem #25 and #26, #27, and #28, which require Gem s#2, Gem #25, and optionally Gem #3 if you want ease, which you do. You might also want to follow Gem #22, Gem #23, and Gem #24 as well as these demonstrate how to use energy.
The Zapper has a lightning effect from tip of mechanical arm and it refuels you!
Hi Paul Dana from Plastic Games again. Building on the previous gems, this gem will add the final functionality to the PlasticZapper object. It will create a Lightning effect from the tip of the mechanical arm to the player and it will add energy to the player and remove energy from the Zapper itself.
1) Unzipping the files
Remember you must first follow the instructions in Gem #20, Gem #25, Gem #26, Gem #27, Gem #28, Gem #2, Gem #25 (and optionally Gem #3, Gem #22, Gem #23, Gem #24). This will give you the thread upgrade and the zapper shape itself and the first two versions of the zapper.cs script file. Next unzip the pg28_zapperMechanicalArm.zip file that comes with this gem. In there you will find a script file called zapper.cs that defines the PlasticZapper class with this gem's updates.
Copy the lightning folder in the .zip file to your ~/data/shapes folder.
2) Updating the script
Copy the zapper.cs file from this gem's zip file over the zapper.cs you created in the previous two gems. This version has all the stuff from those three versions, plus new stuff to make a lightning effect appear as well as recharge the player and drain the zapper.
3) Testing it out

Just run the mission you made in the previous gem. Use the methods described in Gem #24 on energy scripting to make your player's recharge rate zero or at least very low (like 0.01). Now use the methods described there to SET the player's energy level to zero (or if you added jetting just jet around and use up some energy). Now enter the zapper trigger zone and you should see the arm come down and shoot lightning at the player once the arm reaches the end point. You should see the Zapper power meters go down and the player should be refueled. If you did Gem #23 and added an energy bar GUI to your hud then you can more easily see your energy go up and down.
It is hard to see the effect from first person view. If you want to slow down the process so you can see it better, look in the zapper datablock and change the energy transfer rate. Find these lines:
Change both these numbers from 2.0 to 0.1. Now it will take a while for the recharge to take place giving you time to use Alt-C to move to the camera and check it out.
4) Looking at the code
In the fan example from Gem #18, I just gave you a dump of ALL the code to make the fan work without describing how it all actually worked. For the PlasticZapper object I am building up the functionality a bit at a time and try to explain a bit more what is going on as well. Let's take a look at what has changed in the code in zapper.cs.
First off I have included a bunch of code for handling Audio that is commented out. There is some right at the beginning of the file. Some future gem will cover adding sound to the zapper and will provide audio files and show how to make audio scripting code that works in both TGE and TGEA using Gem #5.
OK, so next we need a new datablock for the static shape that we use for the lightning effect:
Assuming you copied the lightning folder to the right place that should work just fine.
Next you will notice we have added an ::onRemove() method:
Why did we add this now? Because we forgot to add it last gem. This is code to cleanup the Tesla Coil effect if the Zapper object is deleted.
Next let's see how the ::onTriggerTick() method looks now:
We have uncommented the code from last gem that ensures the arm only moves when the zapper has energy and when the player needs energy, just as we promised we would. : - ) We have also added the section that actually starts lighting effect and gives energy. Note that %obj.readyToRefuel is only true once the arm finally makes it to the final position.
Next let's look to see how the ::stopRefueling() method looks now:
Notice how we have added some code to stop the lightning effect.
Finally we have the two new methods for actually doing the lightning effect:
I know I should cover these methods in more detail but it's a Friday and 11pm and I'm not thinking super clearly.
5)Other small changes
I also made some small changes while working on the code for this Gem. I removed refernces to %enterObj.insideLandingZone. That code only applied to the flying vehicle you see the example animated image at the top of this gem. I also changed some code like %obj.electrode = 0; to %obj.electrode = "". This is old code and since I wrote it I have changed the way I do things and I now clear object variables by setting them to an empty string rather than the value zero.
Next Week
That's all for this gem. I hope everyone reading this appreciates that all the gems for the past 2 weeks have lead up to this final example object. The purpose of giving such a complex example was to demonstrate the power of these gems when combined. It has certainly wiped me out writing all this, so next week I am handing the Gem-A-Day torch to Anthony Rosenbaum who will take it from here. Go Anthony!

Plastic Gem # 29: Zapper Lightning
Difficulty: Intermediate
Before following this gem, you must follow the instructions in Gem #20, Gem #25 and #26, #27, and #28, which require Gem s#2, Gem #25, and optionally Gem #3 if you want ease, which you do. You might also want to follow Gem #22, Gem #23, and Gem #24 as well as these demonstrate how to use energy.
The Zapper has a lightning effect from tip of mechanical arm and it refuels you!Hi Paul Dana from Plastic Games again. Building on the previous gems, this gem will add the final functionality to the PlasticZapper object. It will create a Lightning effect from the tip of the mechanical arm to the player and it will add energy to the player and remove energy from the Zapper itself.
1) Unzipping the files
Remember you must first follow the instructions in Gem #20, Gem #25, Gem #26, Gem #27, Gem #28, Gem #2, Gem #25 (and optionally Gem #3, Gem #22, Gem #23, Gem #24). This will give you the thread upgrade and the zapper shape itself and the first two versions of the zapper.cs script file. Next unzip the pg28_zapperMechanicalArm.zip file that comes with this gem. In there you will find a script file called zapper.cs that defines the PlasticZapper class with this gem's updates.
Copy the lightning folder in the .zip file to your ~/data/shapes folder.
2) Updating the script
Copy the zapper.cs file from this gem's zip file over the zapper.cs you created in the previous two gems. This version has all the stuff from those three versions, plus new stuff to make a lightning effect appear as well as recharge the player and drain the zapper.
3) Testing it out

Just run the mission you made in the previous gem. Use the methods described in Gem #24 on energy scripting to make your player's recharge rate zero or at least very low (like 0.01). Now use the methods described there to SET the player's energy level to zero (or if you added jetting just jet around and use up some energy). Now enter the zapper trigger zone and you should see the arm come down and shoot lightning at the player once the arm reaches the end point. You should see the Zapper power meters go down and the player should be refueled. If you did Gem #23 and added an energy bar GUI to your hud then you can more easily see your energy go up and down.
It is hard to see the effect from first person view. If you want to slow down the process so you can see it better, look in the zapper datablock and change the energy transfer rate. Find these lines:
energyDrain = 2.0; // how much energy to drain from batteries each tick peroid
energyRecharge = 2.0; // how much to add each trigger periodChange both these numbers from 2.0 to 0.1. Now it will take a while for the recharge to take place giving you time to use Alt-C to move to the camera and check it out.
4) Looking at the code
In the fan example from Gem #18, I just gave you a dump of ALL the code to make the fan work without describing how it all actually worked. For the PlasticZapper object I am building up the functionality a bit at a time and try to explain a bit more what is going on as well. Let's take a look at what has changed in the code in zapper.cs.
First off I have included a bunch of code for handling Audio that is commented out. There is some right at the beginning of the file. Some future gem will cover adding sound to the zapper and will provide audio files and show how to make audio scripting code that works in both TGE and TGEA using Gem #5.
OK, so next we need a new datablock for the static shape that we use for the lightning effect:
// this object is for the lighting effect that goes from arm tip to player...
datablock StaticShapeData(PlasticZapperLightning)
{
// Basic Item properties
shapeFile = "~/data/shapes/lightning/lightning.dts";
};Assuming you copied the lightning folder to the right place that should work just fine.
Next you will notice we have added an ::onRemove() method:
function Zapper::onRemove(%this,%obj)
{
// remove if its still there
if (%obj.electrode)
{
// future gem...
//%obj.electrode.stopAudio(0);
%obj.unmountObject(1);
%obj.electrode.delete();
%obj.electrode = "";
}
}Why did we add this now? Because we forgot to add it last gem. This is code to cleanup the Tesla Coil effect if the Zapper object is deleted.
Next let's see how the ::onTriggerTick() method looks now:
function PlasticZapper::onTriggerTick(%this, %obj, %trigger)
{
//echo("PlasticZapper::onTriggerTick()");
// get the object in side
for (%i=0; %i < %trigger.getNumObjects(); %i ++)
{
%enterObj = %trigger.getObject(%i);
// dont do squat if we are full of energy or the zapper is empty...
if (%obj.getEnergyLevel() > 0 && %enterObj.getEnergyPercent() < 1.0)
{
// if we have not done so...activate
if (!%obj.armActivated)
{
%obj.armActivated = true;
// play the activate animation and que up the rezapping
%obj.playThread(0);
%obj.setThreadDir(0,true);
%obj.activateThread = %this.schedule(2000,"activateFinished",%obj);
}
// don't do squat if we are not ready to refuel
if (%obj.readyToRefuel)
{
if (!%enterObj.lightning)
{
// for future GEM...
// start looping lightning sound
//%enterObj.playAudio(1, %this.refuelingSound);
%enterObj.lightning = true;
%this.startLightning(%obj,%enterObj);
}
// this is the code that does the one small bit of recharging...
// add energy to object...
%energy = %enterObj.getEnergyLevel();
%energy += %this.energyRecharge;
%enterObj.setEnergyLevel(%energy);
// take energy away from zapper...
%energy = %obj.getEnergyLevel();
%energy -= %this.energyDrain;
if (%energy < 0)
%energy = 0;
// set energy & power meter to match...
%this.setPower(%obj, %energy);
}
}
else
{
%this.stopRefueling(%obj,%enterObj);
}
}
}We have uncommented the code from last gem that ensures the arm only moves when the zapper has energy and when the player needs energy, just as we promised we would. : - ) We have also added the section that actually starts lighting effect and gives energy. Note that %obj.readyToRefuel is only true once the arm finally makes it to the final position.
Next let's look to see how the ::stopRefueling() method looks now:
function PlasticZapper::stopRefueling(%this,%obj,%enterObj)
{
//echo("PlasticZapper::stopRefueling()");
// if we are out of energy then turn off the electrode effect
if (%obj.getEnergyLevel() <= 0)
{
if (%obj.electrode)
{
%obj.unmountObject(1);
%obj.electrode.delete();
%obj.electrode = "";
}
}
%obj.readyToRefuel = false;
if (%enterObj.lightning)
{
%enterObj.lightning = false;
%this.stopLightning(%obj,%enterObj);
// for future GEM
//%enterObj.stopAudio(1);
}
if (%obj.armActivated)
{
if (%obj.activeThread)
cancel(%obj.activeThread);
%obj.activeThread = "";
%obj.armActivated = false;
%obj.setThreadDir(0,false);
}
}Notice how we have added some code to stop the lightning effect.
Finally we have the two new methods for actually doing the lightning effect:
//P[ PlasticZapperTweaks
$Zapper::Offset = "0 0 5.35";
//P]
function PlasticZapper::startLightning(%this, %refuelObj, %enterObj)
{
// get position of this mount point on zapper...
//%slot = 0;
//%node = %refuelObj.getMountNodeObject(%slot);
//%nodeXform = %refuelObj.getNodeTransform(%node);
//%pos = getWords(%nodeXform,0,2);
// A DIGRESSION ON FAKERY AND TWEAKING....
// to get position of tip of arm we hard code using an offset...ie we cheat horribly!
// in a later gem we might show some methods for getting locations of mount nodes
// so we can REALLY find the tip of the mechanical arm. Notice how I used a global
// variable for the offset...notice the weird comments around it's definition above.
// hey what is that stuff? Those comments are for the Plastic Tweaker - one of the
// coolest pieces of Plastic technology we have built so far. So cool that we are going
// to release it as a product. But wait! It gets even more cool. Before we release it
// as a product we are going to release a free version of it as a Gem so that my
// faithful gem-a-day fans can get a first look at this awesome tool! What is this tool
// for? Why for tweaking, what else? Knowing I was going to use a hard coded offset to
// find that point was one thing. Actually *finding* the right point was another. Once
// I setup the global it took me thirteen iterations of trying some number and then
// testing to watch the arm come down, then trying a slightly different number, etc. Using
// the PlasticTweaker I was able to do all of those thirteen iterations without leaving
// the game *and* the tweaker automatically saved the changes back into this source file.
// What a time saver! It's like money in the bank.
%zapPos = %refuelObj.getPosition();
%pos = VectorAdd(%zapPos,$Zapper::Offset);
// get position to fire lightning at
%enterPos = getBoxCenter(%enterObj.getWorldBox());
// ok get the distance from lightning start to position to fire lightning AT...
%dist = VectorDist(%pos,%enterPos);
// now get the scale factor to acheive that
// considering that the object itself is 4 units long
%scaleFactor = %dist / 4.0;
// ok so lets point this objects Z axis at the enter object point
%z = VectorSub(%pos,%enterPos);
%z = VectorNormalize(%z);
// get axis angle rotation that points Z axis here...
%rot = VectorGetRotationFromZ(%z);
%obj = new StaticShape()
{
dataBlock = PlasticZapperLightning;
position = %enterPos;
scale = "1 1 " @ %scaleFactor;
rotation = %rot;
};
if (isObject(MissionCleanup))
MissionCleanup.add(%obj);
%enterObj.lightningObj = %obj;
%obj.playThread(0,"ambient");
%obj.setThreadSpeed(0,0.333);
}
function PlasticZapper::stopLightning(%this, %refuelObj, %enterObj)
{
%slot = 4;
if (isObject(%enterObj.lightningObj))
{
%enterObj.lightningObj.delete();
%enterObj.lightningObj = "";
}
}I know I should cover these methods in more detail but it's a Friday and 11pm and I'm not thinking super clearly.
5)Other small changes
I also made some small changes while working on the code for this Gem. I removed refernces to %enterObj.insideLandingZone. That code only applied to the flying vehicle you see the example animated image at the top of this gem. I also changed some code like %obj.electrode = 0; to %obj.electrode = "". This is old code and since I wrote it I have changed the way I do things and I now clear object variables by setting them to an empty string rather than the value zero.
Next Week
That's all for this gem. I hope everyone reading this appreciates that all the gems for the past 2 weeks have lead up to this final example object. The purpose of giving such a complex example was to demonstrate the power of these gems when combined. It has certainly wiped me out writing all this, so next week I am handing the Gem-A-Day torch to Anthony Rosenbaum who will take it from here. Go Anthony!
