• Which the release of FS2020 we see an explosition of activity on the forun and of course we are very happy to see this. But having all questions about FS2020 in one forum becomes a bit messy. So therefore we would like to ask you all to use the following guidelines when posting your questions:

    • Tag FS2020 specific questions with the MSFS2020 tag.
    • Questions about making 3D assets can be posted in the 3D asset design forum. Either post them in the subforum of the modelling tool you use or in the general forum if they are general.
    • Questions about aircraft design can be posted in the Aircraft design forum
    • Questions about airport design can be posted in the FS2020 airport design forum. Once airport development tools have been updated for FS2020 you can post tool speciifc questions in the subforums of those tools as well of course.
    • Questions about terrain design can be posted in the FS2020 terrain design forum.
    • Questions about SimConnect can be posted in the SimConnect forum.

    Any other question that is not specific to an aspect of development or tool can be posted in the General chat forum.

    By following these guidelines we make sure that the forums remain easy to read for everybody and also that the right people can find your post to answer it.

FSX:SE Help needed for Ambient Animation

Messages
45
Country
australia
Hi all,

I'm currently trying to animate wipers.

I've managed to create the animation for them, but it's the getting them to work that I'm struggling with.

This is the code I have in my modeldef.xml file for the wiper knob (left wiper only):

Code:
  <PartInfo>
    <Name>knob_Wiper_left</Name>
    <AnimLength>50</AnimLength>
    <Animation>
      <Parameter>
        <Code>
          (L:Wiper Left, enum) 0 == if{ 0 }
          (L:Wiper Left, enum) 1 == if{ 16 }
          (L:Wiper Left, enum) 2 == if{ 32 }
          (L:Wiper Left, enum) 3 == if{ 50 }
        </Code>
        <Lag>400</Lag>
      </Parameter>
    </Animation>
    <MouseRect>
      <Cursor>Hand</Cursor>
      <MouseFlags>LeftSingle+RightSingle+WheelUp+WheelDown</MouseFlags>
      <CallbackCode>
        (M:Event) 'RightSingle' scmp 0 ==
        (M:Event) 'WheelUp' scmp 0 == or
        if{ (L:Wiper Left, enum) ++ s0 3 &gt; if{ 3 } els{ l0 } (&gt;L:Wiper Left, enum) }
        (M:Event) 'LeftSingle' scmp 0 ==
        (M:Event) 'WheelDown' scmp 0 == or
        if{ (L:Wiper Left, enum) -- s0 0 &lt; if{ 0 } els{ l0 } (&gt;L:Wiper Left, enum) }
      </CallbackCode>
    </MouseRect>
  </PartInfo>

That and the associated animation for the left wiper knob are working like a charm.

I also have the following code in my modeldef.xml for the wiper blades:

Code:
  <Animation name="NonRandomAmbient" guid="94c95bf8-907a-483c-99fe-968825034c40" length="100" type="Sim" typeParam2="NonRandomAmbient" typeParam="AutoPlay" />
  <Animation name="NonRandomAmbient1" guid="bb7a2358-b3f2-4bbd-843a-5070afdc794c" length="100" type="Sim" typeParam2="NonRandomAmbient1" typeParam="AutoPlay" />

    <PartInfo>
    <Name>NonRandomAmbient</Name>
    <Visibility>
      <Parameter>
        <Code>
          (L:Wiper Left, enum) 0 !=
        </Code>
      </Parameter>
    </Visibility>
  </PartInfo>

  <PartInfo>
    <Name>NonRandomAmbient1</Name>
    <Visibility>
      <Parameter>
        <Code>
          (L:Wiper Left, enum) 0 !=
        </Code>
      </Parameter>
    </Visibility>
  </PartInfo>

And the code from my .xanim file:

Code:
  <Anim name="NonRandomAmbient" guid="94c95bf8-907a-483c-99fe-968825034c40" length="100.000" type="Sim" typeParam="AutoPlay" typeParam2="NonRandomAmbient">
    <AnimStream name="Position" id="2" partName="node08" length="100.000">
      <Keyframe time="0.000" type="Vector" data="0.000000;0.000000;0.000000;0.000000"/>
      <Keyframe time="25.000" type="Vector" data="0.000000;0.000000;0.000000;0.000000"/>
      <Keyframe time="50.000" type="Vector" data="0.000000;0.000000;0.000000;0.000000"/>
      <Keyframe time="75.000" type="Vector" data="0.000000;0.000000;0.000000;0.000000"/>
      <Keyframe time="100.000" type="Vector" data="0.000000;0.000000;0.000000;0.000000"/>
    </AnimStream>
    <AnimStream name="Rotation" id="0" partName="node08" length="100.000">
      <Keyframe time="0.000" type="Quaternion" data="0;0;0;1"/>
      <Keyframe time="25.000" type="Quaternion" data="-0.114806;0.337664;0.084416;0.930418"/>
      <Keyframe time="50.000" type="Quaternion" data="-0.213634;0.628336;0.157084;0.731354"/>
      <Keyframe time="75.000" type="Quaternion" data="-0.114806;0.337664;0.084416;0.930418"/>
      <Keyframe time="100.000" type="Quaternion" data="0;0;0;1"/>
    </AnimStream>
  </Anim>
  <Anim name="NonRandomAmbient1" guid="bb7a2358-b3f2-4bbd-843a-5070afdc794c" length="100.000" type="Sim" typeParam="AutoPlay" typeParam2="NonRandomAmbient1">
    <AnimStream name="Position" id="2" partName="node10" length="100.000">
      <Keyframe time="0.000" type="Vector" data="0.000000;0.000000;0.000000;0.000000"/>
      <Keyframe time="25.000" type="Vector" data="0.000000;0.000000;0.000000;0.000000"/>
      <Keyframe time="50.000" type="Vector" data="0.000000;0.000000;0.000000;0.000000"/>
      <Keyframe time="75.000" type="Vector" data="0.000000;0.000000;0.000000;0.000000"/>
      <Keyframe time="100.000" type="Vector" data="0.000000;0.000000;0.000000;0.000000"/>
    </AnimStream>
    <AnimStream name="Rotation" id="0" partName="node10" length="100.000">
      <Keyframe time="0.000" type="Quaternion" data="0;0;0;1"/>
      <Keyframe time="25.000" type="Quaternion" data="0;0;-0.087156;-0.996195"/>
      <Keyframe time="50.000" type="Quaternion" data="0;0;-0.173648;-0.984808"/>
      <Keyframe time="75.000" type="Quaternion" data="0;0;-0.087156;-0.996195"/>
      <Keyframe time="100.000" type="Quaternion" data="0;0;0;1"/>
    </AnimStream>
  </Anim>

No cigar. :(

I've used the following pages for reference:

https://www.fsdeveloper.com/forum/threads/3-speed-wipers.93549/#post-247354
http://www.aerodynamika.com/cgi-bin/yabb2/YaBB.pl?num=1193457453
https://www.fsdeveloper.com/forum/threads/not-sure-if-fsx-or-fsxa.441972/page-2

I just can't figure this out. I'd very much appreciate if anyone can help me understand where I'm going wrong.

To be clear, the above is 'test code'. All I want to do for now is have the left wipers animate when the left wiper knob is not at the 0 setting (ie. 1, 2 or 3). I'll add in multiple speed wipers when I can get my head around the concept of ambient animation.

Ta!

Trent
 
No clue here what's 'ambient' about your animation; there is a default 'ambient' animation, but clearly that's not it.

FWIW, for knob_Wiper_left animation even though it is working you could put it more efficiently, like so:

Code:
<Code>
(L:Wiper Left, enum) 16 * 50 min
</Code>
...
<CallbackCode>
(M:Event) 'RightSingle' scmp 0 == (M:Event) 'WheelUp' scmp 0 == or
if{ (L:Wiper Left, enum) ++ min 3 (>L:Wiper Left, enum) }
els{ (L:Wiper Left, enum) -- 0 max (>L:Wiper Left, enum) }
</CallbackCode>

(Caution, not tested!)

For the two visibility definitions (not animations!) note : no guids are needed, and since the conditional vis is identical why would one need two? Also, maybe I misunderstand sth here, but what's the point of hiding the the wiper blade at all?
 
Last edited by a moderator:
"Ambient Animation" is the wrong approach to use. The "ambient" set are replacements for the ancient "tick18" animation system. They are used to animate objects automatically and continuously, such as a windsock, or rotating light.

Here is the simple script I used in the B737-200C project. You will undoubtedly notice that there is no script that drives the (L:WIPER_POS,number) variable. That is contained in another "logic gauge" along with all the other things that require calculations. I try not to embed logic in the modeldef.xml file since it requires exporting/recompiling the entire model just to make minor adjustments to the logic... :teacher:

This is a "two speed" wiper system. The knob has four positions: -1 = park, 0 = off, 1 = low, 2 = high:
Code:
  <PartInfo>
    <Name>B737_WiperSwitch</Name>
    <AnimLength>30</AnimLength>
    <Animation>
      <Parameter>
        <Code>10 (L:WIPER_SPEED, enum) 10 * +</Code>
        <Lag>200</Lag>
      </Parameter>
    </Animation>
    <MouseRect>
      <Cursor>Hand</Cursor>
      <TooltipText>Wiper Switch</TooltipText>
      <MouseFlags>LeftSingle+RightSingle+WheelUp+WheelDown+LeftRelease+LeftDrag+Leave</MouseFlags>
      <CallbackCode>
        (M:Event) 'LeftSingle' scmp 0 ==
        (M:Event) 'WheelDown' scmp 0 == or
        if{ (L:WIPER_SPEED, enum) -- -1 max (>L:WIPER_SPEED, enum) 1 (>L:XMLSND3,bool) }

        (M:Event) 'RightSingle' scmp 0 ==
        (M:Event) 'WheelUp' scmp 0 == or
        if{ (L:WIPER_SPEED, enum) ++ 2 min (>L:WIPER_SPEED, enum) 1 (>L:XMLSND3,bool) }

        (M:Event) 'LeftRelease' scmp 0 ==
        (M:Event) 'LeftDrag' scmp 0 == or
        (M:Event) 'Leave' scmp 0 == or
        (L:WIPER_SPEED, enum) -1 == and
        if{ 0 (>L:WIPER_SPEED, enum) }
      </CallbackCode>
    </MouseRect>
  </PartInfo>

  <PartInfo>
    <Name>B737_Wiper_Anim</Name>
    <AnimLength>50</AnimLength>
    <Animation>
      <Parameter>
        <Code>
          (L:WIPER_POS,number)
        </Code>
      </Parameter>
    </Animation>
  </PartInfo>
And here is the "logic script" that does the magic:
Code:
     <!-- WIPER CONTROL LOGIC -->
    (A:ELECTRICAL MASTER BATTERY,bool) 0 !=
    if{ (L:WIPER_SPEED,number) 0 &gt; (L:WIPER_POS,number) 1 &gt; or
    if{ (L:WIPER_POS,number) (L:WIPER_SPEED,number) 1.50 * + 50 % d (&gt;L:WIPER_POS,number) } }
    (L:WIPER_SPEED,number) -1 ==
    (L:WIPER_POS,number) 0 &gt; and
    if{ (L:WIPER_POS,number) -- (>L:WIPER_POS,number) }
 
I use ambient animation for radar head rotation in my airport project, never ending rotation and that my very first animation in sim. just remember how happy I was in that time... sorry just told
 
Thanks everyone for clarifying that I was on the wrong track with ambient animation.

Bill, I'm attempting to work through your code and because I'm learning as I go, I've tried to keep it as simple as possible so that it is just working to begin with. So I've forgotten about tying the animation to the wiper knob. I'm just going to set a '1' state in my Alogic.xml file and just have the animation trigger.

Once those components are working, I'll refine it. But I'm still doing something wrong!

From the modeldef.xml file:

Code:
  <PartInfo>
    <Name>wiper_left_a</Name>
    <Animation>
      <Parameter>
        <Code>
          (L:Wiper Left Speed, enum) 0 !=
        </Code>
      </Parameter>
    </Animation>
  </PartInfo>

From my logic gauge I called Alogic.xml:

Code:
<?xml version="1.0" encoding="UTF-8"?>

<SimBase.Document Type="AceXML" version="1,0">
    <Descr>AceXML Document</Descr>

     <!-- WIPER CONTROL LOGIC -->
    1 (&gt;L:Left Wiper Speed, enum)   

</SimBase.Document>

Bill, I note that your code had something like 1 (>L:XMLSND3,bool) which I didn't use as I didn't understand it. This is probably part of my problem. Could you explain what this does?

As you can see, I've tried to assign a default value of 1 to the L:Left Wiper Speed but if I'm doing that wrong then please point it out.

I've placed my ALogic.xml file with all the other xml gauges in the unpacked cab folder within my panel folder.

Any other help is gratefully received. Thanks all!

Trent
 
As an update, I've tried the following logic gauge as well (after realising I hadn't added my new logic gauge to the panel.cfg!!).

Still no cigar.

Code:
<Gauge Name="ALogic">
<Element>
<Select>
<Value>1 (>L:Left Wiper Speed, enum)</Value>
</Select>
</Element>
</Gauge>

Trent
 
You could have a trigger that uses something in the plane, like 'folding wings' or 'tailhook' and the logic;

(tailhook animation,bool) 1 ==
if{ 1 (>L:work my animation now,bool) }
els{ 0 (>L:work my animation now,bool) }

(Not written in correct XML verbage)

You would then add the necessary sections to your aircraft config file for either tailhook or wingfold animations (small section for animating your wings and tailhook).

Then... when you trigger one of those things, you see your animation start and run, then turn off and its much easier then to get an idea of it working properly. Just some humble input.

You could even use Landing Lights. Anything as a logic trigger.

Aircraft config file data sections;

[folding_wings]
wing_fold_system_type=1 // Available
fold_rates = 0.25,0.20 // Left,Right: 1/sec

[TailHook]
tailhook_length = 1
tailhook_position = -15, 0, -1
cable_force_adjust = 1

You would also then need to assign a key in your sim to operate those items. Activate in the keyboard section of Settings.
 
Last edited:
Thanks everyone for clarifying that I was on the wrong track with ambient animation.

Bill, I'm attempting to work through your code and because I'm learning as I go, I've tried to keep it as simple as possible so that it is just working to begin with. So I've forgotten about tying the animation to the wiper knob. I'm just going to set a '1' state in my Alogic.xml file and just have the animation trigger.

Once those components are working, I'll refine it. But I'm still doing something wrong!

From the modeldef.xml file:

Code:
  <PartInfo>
    <Name>wiper_left_a</Name>
    <Animation>
      <Parameter>
        <Code>
          (L:Wiper Left Speed, enum) 0 !=
        </Code>
      </Parameter>
    </Animation>
  </PartInfo>

<snipped for brevity>

Bill, I note that your code had something like 1 (>L:XMLSND3,bool) which I didn't use as I didn't understand it. This is probably part of my problem. Could you explain what this does?
Ah, that entry is a control command for my custom sound system to "play the sound" when the switch is clicked on. I should have snipped it out of the script, or at least have explained that you should ignore it. :ziplip:

The above "(L:Wiper Left Speed, enum) 0 !=" is meaningless. The only thing you should have is the end result of a calculation, i.e., (L:Wiper Left Speed, enum)...

...although I prefer to reserve "Speed" for the speed of the animation, and "POS" for the position of the animation.

Also, you should include the entry <AnimLength>nn</AnimLength> where nn is the total number of keyframes you have set for the wiper's movement. In the example script I posted, my wiper arms are animated from 0 to 50 frames. When the custom variable (L:WIPER_POS,number) is set to zero, the wiper arm is set to the stopped position. As we increase the custom variable's value, the arms will move to the appropriate key frame. We control the "speed" by simply "counting up and down" more rapidly.
Code:
  <PartInfo>
    <Name>B737_Wiper_Anim</Name>
    <AnimLength>50</AnimLength>
    <Animation>
      <Parameter>
        <Code>
          (L:WIPER_POS,number)
        </Code>
      </Parameter>
    </Animation>
  </PartInfo>
The "logic" script requires that we somehow cause the custom variable to "count up from 0 to 50, then reverse the count from 50 to 0". I've chosen to do this through use of the modulo function (the 50 % expression), although there are other ways to accomplish this task. For example:
Code:
(L:WIPER_POS,number) 51 &lt;
if{ (L:WIPER_POS,number) ++ (>L:WIPER_POS,number) }
takes up half way there by 'counting' from 0 to 50 by 1 every gauge cycle (typically 18 frames/second).

Of course, that's only one "wipe" and even then only "half a wipe" truly! So, after we reach 50, we need to reverse the count so that we take the variable back to 0. Again, there are many ways to accomplish this goal. We could add an els{ condition and use subtraction by 1 until we reach zero again.
Code:
(L:WIPER_POS,number) 51 &lt;
if{ (L:WIPER_POS,number) ++ (>L:WIPER_POS,number) }
els{
    if{ (L:WIPER_POS,number) -1 &gt;
      (L:WIPER_POS,number) -- (>L:WIPER_POS,number) }
     }
Now the above is fine if all we want is for the wipers to run continuously, but in reality we want to turn 'em on and off! :laughing:

So, we can add yet another if{ xxx } conditional for that purpose.
Code:
(L:WIPER_SPEED,number) 0 &gt;
if{
  (L:WIPER_POS,number) 51 &lt;
  if{ (L:WIPER_POS,number) ++ (>L:WIPER_POS,number) }
  els{
      if{ (L:WIPER_POS,number) -1 &gt;
          (L:WIPER_POS,number) -- (>L:WIPER_POS,number) }
        } 
  }
The above script will animate the wiper as long as the WIPER_SPEED is greater than 0, but will simply leave the wiper in whatever position it was in when we stopped the animation. Oh my, more complexity! I'll leave as an exercise how to solve this final problem and reset the WIPER_POS variable back to zero when the animation is stopped. :teacher:
 
Hi all,

Success! I figured out a couple of rookie mistakes that were preventing initial lift off and any testing whatsoever...namely that I hadn't assigned a part name to the wiper blades (even though an animation was assigned and working in MCX) and that I didn't add the logic gauge to the virtual cockpit section of the panel.cfg.

Aye aye aye!!

I've utilised Bill's excellent code and adapted it for my own purposes: 0 = off, 1 = periodic, 2 = slow, 3 = fast.

I was able to achieve the periodic wipe by using an animation length of 400. Upward wipe occurring in keyframes 0 - 50, downward wipe occurring in keyframes 51-100 and no activity between 101 - 400.

See below. If anyone is so inclined, I'd appreciate any tips on making the below code more efficient.

The only thing I have left to figure out is how to make the transition from 'Periodic' to 'Slow' a little better. Because of the code logic at this point, it jumps a little bit depending at what position the animation was at when leaving the periodic setting. This is a minor issue and I won't be too upset if I can't figure it out with clean code.

Code:
<?xml version="1.0" encoding="utf-8"?>
<Gauge Name="ALogic" Version="1.0">
  <Element>
    <Select>
      <Value>

     <!-- LEFT WIPER CONTROL LOGIC -->
 
    (L:Wiper Left, enum) 1 == if{ 400 (&gt;L:AnimTrackLeft, enum) } els{ 100 (&gt;L:AnimTrackLeft, enum) }
    (L:Wiper Left, enum) 3 == if{ 6.0 (&gt;L:WiperRateLeft, enum) } els{ 3.0 (&gt;L:WiperRateLeft, enum) }

    (A:ELECTRICAL MASTER BATTERY,bool) 0 !=
    if{ (L:Wiper Left, enum) 0 &gt; (L:Wiper Left Pos, enum) 1 &gt; or
    if{ (L:Wiper Left Pos, enum) (L:WiperRateLeft, enum) + (L:AnimTrackLeft, enum) % d (&gt;L:Wiper Left Pos, enum) } }
    (L:Wiper Left, enum) 0 ==
    (L:Wiper Left Pos, enum) 0 &gt; and
    if{ (L:Wiper Left Pos, enum) -- (>L:Wiper Left Pos, enum) }

     <!-- RIGHT WIPER CONTROL LOGIC -->

    (L:Wiper Right, enum) 1 == if{ 400 (&gt;L:AnimTrackRight, enum) } els{ 100 (&gt;L:AnimTrackRight, enum) }
    (L:Wiper Right, enum) 3 == if{ 6.0 (&gt;L:WiperRateRight, enum) } els{ 3.0 (&gt;L:WiperRateRight, enum) }

    (A:ELECTRICAL MASTER BATTERY,bool) 0 !=
    if{ (L:Wiper Right, enum) 0 &gt; (L:Wiper Right Pos, enum) 1 &gt; or
    if{ (L:Wiper Right Pos, enum) (L:WiperRateRight, enum) + (L:AnimTrackRight, enum) % d (&gt;L:Wiper Right Pos, enum) } }
    (L:Wiper Right, enum) 0 ==
    (L:Wiper Right Pos, enum) 0 &gt; and
    if{ (L:Wiper Right Pos, enum) -- (>L:Wiper Right Pos, enum) }

      </Value>
    </Select>
  </Element>
</Gauge>

Thanks to everyone who assisted, but in particular Bill. I couldn't have managed this without your template code.

Trent
 
Happy to have helped Trent! Before long you'll be in a position to be teaching others new tricks... :coffee:
 
Back
Top