Mission Area ForceField for Flying Vehicles
by Louis Dufresne · 01/25/2005 (10:41 pm) · 2 comments
First thing you want to do is implement Leslie "Xyber" Young's resource. It works like a charm and easy to integrate. You can find it here.
Once that is done make sure it compiles fine and works. Then we need to work in the engine first. In vehicle.h inside of class Vehicle: public ShapeBase, add
Next we must go into vehicle.cc and let it know what a mission area is. Add
Then find Vehicle::Vehicle(). Go to the very end of that function and add
Last thing in code is to add the functions themselves. I went to the bottom of the page and just added them there. Basically they are a simple copy and past of Leslie's functions except they need to be scoped for the Vehicle. Here they are anyways:
and for the ghost check:
Do a build from here and make sure all is correct. Now all there is to do is add this to the script.
I personally went with the Drone in flyervehicle.cs. In here I added 3 functions. Drone::onEnterMissionArea, Drone::onLeaveMissionArea, and Drone::onLeaveMissionAreaViaRoof. I just went to the bottom of the script and added them there like this:
You can of course add that to the car, buggy or sky hawk or your custom model.
Last thing to do is add the forcefield to mission file. If you did this already with Leslie's resource then you are done if not this is what you could add:
A few things to think about here. First inside vehicle.cc where the calls are being made to checkMissionArea and checkGhostMissionArea, they are done right after checkCollisions is called. However I noticed this is inside an if statement checking for isServerObject. I do not know if this only updates the server or if this is the right spot. It works for me but I only have single player mode.
Also inside the script when onLeaveMissionArea and onLeaveMissionAreaViaRoof are called, you can play around with the math there. I dont know if it was the best way to execute this but it works. Feel free to modify this in any way that suits your needs or your expertise. Keep me updated if you find better, easier or more cpu efficient ways. Enjoy!
Once that is done make sure it compiles fine and works. Then we need to work in the engine first. In vehicle.h inside of class Vehicle: public ShapeBase, add
bool mInMissionArea;somewhere in the protected area. I added mine right above bool onNewDataBlock(GameBaseData* dptr); Also inside protected we need to add
void checkMissionArea(); void checkGhostMissionArea();I did this right above public:
Next we must go into vehicle.cc and let it know what a mission area is. Add
#include "game/missionArea.h"to the include statements at the top.
Then find Vehicle::Vehicle(). Go to the very end of that function and add
mInMissionArea = true;Scroll way down and find void Vehicle::updatePos(F32 dt) Inside this function we need to check the mission areas much like is done with the player in Leslie's resource. Go to the if(isServerObject) check and find notifyCollision(); Right under that add
checkMissionArea(); checkGhostMissionArea();
Last thing in code is to add the functions themselves. I went to the bottom of the page and just added them there. Basically they are a simple copy and past of Leslie's functions except they need to be scoped for the Vehicle. Here they are anyways:
void Vehicle::checkMissionArea()
{
// Checks to see if the player is in the Mission Area...
Point3F pos;
MissionArea * obj = dynamic_cast<MissionArea*>(Sim::findObject("MissionArea"));
const RectI &area = obj->getArea();
getTransform().getColumn(3, &pos);
// leslie - mission area - roof collision - start
F32 height;
height = obj->getFlightCeiling();
if (pos.z >= height) {
if(mInMissionArea) {
MissionArea::smWasHit = 1; // leslie : this will alow flash on server too
mInMissionArea = false;
Con::executef(mDataBlock,3,"onLeaveMissionAreaViaRoof",scriptThis());
}
} else
// leslie - end
if ((pos.x < area.point.x || pos.x > area.point.x + area.extent.x ||
pos.y < area.point.y || pos.y > area.point.y + area.extent.y)) {
if(mInMissionArea) {
MissionArea::smWasHit = 1; // leslie : this will allow flash on server too
mInMissionArea = false;
Con::executef(mDataBlock,3,"onLeaveMissionArea",scriptThis());
}
}
else if(!mInMissionArea)
{
mInMissionArea = true;
Con::executef(mDataBlock,3,"onEnterMissionArea",scriptThis());
}
}and for the ghost check:
//----------------------------------------------------------------------------
// leslie - mission area check - start
void Vehicle::checkGhostMissionArea()
{
// - this is to make this client make a flash on it's own mission bounds
// - aa, this is soo cool, it also seems to be updating on other clients
// - and the server when a client hits the border
// - LESLIE : NOTE : if it seems not to be working it might be a timimg
// - problem, cause it does work if a player left te mission area.
// Checks to see if the player is in the Mission Area...
Point3F pos;
F32 height;
const RectI &area = MissionArea::smMissionArea;
getTransform().getColumn(3, &pos);
height = MissionArea::smFlightCeiling;
if (pos.z >= height) {
MissionArea::smWasHit = 1;
}
if ((pos.x < area.point.x || pos.x > area.point.x + area.extent.x ||
pos.y < area.point.y || pos.y > area.point.y + area.extent.y)) {
MissionArea::smWasHit = 1;
}
}
// leslie - end
//----------------------------------------------------------------------------Do a build from here and make sure all is correct. Now all there is to do is add this to the script.
I personally went with the Drone in flyervehicle.cs. In here I added 3 functions. Drone::onEnterMissionArea, Drone::onLeaveMissionArea, and Drone::onLeaveMissionAreaViaRoof. I just went to the bottom of the script and added them there like this:
function Drone::onEnterMissionArea(%this, %obj)
{
// Inform the client
%obj.client.enEnterMissionArea();
}
function Drone::onLeaveMissionArea(%this, %obj)
{
%obj.client.onLeaveMissionArea();
%force = MissionArea.bounce;
%min_x = getWord(MissionArea.area, 0);
%min_y = getWord(MissionArea.area, 1);
%max_x = %min_x + getWord(MissionArea.area, 2);
%max_y = %min_y + getWord(MissionArea.area, 3);
%x = getWord(%obj.getPosition(), 0);
%y = getWord(%obj.getPosition(), 1);
%vx = 0;%vy = 0;%vz = 0;
if (%x<(%min_x+10)) %vx = %force;
if (%y<(%min_y+10)) %vy = %force;
if (%x>(%max_x-10)) %vx = -%force;
if (%y>(%max_y-10)) %vy = -%force;
%vec = %vx @ " " @ %vy @ " " @ %vz;
%vec = VectorScale(VectorNormalize(%vec), 2000);
%pos = %obj.getPosition();
%obj.applyImpulse(%pos, %vec);
}
function Drone::onLeaveMissionAreaViaRoof(%this, %obj)
{
%obj.client.onLeaveMissionArea();
%force = MissionArea.bounce;
%min_x = getWord(MissionArea.area, 0);
%min_y = getWord(MissionArea.area, 1);
%max_x = %min_x + getWord(MissionArea.area, 2);
%max_y = %min_y + getWord(MissionArea.area, 3);
%x = getWord(%obj.getPosition(), 0);
%y = getWord(%obj.getPosition(), 1);
%vx = 0;%vy = 0;%vz = 0;
if (%x<(%min_x+10)) %vx = %force;
if (%y<(%min_y+10)) %vy = %force;
if (%x>(%max_x-10)) %vx = -%force;
if (%y>(%max_y-10)) %vy = -%force;
%vec = %vx @ " " @ %vy @ " " @ %vz;
%vec = VectorScale(VectorNormalize(%vec), 2000);
%pos = %obj.getPosition();
%obj.applyImpulse(%pos, %vec);
}You can of course add that to the car, buggy or sky hawk or your custom model.
Last thing to do is add the forcefield to mission file. If you did this already with Leslie's resource then you are done if not this is what you could add:
new MissionArea(MissionArea)
{
Area = "-1020 -1020 2040 2040";
flightCeiling = "600";
flightCeilingRange = "200";
shakeFactor = "0.3";
normalTexture = "~/data/yourtextures/border0";
hitTexture = "~/data/yourtextures/hit";
boucne = "50";
locked = "true";
};A few things to think about here. First inside vehicle.cc where the calls are being made to checkMissionArea and checkGhostMissionArea, they are done right after checkCollisions is called. However I noticed this is inside an if statement checking for isServerObject. I do not know if this only updates the server or if this is the right spot. It works for me but I only have single player mode.
Also inside the script when onLeaveMissionArea and onLeaveMissionAreaViaRoof are called, you can play around with the math there. I dont know if it was the best way to execute this but it works. Feel free to modify this in any way that suits your needs or your expertise. Keep me updated if you find better, easier or more cpu efficient ways. Enjoy!
#2
I know that if checkGhostMissionArea() is before the else, then it will only show up on the server side and never show on the client. (for the player class and tank class)
putting in the else and then adding the checkGhostMissionArea(), then whenever any player hits the mission wall the flash shows on all players' screens.
I'm not sure if isServerObject() and !isGhost() referring to the same thing. I'm assuming it is.
So you'd probably want to put the checkGhostmissionArea() after the else in the vehicle class
Then I THINK it will show on clients as well. I haven't tested this as I don't have "vehicles" in my project.
02/10/2005 (10:24 pm)
I've implemented this in the tank pack class from Bravetree, and like the playerclass in the updatepos function its doingif(!isGhost())
{
<do stuff>
notifycollision();
checkMissionArea();
}else
checkGhostMissionArea();I know that if checkGhostMissionArea() is before the else, then it will only show up on the server side and never show on the client. (for the player class and tank class)
putting in the else and then adding the checkGhostMissionArea(), then whenever any player hits the mission wall the flash shows on all players' screens.
I'm not sure if isServerObject() and !isGhost() referring to the same thing. I'm assuming it is.
So you'd probably want to put the checkGhostmissionArea() after the else in the vehicle class
}
else {
checkGhostMissionArea();
// Play impact sounds on the client.
if (collided) {
F32 collSpeed = (mRigid.linVelocity - origVelocity).len();
<etc.. etc..>Then I THINK it will show on clients as well. I haven't tested this as I don't have "vehicles" in my project.

Torque Owner Leslie Young
I had some problems with showing the "glow" effect when you hit the field apearing on the other clients, think I just left it like that. Might be that I forgot to do some checking somewhere, or perhaps I got it to work? Geesh, been a while, I can't really recall how I did all this.