deltic009 wrote:cjbarnes5294 wrote:I'm a bit busy atm (and on my phone, making explaining anything and code writing too laborious and fiddly), but I should be able to come back with some suggestions later.

Chris
Sort of on topic, I seem to recall a while ago you were trying to make a Deltic....well, do what a Deltic does! Did you have any joy and you're just extremely busy? Or did you have to let it go because it wasn't working.
The Deltic is on the back bench at the moment unfortunately, Matt, although I do intend to finish it at some point this year - you'll have to blame it partially on the number of steam locos that need to come first.

I realised that it was going to take more work than I originally anticipated, work that really needs to be in place before the particles go on. I had a play with it a few weeks ago though, fancying some deltic thrash at 100mph, so it's not dead.
Righty, now I'm sat at a keyboard...
JamesLit wrote:I am making some modifications to an existing loco in TS purely for my own personal use, and would like to take the opportunity to brush up on some skills that would be useful for more public work. The loco in question is receiving a low RPM 3 cylinder engine, which idles at 290rpm and maxes out at 400rpm.
Ok, I think if you want the emitter to "putt" in time with the engine correctly, the first port of call is to get the RPM value, which I think should be:
- Code: Select all
Call("*:GetControlValue", "RPM", 0);
I would rather have the number of revolutions per second than RPM, so I would declare a global (you could have it as a local but you might want to use it in more than one function) called gRPS and assign it the value of RPM/60.
- Code: Select all
gRPS = Call("*:GetControlValue", "RPM", 0)/60;
Now, I prefer working in radians when it comes trig, circles and circular movement, but you could use degrees just as easily.

There are 2pi radians (360 degrees) in one revolution, so I could declare another variable that gives the RPS in radians for me:
- Code: Select all
gRPS_radians = gRPS*2*math.pi;
Finally, I want another global that will store and update the angle of revolution of the crankshaft, from 0 to 2pi full revolution. To do this, I use the gRPS_radians variable I declared just now, multiply it by time (distance = speed x time) and increment this new global. Before you do any arithmetic on any variable, you must declare it first and assign it a numerical value, otherwise it will try to do nil + nil which is nil, which is ok (but not useful) until you try comparing nil to a non-nil value in an if-else statement. I would declare this in the Initialise function as gRevAngle = 0. If you declare a value in the Update function like that, that's ok, but it will essentially forget the last value it was assigned to and reset everytime the script updates, which isn't what we want.
- Code: Select all
gRevAngle = gRevAngle + gRPS_radians*time;
--I don't want this to exceed 2pi so I reset it if gRevAngle > 2pi
if gRevAngle > 2*math.pi then
gRevAngle = 0;
end
Hopefully my maths is not too shakey tonight and I've not screwed up anything above, but that is the underlying system I would probably use to drive the particles. So onto the fun/dull (depends how you feel at the time) bit of scripting the particles. We have this really useful variable that should accurately give us the angle of the crankshaft in the engine, and we can use this to control the particles, so as to fire them in time with the engine RPM.
JamesLit wrote:The loco in question is receiving a low RPM 3 cylinder engine, which idles at 290rpm and maxes out at 400rpm.
I must admit, I don't know an awful lot about diesel engines, or whether it would make any difference if it is a 2-stroke or 4-stroke machine, but I'm going to assume that each cylinder fires on everything third of a revolution (I'm guessing that if it is a 4-stroke engine, we'd need to allow gRevAngle to increase to 4pi instead of 2*pi, so that each cylinder ignites only once every two cycles). The easiest way of doing this is by using the angle to control the emitters directly, but this could possibly cause problems if the frequency of ignitions or RPM reaches a certain threshold. To keep things simple, we'll go with it for now.

We can just tell the script to turn the emitter on whenever the crankshaft angle is in thirds of 2pi, plus a short range:
- Code: Select all
if gRevAngle > 0 and gRevAngle < 0.1*math.pi then
smokeOn = 1; --as Edward points out, 1 sets the smoke to on and 0 to off
elseif gRevAngle > 0.666*math.pi and gRevAngle < 0.766*math.pi then
smokeOn = 1; --because the devil says so ;)
elseif gRevAngle > 1.332*math.pi and gRevAngle < 1.432*math.pi then
smokeOn = 1;
else
smokeOn = 0; --turn it off
end
Call("ExhaustSmoke:SetEmitterActive", smokeOn);
JamesLit wrote:I'd like to get the smoke changing colour too, something a bit more grey and certainly a lot more thick and longer lasting at higher revs, and if possible, further changes according to the load the loco is pulling.
You have the choice of either changing the colour of the smoke, using different emitters (and hence textures) for the different conditions, or combining the two effects. A simple way to control the colour of just one emitter, based on the RPM, would be to do something like this:
- Code: Select all
gRPMColourDriver = (Call("*:GetControlValue", "RPM", 0) - 290)/110; --400 - 290 = 110
gExhaustColour = 1 - 0.7*gRPMColourDriver; --if you wanted it to go from normal to absolute black, you'd make it 1 - gRPMColourDriver so that full 400RPM leads to an exhaust colour of 0.
Call("ExhaustSmoke:SetEmitterColour", gExhaustColour, gExhaustColour, gExhaustColour); -- again as Edward has defined
And hopefully that's enough for anybody to seek their teeth into for tonight.

Let me know if I've been confusing at any point, or made a mistake anywhere.
Chris