Ergebnis 1 bis 18 von 18

Thema: Expertenfrage (Rundungsfehler des Makers umgehen - wie?)

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1

    Expertenfrage (Rundungsfehler des Makers umgehen - wie?)

    Hi @all,

    kommt selten vor, dass ich eine Tech-Frage stelle ich weiß xD Aber die Lage ist ernst...

    Also. Ich entwickle gerade ein kleines Shooter-Script. Dabei beherrscht der Held eine Art "Spezialangriff", bei dem die Zeit einfriert. Dann erscheint an einer zufälligen Position nahe bei einem Gegner ein Zielfadenkreuz (per Pic), welches sich auf den Gegner zu bewegt. Sobald es sich über dem Gegner befindet, wird es rot (hier muss der Spieler Enter drücken um zu treffen) und sobald es wieder weiter weg vom Gegner ist, erhält es wieder seine normale Farbe (sobald es den Zielpunkt erreicht, gilt der Schuss automatisch als "verfehlt"). Der Start- und Endpunkt der Animation bilden eine Strecke, in deren exakter Mitte sich der Gegner befindet. Da die Startposition des Fadenkreuzes ein Zufallswert ist, wird die eigentliche "Zielposition" des Pics per Vektorrechnung berechnet:

    Ziel.X = Gegner.X + (Gegner.X - Ausgangspunkt.X)
    Ziel.Y = Gegner.Y + (Gegner.Y - Ausgangspunkt.Y)

    Wie ihr anhand des Anfangstextes schon lesen konntet, muss erstens der Spieler jederzeit dazu in der Lage sein, den Vorgang per ENTER zu unterbrechen (--> Trefferabfrage) und zweitens muss das Pic seine Farbe auf Rot und wieder zurück wechseln können. Das hier geht also NICHT

    <>Show Pic (1, Start.X, Start.Y)
    <>Move Pic (1, Ziel.X, Ziel.Y, 1.0s)

    Stattdessen wird die Strecke "zerstückelt" in Teilstücke von jeweils 0.1 Sekunden. Nehmen wir an, die Gesamtdauer der Pic-Bewegung von Anfang bis Ende dauert 2 Sekunden. Das bedeutet, dass wir 20 Teilstrecken zu jeweils 0.1 Sekunden haben. Rechnerisch bedeutet das, dass wir herausfinden müssen, wie die Pic-Position nach jeweils 0.1 Sekunden aussieht. Das geht so:

    Differenz_X = (Endpunkt.X - Anfangspunkt.X) / 20
    Differenz_Y = (Endpunkt.Y - Anfangspunkt.Y) / 20

    Momentane_Pic_Pos.X = Anfangspunkt.X + (time) * Differenz_X
    Momentane_Pic_Pos.Y = Anfangspunkt.Y + (time) * Differenz_Y

    ... wobei (time) für die Anzahl von durchgeführten Move-Pictures steht, beginnend bei 1.


    So weit, so gut. Jetzt das (im Endeffekt simple) PROBLEM:

    Differenz_X = (Endpunkt.X - Anfangspunkt.X) / 20
    Differenz_Y = (Endpunkt.Y - Anfangspunkt.Y) / 20

    ... ergibt KOMMAZAHLEN. Der Maker rundet die natürlich und das Pic landet an einem anderen Zielpunkt als mit dieser Formel vorausberechnet:

    Zielpunkt.X = Anfangspunkt.X + (Gegner.X - Anfangspunkt.X)*2
    Zielpunkt.Y = Anfangspunkt.Y + (Gegner.Y - Anfangspunkt.Y)*2

    Das wäre aber für mein Script absolut unabdingbar. Irgendwelche Vorschläge? Cherry vielleicht was Passendes bei der Hand? xD


    Greetz!



    Alan

  2. #2
    wie wäre es wenn du sobald der held enter drückst einfach das bild löschst? dann kannst du diese teilstrecken ersparen, es sei denn du willst eine ani des pics durchführen wenn die entertaste gedrückt wird. du könntest auch machen das das pild pixel um pixel ( was aber wohl bei gewissen winkel nicht geht (wenn x und y verhältnis nicht passt),

  3. #3
    Zitat Zitat von Mivey Beitrag anzeigen
    du könntest auch machen das das pild pixel um pixel ( was aber wohl bei gewissen winkel nicht geht (wenn x und y verhältnis nicht passt),
    Genau DAS ist ja das Problem. Stattdessen muss man hier mit Teilstrecken arbeiten.

  4. #4
    was ist wenn du bestimmst das die strecke durch irgendeine zahl teilbar sein soll, bestimme die koordinate des ziels, gehe von dieser zufällig in eine richtung aber zb. nur 5 pixel nach x und y, und das zielpunkt des bildes ist dann halt auf der anderen seite vom ziel, dh. du könntest die strecke in 10*1 pixel teilen ( ist nur ein beispiel)

  5. #5
    @Mivey: Ich will den Startpunkt aber zufällig haben, also

    Start.x = Gegner.X +/- Zufallszahl
    Start.Y = Gegner.Y +/- Zufallszahl

    und der Zielpunkt ist dann quasi die "gespiegelte" Strecke, sodass der Gegner wirklich exakt in der Mitte steht.

    Es wäre theoretisch möglich, als Zufallszahlen nur Vielfache von 20 zuzulassen (also 20, 40, 80 etc.), damit die Differenz in JEDEM Fall durch 20 teilbar ist, aber da 40 Pixel mir schon zu weit entfernt sind, fällt diese Methode leider auch flach.


    @Makenshi:

    *Runden* kann der Maker ja richtig (also mathematisch). Das ist nicht das Problem. Das Problem ist, dass beim Runden eine Ungenauigkeit entsteht, die bei mehrfacher Anwendung (wie hier) das eigentliche Ziel bei Weitem verfehlt. Es müsste eine Möglichkeit geben, die Rundungsungenauigkeit auszugleichen. Eliminieren kann man sie nicht, der Maker kann kein Pic auf der Position 23,5/67,54 darstellen. Halbe Pixel gibt's keine xD Mein Ansatz diesbezüglich:

    Der Rundungsfehler3 multipliziert mit dem Faktor X muss ein exaktes Vielfaches (Y) der Zahl 10000 ergeben.
    X entspräche dann der Anzahl von Schritten bis zur Addition. Der addierte Wert entspricht Y.

    Rundungsfehler3*X = 10000*Y

    ==> zwei Varis, eine Gleichung, nicht zu lösen.

    Lua könnte hier in der Tat helfen, da sich dort dann die Rundungsungenauigkeiten dahin gehend reduzieren könnten, da Lua mit Kommazahlen rechnen kann.


    !!!!

    Makenshi, das ist die LÖSUNG! Man berechnet die 20 Koordinatenpaare im Voraus und dividiert DANN durch den Multiplikator.
    Nochmal zum Mitdenken: Multipliziert man alle Werte durch ein Vielfaches von 10, rutscht das Komma nach hinten. Ich nehme hier zum Beispiel 10000. Der "Teilungsfaktor" ist hier natürlich 20, also 20 Animationsschritte.

    Also zum Beispiel:

    Pos1 = Anfangsposition * 10.000
    Pos2 = Anfangsposition * 10.000 + (Differenz / Teilungsfaktor)*10.000
    Pos3 = Pos2 + (Differenz / Teilungsfaktor) * 10.000
    etc.



    Und zum SCHLUSS dann:

    Pos1 = Pos1 / 10000
    Pos2 = Pos2 / 10000
    Pos3 = Pos3 / 10000


    Damit wird die Rundungsungenauigkeit nicht 20 mal angewandt, sondern de facto nur 1 mal. Und alles, was hinter der fünften Kommastelle ist, interessiert sowieso keinen xD


    Danke Makenshi, das war der entscheidende Denkanstoß!

    Geändert von Alan (14.01.2009 um 19:25 Uhr)

  6. #6
    dann nutz den PPC der kann mit relativ genauen gleitkommazahlen arbeiten. ( lua)

  7. #7
    Zitat Zitat von Alan Beitrag anzeigen
    @Makenshi:

    *Runden* kann der Maker ja richtig (also mathematisch). Das ist nicht das Problem. Das Problem ist, dass beim Runden eine Ungenauigkeit entsteht, die bei mehrfacher Anwendung (wie hier) das eigentliche Ziel bei Weitem verfehlt. Es müsste eine Möglichkeit geben, die Rundungsungenauigkeit auszugleichen. Eliminieren kann man sie nicht, der Maker kann kein Pic auf der Position 23,5/67,54 darstellen. Halbe Pixel gibt's keine xD Mein Ansatz diesbezüglich:

    Der Rundungsfehler3 multipliziert mit dem Faktor X muss ein exaktes Vielfaches (Y) der Zahl 10000 ergeben.
    X entspräche dann der Anzahl von Schritten bis zur Addition. Der addierte Wert entspricht Y.

    Rundungsfehler3*X = 10000*Y

    ==> zwei Varis, eine Gleichung, nicht zu lösen.

    Lua könnte hier in der Tat helfen, da sich dort dann die Rundungsungenauigkeiten dahin gehend reduzieren könnten, da Lua mit Kommazahlen rechnen kann.
    Lua wird dir definitv helfen dank Kommavariablen. ^^
    Mein Skript hat mir damals in dem Thema allerdings auch geholfen, da ich halt Divisionen mit dem Skript durchgeführt habe. So ließen sich die Fehler reduzieren, da zwar nicht MIT Nachkommastellen gerechnet wurde, jedoch wurde wenigstens soweit aufgerundet das keine großen Beträge verloren gingen. Der Maker rundet nämlich afaik nicht, sondern schneidet simpel ab.
    Dürften ja Integervariablen sein. ( Vorsicht, ohne Gewähr )

    Edit:
    Genau, du hast es. ^^

  8. #8
    der PPC eignet sich dafür aber nicht, da es relativ lange zum Starten braucht, da externen Programm (bis zu 1 Sek.!), und das bei jedem Aufruf.

    Der große Power Patch (v0.43b) kann dir da aber besser helfen, da er nebenher läuft.

    Bzw. bist du ja auch PP0.85-Betatester, daher könnte man da vllt auch was für dich "drehen".

  9. #9
    Zitat Zitat von Cherry Beitrag anzeigen
    Bzw. bist du ja auch PP0.85-Betatester, daher könnte man da vllt auch was für dich "drehen".
    ??? Seit wann bin ich Betatester? Da weiß ich ja gar nix davon *lol*

  10. #10
    LOL. Du hast du doch ganz ganz zu Beginn gemeldet, wie es dann soweit war, habe ich dir EIGENTLICH die Zugangsdaten geschickt. O.o

  11. #11
    Muss schon verdammt lange her sein, dass ich mich nicht mehr erinnern kann. Aber Zugangsdaten hab' ich garantiert keine bekommen, daran könnte ich mich nämlich mit Sicherheit erinnern.

  12. #12
    Alan, warum machst du das so komplizert? ^^

    Der Maker rechnet immer von links nach rechts, das heißt von links nach rechts summieren sich Rundungsfehler auf. Wenn du den Rundungsfehler erst ganz zum Schluss entstehen lässt, d.h. ganz rechts, dann kann sich da nichts aufsummieren:
    Code:
    position
    = start + (ziel-start)/20(gerundet)*teilstueck
    = (ziel-start)*teilstueck /20(gerundet) + start
    Bei jedem Teilstück, das was du als "time" bezeichnet hast, wird die Gesamtstrecke erneut geteilt. Da brauchst du dann keinen Patch, kein Lua und auch keine durch mal-tausend entsehende Riesenzahlen. Guck dir die Umstellung der Formelstücke genau an. Das ist sehr komprimierte Information.

    Im Maker heißt das dann:
    Code:
    position  = ziel;
    position -= start;
    position *= teilstueck;
    position += 10;
    position /= 20;
    position += start;
    das "plusgleich zehn" ist damit er nicht abschneidet sondern rundet.
    10 ist die Hälfte von 20. Er soll "abrunden", wenn die Zahl, die geteilt wird, bis zu 10 zu groß ist. Das macht er immer, indem er abschneidet. Aber er soll "aufrunden", wenn sie um mehr als 10 zu groß ist. Das kann der Maker ja eigentlich nicht. Mit dem Plus-zehn-Trick geht beides.

    Z.B. ist 47 um sieben zu groß. Er sollte eigentlich abrunden.
    Wenn wir 10 zu der Zahl addieren, schneidet er zum Glück immer noch ab, denn 57/20 ist kleiner als 3. Tada, ein Abrunden simuliert. Und natürlich ist es kein Glück sondern normal.
    Wenn sie mehr als 10 zu groß ist, sollte er eigentlich aufrunden. Aufrunden entspricht in den nächsten 20er-Bereich zu kommen und abzuschneiden. Wenn wir 10 z.B. zu 52 hinzuaddieren (52/20 müsste aufgerundet werden), kommen wir auf 62. Das befindet sich im nächsten 20er-Abschnitt und ergibt beim Durch-20-Teilen und Abschneiden 3. und 52/20 ist gerundet ja wirklich 3.
    Funktioniert also.

    Mathematisch lautet das Prinzip:
    Code:
    (Dividend+[Divisor/2])/Divisor
    = Dividend/Divisor + [Divisor/2]/Divisor
    = Dividend/Divisor + 0,5
    
    für [(Dividend/Divisor modulo 1) < 0,5] gilt: Dividend/Divisor + Nachkommastelle
    für [(Dividend/Divisor modulo 1) >= 0,5] gilt: Dividend/Divisor + 1,x
    Ersteres ist die Abrundebedingung und enspricht beim Abschneiden dem Abrunden.
    Zweiteres ist die Aufrundebedingung und enspricht beim Abschneiden dem Aufrunden.

    Mathe statt Umstand.


    CapSeb

    Geändert von CapSeb (18.01.2009 um 00:00 Uhr)

  13. #13
    Du kannst den PP Compact benutzen. Der erlaubt es Berechnungen per LUA durchzuführen und fertig gerundet zurückgeben zu lassen.

    Alternativ hatte ich so ein Problem auch mal. Hab damals nen kleines Eventskript dazu geschrieben:


  14. #14
    Zitat Zitat von Alan
    De facto ist meiner Meinung nach die Multiplikation mit 10.000 (oder einer noch höheren Zahl) die einzig wirklich gangbare Möglichkeit zur effektiven Lösung dieses Problems mit den Mitteln, die einem im RPG-Maker zur Verfügung stehen. [...]
    Von daher könnte es durchaus sein, dass man einmal auf den Trick von CapSeb zurückgreifen muss...
    Naja, man muss es so sehen: Der zweite Teil meines Posts bezieht sich auf das "+10". Wenn man will, kann man das einfach weglassen.
    Dann gilt es nur noch jedes Mal zu rechnen:

    Code:
    position  = ziel;
    position -= start;
    position *= teilstueck;
    position /= 20;
    position += start;
    Verbrauchte Variablen sind dabei vier Stück - "start", "ziel", "teilstück" und "position". Das Ganze in einem Loop 20 Mal ausführen, das war's. Und die Abweichung beträgt dann null oder ein Pixel. Niemals mehr.
    Gangbar, wie du es nennst, ist es auf jeden Fall. Ich mache das selbst immer so, mit guten Ergebnissen. Beim Mal-10000 musst du darauf achten, nicht die Variablen-Obergrenze zu überschreiten. Auch wenn das hier nicht der Fall sein dürfte, schrecke ich deswegen allgemein davor zurück.
    Aber nimm es am besten als allgemeine Wissenserweiterung. Das Mal-10000 ist ein funktionierendes Prinzip. Beim nächsten Problem brauchst du aber vielleicht eine andere Lösung.


    CapSeb

    kommen wieder die Mathematiker daher, ellenlange Formeln im Gepäck...
    Ist doch nicht lang! Guck dir mal wirklich lange Formeln an! ^^

  15. #15
    Zitat Zitat von CapSeb Beitrag anzeigen
    Aber nimm es am besten als allgemeine Wissenserweiterung. Das Mal-10000 ist ein funktionierendes Prinzip. Beim nächsten Problem brauchst du aber vielleicht eine andere Lösung.
    Ich nehme es auf jeden Fall als "allgemeine Wissenserweiterung", denn das kann nie schaden! Und gerade beim Maker braucht man OFT alternative Lösungen xD

    Zitat Zitat von CapSeb Beitrag anzeigen
    kommen wieder die Mathematiker daher, ellenlange Formeln im Gepäck...
    Ist doch nicht lang! Guck dir mal wirklich lange Formeln an! ^^
    Einfach zu sagen, dass man im Zähler des Bruches die Hälfte des Nenners dazuaddieren muss, um den Maker "richtig" runden zu lassen, hätte allerdings auch leicht ausgereicht xD Geht auch so - ganz ohne Formel xD Trotzdem danke für alles ^^


    Greetz!


    Alan

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •