Hello, Guest the thread was called6.1k times and contains 52 replays

last post from remaxx at the

Sprite in bestimmte Richtung bewegen

  • Hallo Assembler Programmierer ;)
    Schon wieder mal ein Sprite der fliegen lernen soll!


    Ich bastle an einem Befehl der ein Sprite im Interrupt in einer bestimmten Richtung mit einer bestimmten Geschwindigkeit losschicken soll. Sehr ähnlich wie der MOVSPR Befehl vom C128.


    Code
    1. sys6666,spritenr,angle,speed


    Ich bin soweit das die Parameter übertragen werden und der Sprite im Interrupt nach rechts bewegt. (ohne Gebrauch der Parameter)


    Eine x und y Geschwindigkeit könnte ich mit cos(angle) und sin(angle) berechnen da das nur Einmalich bei der Ausführung des Befehls geschieht. Eine Tabelle wäre zwar schneller, aber braucht auch viel mehr speicher.
    Ich denke auch das eine Aufteilung in Quadranten sinnvoll wäre.


    Aufgerufen wird mit:

    Code
    1. sys6666,n,a,s
    2. sys6666,1,11,1


    Die Parameter müssen zwar mit angegeben werden, stehen aber noch nutzlos am Ende des Programms.


    Mein Problem:
    Wie implementiere ich eine x, y „Geschwindigkeit“ in die 50x pro Sekunde Interruptschliefe?




    EDIT by remaxx: Fred gecleant !

  • dafür nimmst du am besten eine fixedpoint zahl als zähler.... zb so


    Code
    1. lda count
    2. clc
    3. adc #speed
    4. sta count
    5. lda position
    6. adc #0
    7. sta position


    du erhöhst quasi die auflösung der position, so das du jeden frame einen bruchteil eben jener aufaddieren kannst und damit auch (fast) beliebige geschwindigkeiten erzielen kannst. wenn du auch schneller als 1 pixel pro frame bewegen willst das ganze entsprechend umfrickeln das auch auf den ganzzahligen anteil der position addiert wird.


    (und ich würde statt 360 grad lieber 256 als teilung für den kreis benutzen, das macht vieles einfacher und schneller)

  • (und ich würde statt 360 grad lieber 256 als teilung für den kreis benutzen, das macht vieles einfacher und schneller)

    OK, die paar Prozent Auflösungsverlust sind weiter nicht schlimm.


    speed_x ist der cos mal 16, also eine Zahl von 0 bis 15
    Für speed_y ist’s der sin.


    Ich lasse also den Carry entscheiden ob das Sprite (position) ein Pixel verschoben wird?


    Dein Beispiel für position_x und nochmal für position_y? Und das Ganze dann für jeden Quadrant.


    Na, dann versuche ich das mal um zu setzen, könnte aber was dauern.

  • Ich lasse also den Carry entscheiden ob das Sprite (position) ein Pixel verschoben wird?

    Wäre eine Interpretation. Man kann das aber auch so sehen, daß Du ein Byte "Nachkommastelle" für die Positionen hast. Wenn man die Label ein bisschen umbenennt, aus Position eine 24Bit-Zahl, aus Speed eine 16Bit-Zahl macht, dann erkennt man auch leicht, was Sauhund mit Tempo > 1 Pixel/frame meint.


    Code
    1. lda position
    2. clc
    3. adc speed
    4. sta position
    5. lda position+1
    6. adc speed+1
    7. sta position+1
    8. lda position+2
    9. adc#0
    10. sta position+2


    Position+1 ist dann die Sprite-Position, Position+2 das MSB für die X-Richtung.

  • Aha, wenn ich dann für speed den Wert 128 nehme, bewegt der Sprite sich jeden zweiten Durchlauf.

    erkennt man auch leicht, was Sauhund mit Tempo > 1 Pixel/frame meint.

    Nehme ich 512 bewegt er sich zwei Pixel pro Durchlauf.
    mit einem Faktor und Offset könnte ich dann noch anpassen bis zum gewünschten Resultat.

  • exakt. \o/


    bei der art steuerung wie du sie da vor hast würde man idr regel das ganze folgendermassen aufziehen:


    - x/y vektor abhängig vom aktuellen drehwinkel aus einer tabelle auslesen (sinus und cosinus)
    - diesen vektor abhängig von der gewünschten geschwindigkeit skalieren (multiplizieren) (*)
    - und den vektor auf die aktuelle position aufaddieren
    (letzteres jeden frame, den rest nur wenn sich winkel und/oder geschwindigkeit ändern)


    der nächste schritt wäre dann nicht den geschwindigkeitsvektor ansich zu nehmen, sondern diesen als beschleunigungsvektor zu behandeln, was wiederum dazu führt das die position bzw das bewegte sprite in bekannter art und weise um die kurve "driftet", beim bremsen verzögert usw. dazu wird das ganze einfach ein bischen erweitert:


    wenn sich winkel und/oder beschleunigung ändert:
    - x/y vektor abhängig vom aktuellen drehwinkel aus einer tabelle auslesen (sinus und cosinus)
    - diesen vektor abhängig von der gewünschten beschleunigung skalieren (multiplizieren) (*)
    - und als beschleunigungvektor merken


    jeden frame: (für das klassische "top view" spiel)
    - beschleunigungsvektor auf den geschwindigkeitsvektor aufaddieren
    - geschwindigkeitsvektor auf die aktuelle position aufaddieren
    - geschwindigkeitsvektor durch einen festen wert teilen. dieser gibt quasi den "grip" an (0: weltraum, keine reibung - gross: viel reibung und kein drift, verhält sich dann wie oben)


    alternativ (für jump'n'run)
    - beschleunigungsvektor auf den geschwindigkeitsvektor aufaddieren
    - gravitationsvektor auf den vertikalen teil des geschwindigkeitsvektors aufaddieren
    - geschwindigkeitsvektor auf die aktuelle position aufaddieren
    - sofern "bodenkontakt", horizontalen teil des geschwindigkeitsvektors durch einen festen wert teilen.


    (*) das kann man sich oftmals sparen und kommt mit einem fixen wert, oder einer sehr begrenzten anzahl tabellen, aus.


    (ich hoffe ich hab mich nich vertüddelt :))

  • Das ist ausführlicher als es nötig war! Es soll ja nur eine Kopie vom MOVSPR-Befehl werden. Später kommt dann noch eine Kollisionsabfrage, verknüpft mit einem GOTO in einem Befehl. Aber ich kann dir Global folgen. (umsetzen in Code ist ne andere Sache :))


    - x/y vektor abhängig vom aktuellen drehwinkel aus einer tabelle auslesen (sinus und cosinus)

    Soll ich die 360 Grad runter skalieren von 0 bis 255? Und dann eine Tabelle mit 255 Werten für sin und 255 für cos? Ist aber schade um den Speicher, der mir für die BASIC-Erweiterung woran ich bastele kostbar ist. Wie auch immer, werde mich erst mal an die Arbeit machen...

  • Ich habe hier eine Kreisfahrt von einem Sprite mit 360 Grad mit dem cc65.
    Wird berechnet aus Integerwerten. Die Gradzahl habe ich mit 8192 multipliziert, damit man das Ergebnis schneller shiften kann mit 13. Es wurden hier mit 32Bit geproggt um das Ergebnis möglichs genau zu bekommen als Integerwert.


    Wenn man mit den Sin/Cos-Daten tricks mit Viertelkreis usw wird der Platzbedarf noch reduziert.


    Mit dieser Tabelle kann man jetzt auch ein Sprite in einer bestimmten Richtung mit einer festen Geschwindigkeit und den Weg auf die Reise schicken.


  • Es geht langsam aber stetig voran. Etwas mehr Struktur und 0-90 Grad funktioniert jetzt.


    Wenn man mit den Sin/Cos-Daten tricks mit Viertelkreis usw wird der Platzbedarf noch reduziert.

    genau das habe ich gemacht :), die sin- und cos- Tabelle von 0 bis 90 Grad habe ich einfach mit Excel generiert.


    Zur Vereinfachung ist das Programm von 0-90 Grad. Für die Geschwindigkeitsanpassung gehe ich von der langsamste Geschwindigkeit „1“ aus(„0“ soll anhalten/stop sein). Ich habe sprite_0_speed_x und sprite_0_speed_y 24-bit genommen um in beide Richtungen genug Spiel zu haben. Ich habe durch 8 geteilt, das ist mir vorerst langsam genug.


    Frage: Ist das teilen einer 24-bit Zahl durch 2 richtig so mit lsr ror ror angefangen mit dem msb? Sehe add_speed im Code.


    Speed soll jetzt der Multiplikationsfaktor werden für sprite_0_speed_x und sprite_0_speed_y.




  • Quote

    Frage: Ist das teilen einer 24-bit Zahl durch 2 richtig so mit lsr ror ror angefangen mit dem msb? Sehe add_speed im Code.


    jein. sofern diese zahl positiv ist, ja. wenn sie negativ ist willst du oben aber eine 1 reinschieben und keine 0. bei zahlen die beides sein können kann man dann zb sowas machen:
    lda m+2
    asl ; 1bit nach links, msb landet im carry
    ror m+2 ; und landet hier wieder im msb
    ror m+1
    ror m+0

  • bei zahlen die beides sein können kann man dann zb sowas machen:
    lda m+2
    asl ; 1bit nach links, msb landet im carry
    ror m+2 ; und landet hier wieder im msb
    ror m+1
    ror m+0

    Gut zu wissen, hatte ich in der Tat nicht berücksichtigt. Bei der Mult. nicht notwendig da das Produkt sowieso positiv ist.


    Wäre es vielleicht nützlicher, nicht 6mal nach rechts, sondern 2mal nach links zu schieben und andere Bytes auszulesen?

    in diesem Fall ja, aber ich hab das schon zu einer schleife geändert damit ich die Anzahl der Teilungen variabel habe.


    Könnt ihr bitte mal ein veständliches Beispiel bringen was funktioniert mit 32bit für positive und negative Zahlen.
    Irgendwie kommt hier keine Lösung raus, ist so ein Eiertanz...

    Da muss ich dich aber wiedersprechen, ich werde hier sogar SUPER geholfen. Im Buch „Maschinenorientierte C64-Programmierung“ von Jim Butterfield steht das auf Seite 51 noch mal sehr gut erklärt. PN falls du das Buch nicht haben solltest.