[[Nasal スクリプト集]]

* 概要 [#pf776953]
ffe.nas は、燃費、予測航続距離及び予測後続時間をダイアログで表示します。ダイアログ部分はおまけなので適当ですが、ご勘弁を。

* インストール方法 [#hf9bc117]
添付ファイルのソース (ffe.nas) を  ~/.fgfs/Nasal/ffe.nas として保存してください (Windows の場合は  C:/Documents and Settings/<ユーザ名>/Applciation Data/flightgear.org/Nasal/ffe.nas)。 あとは FlightGear を起動するだけで準備完了です。特に機体側の変更は必要ありません。

* 使用方法 [#r174603c]
起動後、Nasal コンソールから以下のコマンドを入力し Execute ボタンを押せばダイアログが表示されます。

 ffe.Dialog.show();

毎回入力するのは面倒ですので、一度 ESC を押してフライトギアを終了させると、次回からは Nasal コンソールを開くだけで上記コマンドが表示されますので、Execute ボタンを押すだけで起動するようになります。

* 処理概要 [#t8297fd7]
処理は大きく分けて2つです。1つは燃費等の計算処理で、もう1つはダイアログ表示処理です。
計算処理では、settimer で 5秒毎に表示する3つの値を計算しています。燃費は瞬間燃費のことで「対地速度 / 燃料消費量」とから計算していまして、単位は nm / us-gal (ガロン) です。予測航続距離は「燃費×燃料の残量」でして、単位は us-gal (ガロン) です。要望があればガロン単位に変更します。予想後続時間は「燃料の残量÷燃料消費量」で、書式は HH:MM:SSです。

* ソース [#u781142e]
このソースは参考に表示しているものです。ダウンロードは下の添付ファイルをクリックして保存してください。
 ###############################################################################
 # ffe.nas by Tatsuhiro Nishioka
 # - Shows Fuel Efficiency, Estimate Cruise Range, and Estimate Cruise Time.
 # 
 # Copyright (C) 2008 Tatsuhiro Nishioka (tat dot fgmacosx at gmail dot com)
 # This file is licensed under the GPL license version 2 or later.
 # 
 ###############################################################################
 
 
 var Dialog = {};
 Dialog.init = func (x = nil, y = nil) {
   me.x = x;
   me.y = y;
   me.bg = [0, 0, 0, 0.3];
   me.fg = [[0.9, 0.9, 0.2, 1],[1.0, 1.0, 1.0, 1.0]];
   me.name = "Fuel Efficiency";
   me.namenode = props.Node.new({"dialog-name" : me.name });
   me.dialog = nil;
   me.node = props.globals.getNode("/sim/gui/dialogs/fuel-efficiency");
   me.properties = [
     { property : "efficiency", name : "Efficiency",            format : "%1.4f", unit : "nm/gal", halign : "right" },
     { property : "range",      name : "Estinate Cruise Rqnge", format : "%05d",  unit : "nm",     halign : "right" },
     { property : "time",       name : "Estimate Cruise Time",  format : "%8s",   unit : "time",    halign : "right" }
   ];
   
   me.listeners=[];
   append(me.listeners, setlistener("/sim/startup/xsize", func { me._redraw() }));
   append(me.listeners, setlistener("/sim/startup/ysize", func { me._redraw() }));
 }
 
 Dialog.create = func {
   if (me.dialog != nil)
     me.close();
   
   me.dialog = gui.Widget.new();
   me.dialog.set("name", me.name);
   if (me.x != nil)
     me.dialog.set("x", me.x);
   if (me.y != nil)
     me.dialog.set("y", me.y);
   
   me.dialog.set("layout", "vbox");
   me.dialog.set("default-padding", 0);
   
   me.dialog.setColor(me.bg[0], me.bg[1], me.bg[2], me.bg[3]);
   
   var titlebar=me.dialog.addChild("group");
   titlebar.set("layout", "hbox");
   
   titlebar.addChild("empty").set("stretch", 1);
   titlebar.addChild("text").set("label", "Fuel Efficiency");
   
   var w = titlebar.addChild("button");
   w.node.setValues({"pref-width": 16, "pref-height": 16, legend: "", default: 0}); # key: "esc" is no good
   w.setBinding("nasal", "ffe.Dialog.destroy()");
   
   me.dialog.addChild("hrule");
   
   var content = me.dialog.addChild("group");
   content.set("layout", "table");
   content.set("defalt-padding", 0);
   var row = 0;
   
   foreach (var property; me.properties) {
     var col = 0;
     foreach (var column; ["name", "property", "unit"]) {
       var w = content.addChild("text");
       if (column == "property") {
         w.node.setValues({row: row, col: col, label: "--------", live : 1, 
                           format : property.format, halign : property.halign,
                           property: me.node.getPath() ~ "/" ~ property.property});
       } else {
         var label = property[column]; 
         w.node.setValues({row: row, col: col, label : label, format : "%s", halign : "left"});
       }
       col += 1;
     }
     row += 1;
   }
   
   fgcommand("dialog-new", me.dialog.prop());
   fgcommand("dialog-show", me.namenode);
 }
 
 Dialog._redraw = func {
   if (me.dialog != nil) {
     me.close();
     me.create();
   }
 }
 
 Dialog.close = func {
   fgcommand("dialog-close", me.namenode);
 }
 
 Dialog.destroy = func {
   me.close();
   foreach(var l; me.listeners)
     removelistener(l);
   delete(gui.dialog, "\"" ~ me.name ~ "\"");
 }
 
 Dialog.show = func {
   me.init(-2, -2);
   me.create();
 }
 
 var FuelEfficiency = {};
 FuelEfficiency.new = func(interval) {
   obj = { parents : [FuelEfficiency] };
   obj.speedNode = props.globals.getNode("velocities/groundspeed-kt");
   obj.engineRunningNode = props.globals.getNode("engines/engine/running");
   obj.interval = interval;
   obj.fuelFlow = 0;
   obj.fuelEfficiency = 0;
   obj.range = 0;
   settimer(func { obj.update(); }, 5);
   return obj;
 }
 
 FuelEfficiency.update = func {
   me.updateFuelEfficiency();
   me.calcTotalFuel();
   me.estimateCruiseRange();
   me.estimateCruiseTime();
   settimer(func { me.update(); }, me.interval);
 }
 
 #
 # calculate fuel efficiency (nm/us-gal)
 #
 FuelEfficiency.updateFuelEfficiency = func {
   var fuelFlow = 0;
   var groundSpeed = getprop("/velocities/groundspeed-kt");
   var engineRunning = getprop("/engines/engine/running");
   if (engineRunning == nil) {
     engineRunning = 0;
   } else {
     foreach(var engine; props.globals.getNode("/engines").getChildren("engine")) {
       fuelFlow += me.getFuelFlow(engine);
     }
   }
   me.fuelFlow = fuelFlow;
   me.fuelEfficiency = (engineRunning * fuelFlow == 0) ? 0 : (groundSpeed / fuelFlow);
   setprop("/sim/gui/dialogs/fuel-efficiency/efficiency", me.fuelEfficiency);
 }
 
 FuelEfficiency.getFuelFlow = func(engine) {
   var flowNode = engine.getNode("fuel-flow-gph");
   var flow = 0;
   if (flowNode != nil)
     flow = flowNode.getValue();
   if (flow == 0 or flowNode == nil) {
     flowNode = engine.getNode("fuel-flow_pph");
     if (flowNode != nil)
       flow = flowNode.getValue() / 5.92;
     else
       flow = 0;
   }
   return flow;
 }
 
 #
 # calculate total fuel (us-gal)
 #
 FuelEfficiency.calcTotalFuel = func {
   var totalFuel = 0;
   foreach (var tank; props.globals.getNode("/consumables/fuel").getChildren("tank")) {
     var fuelLevelNode = tank.getNode("level-lb");
     if (fuelLevelNode != nil) {
       totalFuel += fuelLevelNode.getValue() / 5.92;
     }
   }
   setprop("/sim/gui/dialogs/fuel-efficiency/fuel-gal", totalFuel);
   me.totalFuel = totalFuel;
 }
 
 FuelEfficiency.estimateCruiseRange = func {
   var range = me.fuelEfficiency * me.totalFuel;
   setprop("/sim/gui/dialogs/fuel-efficiency/range", range);
   return range;
 }
 
 FuelEfficiency.estimateCruiseTime = func {
   var time = 0;
   if (me.totalFuel > 0) {
     time = me.totalFuel / me.fuelFlow * 60;
   }
   var hour = int(time / 60);
   var min = int(math.mod(time, 60));
   var sec = int(math.mod(time * 60, 60));
   setprop("/sim/gui/dialogs/fuel-efficiency/time", sprintf("%02d:%02d:%02d", hour, min, sec));
   return 
 }
 
 var efficiency = nil;
 
 _setlistener("/sim/signals/fdm-initialized", func {
   efficiency = FuelEfficiency.new(1);
 });

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS