[[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);
});