Game Development Community

BraveTree Tank Port to T3D

by John "Mythic" Henry · in Torque 3D Professional · 05/21/2011 (6:11 am) · 34 replies

Okay to start with, This is not the Complete Port instructions to T3D.
I figured I'd pass on somethings I ran into when I took a different way
on the port to T3D of this Add-On..

I originally started along the same lines as this post:
www.garagegames.com/community/resources/view/17217/1#comment-175349

But as you can see in my posts, I decided to try it a different way.
I went along the lines that the following is true:
A tank is nothing more then a Wheeled vehicle...

So I created a new class [ treadvehicle ]
based off of the [wheeledvehicle] and adapted it to the following:
Multiple wheels beyond [8]
Wheels did not do the steering directly
Changed to [Left/Right] keys for turning
Adjust Wheel speeds on the side to turn towards (Slow down the turn side)
Multiple mount points (Passengers/Weapons]

As I LOVE inheritance, this meant I could setup some Basic functions
that ALL vehicles would have and could then do tests like isMemberofClass(Vehicle)
and know I would get all my vehicle types :)

It works so far, Can move forward/backwards turn left/right AND fire the main turret.
I split the Turret/Gun from the shape and mounted the whole thing as a weaponImage.
This is where I ran into an issue...

Vehicle class deals with the trigger[x] in a simple way,
Trigger[0] activates the Image in Slot[0] (mountpoint[0])..
NOT GOOD..

For consistency we need the same thing across the board.
Basic Vehicle system was assuming Driver Slot [0]
And was dismounting Player.weaponslot[0] on driver being put in vehicle.slot[0]
So what was there for the Vehicle class to Trigger?? Nada.

(This is all simplified info remember, not the actual code, heres some of the actual code)

vehicle.cpp
void Vehicle::updateMove(const Move* move)
{
   PROFILE_SCOPE( Vehicle_UpdateMove );

   mDelta.move = *move;

   // Image Triggers
   if (mDamageState == Enabled) {
      setImageTriggerState(0,move->trigger[0]);
      setImageTriggerState(1,move->trigger[1]);
   }

   // Throttle
   if(!mDisableMove)
      mThrottle = move->y;
......

Script code : ../scripts/server/vehicle.cs
function VehicleData::setMountVehicle(%this, %vehicle, %player)
{
   //echo("c4VehicleData::setMountVehicle("@ %this.getName() @", "@ %vehicle @", "@ %player.client.nameBase @")");

   if (isObject(%vehicle) && %vehicle.getDamageState() !$= "Destroyed")
   {
      %node = %this.findEmptySeat(%vehicle, %player);
      if (%node >= 0)
      {
         //echo("c4Mount Node: "@ %node);
         %vehicle.mountObject(%player, %node);
         //%player.playAudio(0, MountVehicleSound);
         %player.mVehicle = %vehicle;
      }
   }
}

Very simple system, but just doesn't work out of the box if the Vehicle has weapons
as well as Driver/Passengers.

So for any vehicle type with weapons as well as passengers we have to overide the
XXX::updateMove(...)
and deal with our weapons...
But to do this you need to track what slot the weapons are mounted in.
There are alot of more complex issues and ideas to deal with as well, but for
simplicity, just create a few datablock vars that can be set for any vehicle.

example:
[a Datablock for a vehicle]
....
   numMountPoints       = 2;        //Actually 5 but 3 are for Parts/Guns 
   mountPose[0]         = sitting;
   mountPose[1]         = sitting;
   wheelCount           = 12;       //2Front / 2Rear / 4*2 Inner
   
   //Lets Make it easier to deal with Multiple weapon types
   numWeaponPoints      = 2;
   startWepMountPoint   = 2;
...

Then you have to add them to the vehicle class you've created like so...
void TreadVehicleData::initPersistFields()
{
   ...
   ... 
	//Due to Vehicle Checking and Setting Slots 0/1 as the default
	//We have to Know what slots to set for Weapons
	//	mNumMountPoints = Driver/Passenger1/Pass..x (How many passengers including Driver
	//	mNumWeaponPoints = Main/Sec(x) How many weapon mount points
	//	mStartWepMountPoint = Main/Sec(x) Starting Slot for weapons mounted
   addField("numMountPoints", TypeS32, Offset(mNumMountPoints, TreadVehicleData),
      "Driver/Passengers [Driver Node/Slot == 0], How many seats?" );
	addField("numWeaponPoints", TypeS32, Offset(mNumWeaponPoints, TreadVehicleData),
      "How many weapons mountpoints?" );
   addField("startWepMountPoint", TypeS32, Offset(mStartWepMountPoint, TreadVehicleData),
      "starting slot (Node) for first weapon mounted." );
   ...
   ...

That is only part of adding it, you have to do the full monty and add those in just
like the variable engineTorque, etc...

Then when do an ::updateMove(...)
void TreadVehicle::updateMove(const Move* move)
{
	//Mythic DEBUG
	//	For Treaded Vehicles we have to take over the movement to Steer by 
	//	Adjusting the Speed of one set of wheels or the other
   Parent::updateMove(move);

   // Trigger images
   if (mDamageState == Enabled) 
   {
		//	Drivers / Passenger			-- mNumMountPoints
		//	Number of possible weapons -- mNumWeaponPoints
		//	First Node for weapons		-- mStartWepMountPoint);
		//
		//	This is going to be a bit tricky...
		//	Do we just leave it as [2] Triggers?
		//	Or do we get fancy? Such as Changing Which one
		// is our current Main Weapon?
		// For the moment Keep it simple
		//
		//	Have to be carefull here...
		//	Anything can be mounted, so we should do a check that it is a Weapon
		//

		// Do we have any Weapons??
		if( mDataBlock->mNumWeaponPoints > 0 )
		{
			bool altTriggerFired = false;
			S32 triggerNum = 0;
			S32 start = mDataBlock->mStartWepMountPoint;
			S32 end = start + mDataBlock->mNumWeaponPoints;
			for( S32 mWeap=start; mWeap<end; mWeap++)
			{
				//	If Weapon is mounted Activate Trigger Sequence YEAH!!
				//	VERY SIMPLE, First Image Mounted is Sent Trigger[0]
				//	If other weapons, they Get trigger[1]
				//	Or Else trigger[1] goes to Main as well
				//
				if ( getMountedImage( mWeap ) )
				{
					setImageTriggerState( mWeap, move->trigger[triggerNum] );
					triggerNum = 1;
				}
			}
			// Here we Send trigger[1] to Main Weapon
			// This ALSO allows us to Just fire on the AltTrigger interestingly
			if(!altTriggerFired)
			{
				if ( getMountedImage( start ) )
					setImageTriggerState( start, move->trigger[triggerNum] );
			}
		}
...
...

This last bit was the final tie into the ShapeBaseImage so we could now
get Fire/Recoil/ShellCasings all now function Whoopiee!!

Next parts to do...

Fire the 2 machineguns on the front (Dealing with Sherman tank at moment)
Plan to fire these as one adjusting the aim so they point together.

Connect the Turret/Gun to mouse movement so we get a rotating turret and elevating gun.

As I explained in the posts I did previously (see link above)
I hope to be able to Adjust the animation of the Tread materials on the fly
according to speed / direction of tank and turning.

More to come..

By the way, the reason the Wheels function correctly with this setup is due to the following:
I modified the Original shape and removed the Turret / wheels
I then created 2 wheels, Idler / Inner
I also created a new skeleton with hubs for each wheel
I havent done the springs yet, but wont be hard to do now.
This is also where I modified the Mountpoints for Driver/weapons

The Treads are not included in the Body Collision shape, (same in original), so the
tires ignore the Treads and collide with the ground, thus getting traction. When I
do the springs, I'll connect the tread shapes to those and will be able to get some
tread deformation with the springs during movement.

**EDIT**
Successfully completed... I used the following resource to solve Rotation/Elevation..
www.garagegames.com/community/blogs/view/17759
I slightly modified it to allow me to use the mCameraRot so it should work networked.
That is for a bit later testing. Still some fine tuning needed...
Page «Previous 1 2
#1
05/21/2011 (6:21 am)
This needs alot more fine tuning. Those DataBlock Vars should be
in Vehicle.cpp so ALL types inherting from it have the ability
to define weapon points.
#2
05/21/2011 (6:30 am)
For the Steering at the moment I deal with it during the processTick()
void TreadVehicle::processTick(const Move* move)
{
   Parent::processTick(move);

	//Mythic DEBUG
	// We catch the Changes to the treads here
   //Point3F leftTread0;
   //Point3F rightTread0;
   //if (isClientObject())
      //markTreads(leftTread0,rightTread0,getTransform());

	//	Heres the tougher one... 
	//	We have to let the Parent process first so it can fill
	//	[move] with the Delta or Null it
	//
	//	SOOooo we use the Left and Right Keys to Steer so we
	//	Can control the Turret with the Mouse
   // Steering
	if(move != NULL) 
	{
		mSteerControl = 0;
		if( move->x != 0.0 )
			mSteerControl = ( move->x > 0.0 ) ? 1 : -1;
	}
}

Not the most efficient way, but it works at the moment.
This all needs more testing with it networked later.

The mSteerControl was added so I could leave the yaw/pitch
alone and use for moving the turret itself.

.... (cont)
#3
05/21/2011 (6:32 am)
(cont)...

Then using that [mSteerControl] here:
void TreadVehicle::updateForces(F32 dt)
{
   PROFILE_SCOPE( TreadVehicle_UpdateForces );

   extendWheels();

   F32 aMomentum = mMass / mDataBlock->wheelCount;

   // Get the current matrix and extact vectors
   MatrixF currMatrix;
   mRigid.getTransform(&currMatrix);

   Point3F bx,by,bz;
   currMatrix.getColumn(0,&bx);
   currMatrix.getColumn(1,&by);
   currMatrix.getColumn(2,&bz);

   // Steering angles from current steering wheel position
   F32 quadraticSteering = -(mSteering.x * mFabs(mSteering.x));
   F32 cosSteering,sinSteering;
   mSinCos(quadraticSteering, sinSteering, cosSteering);

   // Calculate Engine and brake torque values used later by in
   // wheel calculations.
   F32 engineTorque,brakeVel;

	//Mythic DEBUG
	// Attempt to Manage Steering by Reducing Wheel Speed
	//	Simple adjustment of Speed for the moment
	//	Left == mSteering.x == -1 / Right == mSteering.x == 1
	//
   F32 engineTorqueLeft,engineTorqueRight,brakeVelLeft,brakeVelRight;

   if (mBraking) 
   {
      brakeVel = (mDataBlock->brakeTorque / aMomentum) * dt;
      engineTorque = engineTorqueLeft = engineTorqueRight = 0;
		if( mSteerControl == 0 )
		{
			brakeVelLeft = brakeVelRight = brakeVel;
		}
		else
		{
			brakeVelLeft  = (mSteerControl == -1) ? brakeVel : (brakeVel * 0.25);
			brakeVelRight = (mSteerControl == 1)  ? brakeVel : (brakeVel * 0.25);
		}
   }
   else 
   {
      if (mThrottle) 
      {
         engineTorque = mDataBlock->engineTorque * mThrottle;
         brakeVel = 0;
         // Double the engineTorque to help out the jets
         if (mThrottle > 0 && mJetting)
            engineTorque *= 2;

			brakeVelLeft = brakeVelRight = brakeVel;
			if( mSteerControl == 0 )
			{
				engineTorqueLeft = engineTorqueRight = engineTorque;
			}
			else
			{
				engineTorqueLeft  = (mSteerControl == -1) ? (engineTorque * 0.25) : engineTorque;
				engineTorqueRight = (mSteerControl == 1)  ? (engineTorque * 0.25) : engineTorque;
			}
		}
      else 
      {
         // Engine brake.
         brakeVel = (mDataBlock->engineBrake / aMomentum) * dt;
			engineTorque = engineTorqueLeft = engineTorqueRight = 0;
			if( mSteerControl == 0 )
			{
				brakeVelLeft = brakeVelRight = brakeVel;
			}
			else
			{
				brakeVelLeft  = (mSteerControl == -1) ? brakeVel : (brakeVel * 0.25);
				brakeVelRight = (mSteerControl == 1)  ? brakeVel : (brakeVel * 0.25);
			}
      }
   }
...

....(cont)
#4
05/21/2011 (6:34 am)
(cont)...

//Mythic DEBUG
		// Change to Torque / Brakeing to do Left Right turns
		//	Instead of Tire Deformations :)
		if( mSteerControl == 0 )
			wheel->avel += (((wheel->torqueScale * engineTorque) - Fy * wheel->tire->radius) / aMomentum) * dt;
		else	//Turn Baby
		{
			//Track Speed Modifications
			F32 tempTorque = engineTorqueLeft;
			for(int i=0; i<mDataBlock->wheelCount; i++)
			{
				if(wheel == &mWheel[i])
				{
					tempTorque = (i<6) ? engineTorqueRight : engineTorqueLeft;
					wheel->avel += (((wheel->torqueScale * tempTorque) - Fy * wheel->tire->radius) / aMomentum) * dt;
				}
			}
		}
      // Adjust the wheel's angular velocity based on brake torque.
      // This is done after avel update to make sure we come to a
      // complete stop.
		if (brakeVel > mFabs(wheel->avel))
			wheel->avel = 0;
		else
		{
			if( mSteerControl == 0 )
			{
				if (wheel->avel > 0)
					wheel->avel -= brakeVel;
				else
					wheel->avel += brakeVel;
			}
			else	//Turn Baby
			{
				//Track Speed Modifications
				F32 tempBrake = brakeVelLeft;
				for(int i=0; i<mDataBlock->wheelCount; i++)
				{
					if(wheel == &mWheel[i])
					{
						tempBrake = (i<6) ? brakeVelLeft : brakeVelRight;
						if (wheel->avel > 0)
							wheel->avel -= tempBrake;
						else
							wheel->avel += tempBrake;
					}
				}
			}
		}
   }

   // Jet Force
   if (mJetting)
....

Its not very pretty, but it works... The Wheels do NOT add any
direction to the Turn as Steering is Turned OFF on all wheels.
#5
05/29/2011 (11:41 am)
After alot more work I've run into a snag with Animating the Mounted Turret.
Before I discuss the issue, I'll bring ya up to speed with what
I've done so far...

The current state of it is as follows:
-------------------------------------------
TankVehicle Class (Based of WheeledVehicle)
Wheels are Instantiated during onAdd with Steering off

Steering uses the move->x value clamped to -1/+1 slowing down
the one set of wheels (Works like a champ).

A few things were moved into Vehicle.cpp :
VehicleData::
-----------------
//Mythic DEBUG -->
	mNumMountPoints = 0;
	mNumWeaponPoints = 0;
	mStartWepMountPoint = 0;
	for( S32 i = 0; i<MaxTriggerKeys; i++)
		mMountTrigger[i] = -1;
	//Mythic DEBUG <--
--------------------------
These were added to Base [datablock xxxVehicleData(xxx)]
so we could reuse code for other vehicles later..

mNumMountPoints --> Number of Mount Points (Players)
mNumWeaponPoints --> Number of Weapon Points
mStartWepMountPoint --> Starting Mountpoint for weapons

(This allows us to Mount Players up to that mount point)
Example:

TankVehicle: 2 Players, 3 weapons
---------------------------------
mNumMountPoints = 2;

startWepMountPoint = 2; // First MountPoint for weapons (Turret)
numWeaponPoints = 3; // 3 weapons Turret / MiniGun / MiniGun
mountTrigger[0] = 0; //Trigger[0] assigned to this weapon
mountTrigger[1] = 1; //Trigger[1] assigned to this weapon
mountTrigger[2] = 1; //Trigger[1] assigned to this weapon

------------------------------
The mountTrigger[x] system takes over when the Fire system activates
and sends the trigger signal to the correct weapon Image.

The primary reason I'm trying to do it this way is to use the current
system of weapon Images that works so well.

Everything is working fine even in multi-player at the moment except
for turning/elevating the turret/barrel.

I have tried a few things:
1: Turret Shape (Dts) has 3 sequences (fire/rotate/elevate)
2: Firing sequence / image system works well, ejects shells/flash
3: turret / barrel Nodes for manually rotating as alternative

So i first tried it this way:
=============================

TreadVehicle.cpp
TreadVehicleData::TreadVehicleData()
{
   tireEmitter				= 0;
....
....
	mTurretMount			= -1;
	sRotateSeq				= "";
	sBarrelSeq				= "";
}

mTurretMount == the specific Mount Point for Turret (Temp setup)
sRotateSeq / sBarrelSeq are in the Datablock for easy changing
These get sent in the pack/unpackData()

I'm using a single Rotation Variable for testing (mRot) in TreadVehicle
TreadVehicle::TreadVehicle()
{
...
...
   mRot.zero();
}

I only use the mRot.x / mRot.z for testing this out as thats
all we care about to get it rotating/elevating.

Now we have a small issue here with trying to use Animation Threads...
When the Tank is Added it doesn't have a Turret. I tried a setup
where the TurretImage Datablock was in stored in the TreadVehicle
Datablock and then loaded during the onAdd() call. This worked
the same with it Mounted afterwards from script, so I dropped that
for the moment.
(continued)....
#6
05/29/2011 (11:43 am)
To get the Threads / Sequences sorted out during load up I created
the following:

In Script:
function TreadVehicleData::onAdd(%this, %obj)
{   
   Parent::onAdd(%this, %obj);

   //Modified by Tank Type
   //We need to Add the Front/Inner/Rear tire types
   //As we have a Left/Right side of even wheels :)
   %countTot = %obj.getDataBlock().wheelCount;
   %countSide = %countTot / 2;
   //Right Side
   for(%i=0; %i<=%countSide-1; %i++)
   {
      %tire       = (%i==0 || %i==%countSide-1) ?  TankFrontTire   : TankInnerTire;
      %spring     = (%i==0 || %i==%countSide-1) ?  OuterTankSpring : InnerTankSpring;
      
      %obj.setWheelTire(%i, %tire);
      %obj.setWheelSpring(%i, %spring);
      %obj.setWheelPowered(%i, true);
      %obj.setWheelSteering(%i, false);
   }
   //Left Side
....
....   
   //Now we mount the Turrent w/Gun
   %obj.mountImage(TurrentGunImage, 2);
   %obj.setInventory(TankPrimaryTurret, 1);
   %obj.setInventory(TankPrimaryTurretAmmo, 1000);
   %obj.mountable = true;
   %obj.onTurretMounted();
}

in TreadVehicle.cpp
//--------------------------------------------------------------
//	Turret System Controls
//--------------------------------------------------------------
void TreadVehicle::onTurretMounted()
{
	//Checking things here
	Con::printf("TreadVehicle::onTurretMounted() ... [ %s ]", isServerObject()?"ServerCall":"ClientCall");

	//Here goes..
	TSShape* turretShape = getMountedImage(mDataBlock->mTurretMount)->shape;
	if( turretShape != NULL )
	{
		//Checking things here
		Con::printf("Valid (turretShape) ...");

		mRotateSequence = turretShape->findSequence(mDataBlock->sRotateSeq);
		mElevateSequence = turretShape->findSequence(mDataBlock->sBarrelSeq);
	}
	if( mRotateSequence && mElevateSequence )
	{
		//Checking things here
		Con::printf("Valid (mRotateSequence) && (mElevateSequence) ...");

		TSShapeInstance* turretInst = getImageShapeInstance(mDataBlock->mTurretMount);
		if( turretInst != NULL )
		{
			//Checking things here
			Con::printf("Valid (turretInst) ...");

			mRotateThread = turretInst->addThread();
			turretInst->setSequence(mRotateThread,mRotateSequence,0);
			turretInst->setTimeScale(mRotateThread, 1.0);
			turretInst->setBlendEnabled(mRotateThread, true);

			mElevateThread = turretInst->addThread();
			turretInst->setSequence(mElevateThread,mElevateSequence,0);
			turretInst->setTimeScale(mElevateThread, 1.0);
			turretInst->setBlendEnabled(mElevateThread, true);
		}
	}
}
//----------------------------------------------
DefineEngineMethod( TreadVehicle, onTurretMounted, void, ( ),,
   "Activate the mounted Turret.")
{
	object->onTurretMounted();
}
//----------------------------------------------

(continued)......
#7
05/29/2011 (11:50 am)
This works just fine. Its mounts the Turret and it stays with Vehicle.
It fires (uses the Fire Sequence)
It decrements Ammo (Which gets displayed on screen)
It ejects a shell / Creates a Flash etc...
No Probems there...

For the firing sequence to work we did the following:

Turret DataBlocks:
//-----------------------------------------------------
// Ammo Item
datablock ItemData(TankPrimaryTurretAmmo)
{
   category             = "Ammo";
   className            = "Ammo";
   shapeFile            = "art/shapes/vehicles/Sherman/tankshell.dts";
   mass                 = 1;
   elasticity           = 0.2;
   friction             = 0.6;
	pickUpName           = "tank primary ammo";
   maxInventory         = 1000;
};
//-----------------------------------------------------
// Weapon Item.
datablock ItemData(TankPrimaryTurret)
{
   category             = "Weapon";
   className            = "Weapon";
   shapeFile            = "art/shapes/vehicles/Sherman/sherman_top.dts";
   mass                 = 1;
   elasticity           = 0.2;
   friction             = 0.6;
   emap                 = true;

	pickUpName           = "primary tank weapon";
	image                = TurrentGunImage;
	maxInventory         = 1;

   // weaponHUD
   previewImage         = 'turret.png';
   reticle              = '';
   zoomReticle          = '';
   itemType             = "tklauncher";
	trayIcon             = "tklauncher01.png";
};

(continued)....
#8
05/29/2011 (11:53 am)
Main Image:

//-----------------------------------------------------
datablock ShapeBaseImageData(TurrentGunImage)
{
   className            = "WeaponImage";
   shapefile            = "art/shapes/vehicles/Sherman/sherman_top.dts";
   emap                 = true;
   // Specify mount point & offset for 3rd person, and eye offset
   // for first person rendering.
   mountPoint           = 2;
   //offset             = "0.0 0.15 0.025";
   eyeOffset            = "0.25 0.6 -0.4"; // 0.25=right/left 0.5=forward/backward, -0.5=up/down

   // When firing from a point offset from the eye, muzzle correction
   // will adjust the muzzle vector to point to the eye LOS point.
   correctMuzzleVector  = true;
   MeleeWeapon          = false;

	// Crosshair
   maxSpread            = 6.0;
   minSpread            = 4.0;

   // Projectile && Ammo.
   Item                 = TankPrimaryTurret;
   ammo                 = TankPrimaryTurretAmmo;
   projectile           = TankPrimaryProjectile;
   projectileType       = Projectile;

   // shell casings
   casing               = TankShellCasing;
   shellExitDir         = "0.5 0.1 0.3";
   shellExitOffset      = "0.25 0.2 0.1";
   shellExitVariance    = 10.0;
   shellVelocity        = 8.0;
   
   // Let there be light - NoLight, ConstantLight, PulsingLight, WeaponFireLight.
   lightType            = "WeaponFireLight";
   lightColor           = "1.0 1.0 0.9";
   lightDuration        = 200;
   lightRadius          = 10;
   // Images have a state system which controls how the animations
   // are run, which sounds are played, script callbacks, etc. This
   // state system is downloaded to the client so that clients can
   // predict state changes and animate accordingly. The following
   // system supports basic ready->fire->reload transitions as
   // well as a no-ammo->dryfire idle state.

   // Initial start up state
   stateName[0]                     = "Preactivate";
   stateTransitionOnLoaded[0]       = "Activate";
   stateTransitionOnNoAmmo[0]       = "NoAmmo";
   
   // Activating the gun.
   // Called when the weapon is first mounted and there is ammo.
   stateName[1]                     = "Activate";
   stateTransitionOnTimeout[1]      = "Ready";
   stateTimeoutValue[1]             = 0.6;
   stateSequence[1]                 = "Activate";

   // Ready to fire, just waiting for the trigger
   stateName[2]                     = "Ready";
   stateTransitionOnNoAmmo[2]       = "NoAmmo";
   stateTransitionOnTriggerDown[2]  = "Fire";
   stateSequence[2]                 = "Ready";
   // Fire the weapon. Calls the fire script which does the actual work.
   stateName[3]                     = "Fire";
   stateTransitionOnTimeout[3]      = "PostFire";
   stateTimeoutValue[3]             = 1.9;
   stateFire[3]                     = true;
   stateRecoil[3]                   = LightRecoil;
   stateAllowImageChange[3]         = false;
   stateSequence[3]                 = "Fire";
   stateScript[3]                   = "onFire";
   stateSound[3]                    = TankPrimaryFireSound;
   stateEmitterNode[3]              = TankSmokeEmitterNodeData;
   stateEmitter[3]                  = TankFireSmokeEmitter;
   stateEmitterTime[3]              = 0.9;
....
....

(continued)....
#9
05/29/2011 (11:55 am)
To get it to actually Fire correctly with the Builtin ImageSystem
I modified Vehicle.cpp this way:

void Vehicle::updateMove(const Move* move)
{
   PROFILE_SCOPE( Vehicle_UpdateMove );

   mDelta.move = *move;

	//Mythic DEBUG -->
   // Image Triggers
//   if (mDamageState == Enabled) {
//      setImageTriggerState(0,move->trigger[0]);
//      setImageTriggerState(1,move->trigger[1]);
//   }
   // Trigger images
   if (mDamageState == Enabled) 
	{
		//
		//	Drivers / Passenger			 -- mNumMountPoints
		//	Number of possible weapons  -- mNumWeaponPoints
		//	First Node for weapons		 -- mStartWepMountPoint);
		// Trigger to Mount Assignment -- mMountTrigger[x]
		//	Defaults to [-1] to Skip it example: mountTrigger[x] = -1;
		// Thus we can assign ANY of the [19] Triggers to Any Mount point
		//
		// (Not So tricky now) (ADDED mMountTrigger[x])
		//
		//	Have to be carefull here...
		//	Anything can be mounted, so we should do a check that it is a Weapon
		//

		// Do we have any Weapons??
		if( mDataBlock->mNumWeaponPoints > 0 )
		{
			//	With Trigger Assignment We loop thru the Triggers :)
			//
			S32 start = mDataBlock->mStartWepMountPoint;
			for( S32 trigAssign=0; trigAssign<MaxTriggerKeys; trigAssign++)
			{
				//	If Weapon is mounted Activate Trigger Sequence YEAH!!
				// Very Simple system, if ImageSlot[ mMountTrigger[x]]
				//	Image Mounted is Sent trigger[ x ]
				//
				if( mDataBlock->mMountTrigger[trigAssign] >=0 )
				{
					S32 mWeap = start + mDataBlock->mMountTrigger[trigAssign];
					if ( getMountedImage( mWeap ) )
						setImageTriggerState( mWeap, move->trigger[trigAssign] );
				}
			}
		}

		// Throttle
		if(!mDisableMove)
			mThrottle = move->y;
...
...

Which solved it quite nicely and is flexible as well..
#10
05/29/2011 (12:05 pm)
Now for the Final Problem, you should be able to follow the above
to where we now have to Change the Animation on the Turret to
allow the player to control it (Aim the Turret)...

So we have a Player
Controlling a Vehicle (TreadVehicle Class)
With a Weapon Image Mounted as well..

Tank with the following Mounted:
Mount0 = Player
Mount1 = empty (Passenger)
Mount2 = Turret (WeaponImage)
Mount3 / Mount4 (Currently empty)

So we catch the Update Move either in ::ProcessTick()
or ::updateMove()
It works the same in both (meaning it hasnt worked at all lol).
by doing the following...

TreadVehicle.cpp
void TreadVehicle::updateMove(const Move* move)
{
	//Mythic DEBUG
	//	For Treaded Vehicles we have to take over the movement to
	//	Adjust the Speed to Steer of one set of wheels or the other
   Parent::updateMove(move);

   // Trigger images
   if( mDamageState == Enabled ) //&& getControllingObject() != NULL )
   {
		//Checking things here
		//Con::printf("TreadVehicle::updateMove() ... [ %s ]", isServerObject()?"ServerCall":"ClientCall");

		// Brake on trigger
		mBraking = move->trigger[2];
		// Set the tail brake light thread direction based on the brake state.
		if (mTailLightThread)
			mShapeInstance->setTimeScale(mTailLightThread, mBraking? 1.0f : -1.0f);

		//	Can control the Turret with the Mouse
		// Steering
		if(move != NULL) 
		{
			//Checking things here
			//Con::printf("Active Move ... ");

			mSteerControl = 0;
			if( move->x != 0.0 )
				mSteerControl = ( move->x > 0.0 ) ? 1 : -1;

			// get Turret values
			mRot.x += (move->yaw / M_PI_F);
			mRot.z += (move->pitch / M_PI_F);
			mRot.x = mClampF(mRot.x,-1.0f,1.0f);
			mRot.z = mClampF(mRot.z,-1.0f,1.0f);

			updateTurretAnimation();
			setMaskBits(MoveMask);
		}
	}
}

The mSteerControl is a basically a duplicate for testing as we
dont use the full range of move->x, we leave mSteering alone and
use this for the Tank Tread turning... Works fine this way.

We catch the yaw/pitch changes and store in mRot and added a flag
(MoveMask) that causes the changes to be networked...

the updateTurretAnimation() is where I have tried many different things
to get the Turret to move..

(continued)...

#11
05/29/2011 (12:08 pm)
And here are some of the things I have Tried to get that Dang Turret
to Move..

//-----------------------------------------------------
void TreadVehicle::updateTurretAnimation()
{
	//Checking things here
	//Con::printf("TreadVehicle::updateTurretAnimation() ... [ %s ]", isServerObject()?"ServerCall":"ClientCall");

	//Turret / Weapon Movement
	//---------------------------------
	//	Attempt 1
	//--------------------------------
/*
	TSShape* turretShape = getImageShapeInstance(mDataBlock->mTurretMount)->getShape();
	if( turretShape != NULL )
	{
		TSShapeInstance* turretInst = getImageShapeInstance(mDataBlock->mTurretMount);
		if( turretInst != NULL )
		{

			S32 node = turretShape->findNode("turret");
			MatrixF * mat = &turretInst->mNodeTransforms[node];
			Point3F defaultPos = turretShape->defaultTranslations[node];
			mat->set(EulerF(mRot.x,0,0));
			mat->setColumn(3,defaultPos);
		}
	}
*/
	//--------------------------------
	//	Attempt 2
	//--------------------------------
	TSShapeInstance* turretInst = getImageShapeInstance(mDataBlock->mTurretMount);
	if( turretInst != NULL )
	{
		if( mRotateThread )
		{
			U8 posTurret = (mRot.x > 0 )? U8(mRot.x / 0.04) + 25 : U8(abs(mRot.x / 0.04));
			turretInst->setPos(mRotateThread, posTurret);
			turretInst->setDirty(TSShapeInstance::TransformDirty);
			turretInst->animate();
		}
		if( mElevateThread )
		{
			U8 posBarrel = (mRot.z > 0 )? U8(mRot.z / 0.1) + 10 : U8(abs(mRot.z / 0.1));
			turretInst->setPos(mElevateThread, posBarrel);
			turretInst->setDirty(TSShapeInstance::TransformDirty);
			turretInst->animate();
		}
	}
/*
	//--------------------------------
	//	Attempt 3
	//--------------------------------
	TSShapeInstance* turretInst = getImageShapeInstance(mDataBlock->mTurretMount);
	if( turretInst != NULL )
	{
		//Checking things here
		Con::printf("Valid (turretInst) ... ");

		TSShape* turretShape = turretInst->getShape();
		if( turretShape != NULL )
		{
			//Checking things here
			Con::printf("Valid (turretShape) ... ");

			// set turret... [Use Root]
			S32 node = turretShape->findNode("turret");
			MatrixF * mat = &turretInst->mNodeTransforms[node];
			Point3F defaultPos = turretShape->defaultTranslations[node];
			mat->set(EulerF(0,0,mRot.z));
			mat->setColumn(3,defaultPos);

			// set weapon... [Use turretpivot]
			node = turretShape->findNode("barrel");
			mat = &turretInst->mNodeTransforms[node];
			defaultPos = turretShape->defaultTranslations[node];
			mat->set(EulerF(mRot.x,0,0));
			mat->setColumn(3,defaultPos);
		}
	}
*/
	//mShapeInstance->setDirty(TSShapeInstance::TransformDirty);
	//mShapeInstance->animate();

   //setMaskBits(ImageMaskN << mDataBlock->mTurretMount);
}

TO no avail at any point.. I know I must be missing something
simple here, but I have banged my head against this for too long.
Time I asked for help :)
#12
05/29/2011 (12:17 pm)
(3) sequences ( fire / rotate / elevate)
----------------------------------------
Bones:
ejectPoint / mountPoint (these arent connected to root)
Root -> turret -> barrel -> muzzle -> muzzlePoint
----------------------------------------

The Sequences are timed so I should be able to just set it to a
specific point in the thread that roughly matches the angle of
mRot.x, Not the most accurate, but good enough for testing.

The Rotate sequence is 50 frames, 25 on one side (180)
The Elevate is 20 frames, going from lowest to Highest point,
frame 1 lowest, frame 10 center, highest elevation 20.

I've checked these in the Editor and they have come through from
MS3D just fine and all work except for actually in game :(

Altho the (fire) sequence works just fine.

So any questions I'll be happy to answer, but Help would be
greatly appreciated...
#13
05/29/2011 (1:59 pm)
Alrite, I think I have found part of the problem...

void ShapeBase::setImage(  U32 imageSlot, 
                           ShapeBaseImageData* imageData, 
...
...
   // The server needs the shape loaded for muzzle mount nodes
   // but it doesn't need to run any of the animations.
   image.ambientThread = 0;
   image.animThread = 0;
   image.flashThread = 0;
   image.spinThread = 0;
   if (isGhost()) {
      if (image.dataBlock->isAnimated) {
         image.animThread = image.shapeInstance->addThread();
         image.shapeInstance->setTimeScale(image.animThread,0);
      }
...
..

Something I hadnt understood before...
The basic shapeinstance with a mounted object checks the base shape
for sequences when you try to add threads (Which is why I had been
accessing the MountedImage shapeinstance instead), and for mounted
WeaponImages it takes over the animation and doesnt properly work with
adding threads???

One possible solution would be to add another 1-2 animation threads
to weaponImages?

Or perhaps I just need to tie it into the camera somehow?
Im lost and need a short break...

#14
06/11/2011 (7:53 am)
Solved...
As I added to the Main Section at top, using that Camera resource
I was then able to use the following to Rotate/Elevate, basically
used parts of the original code but matched it to use with the
Vehicle Class:

//----------------------------------------------
void TankVehicle::updateAnimation(bool muzzleOnly)
{
	S32 node;
	MatrixF * mat;
	Point3F defaultPos;
	Point3F tCameraRot = getCameraRotation();

   // set Turret...
   node = mDataBlock->mTurretNode;
   mat = &mShapeInstance->mNodeTransforms[node];
   defaultPos = mDataBlock->mShape->defaultTranslations[node];
   mat->set(EulerF(0,0,tCameraRot.z));
   mat->setColumn(3,defaultPos);

	// set Barrel...
   node = mDataBlock->mWeaponNode;
   mat = &mShapeInstance->mNodeTransforms[node];
   defaultPos = mDataBlock->mShape->defaultTranslations[node];
   mat->set(EulerF(tCameraRot.x,0,0));
   mat->setColumn(3,defaultPos);

   if( isGhost() )
   {
      if( muzzleOnly )
      {
         // tank suspension...
         node = mDataBlock->mSuspensionNode;
         mat = &mShapeInstance->mNodeTransforms[node];
         defaultPos = mDataBlock->mShape->defaultTranslations[node];
         mat->identity();
         mat->setColumn(3,defaultPos);
      }
      else
      {
         // wheel suspension...
			for (S32 i = 0; i < mDataBlock->tankWheelCount; i++) 
			{
				if( mTankWheel[i].data->treadNode != -1 )
				{
					node = mTankWheel[i].data->treadNode;
					mat = &mShapeInstance->mNodeTransforms[node];
					defaultPos = mDataBlock->mShape->defaultTranslations[node];
					defaultPos.z -= mTankWheel[i].spring->length * mTankWheel[i].extension;
					mat->identity();
					mat->setColumn(3,defaultPos);
				}
         }

			// tank suspension...
/*         node = mDataBlock->mSuspensionNode;
         mat = &mShapeInstance->mNodeTransforms[node];
         defaultPos = mDataBlock->mShape->defaultTranslations[node];
         defaultPos.z -= mTankSpringPos.z;

         Point3F z = mTankSpringPos;
         z.z=1.0f;
         z.normalize();
         Point3F x,y;
         mCross(Point3F(0,1,0),z,&x);
         x.normalize();
         mCross(z,x,&y);

         mat->setColumn(0,x);
         mat->setColumn(1,y);
         mat->setColumn(2,z);
         mat->setColumn(3,defaultPos);
*/
      }
   }
   mShapeInstance->setDirty(TSShapeInstance::TransformDirty);
   mShapeInstance->animate();
}
This gives me a properly rotating Turret and Elevating
Barrel.
Interestingly I ran into what is either an Issue with my MS3D
versions or I dont know what, but I had switch which ones
I used for Pitch/Yaw as they weren't working the way I expected,
seemed like they were reversed.
I'll post some of the changes to Vehicle Class as well..
#15
06/11/2011 (7:59 am)
I still need to finish the Recoil system and add in a Fire Animation.
At the moment the Treads now stick to the bottom of the wheels (Inner),
it was the easiest way to go in the above code.
As it works just like the other vehicles, it uses a Rigid Body
that is handled by the wheels/vehicle parent so collides nicely.

//----------------------------------------------------------------------------
void Vehicle::updateMove(const Move* move)
{
   PROFILE_SCOPE( Vehicle_UpdateMove );

   mDelta.move = *move;

   // Mythic DEBUG -->
	//	New Weapon System
   if (mDamageState == Enabled) 
	{
		//
		//	Drivers / Passenger			 -- mNumMountPoints
		//	Number of possible weapons  -- mNumWeaponPoints
		//	First Node for weapons		 -- mStartWepMountPoint);
		// Trigger to Mount Assignment -- mMountTrigger[x]
		//	Defaults to [-1] to Skip it
		// Thus we can assign ANY of the [19] Triggers to Any Mount point
		//	Have to be carefull here...
		//	Anything can be mounted, so we should do a check that it is a Weapon
		//
		//	If Weapon is mounted Activate Trigger Sequence YEAH!!
		// Very Simple system, if ImageSlot[ mMountTrigger[x]]
		//	Image Mounted is Sent trigger[ x ]
		// We also ONLY activate on a WeaponImage, So mounted Item
		//	MUST be a WeaponImage Class Type! 
		// Reduce Calls / Reduce CPU cycles / Speed up Game
		//
		// Do we have any Weapons??
		if( mDataBlock->mNumWeaponPoints > 0 )
		{
			S32 start = mDataBlock->mStartWepMountPoint;
			for( S32 trigAssign=0; trigAssign<MaxTriggerKeys; trigAssign++)
			{
				S32 setTrigger = mDataBlock->mMountTrigger[trigAssign];
				if( setTrigger >=0 )
				{
					S32 mWeap = start + trigAssign;
					ShapeBaseImageData* tempWeapon = getMountedImage( mWeap );
					if ( tempWeapon != NULL ) // &&
						//( (SimObject*)tempWeapon->getClassRep()->isClass( AbstractClassRep::findClassRep("WeaponImage"))) )
						setImageTriggerState( mWeap, move->trigger[setTrigger] );
				}
			}
		}
	}
   // Mythic DEBUG <--

   // Throttle
   if(!mDisableMove)
      mThrottle = move->y;

   // Steering Mythic DEBUG -->
   if (move != &NullMove) 
	{
		//	DataBlock Control of the Turn/Rotate/Elevate speed limiters
		//	So Vehicles can behave differently
		// Have to reset mSteeringLR as move->x is only : -1 / 0 / 1
		//

		//	[ <- | -> ] steering system [keys A-S ] -->
		if( move->x != 0.0f )
		{
			F32 lr = (move->x * M_PI_F/mDataBlock->mMaxTurnSpeed); //move->x is the A/D keys!
			mSteeringLR = mClampF(mSteeringLR + lr,-mDataBlock->maxSteeringAngle, mDataBlock->maxSteeringAngle);
		}
		else
			mSteeringLR = 0.0f;
		//	[ <- | -> ] steering system [keys A-S ] <--

		//	Flying/HoverCraft steering -->
		F32 y = move->yaw;
		mSteering.x = mClampF(mSteering.x + y,-mDataBlock->maxSteeringAngle,
 							  mDataBlock->maxSteeringAngle);
      F32 p = move->pitch;
      mSteering.y = mClampF(mSteering.y + p,-mDataBlock->maxSteeringAngle,
                            mDataBlock->maxSteeringAngle);
		//	Flying/HoverCraft steering <--

		//	Camera/Vehicle Rotation/Elevation -->
		//	Pitch [Up-Down]
		mDelta.cameraRotVec = mCameraRot;
		p = (p * M_PI_F/mDataBlock->mMaxPitchSpeed);
		if (p > M_PI_F)
			p -= M_2PI_F;
		if (mDataBlock->freeCamPitch)
			mCameraRot.x = mClampF(mCameraRot.x + p, -M_PI_F, M_PI_F);
		else
			mCameraRot.x = mClampF(mCameraRot.x + p, mDataBlock->minCamPitchAngle, mDataBlock->maxCamPitchAngle); //constrain to datablock values
		//	Yaw [Left-Right]  
		y = (y * M_PI_F/mDataBlock->mMaxYawSpeed);
		if (y > M_PI_F)
			y -= M_2PI_F;
		if (mDataBlock->freeCamYaw)
			mCameraRot.z = mClampF(mCameraRot.z + y, -M_PI_F, M_PI_F);
		else
			mCameraRot.z = mClampF(mCameraRot.z + y, mDataBlock->minCamYawAngle, mDataBlock->maxCamYawAngle); //constrain to datablock values
		mDelta.cameraRot = mCameraRot;
		mDelta.cameraRotVec -= mCameraRot;   
		//	Camera/Vehicle Rotation/Elevation <--
	}
   // Steering Mythic DEBUG <--
   else 
	{
      mSteering.x = 0;
      mSteering.y = 0;
		mSteeringLR = 0.0f;
   }

   // Jetting flag
   if (move->trigger[3]) {
      if (!mJetting && getEnergyLevel() >= mDataBlock->minJetEnergy)
         mJetting = true;
      if (mJetting) {
         F32 newEnergy = getEnergyLevel() - mDataBlock->jetEnergyDrain;
         if (newEnergy < 0) {
            newEnergy = 0;
            mJetting = false;
         }
         setEnergyLevel(newEnergy);
      }
   }
   else
      mJetting = false;
}

This is still a rough working code, but it's doing the job so far.
I still have to look at the code that checks the Image is a weapon image.
That little bit is commented out until I get back to it.
#16
06/11/2011 (8:03 am)
It turned out fairly simple once I figured out the issue with the
turret/barrel system. To try and make it a bit more flexible
I added a bit to Vehicle Datablocks so I could stick with one
Call for onAdd()... (Alot of these Vars are now in all Vehicles)

Heres one of the DataBlocks:
//    Sherman Tank
//-----------------------------------------------------------------------
datablock TankVehicleData(ShermanTank)
{
   category = "Tanks";
   shapeFile = "art/shapes/vehicles/sherman/sherman_hull.dts";
   emap = 1;

   totalMountPoints     = 4;        //Dynamic ALL MountPounts script use only
   numMountPoints       = 1;        
   pilotNode            = 0;
   mountPose[0]         = sitting;

   // All Vehicles can Declare these for Weapon Mounting
   startWepMountPoint   = 1;  
   numWeaponPoints      = 3;
   mountTrigger[0]      = 0;     //Trigger[0] assigned to MountPoint[ startWepMountPoint + mountTrigger[0] ]
   mountTrigger[1]      = 1;     //Trigger[1] assigned to MountPoint[ startWepMountPoint + mountTrigger[1] ]
   mountTrigger[2]      = 1;     //Trigger[1] assigned to MountPoint[ startWepMountPoint + mountTrigger[2] ]

   //Wheels
   numInnerWheelsPerSide = 6;    // in addition to the 2 outer wheels per side
   tankWheelCount        = 16;   // 2Front / 2Rear / numInnerWheelsPerSide * 2

   useEyePoint          = true;  // Use the vehicle's camera node rather than the player's

   shadowEnable         = true; 
   shadowSize           = 256;
   shadowProjectionDistance = 14.0;

	freeCamPitch         = false;	// true = ignore values and rotate 360 degrees.
	minCamPitchAngle     = -1.0;  // Lowest angle (radians) the player can look
	maxCamPitchAngle     =  0.4;  // Highest angle (radians) the player can look

	freeCamYaw           = false;	// true = ignore values and rotate 360 degrees.			
	minCamYawAngle       = -2.0;  // Left turn (radians) the player can look
	maxCamYawAngle       =  2.0;  // Right turn (radians) the player can look

	maxTurnSpeed         = 10.0;  // degrees/second 
   maxPitchSpeed			= 20.0;		   
   maxYawSpeed				= 20.0;
   		   
   maxSteeringAngle     = 0.585; // Maximum steering angle, should match animation

   //Suspension Settings
   primaryRecoil        = 10.0;  // Recoil amount for the primary weapon
   suspensionRange      = 0.95;  // proportion of wheel size for wheel to move up/down
   springRangeX         = 0.02;  // How much the tank can rock back and forth
   springRangeY         = 0.02;  // How much the tank can rock side to side
   springVelScale       = 1.0;   // How fast the springs rock
   springLooseness      = 0.8;   // How "tight" the springs are (0 = loose, 1.0 = tight)

   // 3rd person camera settings
   cameraRoll           = false; // Roll the camera with the vehicle
   cameraMaxDist        = 7.8;   // Far distance from vehicle
   cameraOffset         = 1.0;   // Vertical offset from camera mount point
   cameraLag            = "0.3"; // Velocity lag of camera
   cameraDecay          = 1.25;  // Decay per sec. rate of velocity lag

   // Rigid Body
   mass                 = "800";
   massCenter           = "0 -0.2 0";  // Center of mass for rigid body
   massBox              = "0 0 0";     // Size of box used for moment of inertia,
                                       // if zero it defaults to object bounding box
   drag                 = 0.6;   // Drag coefficient
   bodyFriction         = 0.6;
   bodyRestitution      = 0.4;
   minImpactSpeed       = 5;     // Impacts over this invoke the script callback
   softImpactSpeed      = 5;     // Play SoftImpact Sound
   hardImpactSpeed      = 15;    // Play HardImpact Sound
   integration          = 8;     // Physics integration: TickSec/Rate
   collisionTol         = "0.1"; // Collision distance tolerance
   contactTol           = "0.1"; // Contact velocity tolerance
....
cont..
#17
06/11/2011 (8:05 am)
cont..
// Engine
   engineTorque         = 4300;     // Engine power
   engineBrake          = "1000";   // Braking when throttle is 0
   brakeTorque          = "8000";   // When brakes are applied
   maxWheelSpeed        = 50;       // Engine scale by current speed / max speed

   // Energy / Damage
   maxEnergy            = 100;
   maxDamage            = 100;
   destroyedLevel       = 100;

   engineSoundA         = ShermanIdleSound;
   engineSoundB         = ShermanEngineSound;
   softImpactSound      = softImpact;
   hardImpactSound      = hardImpact;

   // Dynamic fields accessed via script
   nameTag              = 'Sherman';
   maxDismountSpeed     = 10;
   maxMountSpeed        = 5;
   tireEmitter          = "TankTireEmitter";
   dustEmitter          = "TankTireEmitter";
   dustHeight           = "1";

   // Weapons List.. Interesting and Flexible
   weaponImage[0]       = TankPrimaryWeaponImage;
   weaponSlot[0]        = TankPrimaryWeapon;
   weaponAmmo[0]        = TankPrimaryWeaponAmmo;
   weaponAmmoCnt[0]     = 10;
   weaponImage[1]       = TankSecondaryWeaponImage;
   weaponSlot[1]        = TankSecondaryWeapon;
   weaponAmmo[1]        = TankSecondaryWeaponAmmo;
   weaponAmmoCnt[1]     = 500;
   weaponImage[2]       = TankTertiaryWeaponImage;
   weaponSlot[2]        = TankTertiaryWeapon;
   weaponAmmo[2]        = TankTertiaryWeaponAmmo;
   weaponAmmoCnt[2]     = 500;
   
   // Allowable Inventory Items
   maxInv[TankPrimaryWeapon]        = 1;
   maxInv[TankPrimaryWeaponAmmo]    = 100;
   maxInv[TankSecondaryWeapon]      = 1;
   maxInv[TankSecondaryWeaponAmmo]  = 1000;
   // This tank has 2 machine guns on the front
   maxInv[TankTertiaryWeapon]       = 1;
   maxInv[TankTertiaryWeaponAmmo]   = 1000;
};

So now I'm gonna have to finalize this :)
Then I have to deal with the Striker....
#18
06/17/2011 (7:04 am)
I just spotted a [Brain Fart] I had with Weapon Images and MountPoints :)

if( mDataBlock->mNumWeaponPoints > 0 )
		{
			for( S32 trigAssign=0; trigAssign<MaxTriggerKeys; trigAssign++)
			{
				S32 mWeap = mDataBlock->mMountTrigger[trigAssign];
				//Have to deal with the HardCoded Limit of [4] Mounted Images MAX
				//Will look into wether or not we need more later
				if( mWeap >= 0 && mWeap < 3)
				{
					ShapeBaseImageData* tempWeapon = getMountedImage( mWeap );
					if ( tempWeapon != NULL )
						setImageTriggerState( mWeap, move->trigger[trigAssign] );
				}
			}
		}

Is the correct way to do it.. Totally forgot the weaponImages
declare their MountPoints in the DataBlock and its not the slot
you specify in the setImage ... *chuckle* I think I was working
too hard on this before lol
#19
08/08/2011 (1:36 pm)
Hello John,

Do you think it"s would be possible to get a copy of your TreadVehicle.ccp and TreadVehicle.h?

Thanks,

Sylvain
#20
08/08/2011 (3:38 pm)
Part of the problem with giving out those two is that they do use parts
of the Main system (Bravetree tank) and I can't really give out their
work. If I'm able to set it up fully without any of the original code,
I have been thinking of just posting it as a resource later.
So for the moment I can't post the full files :(
The main feature that would be lost is the turret control/fire system
so it kinda makes it a bit useless without those bits. Sorry, but I do
believe in people being able to make money from their hard work..
My original work tried to do it without using any of the tank code. I was
able to do all but the Turret movement.
That is why I've tried not to post any of the original code. With the
several posts I've done, you should be able to piece it together. I've
posted alot of the work I've tried.

You also need to slightly modify the base vehicle class to mix this one
in the way I did it.
Page «Previous 1 2