Ship propeller spin linked to throttle
by Denise Bacher · in Torque Game Engine · 08/06/2007 (10:19 am) · 9 replies
I've been digging through the forum looking for information about how to create a flying/underwater vehicle that has a back propeller that is linked with the throttle. Currently I have an animation working, but it doesn't speed up or slow down with the throttle speed of the ship. It just starts while going forward, and stops and resets to the beginning of the animation when I stop pushing the forward button. I'm in the process of attempting to add a HUB to the flying vehicle source code as suggested here. It seems like this would be the way to go about doing it, but I'm not sure exactly how to get it to work. What I'm trying is looking through the wheeled vehicle code and trying to pull out the parts that involve wheels and integrate them into my flying vehicle code. But I'm not convinced that's what I want to be doing. I don't want wheels, which is why I'm not using the wheeledFlying vehicle. All I need is one HUB (or something similar) on the back of my ship to control the propeller spin speed when throttling forward and backward as well as the residual throttle.
Here are a couple of renders from our artists to give you an idea of what our ship looks like.

Here are a couple of renders from our artists to give you an idea of what our ship looks like.

#2
08/07/2007 (8:22 am)
I'm using a modified version of the flying vehicle class and I'm using a cs file to combine my dts and dsq file and trigger my animation that looks like this:datablock TSShapeConstructor(ShipDTS)
{
baseShape = "./VirusShip.dts";
sequence0 = "./VirusShip_activate.dsq ActivateBack";
sequence1 = "./VirusShip_propeller.dsq MaintainBack";
}If this is not the best way to be doing it, having some examples of how to set up the animation thread would be very helpful. It definitely seems like it should be easier, and makes more sense, than trying to add a HUB to the back of the ship.
#3
This will require some code changes. Here is a resource which does this:
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=11321
08/07/2007 (8:46 am)
If you want to stick to the animation approach, you can change the timeScale for the TSThread that is playing the propeller animation.This will require some code changes. Here is a resource which does this:
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=11321
#4
08/07/2007 (11:45 am)
That's not quite what I'm looking for. What I want to happen is when you begin moving forward the propellers begin spinning slowly and increase in speed as you reach max forward speed, and as you stop moving forward have the propeller spin decrease and stop when the vehicle comes to rest. Basically I want the propeller animation speed linked to the throttle/force values.
#5
Thanks,
Denise
08/08/2007 (8:17 am)
@Gabriel - I think this is the type of solution I need to be pursuing, but I'm still unsure about how to go about it. I haven't worked with animation threads at all, other than in the TSShapeContstuctor blocks. In running my program and outputting the mThrottle and dt values they are 0 and -536870912 respectively. It doesn't matter if I'm going forward, backward, or not moving at all, the values are always the same. If you could elaborate more on idea that would be extremely helpful. I'm using the flying vehicle, I've just turned of gravity and the gyroscopes. Thanks,
Denise
#6
Above is a zip file which includes a modified version of a hover vehicle. It demonstrates using animation threads controlled by input. I will be commenting on the different things required and reference the code from such.
I don't know what level of programming experience you have, so I will attempt to achieve the right level of description.
DATABLOCK
In the HoverTankData::initPersistFields() I expose these to scripting to allow the user to specify the names of the threads being used (specified in the datablock).
VEHICLE CLASS
You can ignore the networking code for the position and velocity values (they are commented out already), as I realized that updateforces is server side and so does not require these values to be networked to the client.
I hope this is clear enough and not to overly specific.
Gabriel
08/08/2007 (12:45 pm)
www.gabriel-notman.com/upload/hoverTank.zipAbove is a zip file which includes a modified version of a hover vehicle. It demonstrates using animation threads controlled by input. I will be commenting on the different things required and reference the code from such.
I don't know what level of programming experience you have, so I will attempt to achieve the right level of description.
DATABLOCK
[header file] StringTableEntry TurretThread; StringTableEntry BarrelThread; S32 TurretSequenceID; S32 BarrelSequenceID;I have specified member variables for the names of threads being used and their sequence IDs.
In the HoverTankData::initPersistFields() I expose these to scripting to allow the user to specify the names of the threads being used (specified in the datablock).
bool HoverTankData::preload(bool server, char errorBuffer[256])
{
if (Parent::preload(server, errorBuffer) == false)
return false;
TurretSequenceID = shape->findSequence(TurretThread);
BarrelSequenceID = shape->findSequence(BarrelThread);
return true;
}In the preload function I look up the sequence IDs based on the thread names (default values for the IDs is -1). In my situation I was using embedded named sequences, whereas you are specify the sequences in the datablock and naming and numbering them explicitly. This means you probably could hard code the sequence number but you need to be careful and probably need to do some error check to make sure the script specification is correct.VEHICLE CLASS
[header file] F32 mTurretPos; F32 mTurretVel; F32 mBarrelPos; F32 mBarrelVel; TSThread* mTurretThread; TSThread* mBarrelThread;I specify member variables for the positions of the animated parts and pointers to thread objects.
bool HoverTank::onNewDataBlock(GameBaseData* dptr)
{
mDataBlock = dynamic_cast<HoverTankData*>(dptr);
if (!mDataBlock || !Parent::onNewDataBlock(dptr))
return false;
if (mDataBlock->TurretSequenceID != -1) {
mTurretThread = mShapeInstance->addThread();
mShapeInstance->setSequence(mTurretThread,mDataBlock->TurretSequenceID,0);
}
else
mTurretThread = 0;
if (mDataBlock->BarrelSequenceID != -1) {
mBarrelThread = mShapeInstance->addThread();
mShapeInstance->setSequence(mBarrelThread,mDataBlock->BarrelSequenceID,0);
}
else
mBarrelThread = 0;
...
}The above function is called when a console object is created and the applicable datablock is applied. Here I check to see if the sequence IDs are valid, and if they are I add a new thread based on the ID and reset its position to zero.void HoverTank::updateMove(const Move* move)
{
mTurretVel=move->yaw*mDataBlock->TurretMaxRotVel;
mBarrelVel=-move->pitch*mDataBlock->BarrelMaxRotVel;
...
}In the above function I am pulling the user input and saving it to modify the threads. I am using the yaw and pitch but other values are available. Note that these can be analog values.void HoverTank::updateForces(F32 dt)
{
if (mDamageState != Enabled)
return;
Parent::updateForces(dt);
mTurretPos+=mTurretVel*dt;
mBarrelPos+=mBarrelVel*dt;
if (mTurretPos>1)
mTurretPos-=1;
else if (mTurretPos<0)
mTurretPos+=1;
if (mBarrelPos>1)
mBarrelPos=1;
else if(mBarrelPos<0)
mBarrelPos=0;
if (mTurretThread)
mShapeInstance->setPos(mTurretThread, mTurretPos);
if (mBarrelThread)
mShapeInstance->setPos(mBarrelThread, mBarrelPos);
mShapeInstance->animate();
setMaskBits(BarrelMask);
}The above function is server side, and is passed the parameter dt. This specifies how many seconds (as floating point value and is generally <1) have passed since the last update. Using this value I update the position values mTurretPos+=mTurretVel*dt; ... and then apply the value to the actual animation threads mShapeInstance->setPos(mTurretThread, mTurretPos);. These animation threads were setup as blend animations between 2 keyframes, so 0 is initial state 1 is final state. I also wrap the values around 0.0 and 1.0. You probably should setup the propeller rotation as cyclic, this means that values of greater then 1.0 should automatically wrap.You can ignore the networking code for the position and velocity values (they are commented out already), as I realized that updateforces is server side and so does not require these values to be networked to the client.
I hope this is clear enough and not to overly specific.
Gabriel
#7
Any suggestions?
08/13/2007 (11:14 am)
Ok, I think I have this mostly figured out but when I try to set the animation SequenceID in the preload function SequenceID = shape->findSequence(PropellerThread);it's returning -1. I'm pretty sure I'm doing it wrong in my script files. I'm doing it like this in my vehicle datablock in the script file:
PropellerMaxRotVel = 2; PropellerThread = "~/data/shapes/VirusShip_propeller.dsq";and in my datablock I added the PropellerMaxRotVel and PropellerThread variables.
Any suggestions?
#8
ie:
The reason it is returning -1 is because it cannot find the named sequence. The above data block addition should cause the findSequence() function to return 0 (sequence0=propellerthread). However I used an embedded sequence, so I have not tested it this way.
Gabriel
08/13/2007 (1:29 pm)
You either need to embed an named sequence call "PropellerThread" within your dts, or specify one in the data blockie:
sequence0 = "./VirusShip_activate.dsq PropellerThread";
The reason it is returning -1 is because it cannot find the named sequence. The above data block addition should cause the findSequence() function to return 0 (sequence0=propellerthread). However I used an embedded sequence, so I have not tested it this way.
Gabriel
#9
08/20/2007 (9:20 am)
I finally got it working. Thanks for all the help.
Torque Owner Gabriel Notman
Something like this.
Add to updateForces(...)
mPropPos+=mThrottle*dt; if (mPropThread) mShapeInstance->setPos(mPropThread, mPropPos);This assumes that you have properly loaded an animation thread called mPropThread and added an member variable mPropPos. Also you may need to wrap mPropPos around 0..1, but if its a cyclic animation this shouldn't be necessary.You may wish to add an idle spin and a multiplier:
If you need some examples of setting up the animation thread I can help you with that.
Hope this helps.
Gabriel