Jump to content

Lua-Tables in V5


Empfohlene Beiträge

Hallo,
ich habe mal ein kleines Beispiel angehängt, wie man in V5 eine Lua-Tabelle (table) einsetzen kann.
Ich denke, im Bereich der Animationen kann dies sehr hilfreich sein. Vielleicht auch im Bereich Blockdefinitionen etc., generell eigentlich überall dort, wo man sonst sehr viele Objekte mit vielen Objektvariablen füttern müßte. Ein table ist für einen schnellen Überblick und schnelle Editiermöglichkeiten wohl sehr hilfreich.
Ich hab's jetzt nicht in den Katalog geladen, weil vielleicht noch weitere Erklärungen rein müßten.
Die Kommentare in den zwei Skripten sollten aber eigentlich für sich sprechen.
Weitere praktische kleine Demos rund um das Thema tables wären hier wohl sehr erwünscht.

Gruß
  Andy

 

Animationstabelle.mbp

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo @Goetz,

da es auch andere 'treffen' kann, erkläre ich es mal etwas genauer:

Meine Anlage ist zeitgesteuert und soll später wie koriander's Anlagen mal wie ein Film ablaufen. Meine alte Silvester-Version hat das schon gemacht.
Du hast also eine Zeitvariable, die jede Sekunde einmal vorwärts tickt und damit auf die Animationen losgeht, die auslösenden Schalter waren nur ein Beispiel.
Soll er nun jedesmal zig Ereignisse abklappern, ob die Zeit gekommen ist? Das belastet die EV zu sehr und das Protokoll wird unlesbar.
Fasst man alle Animationen in ein Skript zusammen, sieht's so aus:

if value == 300 then
  $("Eurofima Deutschland 1").animations["Licht Beleuchtung Innenraum"]:play(0, 1)
  $("Eurofima Deutschland 2").animations["Licht Beleuchtung Innenraum"]:play(0, 1)
  $("Eurofima Deutschland 3").animations["Licht Beleuchtung Innenraum"]:play(0, 1)
  $("Eurofima Deutschland 4").animations["Licht Beleuchtung Innenraum"]:play(0, 1)
  $("Eurofima Deutschland 4").animations["Licht Schlusslicht hinten"]:play(0, 1)
  $("E 10 \"Bügelfalte\"").animations["Licht vorn weiß"]:play(0, 1)
  $("E 10 \"Bügelfalte\"").animations["Licht hinten rot"]:play(0, 1)
  $("Ae 6/6").animations["Licht weiss vorn oben"]:play(0, 1)
  $("Ae 6/6").animations["Licht weiss vorn links"]:play(0, 1)
  $("Ae 6/6").animations["Licht weiss vorn rechts"]:play(0, 1)
  $("Ae 6/6").animations["Licht rot hinten oben"]:play(0, 1)
...
  $("Ae 6/6").animations["Licht rot hinten links"]:play(0, 1)
  $("Ae 6/6").animations["Licht rot hinten rechts"]:play(0, 1)
  $("BR 80").animations["Scheinwerfer vorn weiß"]:play(0, 1)
  $("BR 80").animations["Scheinwerfer hinten rot"]:play(0, 1)
  $("Lichtscheibe Henschel oben").state = 1
  $("Lichtscheibe Henschel unten links").state = 1
  $("Lichtscheibe Henschel unten rechts").state = 1
end

if value == 500 then
  $("A08 Wohnstallhaus").animations["Licht an/aus"]:play(0, 1)
end
if value == 502 then
  $("A10 Wohnhaus").animations["Licht an/aus"]:play(0, 1)
end
...

das sind alleine für 'Licht ein' 339 Zeilen. Entlastet das Protokoll, aber sonst nichts.
Was tun?  table verwenden, die 'Zeilen' zeitsortieren mit der Schaltzeit als ersten Eintrag und einen Index laufen lassen (mit next oder so). Dann schaut er sich *einen* Eintrag an, ob die Zeit gekommen ist, führt den aus, hüpft weiter, vielleicht noch einer, ansonsten raus aus der Routine. Den Index merkt er sich für den nächsten Tick. Blitzschnell!
Immense Zeiteinsparung und diese Tabelle ist schön lesbar, eben weil sie nicht mit eingebauten Funktionen zugepfeffert ist. Hier geht mir gute Lesbarkeit und schnelle Editierbarkeit vor elegante Effizienz.
Es sind ja, wie Du siehst, auch Schalter dabei (siehe Lichtscheiben). Die muß ich da auch irgendwie unterkriegen. Und ich brauche sogar noch Escapecodes
(negative Werte anstelle der Zeit), um Spezialitäten auszulösen. Vielleicht brauche ich noch Parameter, weiß ich noch nicht. Bin nicht sicher, ob ich die table so kriege wie ich sie mir vorstelle.
Läuft dieses Verfahren aber dann tatsächlich so wie gewollt, kann man auf ähnliche Weise das Movieskript mit den Kameraaufrufen gestalten.
Ich bastel mal dran, dann kannst Du gerne noch mal drüber schauen. Und Danke, dass Du's hier schon getan hast, habe auf einen Kommentar von Dir gehofft.
 Deine Art und Weise werden wir bestimmt auch noch brauchen.

Gruß
  Andy

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo Andy, hallo Goetz,

... interessante Anregungen:)

... wobei ich allerdings anmerken muß, dass ich Andy noch folgen kann...
... bei Goetz kann ich zwar ziemlich nachvollziehen wie es abläuft (... aber nicht wie man zu so etwas kommt:o) ...
(... hat trotzdem ein "Gefällt mir" bekommen... man muß ja nicht alles verstehen was gefällt...)

... erste Experimente sind auf jeden Fall schon mal gestartet...

Gruß
EASY

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 2 Stunden schrieb EASY:

... man muß ja nicht alles verstehen

Ich würde dir gerne helfen, es zu verstehen. Denn das ist der Zweck, den ich damit verfolge.

Ich mag keine langen if-Konstrukte.

Ein if ist gut, wenn ich einen ja/nein Fall habe. Aber wenn ich viele mögliche Werte habe, auf die ich unterschiedlich reagieren will, dann klappere ich die nicht gerne mit if-Ketten ab. Insbesondere die Tabellen, die Lua bietet, sind da ein bequemerer Weg. Wenn ich die möglichen Werte, die ich zur Auswahl bekomme, als Tabellenindexe (Indizes?) nutze und unter diesen Adressen das ablege, was ich im Falle des jeweiligen Wertes brauche, dann kann ich den entstandenen Wert direkt nutzen, um aus der Tabelle das passende rauszupicken.

Anhand eines Beispiels kann ich es vielleicht besser verdeutlichen.
Nehmen wir ein Signal mit vier Stellungen und die Geschwindigkeiten, die der Zug fahren darf:

  • Stellung 0 - HP0 - Geschwindigkeit 0
  • Stellung 1 - HP1 - Geschwindigkeit 120 (nur für dieses Beispiel. HP1 bedeutet "Fahrt")
  • Stellung 2 - HP2 - Geschwindigkeit 40
  • Stellung 3 - SH1 - Geschwindigkeit 25

Ich kann jetzt die Stellung auslesen und dann alle Möglichkeiten durchtesten:

Stellung = signal.state

if Stellung == 0 then
  vehicle.targetSpeed = 0
elseif Stellung = 1 then
  vehicle.targetSpeed = 120
elseif Stellung = 2 then
  vehicle.targetSpeed = 40
elseif Stellung = 3 then
  vehicle.targetSpeed = 25
end

 

Oder ich weise die Geschwindigkeiten in einer Tabelle den Signalstellungen zu:

Stellung = signal.state

SpeedTable = {
  [0] =   0,
  [1] = 120,
  [2] =  40,
  [3] =  25
}

vehicle.targetSpeed = SpeedTable[Stellung]

Ich benutze hier die Signalstellung als Index, um mir aus der Tabelle den passenden Wert rauszupicken.

Die Nummern vorne in den eckigen Klammern wären nicht nötig. Bis auf eine: die Null. Wenn man keinen Index vergibt, dann bekommt das erste Element in einer Tabelle die Nummer 1. Deshalb habe ich die Null in eckige Klammern als Index vorgeben müssen. Und dann habe ich das Prinzip für die übrigen Werte beibehalten.

 

Alternativ ginge es auch so:

Stellung = signal.state
SpeedTable = {0, 120, 40, 25}
vehicle.targetSpeed = SpeedTable[Stellung + 1]

aber die erste Form macht deutlicher, was wozu gehört.

 

Man kann dieses Prinzip auf die Spitze treiben, indem man an passenden Stellen keine Werte in der Tabelle ablegt, sondern ganze Funktionen. 

Lua macht da keinen Unterschied, weil es eigentlich immer nur Pointer sind, die an diesen Stellen liegen. Also Adressen. Ob dann an dieser Adresse eine Zahl, ein Text, eine weitere Tabelle oder eine Funktionsdefinition hinterlegt ist, spielt für den Tabelleneintrag keine Rolle.

Bearbeitet von Goetz
Ergänzungen
Link zu diesem Kommentar
Auf anderen Seiten teilen

@EASY,

mir hat z.B. Dein Container-Beispiel geholfen zu verstehen, wie man den Koordinatenzugriff einsetzt. Das habe ich alleine nicht hingekriegt. Da gab's nil-Fehler ohne Ende.
Danke dafür! Jedes kleine Demo hier hilft weiter, bei anderen Verständnislücken zu schließen. Je kleiner das Beispiel, desto besser.

Ich habe an meinem Beispiel sehr lang dran geknabbert, weil ich folgenden Fehler gemacht habe:

AnimTable =
{
  { Objekt = "Riesenrad", Animation = "Rad drehen", FuncEin = animplay, FuncAus = animstop },
  { "Riesenrad", "Licht",      animplay, animstop }
}

Ich dachte, er nimmt die in der ersten Zeile  angegebenen Bezeichner als eine Art Template (Vorlage), um auf die anderen zuzugreifen.
Also,  AnimTable[2].Animation, dachte ich, zeigt auf "Licht". Falsch!
Offensichtlich trennt er hier intern die Dinge auf. Diejenigen mit Bezeichner und die ohne. Das folgende Beispiel zeigt das auf:

function animplay()
end
function animstop()
end

AnimTable =
{
--  { Objekt = "Riesenrad", Animation = "Rad drehen", FuncEin = animplay, FuncAus = animstop },
  { "Riesenrad", "Rad drehen",  animplay, animstop },
  { "Riesenrad", "Licht",      animplay, animstop }
}

print(AnimTable[2][2])
print(AnimTable[1][2])

So gibt er "LIcht" und "Rad drehen" aus.
Setzt man die Kommentarzeichen hingegen auf die zweite Zeile, findet er "Rad drehen" mit Indexangabe nicht mehr!
Also, selbst mit der Unterstützung von Götz' Tutorial sind da noch einige Dinge zu erforschen.

Gruß
  Andy

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich habe eine nette Demo als Entwurf hochgeladen. Dieser Code sollte wirklich wiederverwendbar sein.
 

Entwurf: Animationstabellen

54901AE0-3E05-4444-9295-7337D883DD1A

Es werden hierfür nur zwei Modulvariablen gebraucht. Ein Sekundenzähler und eine Variable um den Fortschritt in der Tabelle zu merken.
- Das Auslösen des Schalters zeigt, wie sie initialisiert werden müssen und startet den Sekundentimer, der auf autom. Neustart eingestellt ist.
- Der Sekundentimer tickt einen Sekundenzähler.
- Das Hochzählen des Sekundenzählers ruft das eigentliche Skript auf.
Mehr gibt's da eigentlich nicht zu sagen. Es gibt einige Kommentare im Skript.
Wen's verwirrt: der Sekundenzähler heißt SminuteAnim, weil bei Gebrauch der virtuellen Zeit eine echte Sekunde eine Minute in der kleinen Welt sein sollte/könnte.

Vielleicht noch folgende Bemerkung:
durch die Verwendung von $("objektname") in der Tabelle weiß die EV, dass sie die Objektnamen an dieser Stelle auch mitändern muß, falls man
auf die Idee kommt, ein Objekt nachträglich nochmal umzubennen. Da muß man nicht drauf achten, das ändert er hier mit.
Verwendet man das $ über Tastatur, (z.B. für einen Neueintrag), verlangt er unmittelbar ein Objekt aus der Auswahlliste.
Man kann dies umgehen, indem man in einem externen Editor Einträge vorbereitet und dann einfügt. Das macht er klaglos mit.

Gruß
  Andy

Bearbeitet von Andy
ps
Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo Goetz,

vor 7 Stunden schrieb Goetz:

ich mag keine langen if-Konstrukte

In Lua fehlt leider "Select...Case" (von VB)...
... und dass diese Art von Tabelle dazu benutzt werden kann, habe ich schnell verstanden und hat mich sofort begeistert...

vor 7 Stunden schrieb Goetz:

Ich würde dir gerne helfen, es zu verstehen. Denn das ist der Zweck, den ich damit verfolge.

es ist nur...
 

[1] = function(axis)
    axis:play(-1, 1)    -- axis enthält die komplette Adresse für die Funktion
  end,

... ab hier wird es bei mir mit dem Verstehen etwas schwerer... der ":" hat mich dann doch etwas sehr verwirrt...

Gruß
EASY

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 20 Minuten schrieb EASY:

der ":" hat mich dann doch etwas sehr verwirrt...

Der Doppelpunkt gibt den Teil links davon als erstes Argument an den Funktionsaufruf, der rechts vom Doppelpunkt steht. Diese Schreibweise ist dann sinnvoll, wenn die Funktion in derselben Tabelle steht wie die Daten, welche die Funktion nutzen soll.

Im MBS sind viele Funktionen Teil der jeweiligen Modelle. Ein Riesenrad enthält je eine Funktion play und eine Funktion stop für jede darin verbaute Achse. Deshalb wandelt das MBS diesen Eintrag in der EV

2042126281_EVundLuamitDoppelpunkt.JPG.b1d123be45e983c08aacc08891625e4a.JPG

in diesen Lua Code um:

$("Riesenrad").animations["Rad drehen"]:play(0, 1)

Ich habe lediglich in meinem Beispiel den langen Adressteil links vom Doppelpunkt zuerst in einem kurzen Namen zusammengefasst und dann die Funktion aufgerufen. Sonst werden mir die Zeilen zu lang und unleserlich.

 

Die Funktionen play und stop sind im MBS Teil einer Klassendefinition. Deshalb muss man beim Aufruf der Funktionen die Adresse des Objekts und seiner Achse als Argument mit übergeben. Neo hat sich bei solchen Funktionsaufrufen an die in Lua übliche Schreibweise gehalten. Lua kennt zwar keine Klassen, aber die Tabellen kommen dem schon recht nahe. 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Götz, ich habe da auch noch eine Frage:
Meinst Du, es macht einen Performance-Unterschied, wo der table definiert ist? Muß er sich da immer wieder durchackern, wenn er in ein Skript reinkommt, das in Untermodulen liegt? Oder macht er derlei Dinge gleich beim Programmstart und geht dann im Skript direkt drüber weg?
Im ersten Fall wäre es ja sinnvoll alle tables aus den Untermodulen ins Hauptskript abzuziehen. Das wäre nicht so schön.

Gruß
  Andy
 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 1 Minute schrieb Andy:

Meinst Du, es macht einen Performance-Unterschied, wo der table definiert ist?

Ich weiß es ehrlich nicht, aber meine Vermutung ist, dass es keinen Unterschied macht. Weil eben in einer Tabelle nur Adressen liegen. Da dürfte auch eine Schnitzeljagd über mehrere gestaffelte Adressen keine Belastung darstellen. Auch dann nicht, wenn diese Adressen während des Programmablaufs dynamisch gebildet werden.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo,

vor 45 Minuten schrieb Goetz:

meine Vermutung ist, dass es keinen Unterschied macht.

im Großen und Ganzen ist das korrekt. Ob eine Tabelle im Hauptmodul oder einem Untermodul erzeugt wird, spielt keine Rolle, weil alle Skripte aller Module beim Speichern der EV zusammengesetzt werden. Hat sich die EV geändert, werden alle Skripte einmalig kompiliert. Dabei werden auch die Tabellen erzeugt. Anders ausgedrückt, globale Tabellen werde nur einmal erzeugt, da spielt die Performance keine nennenswerte Rolle.

Etwas anders sieht es aus, wenn Tabellen in Funktionen erzeugt werden, und diese Funktionen sehr häufig aufgerufen werden. Dann werden die Tabellen nämlich bei jedem Aufruf neu erzeugt.

Viele Grüße,

Neo

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo,

... mein erster Versuch mit einer Tabelle ist gelungen:)

mein Ziel ist es eine einfache Steuerung für Kräne zu entwerfen, bei der es möglichst einfach ist, noch einen Kran hinzuzufügen oder dem einzelnen Kran Aufgaben zuzuweisen...
... mit der Tabelle werden die Aufgaben definiert (Objekt->Ziel). Ist momentan noch eine Tabelle ("nur" 2 unterschiedliche Aufgaben je Kran), aber wahrscheinlich ist es besser für jeden Kran eine eigene zu machen, wenn die Aufgabenliste länger wird...

P.S. Da es für Objektvariablen noch keine Felder gibt... mußte ich mir beim Kran eben mit einzelnen Variablen für jedes Objekt/Ziel behelfen...
...aber Neo wollte ja diesbezüglich noch einmal in sich gehen;)...

p.P.S. Da sich Objektvariablen über Lua nicht löschen lassen setze ich .Objektx und .Zielx auf "nil" [Leer] um verfolgen zu können was schon abgearbeitet ist...

Kransteuerung02.thumb.jpg.673fdb277cf660491012a281cf420c73.jpg

Kransteuerung02.mbp

... Anregungen gerne:)...

Gruß
EASY

Link zu diesem Kommentar
Auf anderen Seiten teilen

Objektvariablenarrays kann ich nur unterstützen. Die bräuchte ich für meine Weichenlisten in den Fahraufträgen und natürlich auch in den Fahrplänen für die Aufträge.
Eigentlich könnte man die ja oft in echte Lua-Arrays auslagern. Aber dann haben sie einen entscheidenden Nachteil: man kann ihren Wert nicht einsehen. Oder doch?
Und wenn ja, wie?

Gruß
  Andy

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo,

vor einer Stunde schrieb EASY:

Anregungen gerne

bitte :)

Hat es einen bestimmten Grund, warum du ein benutzerdefiniertes Ereignis "Kraninit" verwendest, um die Kräne zu initialisieren? Da du komplett auf Lua setzt, hätte ich erwartet, dass du einfach eine Funktion in deinem Modulskript aufrufst.

Das Konzept hinter den globalen Tabellen "objekte" und "ziele" finde ich persönlich nicht so schön. Die einzelnen Funktionen in "AblaufTable" besitzen eine hohe Redundanz und unterscheiden sich oft nur in wenigen Details. Hinzu kommt, dass du erst die Funktion aufrufst, um globale Tabellen zu befüllen, um anschließend direkt wieder auf den Tabellen zu arbeiten. Das ist sehr anfällig für Seiteneffekte. Besser wäre es, wenn du eine Funktion schreibst, die die Daten über return zurück gibt, und du so nicht mit globalen Daten arbeiten musst.

Prototypisches Beispiel:


-- Modulskript
Kran10 = function()
  local objekte = {}
  local ziele = {}
  for i = 1, 4 do
    objekte[i] = "Fass1"..i
    ziele[i] = "k1"..i
  end
  return objekte, ziele
end

function Kraninit(kran, objekte, ziele)
  if not kran.variables["buzzy"] then
     ...
  end
end

-- Ereignis
if controller.state == 1 then
  local objekte, ziele = Kran10()
  Kraninit($("Kran1"), AblaufTable["objekte"], AblaufTable["ziele"])
else
  ...
end

Der nächste Schritt wäre dann die KranXX-Funktionen zu vereinheitlichen. Aber das kannst du dir vermutlich sparen. Es wird (wenn auch nicht sofort) Arrays als Objektvariablen geben, wodurch du die Objekte und Ziele eines Krans direkt beim Kran definieren kannst und nicht über eine Funktion initialisieren musst.

StartK1 bis StartK3 kannst du dann auch zu einem Ereignis zusammenfassen, da du im Schalter eine Referenz zum entsprechenden Kran hinterlegen kannst.

Gibt bestimmt noch weitere Tipps, ich freue mich auf die nächste Iteration :)

Viele Grüße,

Neo

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo,

vor 16 Stunden schrieb Neo:

Hat es einen bestimmten Grund, warum du ein benutzerdefiniertes Ereignis "Kraninit" verwendest, um die Kräne zu initialisieren?

das kleine Projekt unterliegt einer dynamischen Veränderung mit dem Sinn des Lernens und Ausprobieren von Möglichkeiten...

Zitat

Neues Ereignis "Benutzerdefiniert"

  • Wird durch eine manuell platzierte Aktion ausgelöst.
  • Ermöglicht das Ausführen von gemeinsam genutzten Aktionen, mit bis zu 10 Aufrufparametern.

... dies ist für mich so etwas wie eine "globale" Funktion und es ist (noch) drin, weil

vor 16 Stunden schrieb Neo:

Da du komplett auf Lua setz...

diese Annahme etwas verfrüht ist... natürlich möchte ist auch wissen, was mit MBS-Funktionen möglich ist...
... und das benutuzerdeninierte Ereignis finde ich eine sehr gute Idee von Dir(y)

vor 16 Stunden schrieb Neo:

Hinzu kommt, dass du erst die Funktion aufrufst, um globale Tabellen zu befüllen, um anschließend direkt wieder auf den Tabellen zu arbeiten.

Dies ist eine "Übersetzung", da das benutzerdeninierte Ereignis keine Arrays/Felder als Übergabeparameter zuläßt... (hatten wir schon:P)...

vor 16 Stunden schrieb Neo:

Hinzu kommt, dass du erst die Funktion aufrufst, um globale Tabellen zu befüllen, um anschließend direkt wieder auf den Tabellen zu arbeiten. Das ist sehr anfällig für Seiteneffekte

...:/...Seiteneffekte???????o.O

... meine Vorgehensweise bei diesem Projekt folgt noch nicht der strengen Logik das Ziel (nach meinen Möglichleiten) "optimal" zu erreichen...

Wenn ich auf etwas treffe was mich neugierig macht wie es geht und ich es mit diesem Projekt ausprobieren kann, wird es erst einmal "gnadenlos" eingebaut (benuzerdefiniertes Ereignis, Tabellen...)...
(... und manchmal muß man eben noch Umwege gehen, weil der Programmierer keine Arrays/Felder vorgesehen hat...)

... Anregungen (wie jetzt von Dir) nehme ich gerne auf um das Projekt zu verfeinern...

Mein Ziel wäre es so etwas wie einen Baustein zu schaffen / bereitstellen, um in ein Projekt eine Steuerung für Kräne einzubauen...

P.S. ... da sich das ganze thematisch etwas von "Lua-Tables in V5" entfernt, kannst Du auch gerne ein neues Thema "Kransteuerung-V5" oder irgendwie so ähnlich aufmachen und meine letzten Beitrag und den Dialog dahin verschieben... die Entscheidung überlasse ich Dir...

Gruß
EASY

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo,

vor 21 Stunden schrieb EASY:

Seiteneffekte???????

Seiteneffekte bezeichnen ungewollte Änderungen von globalen Variablen, die so nicht beabsichtigt waren. Zum Beispiel:

objekte = {}

function InitObjekte()
  objekte['ABC'] = 'Mein Gleis'
end

function ClearObjekte()
  objekte = {}
end

function VerarbeiteObjekte(modus)
  objekte['ABC'].verarbeite(modus)
  ClearObjekte()
end

VerarbeiteObjekte(1)
VerarbeiteObjekte(2) -- Peng!

Dieses konstruierte und sinnlose Beispiel soll verdeutlichen, wie schnell eine globale Variable unbeabsichtigt geändert wird. Weil in VerarbeiteObjekte nach der Verarbeitung ein ClearObjekte steht, ist die Tabelle beim zweiten VerarbeiteObjekte-Aufruf leer. Für jemanden, der dein Skript nur schnell überfliegt, könnte es nicht ersichtlich sein, dass ein VerarbeiteObjekte nach dem Verarbeiten die Objekte löscht. Man provoziert so also schnell riskante Situationen, die speziell bei "Modulen", die anderen zur Verfügung gestellt werden sollen, zu Fehlern führen. Daher mein Tipp, auf so viele globale Variablen wie möglich zu verzichten.

Viele Grüße,

Neo

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 2 Wochen später...

Hello Goetz,

one question concerning the tables :

Imagine a layout where you have 3 switches at the entry of a station.  To go to the plateform n°1, you only need the first switch; for plateform n° 2, one need switches 1 & 2 and to go to plateform 3, one need the 3 switches.

I've build the Following table containing the pos required for the switches for the tree trajects T1, T2 and T3:
Pos = {
  T1 = {0, track.variables["switch2"].state, track.variables["switch3"].state},
  T2 = {1, 0, track.variables["switch3"].state},
  T3 = {1, 1, 0}
}

where switch1, switch2 and switch3 are object variables (type = object) with the real name of the switches SW1, SW2 ans SW3

and the actions

trajet =  vehicle.variables["Trajet"]

$("SW1").state = Pos[trajet][1]
$("SW2").state = Pos[trajet][2]
$("SW3").state = Pos[trajet][3]

So only the needed switches are toggled.  But do you have another method to replace the "track.variables["switch3"].state in order to avoid the toggle of the unused switch?

Many Thanks

André

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hello André

see if this works, please

Pos = {
  T1 = {0}
  T2 = {1, 0}
  T3 = {1, 1, 0}
}

trajet = vehicle.variables["Trajet"]

$("SW1").state = Pos[trajet][1]
if Pos[trajet][2] then
  $("SW2").state = Pos[trajet][2] 
  if Pos[trajet][3] then
    $("SW3").state = Pos[trajet][3]
  end
end

 

greets
Goetz

Bearbeitet von Goetz
Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 33 Minuten schrieb Goetz:

see if this works, please

Hi Goetz,

Thank you and, of course, it works!  So my example was too simple, I guess.

In fact, my concern is to build a table where some some gap may exists like, for example :

Pos = {
  T1 = {0, , 1},                     This produce a Script error (10)
  T2 = {1, 0},
  T3 = {1, 1, 0}
}

Pos = {
  T1 = {0, nil, 1},                 This is OK for the syntax but produce an error while attempting to toggle with a nil value
  T2 = {1, 0},
  T3 = {1, 1, 0}
}

Pos = {
  T1 = {0, "" , 1},                This is OK for the syntax but "" is interpreted as 0 (zero)
  T2 = {1, 0},
  T3 = {1, 1, 0}
}

So, my final objective is to create a table to pilot my trains according to defined trajects; currently, I'm thinking and searching a good way to do that and tables seem to be the best solution.

Regards

André

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 2 Stunden schrieb ademes:

my concern is to build a table where some some gap may exist

Your second version should work if you alter my code a little bit. 
Your first list produced an error because in Lua you may not leave a field empty. 
Your third list failed because in Lua an empty string is considered true (and equally a 0 is considered true too)

I built the previous example according to your request and it only checked for a switch 3 value when one for switch 2 was present.
Here's the fix, where every switch is checked individually:

Pos = {
  T1 = {0, nil, 1},
  T2 = {1, 0},
  T3 = {1, 1, 0}
  T4 = {nil, 1, nil, nil, 0, 1}
} 

trajet = vehicle.variables["Trajet"]

if Pos[trajet][1] then $("SW1").state = Pos[trajet][1] end
if Pos[trajet][2] then $("SW2").state = Pos[trajet][2] end
if Pos[trajet][3] then $("SW3").state = Pos[trajet][3] end
if Pos[trajet][4] then $("SW4").state = Pos[trajet][4] end
if Pos[trajet][5] then $("SW5").state = Pos[trajet][5] end
if Pos[trajet][6] then $("SW6").state = Pos[trajet][6] end

 

Better build this in a loop. To do so, you need the switch objects in a table too:

Pos = {
  T1 = {0, nil, 1},
  T2 = {1, 0},
  T3 = {1, 1, 0}
  T4 = {nil, 1, nil, nil, 0, 1}
} 

SwitchList = {$("SW1"), $("SW2"), $("SW3"), $("SW4"), $("SW5"), $("SW6")}

trajet = vehicle.variables["Trajet"]

for k, v in pairs(SwitchList) do
  if Pos[trajet][k] then 
    v.state = Pos[trajet][k] 
  end
end

 

Please note that you must enter the switch objects into your list by typing the Dollar-Sign and then picking the item from the object list. The names are only a reminder and do not function as a reference! Hence you cannot copy the complete switch table from my example.

 

My entire construct is not an ideal solution. I did my best to stay close to your attempt.
My observation is that people learn best when they can build on what they already know.

Bearbeitet von Goetz
Link zu diesem Kommentar
Auf anderen Seiten teilen

Hi,

vor 11 Minuten schrieb Goetz:

The names are only a reminder and do not function as a reference! Hence you cannot copy the complete switch table from my example.

just to clarify: It is possible to copy $-signs as long as the named objects only exist once in the layout. MBS automatically creates an internal reference when manually entering $("..."). Only if multiple objects share the same name, than the result of a $-copy is undefined.

Kind regards,

Neo

Link zu diesem Kommentar
Auf anderen Seiten teilen

Erstelle ein Benutzerkonto oder melde dich an, um zu kommentieren

Du musst ein Benutzerkonto besitzen, um einen Kommentar verfassen zu können

Benutzerkonto erstellen

Neues Benutzerkonto für unsere Community erstellen.

Neues Benutzerkonto erstellen

Anmelden

Du hast bereits ein Benutzerkonto? Melde dich hier an.

Jetzt anmelden
×
×
  • Neu erstellen...