Seite 1 von 3

Bufferwechsel und Draw-Initialisierung bei Spriterotationen

Verfasst: 07.12.2004 23:13
von Kekskiller
Ich bin gerade dabei, ein paar kleine Effekte in mein Spielchen einzubauen,
nur kommen da arge Probleme mit Wechsel der Buffer während des Lesens
und Zeichens auf dem Bildschirm und einer Sprite auf. Beispiel:

Code: Alles auswählen

Procedure DrawRotatedSprite(sprite.l, x.w,y.w, rot.w)
If IsSprite(sprite) <> 0
  w.w = SpriteWidth(sprite)
  h.w = SpriteHeight(sprite)
  ;...
  For zy.w = 0 To h-1
    ry = y + Cos(rot) * zy
    For zx.w = 0 To w-1
      rx = x + Sin(rot) * zx
      If rx <= #TMP_Screen_Width And rx >= 0
        If ry <= #TMP_Screen_Height And ry >= 0
            ;...
            c.l = Point(zx,zy)
            ;...
            Plot(rx,ry,c)
            ;...
        EndIf
      EndIf
    Next
  Next
  ;...
EndIf
EndProcedure
Bei dieser Funktion soll eine Sprite in einem bestimmten Winkel rotiert
dargestellt werden. Ich gehe Punkt für Punkt durch und drehe den nächsten
Punkt entsprechend zum Winkel in den Parametern. Theoretisch müsste
ja auch prima funktionieren, nur bin ich mit der Geschwindigkeit des Ganzen
nicht zufrieden, und damit meine ich den Wechseln von den verschiedenen
Ausgabeflächen, sprich Sprite und Screen. Ich hatte zuerst versucht, bei
Point und Plot jedesmal Startdrawing anders einzusetzen (die Ausgabefläche
zu ändern), was aber wegen der kleinen Verzögerung arg in die Hose ging.
Desweiteren grübelte ich über ein Möglichkeit irgendwie alles per Sprites
zu lösen, auch nen Fehlschlag. Dann die bescheuerteste, aber doch effektivste
und schnellste Möglichkeit: Vorberechnen. Aber das will ich nicht, kostet
Zeit und verstopft Speicher. Ist zudem für so ein Minispiel zu aufwendig.
Gibt es eine Möglichkeit, in irgendeiner Weise einen schnellen und
unkomplizierten Wechseln zwischen den Ausgabeflächen zu produzieren?
Die ;... - Punkte sind Stellen, an denen ich mir gedacht habe, dass gezielt
plazierte Bufferwechselbefehle hilfreich wären, aber helfen tuhen sie mir
jetzt auch nicht wirklich...

Btw: Irgendwie will der Code auch so nicht funktionieren. Ist die Überlegung
denn komplett falsch?

Verfasst: 08.12.2004 15:08
von PMV
Ich hab mir das jetzt nicht ganz genau angeschaut, ... aber auf Purearea.net gibs im CodeArchive ein Beispiel, wo ein Sprite gedreht wird.

Unter Codearchive -> Graphic -> DrawingBuffer -> DrawingBuffer.pb
Downloadlink: http://www.purearea.net/pb/CodeArchiv/G ... gBuffer.pb

Eine andere möglichkeit wäre doch, das ganze mit der Sprite3D Library zu machen. Oder gibs da gründe, warum du die Rotation unbedingt selber programmieren willst?

Also, ob der gedankengang selber jetzt komplet Falsch ist, kann ich nicht beurteilen. Aber so fern an deinem code oben in der Procedure nichts fehlt, so fällt mir auf, das du vom Screen oben links ließt. Ist dort überhaupt das gewollte Sprite angezeigt? Und was wäre, wenn x.w und y.w auch nahe an den Koordinaten 0,0 wären? ... Dann würdeste doch das vorhanden Sprite übermalen und so könnte das nicht funktionieren :D .

MFG PMV

Verfasst: 08.12.2004 19:25
von NicTheQuick
Außerdem solltest du lieber mal Longs verwenden und keine Words. Longs sind zwar auch nur einen Tick schneller, aber immerhin.

Verfasst: 08.12.2004 19:39
von Robert Wünsche
genau, weil der PC mit 32 bit rechnet, bei long sinds 4 byte, aber bei word nur 2, also muss der speicher selektiert werden, damit der PC das normal berechnen kann, und das kostet halt zeit !

PS: bei einem Bild mit einer größe von 100 mal 100 punkten sind das 10'000 Punkte, bei denen der Cos / sin wert berechnet werden muss.
Das ist jede menge arbeit.

Verfasst: 08.12.2004 21:06
von Stefan
@Kekskiller
Ich habe vor kurzem diese Funktion programmiert: :D

Code: Alles auswählen


;Achtung:
;Benötigt die Userlibs E2D und SpriteEx.

Procedure PutRotatedSprite(Sprite,XPos,YPos,Angle.f)
  SpriteWidth=SpriteWidth(Sprite)-1
  SpriteHeight=SpriteHeight(Sprite)-1
  ScreenWidth=ScreenWidth()-1
  ScreenHeight=ScreenHeight()-1
  
  Dim SpriteArray(SpriteWidth,SpriteHeight)
  
  StartDrawing(SpriteOutput(Sprite))
  For x=0 To SpriteWidth
    For y=0 To SpriteHeight
      SpriteArray(x,y)=PointFast(x,y)
    Next
  Next
  StopDrawing()
  
  StartDrawing(CurrentBufferOutput())
  
  Angle.f=(Angle*ACos(-1)*2)/360
  
  Cos.f=Cos(Angle.f)
  Sin.f=Sin(Angle.f)
  NSin.f=-Sin
  
  SpriteWidth2=SpriteWidth/2
  SpriteHeight2=SpriteHeight/2
  
  For x=0 To SpriteWidth
    
    Xv=XPos+(x-SpriteWidth2)*Cos
    Xv2=(x-SpriteWidth2)*Sin
    
    For y=0 To SpriteHeight
      
      Xp=Xv+(y-SpriteHeight2)*NSin
      Yp=Xv2+(y-SpriteHeight2)*Cos+YPos
      
      If Xp>=0 And Xp<ScreenWidth And Yp>=0 And Yp<=ScreenHeight
        Color=SpriteArray(x,y)
        Plot(Xp,Yp,Color)
        Plot(Xp+1,Yp,Color)
      EndIf
      
    Next
  Next
  StopDrawing()
  
  Dim SpriteArray(0,0)
EndProcedure


InitSprite()

OpenScreen(800,600,16,"PutRotatedSprite()")

LoadSprite(1,"D:\Purebasic\examples\sources\data\Geebee2.bmp",#PB_Sprite_Memory)

For Angle=0 To 360
  ClearScreen(0,0,0)
  PutRotatedSprite(1,300,300,Angle)
  FlipBuffers()
Next
Vielleicht kannst du sie ja gebrauchen ?

Gruß
Stefan

Verfasst: 08.12.2004 21:17
von Kekskiller
Ähm... ich glaube, ihr habt mich völlig falsch verstanden. Der Code ist bar
jeder Optimierung, der ist in ein paar Minuten hingeschludert. Es geht mir
um einen schnellen Wechsel vom Spritebuffer zum Screenbuffer per
StartDrawing(). Denn jedesmal wenn ich versuche, StartDrawing()
großraumig/oft einzusetzen, gibt es diese kleine, nervige Verzögerung, der
Befehl ist ja auch nicht gerade schnell, dient ja nur zur Aktivierung des
Zeichnens. Ich sollte meine Probleme verständlicher schildern -_-" ...
Und hier noch ein paar @'s zum Klarstellen:

@PMV:
Bei deinen Fragen zum Sprite auf dem Bildschirm, kann ich nur sagen, dass
die ;...-Dinger vermutliche Bufferwechsel darstellen. Das hat nichts zu tun
mit dem ablesen von Farbwerten auf dem Bildschirm, die werden vom Sprite
gelesen. Warum eine eigene Funktion? Na ich bin in Sachen Grafikkram eher
eigen. Entweder komplett selbst der im Team, da mag ich vorgefertigte
Sachen nicht so sehr. Und Sprite3D kann ich nicht nutzen, habe keine 3D-
fähige Grafikkarte, daher der "Selbstversuch" . Der Code ist interessant...
Werde mal sehen, wie ich ihn verwenden kann. Aber mir kommt gerade
eine famose Idee in den Kopf... *denk* Hey, das könnte sogar klappen :D !

@Nic und Wünsche:
Ja, das sagt man mir auch immer, aber ich bastel gerne mit dem Minimalstem
rum, eine doofe Angewohnheit -_- ...

Nachtrag: Das mit dem Vorberechnen meinte ich nicht wirklich so, wie es
sich anhört, ich meinte damit Farbwerte vorher auslesen und dann direkt
plotten, wäre um einiges schneller, aber andererseits auch umfassender.
Wenn meine Idee klappt, kötne ich sie ja mal ausstellen :allright: .
Aber ob das dann wirklich zumutbar ist :| ...

Verfasst: 08.12.2004 21:22
von Kekskiller
@S.M. (ist der Name ernstgemeint :? ... ? ):
Genau diesen doppelten durchlauf wollte ich vermeiden, dass zutscht
nähmlich ziemlich an der Geschwindigkeit, Schleifen können laaaang sein...
Zudem bitte ich dich mal deinen anderweitig standartisierten Befehlen in
PB-internes umzuwandeln, nicht jeder hat solche Funktionen mit drinne.
Aber ich werde ihn mir mal zu Gemüte führen, sieht mehr als ähnlich wie
der Beispielcode aus.

Verfasst: 09.12.2004 00:01
von Kaeru Gaman
mein standart-tip zu grossen schleifen mit trigo-functions:

vorher 360felder grosse arrays erstellen mit den ergebnissen
für alle sin() und cos() operationen für die 360° grad die du brauchst.
natürlich nur integers verwenden für die gradzahlen.

array-zugriff ist x-mal schneller als ne sin() oder ne cos()

ausserdem kann man evtl. gleichbleibende faktoren gleich mit einbauen...

tip zwei:

spar dir drawing,
ermittle den sprite-pointer und klotz die farbwerte direkt rein mit Poke.
oder am besten gleich in ASM.

Verfasst: 09.12.2004 16:26
von Kekskiller
Stimmt, hast recht, Drawing ist an dieser Stelle Mist...
Mit Pointer, Peek und Poke (klingt zusammen irgendwie cool) unter PB habe
ich mich noch nicht wirklich beschäftigt, wäre aber hier wohl wirklich
angebracht. Nur, wie meinst du das mit Spritepointer? Direkt aus dem Sprite-
Speicher nehmen...? Hm...

Verfasst: 09.12.2004 20:24
von Kaeru Gaman
nein, du erzeugst ein sprite mit createsprite,

und benutzt seinen pointer.. (geht das eigentlich, fällt mir grad auf????)

wenn das direkt nicht geht, dann erzeugst du ein array,
von diesem kannst du den pointer ermitteln ( @name )
schreibst die daten in diesen speicher,
und führst ein catchsprite auf den speicher aus.

du musst hierbei allerdings extrem drauf achten, das array gross genug
zu DIMensionieren,
damit du dir nicht andere variablen oder schlimmeres zerschiesst.

kannst natürlich auch einfach ein AllocateMemory durchführen,
das liefert einen speicher-pointer zurück.
mit PokeL (*speicher, farbe) schreibst du's dann rein...

kommando zurück, ich seh grad, dass catchsprite nen BMP-header erwartet, schiet

also, dann musst du doch irgentwie den pointer von nem CreateSprite rausfinden...

oder, du lädst ne leere bitmap der entsprechenden grösse in den speicher...hmm...

also, da muss es doch eine möglichkeit geben, an nen sprite-pointer zu kommen.
weiss das vielleicht irgendjemand