Beiträge von Mars

    Moin,


    seit es in AutoIt nun offiziell den Map-Datentyp gibt dachte ich mir: Warum keine UDF für doubly linked lists basteln?


    Idee dahinter: Es gibt keinen nativen List-Datentyp, und (mangels Pointer und dynamischer Allokation) auch keine Möglichkeit selbst eine Liste aufzubauen (ja, es geht mit Structs die man vor dem automatischen Löschen schützt, aber die können keine "AutoIt-Variablen" speichern). Daher: Nutze eine Map als "dynamischen Speicher" und packe die [value, previousPointer, nextPointer] tripel einfach in eine Map.


    Geschwindigkeitstests habe ich nur bei relevanten Funktionen gemacht:

    Datengröße: 0 - 1000

    - List schneller (ca. 2x - 10x) _ArrayAdd vs _ListPushBack, _ArrayPop vs _ListPopBack, (und ähnliche Funktionen) (Iteratorversion)

    - List schneller (ca. 1x - 100x) _ArrayDelete vs _ListRemove, _ArrayInsert vs _ListInsert (Iteratorversion)

    - Array schneller (100x+) Direktzugriff vs _ListRead & _ListWrite (Indexversion)

    - Array schneller (ca. 2x) Direktzugriff vs (inlined) _ListRead & _ListWrite (Iteratorversion)


    Von vielen List-Funktionen gibt es eine Indexversion und eine Iteratorversion. Die Indexversion hat immer Komplexität O(n/2). Die Iteratorversion ist (näherungsweise) O(1) und damit meistens halbwegs flott. Das allerschlimmste was man tun kann ist der Direktzugriff via Index (das ist 100x+ langsamer). Insgesamt kam das heraus was wir alle vorher schon wussten: Das was Lists in O(1) und Arrays in O(n) machen ist ab einer Größe von ca. 5 Elementen schon schneller, alles andere ist langsamer.


    Manche List-typische Funktionalität fehlt leider:

    - Es gibt keine Mergefunktion (hier würden Listen auch extrem gut abschneiden, da man nur ein paar Pointer ändert und nichts kopiert)

    - Es gibt keine Splitfunktion (s.o.)

    Grund dafür ist: Es ist (zumindest mit dem jetzigen Aufbau der UDF) nicht möglich von einer Liste auf eine andere zu verlinken. Ein "ListPool" der komplett innerhalb einer Map liegt könnte das Problem lösen, würde aber auch einiges an Overhead mitbringen.

    - Insgesamt ist der Umfang/Errorhandling/etc. nicht mit Array.au3 vergleichbar, sondern nur ein sehr kleines Subset was mit der Zeit vielleicht noch etwas wächst :)


    Wie immer gilt: Viel Spaß mit der UDF und meldet Fehler/Wünsche. Falls ich Zeit und Lust habe kümmere ich mich darum.


    lg

    Mars

    Ich spiele das immer solo, bin eigentlich eher jemand der sich freut wenn Zahlen größer werden. Daher versuche ich viele Felder auf dem Planeten einzunehmen und viele Ressourcen zu sammeln^^

    Mich hat das Spiel damals auch ziemlich überrumpelt. Hab sowas immer gesucht, und auf ein Mal war es da ^^


    Dokumentation (Work in Progress). Die soll mal in "Post 2" verschoben/kopiert werden (muss ein Mod machen)


    Dokumentation (version 0.2)


    Logik Komponenten:


    Name (Englisch)
    BeschreibungSpezifikationen
    Message
    Größe 1x1
    Zur Anzeige von Text.
    Anzahl Zeichen: 400
    Switch
    Größe: 1x1
    Kann vom Spieler ein- und ausgeschaltet werden.
    Micro Processor
    Größe: 1x1
    Führt Instruktionen aus.
    Instruktionen pro Sekunde: 120 (IPS/Größe: 120)
    Programmspeicher: 1000 Instruktionen (Speicher/Größe: 1000)
    Logic Processor
    Größe: 2x2
    Führt Instruktionen aus.
    Instruktionen pro Sekunde: 480 (IPS/Größe: 120)
    Programmspeicher: 1000 Instruktionen (Speicher/Größe: 250)
    Hyper Processor
    Größe: 3x3
    Führt Instruktionen aus.
    Instruktionen pro Sekunde: 1500 (IPS/Größe: 167)
    Programmspeicher: 1000 Instruktionen (Speicher/Größe: 111)
    Memory Cell
    Größe: 1x1
    Bietet Random Access Memory.
    Speicherkapazität: 64 (Speicher/Größe: 64)
    Memory Bank
    Größe: 2x2
    Bietet Random Access Memory.
    Speicherkapazität: 512 (Speicher/Größe: 128)
    Logic Display
    Größe: 3x3
    Zur Anzeige von Pixelgrafik.
    Auflösung: 80x80 Pixel
    Large Logic Display
    Größe: 6x6
    Zur Anzeige von Pixelgrafik.
    Auflösung: 176x176 Pixel



    Random Info:

    • Alle Drawcalls sind je Prozessor auf 128 Calls beschränkt. Danach muss ein DrawFlush durchgeführt werden, falls man weitere Drawcalls ausführen möchte. Die Limitierung ist "pro Prozessor" und nicht "pro Display". Teilt man also z.B. ein 80x80 Display in 40x40 auf und bearbeitet jedes mit einem eigenen Prozessor, dann kann man mit 4 parallelen DrawFlushes insgesamt 512 Drawcalls gleichzeitig auf den Schirm bringen.
    • Alle Messages sind auf 400 Zeichen beschränkt. Jeder Printflush überschreibt den vorherigen Inhalt. Dieses Limit kann nicht durch paralleles beschreiben umgangen werden.
    • Es gibt in der Mindustry Logic sprache ausschließlich globale Variablen. Im Compiler (v0.2) wird aktuell noch keine Unterscheidung zwischen Local und Global unternommen, hier ist also aktuell auch alles Global.
    • Aktuell (Stand v0.2) werden nur einfache Expressions unterstützt. Etwas wie z.B. a = b * c + d geht nicht, da das mehrere Operationen beinhaltet. Klammersetzung gibt es auch nicht.
    • Aktuell (Stand v0.2) werden keine Minuszeichen vor Variablen unterstützt (Mindustry Logic unterstützt das leider nicht). Etwas wie "a = -b" geht also nicht. Stattdessen lieber "a = 0 - b" schreiben.
    • Aktuell (Stand v0.2) Warum gibt es keine "Funktionen"?
      • Grund dafür ist der enorme Overhead. "Richtige" Funktionen haben Parameter und Returnwerte, sie benötigen einen Stack (Aufrufkonvention) um Parameter zu verwenden. Ein Stack benötigt im besten Fall 3 Takte für Push und Pop. Variablen werden vor dem Aufruf gepusht, in der Funktion selbst gepoppt, am ende der Funktion erneut gepusht und nach der Funktion wieder gepoppt. Das macht 4 * 3 Takte pro Variable und einmalig 2 * 3 Takte für die Sprungadressen. Bei z.B. 4 Variablen sind das bereits 4 * 4 * 3 + 2 * 3 = 54 Takte BEVOR irgendwelcher Code ausgeführt wird. Da wir nur Taktraten im 100 bis 1000er Bereich (pro Sekunde) haben würde allein der Aufruf bereits viel Zeit beanspruchen. Außerdem (bei kleinen Funktionen) wäre der Aufruf selbst kostspieliger als der eigentliche Code. Daher gibt es "erstmal" Subroutinen.
    • Aktuell (Stand v0.2) Was sind Subroutinen?
      • Das sind quasi "Funktionen mit Einschränkungen". Aktuell (Stand v0.2) gibt es nur "ausgelagerten Code" als Subroutine, später soll es aber noch mehr geben. Die Einschränkungen sind: Es gibt keine Stacks (weder für Variablen, noch für Rücksprungadressen), also sind Subroutinen nicht Rekursiv verwendbar (genauer: Es kann immer nur "ein" call gleichzeitig laufen. Man kann also in mySub die Subroutine mySub2 ohne Probleme aufrufen, man kann aber keine Situation erzeugen in der mySub aufgerufen wird während mySub noch aktiv ist. Also ist es im hiesigen Beispiel nicht möglich mySub in mySub2 aufzurufen). Parameter können (ohne Stack) hardcoded (templatisierung) implementiert werden. Dann hat mySub z.B. die Parameter "a" und "b", die intern als "_SUBPARAM_mysub_a" gehandhabt werden. Statt einem Stack werden diese Variablen vor dem Subroutine Aufruf befüllt (1 Takt / Variable zum Befüllen, 0 Takte innerhalb der Funktion, da hier substituiert werden kann, wenn man templatisiert, oder 1+1 Takte innerhalb wenn man nicht templatisiert). Ähnlich verhält es sich mit dem Returnwert, die Intern als "_SUBRETURN_mysub" vorliegt und nur einen Takt um Lesen und Schreiben braucht.
      • Was soll das Ganze? Da wir so wenige Takte zur Verfügung haben, und weil ein Stack Speicherzellen benötigt (es gibt keine Programmspeicherpointer) gibt es Subroutinen die so Funktionsähnlich wie möglich sind, dabei aber deutlich bessere Performance haben und keine zusätzlichen Blöcke (Speicherzellen) benötigen.
      • Ein weiterer Punkt ist, dass ich Subroutinen aufgrund dessen, dass sie komplett Hardcoded sind "vermutlich" in andere Prozessoren auslagern lassen (dann bräuchte man doch eine Speicherzelle). In der Speicherzelle müssten #Params + 2 Orte reserviert werden (kann Hardcoded sein). in [0] steht eine 0, 1 oder 2 (0 = nix, 1 = Der andere Prozessor überwacht diesen Speicherplatz, sobald hier eine 1 steht holt er sich die nächsten N Variablen, führt die Funktion aus und Schreibt das Ergebnis in das Feld für den Returnwert. Anschließend setzt er [0] auf 2, sodass der Mainthread via Join() sehen kann, dass die Funktion fertig ausgeführt wurde. Den Returnwert holt er sich anschließend und setzt [0] wieder auf 0. (Das hier ist nur eine Idee. Für größere Programme ist Multithreading unabdingbar, vorallem bei Echtzeitanwendungen die z.B. nur 100 Takte / Frame haben).


    Instruktionen:

    Funktionen (Wrapped)
    Mindustry Logic
    Beschreibung
    result = Read(cell, index)
    read result cell index
    Liest den Wert einer Memory Cell oder Memory Bank an einem gewissen Index aus
    result = Sensor(block, @material)
    sensor result block @material
    Liest einen Wert aus einem Block aus. Auslesbare Werte beginnen mit @. Beispiele @scrap, @slag, @totalAmmo
    result = GetLink(index)
    getlink result index
    Gibt ein Handle zum mit dem Prozessor verbundenen Objekt an einem bestimmten Index zurück



    Mathe (Wrapped)
    Mindustry Logic
    Beschreibung
    result = And(a, b)op land result a bLogisches und
    result = Or(a, b)op or result a bLogisches oder (hier: Äquivalent zu BitOr)
    result = BitOr(a, b)
    op or result a bBitwise OR
    result = BitAnd(a, b)
    op and result a bBitwise AND
    result = BitXor(a, b)
    op xor result a bBitwise XOR
    result = BitNot(a)
    op not result a 0Bitwise NOT
    result = BitShl(a, b)
    op shl result a bBitShift, shifts "a" by "b" bits to the left
    result = BitShr(a, b)
    op shr result a bBitShift, shifts "a" by "b" bits to the right
    result = Sin(a)
    op sin result a 0Sinus im Gradmaß
    result = Cos(a)
    op cos result a 0Cosinus im Gradmaß
    result = Tan(a)
    op tan result a 0Tangens im Gradmaß
    result = ASin(a)
    op asin result a 0Arkussinus im Gradmaß
    result = ACos(a)
    op acos result a 0Arkuscosinus im Gradmaß
    result = ATan(a)op atan result a 0Arkustangens im Gradmaß
    result = ATan2(a, b)
    op angle result a b
    Arkustangens2 im Gradmaß (TODO: Check wo hier x und y ist, da ATan2(y, x) üblich ist)
    result = Max(a, b)
    op max result a bGibt den größeren der beiden Werte zurück
    result = Min(a, b)
    op min result a bGibt den kleineren der beiden Werte zurück
    result = Angle(a, b)
    op angle result a bAlias für ATan2
    result = Len(a, b)
    op len result a bGibt die Länge des Vektors [a, b] zurück. (result = Sqrt(a^2 + b^2))
    result = Noise(a, b)
    op noise result a bGibt den Werte eines 2D Noisegenerator mit 2 Koordinaten zurück
    result = Abs(a)
    op abs result a 0Gibt den Absolutwert von a zurück
    result = Log(a)
    op log result a 0Gibt den Logarithmus zur Basis e von a zurück
    result = Log10(a)
    op log10 result a 0Gibt den Logarithmus zur Basis 10 von a zurück
    result = Floor(a)
    op floor result a 0
    Rundet a ab
    result = Ceiling(a)
    op ceil result a 0Rundet a auf
    result = Sqrt(a)
    op sqrt result a 0Quadratwurzel aus a
    result = Random(a)
    op rand result a 0Gibt eine float Zufallszahl zwischen 0 und a zurück.
    Calls (Wrapped)
    Mindustry Logic
    Beschreibung
    Lightcolor(block, col)
    control color block col 0 0 0
    Setzt die Farbe eines Illuminierers
    Print(string)print stringSchreibt eine Zeichenkette in den Printbuffer
    PrintFlush(message)printflush messageSchreibt den Printbuffer in den Messageblock
    Write(value, cell, index)
    write value block indexSchreibt den Wert value in die Speicherzelle an Position index. Gegenstück zu Read().
    Sleep(seconds)sleep secondsUnterbricht das Programm für eine vorgegebene Zeit in Sekunden (nicht Millisekunden)
    Enabled(block, flag)control enabled block flag 0 0 0Aktiviert (flag = 1) oder deaktiviert (flag = 0) einen Block
    DrawCalls (Wrapped)
    Mindustry LogicBeschreibung
    Stroke(width)draw stroke width 0 0 0 0 0Setzt die Stiftbreite für Zeichnungen
    Color(R, G, B, A)
    draw color R G B A 0 0Setzt die Füllfarbe
    Color(%RRGGBBAA)draw col %RRGGBBAA 0 0 0 0 0Setzt die Füllfarbe (anderes Format... warum ein Prozentzeichen... wessen Idee war das?!)
    Clear(R, G, B)
    draw clear R G B 0 0 0Füllt den Drawbuffer vollkommen mit einer Farbe
    Image(x, y, @image, size, rotation)
    draw image x y @image size rotation 0Zeichnet das Bild @image (z.B. @copper) an die vorgegebene Stelle
    DrawFlush(display)drawflush displayZeichnet den Drawbuffer auf das Display
    LinePoly(mX, mY, n, radius, angle)
    draw linepoly mX mY n radius angle 0
    Zeichnet ein gleichseitiges Polygon mit Mittelpunkt [mX, mY], n Seiten, radius (in Pixeln) und Drehwinkel
    Triangle(x1, y1, x2, y2, x3, y3)
    draw triangle x1 y1 x2 y2 x3 y3
    Füllt ein Dreieck
    LineRect(x, y, w, h)
    draw linerect x y w h 0 0
    Zeichnet ein achsenausgerichtetes Rechteck
    Line(x1, y1, x2, y2)
    draw line x1 y1 x2 y2 0 0Zeichnet eine Linie
    Rect(x, y, w, h)
    draw rect x y w h 0 0Füllt ein achsenausgerichtetes Rechteck
    Poly(mX, mY, n, radius, angle)
    draw poly mX mY n radius angle 0Füllt ein gleichseitiges Polygon mit Mittelpunkt [mX, mY], n Seiten, radius (in Pixeln) und Drehwinkel
    Kontrollfluss (Wrapped)
    Mindustry Logic
    Beschreibung
    Goto(int)jump int always 0 0
    Springt zu einer Programmzeile (Zeile im Mindustry Logic code, NICHT im Code den man schreibt)
    Goto(var)set @counter var
    Springt zu einer variablen Programmzeile (Zeile im Mindustry Logic code, NICHT im Code den man schreibt)
    If (a operation b) Goto(int)
    jump int operation a b
    Contitional Goto
    ExitstopHält den Prozessor permanent an (gleichbedeutend mit "Beendet das Programm")
    ResetendStartet den Prozessor neu
    Sonstige (Wrapped)
    Mindustry LogicBeschreibung
    ShootP(block, unit, shoot)
    control shootp block unit shoot 0 0
    ...?
    Config(block, flag)
    control config block flag 0 0 0...?
    Shoot(block, x, y, shoot)
    control shoot block x y shoot 0...?
    var = a
    set var a
    A kann Variable, Zahl oder String sein
    var = a operation b
    op operation var a b
    A und B können Variable, Zahl oder String sein. Operationen: [+ - * / ^ % = < > == != <> <= >= //]
    Manche Operationen sind Äquivalent wie z.B. = und ==, sowie != und <>.
    var operation= a
    op operation var var a
    A kann Variable, Zahl oder String sein. Operationen [+= -= *= /= ^= %= //=]
    Radar(...)-Nicht implementiert (Stand v0.2)
    Unit(...)-Nicht implementiert (Stand v0.2)
    Additional Functionality (Stand v0.1)
    Substitution
    Beschreibung
    #myLabel-Ein Label zu dem man springen kann
    Goto(#myLabel)jump #mylabel always 0 0
    #myLabel wird zu int resolved
    If (Expression)
    ...
    EndIf

    -Erlaubt einen Codeblock konditional auszuführen
    If (var)
    ...
    EndIf

    If (var != 0)
    ...
    EndIf

    Verpackung für alleinstehende Variablen
    If (!var)
    ...
    EndIf

    If (var = 0)
    ...
    EndIf

    Verpackung für alleinstehende Variablen
    For (i = 0, i < 9, i++)
    ...
    Next

    -Führt einen Codeblock mit Zählervariable mehrfach aus. Obacht, keine Semikolons, sondern Kommata.
    var++op add var var 1Inkrement (kein Returnwert, also var1 = var2++ geht nicht)
    var--op sub var var 1Dekrement (kein Returnwert, also var1 = var2-- geht nicht)
    Enable(block)Enabled(block, 1)Aktiviert einen Block
    Disable(block)Enabled(block, 0)Deaktiviert einen Block
    ContinueLoop-Springt wieder zum Anfang des aktuellen Loops (z.B. nächste Runde einer For-Schleife)
    ExitLoop-Springt aus dem aktuellen Loop heraus (z.B. eine For-Schleife)
    Additional Functionality (Stand v0.2)
    SubstitutionBeschreibung
    result = Chance(percentage)result = Random(1)
    result = result < percentage

    Gibt mit einer gewissen Wahrscheinlichkeit 0 oder 1 aus
    result = Random()
    result = Random(1)
    Gibt einen Zufallswert (float) zwischen 0 und 1 aus
    result = Random(min, max)
    result = max - min
    result = Random(result)
    result += min

    Gibt einen Zufallswert (float) zwischen min und max aus
    Loop
    ...
    EndLoop

    -
    Führt einen Codeblock ohne Zählervariable endlos aus.
    Sub mySub()
    ...
    EndSub

    -
    Versieht einen Codeblock mit den nötigen Labels um ihn später von außerhalb anspringen zu können
    Der Raum innerhalb der Subroutine ist NICHT abgekapselt, es gibt keine Lokalen Variablen, keine Parameter,
    keine Returnwerte und sonst auch nichts (Stand v0.2).
    mySub()-Springt zum Codeblock "mySub" und führt ihn aus. Springt automatisch wieder zurück
    myArray = Array(cell)
    ...Verwendet "myArray" als Alias für den Parameter "cell" in zukünftigen Array-Funktionen
    result = myArray[index]
    result = Read(cell, index)
    Erfordert vorheriges verwenden von "myArray = Array(cell)"
    myArray[index] = value
    Write(value, cell, index)
    Erfordert vorheriges verwenden von "myArray = Array(cell)"
    If (...)
    ...
    Else
    ...
    EndIf

    -
    Unterstützung von Else



    Ggf. hau ich dich demnächst mal an, auf Steam gibts das Spiel ja für kleines Geld!

    Das Spiel ist kostenlos, wenn du es von der Entwicklerseite (https://github.com/Anuken/MindustryBuilds/releases) als .jar herunterlädst. Mindustry war (glaube ich) schon immer ein "Pay what you want" Spiel. Niemand "muss" bezahlen, aber jeder "kann" bezahlen so viel oder so wenig er möchte.


    Wie ist der aktuelle Stand?

    Ich weiß garnicht wie man das sinnvoll auflistet, da ich nicht Buch führe was ich mache^^

    Sachen die "jetzt" (bei mir, die Version im Startpost kann das nicht) gehen und vorher nicht gingen:
    - If () ... (ohne then)
    - If Else Endif (das else ist neu)
    - Random(min, max)
    - Chance(number between 0 and 1) (gibt true/false aus)
    - Loop ... Endloop (einfach ein "unendlicher" loop ohne counter)
    - Bugfixes (Das sind die wichtigsten, vorallem die andauerenden crashes wenn man die syntax falsch hat... aber da gibts noch hunderte, also vllt ein autosave feature einbauen^^)
    - Vermutlich noch 10 Sachen die ich einfach vergessen habe.

    TODO (danach gibt es hier ein Update)

    - Array Datenstruktur (braucht eine Speicherzelle)

    - Stack Datenstruktur (braucht eine Speicherzelle)

    - Diese dämliche Syntax ändern die ich mir vorher ausgedacht habe in der "//" Kommentare einleutet und "/%" die Integerdivision ist. Außerdem ist "^" aktuell xor. Das wird alles geändert, wir sind hier nicht bei C.

    - Subroutines (ausnahmsweise mal etwas "anderes" als Funktionen)
    - Syntax ist:

    Code
    Sub MySub()
      do something
    EndSub

    - Erstmal ohne alles (ohne Parameter etc.) Das Problem ist der Overhead bei "Funktionen". Im Prinzip muss man ja einen Parameterstack & Returnstack (die brauchen eine Speicherzelle im Spiel, laufen also nicht zu 100% auf dem Prozessor) etc. haben. Alles davon braucht ziemlich viele Takte, gibt aber auch ziemlich viele Möglichkeiten (z.B. Rekursion). Daher wird es die Trennung zwischen "Subroutine" = "Funktion die keine Rekursion kann und zu 100% auf dem Prozessor läuft" und "Funktion" = "Funktion die eine Speicherzelle braucht und alle üblichen Freiheiten beinhaltet" geben. Subroutines will ich auch so gestalten, dass man sie inlinen kann.


    Auch wichtig ist eine vollständige Dokumentation... Ich habe viele Logic Compiler ausprobiert (ich bin ja nicht der erste der einen gebastelt hat) und bei keinem einzigen gibt es eine Dokumentation. Also kann außer dem Ersteller des Compilers niemand damit etwas anfangen...

    Im alten Code ist das in script_parser.cpp::Parser_Keyword_DIM (1920) mit bReDim = True. In den Kommentaren steht aber, dass ReDim eine eigene Funktion bekommen soll, also wird das nach 10+ Jahren wohl nicht mehr genau so sein wie es dort ist^^

    Und so wie ich das dort sehe wird hier ebenfalls ein neues Array angelegt und eine komplette Kopie gemacht (lustigerweise "von Hand", vermutlich weil kein Standardcontainer verwendet wird, also das "Array" ist zusammengesetzt aus einem ->Data Feld (pointerliste auf Variants, also **Variant) und irgendwelchen Extras um die Indices zuzuordnen)...

    Edit2: realloc? Wahre Meister verwenden "new" :D


    Edit: In den Code schaue ich immer rein, wenn ich mich gut fühlen will :D

    Ich bin nicht sicher, ob sich das AutoIt-Intern geändert hat, aber kürzlich habe ich jede Menge Timings aufgenommen, und ReDim war eines davon. Und es sieht so aus, als würde ReDim grundsätzlich "alles was danach noch vorhanden ist" kopieren, egal ob man die Größe gleich lässt, vergrößert, oder verkleinert.

    Das Ergebnis müsste sein, dass alle 3 Versionen (verkleinern, vergrößern, gleichlassen) genausoviel Zeit beanspruchen, obwohl z.B. verkleinern um 1 element intern eigentlich nur "eine einzige integer substraktion" sein sollte und damit im Nanosekundenbereich liegen sollte, genauso wie ein ReDim ohne Größenänderung...


    lg

    M

    Ich dachte, dieses Thema schon einmal hier im Forum angesprochen zu haben, du hattest übrigens dazu auch ein Script gepostet... :P

    Das ist der Beweis dafür, dass ich jetzt auch "zu den alten" gehöre. Ich habe selbst absolut keinen Überblick mehr über das was ich die letzten 10+ Jahre hier gepostet habe^^


    lg

    M

    Keyboardstate ist quasi "IsPressed" für alle Tasten gleichzeitig. Um das zu nutzen müsste man extrem oft Abfragen machen und quasi (hier 256) alle Keys andauernd abfragen um zu schauen ob etwas gedrückt wurde. Das ist für ein "paar wenige" Keys ggf eine gute Idee, aber wenn ich ca. 150 mögliche Keys überwachen muss, nur damit ab und zu einer davon gedrückt und erkannt wird, dann sind 99.9% der Abfragen nutzlos^^

    Damit auch schnelle Tastendrücke erfasst werden wäre man außerdem gezwungen mit hoher Frequenz zu prüfen (da die Events hier ungepuffert sind).


    Ich lass die Idee noch ein bisschen sacken, und dann wirds wahrscheinlich die Version von Oscar (Eigenes Window + Proc) mit sämtlichen Sachen die ich vergessen habe (wovon BugFix einige aufgezeigt hat). Wobei ich noch nicht ganz sicher bin, die WMs (ohne ein eigenes Window) sind auch verlockend, vermutlich weniger Komplexität in der Implementierung, dafür mehr Overhead. Allerdings ist laut der Hilfe WM_CHAR nicht immer nutzbar, wo das vermutlich am einfachsten wäre (auch in Bezug auf das Gedrückthalten von Tasten und Kombinationen von Tasten)...


    Da fällt mir direkt eine Frage ein: GUIRegisterMsg hat ja keinen Parameter für hWND. Hat ein Layered-Window dort einen eigenen Zugang (GuiSwitch und dann GUIRegisterMsg? Ich kenne mich damit leider nicht aus...), sodass ich z.B. WM_CHAR im Layered-Window registrieren kann (weil ich ja 100% sicher sein kann, dass ich kein Edit-Ctrl habe, also müsste WM_CHAR verfügbar sein)?


    Edit: Ich glaube ich bin da auf dem mentalen Holzweg. Kann es sein, dass die von RegisterMsg registrierten Funktionen mit den via SetWindowLong(..., WNDPROC, ...) registrierten Funktionen auf ein und dasselbe verweisen und diese Methode quasi die oben angesprochene GUIRegisterMsg Version "mit" HWND ist? Falls das so ist glaube ich es jetzt ansatzweise verstanden zu haben...


    Mensch, ein simples einfaches Texteingabefeld ist viel zu kompliziert... :rofl:


    lg

    M

    Moin,


    Um einem XY Problem vorzubeugen gleich vorweg das Ziel: Ich möchte ein GDI+ Ctrl basteln welches ähnlich zu einem Input-Ctrl arbeitet. (Texteingabe möglich). Außerdem soll es intern "keine" AutoIt-Ctrls verwenden, also kein "verstecktes" Ctrl das ausgelesen wird. Da das ganze angezeigt wird ist ein GUI vorhanden, RegisterMsg etc. funktioniert, GUIOnEventMode ist an. Die Tasten sollen nur gecaptured werden, wenn das GUI auch aktiv ist. Gedrückthalten von Tasten soll sich genauso verhalten wie man es vom InputCtrl gewohnt ist (also zunächst 1 Zeichen, dann kurze Pause, dann am laufenden Band neue Zeichen). Zu allem überfluss soll das ganze im Leerlauf möglichst wenig Performance brauchen, es wäre unschön, wenn ein Programm alleine 50% der Rechenzeit dafür aufwendet um ein InputCtrl zu verwalten.


    Anätze


    > IsPressed/Keyboardstate:

    - Sehr viel Code muss ausgeführt werden um anständig festzustellen was gedrückt wurde.

    - Kombinationen müssen von Hand ausgewertet werden (z.B. Shift + Taste)

    - Wird immer ausgeführt egal ob GUI aktiv ist, oder nicht.

    - Das Verhalten von "gedrückt halten einer Taste" muss manuell nachgebildet werden.


    > Hotkeys:

    - Unmengen Hotkeys müssen registriert werden.

    + Kombinationen wie Shift + Taste oder ähnliches ohne weitere Logik abrufbar.

    - Wird immer ausgeführt egal ob GUI aktiv ist, oder nicht.

    + Das Verhalten von "gedrückt halten einer Taste" wird unterstützt.


    > GUISetAccelerators:

    + Alle "Hotkeys" sind schnell und einfach initialisierbar (2D Array)

    + Kombinationen werden unterstützt.

    ? Belastet den GUIMessageLoop/EventLoop (wir sind im GUIOnEventMode, also werden die Accelerators -> Msgloop/Eventloop weitergeleitet) Keine ahnung "wie belastend" das ist, wenn da 150 Registrierungen drin sind.

    + Funktioniert nur wenn GUI aktiv.

    - Braucht "versteckte Ctrls" (DummyCtrl).

    ? Das Verhalten von "gedrückt halten einer Taste" wird unterstützt?


    > GUIRegisterMsg + Keymessages:

    + (glaube ich) Kombinationen werden unterstützt.
    + Belastet soweit ich weiß den Message/Eventloop nicht.

    ? Messages werden nur verschickt, wenn GUI aktiv?

    + (glaube ich) Man hat Zugriff auf zusätzliche Infos, weil lParam und wParam mehr als nur den Key der gedrückt wurde beinhaltet?

    ? Das Verhalten von "gedrückt halten einer Taste" wird unterstützt?


    Jetzt kommt die Frage: Was habe ich übersehen (gibt es noch weitere Wege?), und gibt es einen "richtigen" Weg bei der Sache?

    Einige Punkte habe ich mit Fragezeichen markiert, weil ich nicht genau weiß wie sich die Funktionen verhalten und weil ich nicht alles ausprobieren will.


    Hier braucht niemand irgendwelchen Code zu posten, alles was ich möchte ist (falls ihr etwas in der Art schonmal gemacht habt) eine Info wie man sowas richtig angeht.


    Meine Tendenz ist GUIRegisterMsg zu verwenden, aber vllt hat ja jemand hier mehr Erfahrung und kann mir einen Tipp geben.


    lg

    M

    Alina und Exit

    Klärt uns unwissende bitte auf. Ich bin mir fast sicher, dass ich Au3toCmd nicht verwenden werde, aber wenn jemand anderes mal ein Problem ähnlicher Art hat, wird er (sofern er weiß wie man die Suche benutzt) früher oder später hier landen (Keywords wurden in diesem Thread ja zu genüge verwendet). Dann wäre es schön, wenn hier ein Abschluss für offene Fragen steht.


    Was war das Problem?

    Was war der Bedienfehler?

    Wie vermeidet man den Bedienfehler?

    Ich glaube oh-ha meint damit, dass du aus der .png ein .ico machen sollst. Eigentlich willst du ja aber die .png so wie sie ist in einem Ctrl verwenden.


    Ich vermute, dass UEZ dafür eine Funktion hat (wahrscheinlich sogar 5 verschiedene für jeden nur erdenklicken Ctrltyp + GUIs). Habe auch etwas gegoogelt, aber nicht die richtige gefunden (nur eine die das komplette Fenster benutzt um eine .png anzuzeigen). Ich bin leider nicht fit mit Winapi & Sendmessage, sonst würde ich die 3 Zeilen selbst aufschreiben...


    lg

    M

    Vorab: Vielleicht habe ich einfach nicht gesehen, ob diese Funktionalität vorhanden ist. Dann ist dieser Beitrag obsolet.


    Vorallem wenn man mit z.B. Kugelkoordinaten, etc. arbeitet braucht man oft Intervalle (Range) mit inklusiven, oder exklusiven Rändern.

    z.B. Das Intervall [0, 2PI] ist NICHT dasselbe wie (0, 2PI). Dafür verwende ich gerne folgende Funktion:

    Das ermöglicht es einen kontinuierlichen Raum disket zu sampeln, während man gleichzeitig auswählen kann welchen Rand die Intervalle haben (Abgeschlossen, oder Offen).

    (Gilt natürlich in dieser Beispielfunktion nur für lineare Räume, wenn man hier eine Funktion anwendet wie x^2, dann stimmt das Sampling nicht mehr, sobald mindestens ein Rand offen ist)


    Das wäre ein Vorschlag für etwas das man hier ergänzen könnte (ich weiß aber nicht wie man das hier geschickt einbaut ohne unnötig viele Parameter zu haben, vielleicht wirklich via String parsing (also "(0, 1)" steht für das beidseitig offene Intervall, "[0, 1]" steht für das beidseitig abgeschlossene Intervall).


    lg

    M

    Ich kann hier nur über meine persönliche Meinung dazu sprechen (mögen andere mich korrigieren).

    Ich halte AdlibRegister für weitestgehend nutzlos. Eine (meiner Meinung nach) bessere Methode sind Funktionen mit Static Timer, da diese an einem Ort ausgeführt werden den "ich" festlege, während AdlibRegister Funktionen "überall" aufgerufen werden können und den Programmablauf damit durcheinanderbringen (außer man hat seine Programmstruktur extra darauf ausgelegt).


    Beispiel:

    Man kann diese Funktionalität auch Wrappen, sodass man z.B. eine Funktion hat die "SetTimer($xFunc, $ms)" hat, usw.


    Wenn du nicht willst, dass der Nutzer davon etwas mitbekommt musst du dafür sorgen, dass die Abfragen einzeln relativ schnell durchlaufen, dann kannst du im Mainloop z.B. immer ein paar Millisekunden zur Verfügung stellen um Abfragen abzuarbeiten. Sind diese Millisekunden aufgebraucht werden die restlichen Abfragen erst im nächsten Schleifendurchlauf angegangen. Sowas lässt sich mittels Queue + Timer regeln (z.B. Alle 5 Sekunden sollen 100 Abfragen gemacht werden, dann werden alle 5 Sekunden die 100 Abfragen in den Queue gesteckt (das geht sehr schnell), und in jedem Schleifendurchlauf werden ?? Millisekunden lang Abfragen bearbeitet bis der Queue leer ist. Da muss man aber aufpassen wenn Abfragen aus welchem Grund auch immer nicht abgearbeitet werden können, dann wird der Queue immer länger und das wollen wir ja nicht).


    lg

    M

    Plottest du das direkt aus AutoIt heraus? Falls ja - wie?

    Da muss ich dich direkt vorwarnen, das folgende ist keine UDF die es in die Öffentlichkeit geschafft hat. Sie ist in keinem guten Zustand und jedes Mal, wenn ich etwas plotten will baue ich genau die funktion die ich gerade brauche ein^^

    Die Funktion gibt es eigentlich nur, weil ich im Stil von _ArrayDisplay "schnell und einfach" eine Funktion haben wollte um Arrays anzusehen. Es gibt (auch hier im Forum) UDFs die Daten plotten können, ich schätze, wenn man es ernsthaft angeht sollte man mit so einer UDF eine Anzeige basteln...


    lg

    M

    Was ich in der SB gepostet hatte: https://imgur.com/a/wrzZjAa


    Die Version hier (nach einigen kleinen Anpassungen) funktioniert schonmal deutlich besser. Peaks in den angeschauten Frequenzen sind sauber, deutlich und ohne übertriebenes Überschwingen.


    Inputdaten (mit dem bloßen Auge erkennt man hier höchstens, dass da "irgendwas schnell schwingt", die 2te Schwingung sieht man selbst mit scharfem Blick nicht):


    amplitude der DFT (angepasst, sodass man über Frequenzbereiche gezielt drüberlaufen kann, wobei "eine Arraylänge" immer 2PI entspricht)

    (die X-Achse ist etwas doof beschriftet, der erste Peak ist NICHT bei 0.85, sondern tatsächlich etwa bei 1.0, also da wo er hingehört)


    Danke nochmal für die Hilfe :thumbup:


    lg

    M

    Achso, ich glaube ich habe den Unterschied zwischen FT und DFT immernoch nicht verstanden.

    Was ich dachte ist folgendes: Die Abtastfrequenz gibt an welche Frequenzen im Array überprüft werden, also dass ich z.B. soetwas wie "alle Frequenzen von 0 bis 5 in 0.1er Schritten" ablaufen kann. Vermutlich ergibt das im Grenzwert wieder eine kontinuierliche FT. Das muss ich wohl nachlesen :/


    Ein Glück, dass ich mit Signalverarbeitung nichts am Hut habe, sonst hätte man mich für so viel Blödheit bestimmt schon verprügelt :part:


    lg

    M