SFML - Animationen

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • SFML - Animationen

    Hallo!
    Ich überlege jetzt schon wie ich Animationen mit SFML machen lassen kann.
    Mit Sicherheit über ein Rect usw. Doch die Anwendung ist mir nur dunkel bekannt. habe im Wiki schon geguckt, jedenfalls bei Tutorials, und Google benutzt. Ich stoße aber immer auf Leute, die wissen wie man SFML Rects anwendet.
    Ich hänge jetzt zum Beispiel daran, das Ganze zu laden und zuzuordnen.
    In der SDL wäre das ja ungefähr so, ein Pseudocode:

    Quellcode

    1. ...
    2. Rect.y = FrameWidth; //Bei allen
    3. Rect.h = FrameHeight; // Drei habe
    4. m_NumFramesX = m_pImage->w / m_FrameWidth; // ich Probleme....
    5. ...

    Dann wird das Ganze ja dann z.B. so verarbeitet:

    Quellcode

    1. ...
    2. int Column = static_cast<int>(fFrameNumber)%m_NumFramesX;
    3. int Row = static_cast<int>(fFrameNumber)/m_NumFramesX;
    4. m_FrameRect.x = Column * m_FrameWidth;
    5. m_FrameRect.y = Row*m_FrameHeight;
    6. SDL_BlitSurface ...


    So ziemlich an den angegebenen Stellen hänge ich ein bisschen. Ich weiß nicht wie ich das umzusetzen habe...

    MfG
    Check
  • Naja wenn man das mal selbert durch rechnet sollte man doch Drauf kommen oder?

    Du hast ein Bild der Breite b und der Höhe h. Anschliessend berechnest du ein ein Teilrechteck von diesem Bild welchen du über den Bildindex ermitteln kannst.
    Dieses Rechteck besteht Normalerweise aus zwei Kordinaten die den Anfang und das Ende angeben.

    Ich machs mal Anhand dieses Beispiels (Quelle sfml-dev.org/wiki/en/sources/anisprite):
    [Blockierte Grafik: http://www0.xup.in/tn/2011_03/64327457.jpeg]

    Das Bild hat die größen 191(b)x256(h) Pixel (> m_pImage->w, m_pImage->h) die einzelnen Framebilder haben die Größe 47(b)x64(h) Pixel (> FrameWidth, FrameHeight).

    Dann kommen die Berechnungen raus:

    Quellcode

    1. m_NumFramesX = m_pImage->w (191) / m_FrameWidth (47) = 4;
    2. m_NumFramesY = m_pImage->h (256) / m_FrameHeight(64) = 4;
    3. TotalFrames = m_NumFramesX(4) * m_NumFramesY(4) = 16;

    Das sagt uns das es jeweil vier Bilder in der X und vier in der Y Achse sind, das macht dann insgesamt 16 Frames (Einzelbilder) aus;

    Jetzt kann man seine Teilbereiche Berechnen, mal angenohmen man will das 6 Teilbild auswählen und Zeichnen, dh. man muss die Posiion berechnen:

    Quellcode

    1. -> Zeile und Spalte aus dem Frameindex Berechnen:
    2. spalte = fFrameNumber(6)%m_NumFramesX(4) = 2(Rest);
    3. zeile = fFrameNumber(6)/m_NumFramesY(4) = 1;

    Nun muss man um den Startpunkt zu Berechnen einfach die Spalte mit der Frambreite und dieZeile mit der Framehöhe multiplitzieren und man hat den ersten Eckpunkt.
    Der Zweite kann nun entweder genauso Berechnet werden oder durch einfaches dazu addieren der Framedimensionen vom Startpunkt.
    Startpunkt:

    Quellcode

    1. x = 2*47 = 94px;
    2. y = 1*64 = 64px;


    Mfg Rushh0ur

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Rushh0ur ()

  • Mir geht es hauptsächlich eher darum, wie ich ein Nicht-Pointer (sf::Image Image) nutze bzw. mit z.B. sf::Image *Image2 angleiche.
    Denn ich benötige ja einen Pointer um ihn als This-Zeiger nutze. Wenn ich sf::Image Image gleich als Pointer setze dann gibt es an bestimmten Stellen bestimmte Komplikationen. -.-

    MfG
    Check

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Checkmateing ()

  • Init:

    Quellcode

    1. void lwtGraphic::Graphic::Init(const string Filename, int FrameNumber,
    2. int FrameWidth, int FrameHeight, sf::Image Image)
    3. {
    4. if(!Image.LoadFromFile(Filename)) //File laden
    5. exit (3); //ist fehlgeschlagen, also schließen
    6. //Rect für Animationsphase initialisieren
    7. lwtGraphic::Graphic::m_FrameNumber = FrameNumber;
    8. lwtGraphic::Graphic::m_FrameWidth = FrameWidth;
    9. lwtGraphic::Graphic::m_FrameHeight = FrameHeight;
    10. m_FrameNumberX = lwtGraphic::Graphic::Image->GetWidth() / FrameWidth; //Berichtigen
    11. m_FrameNumberY = lwtGraphic::Graphic::Image->GetHeight() / FrameHeight; //Berichtigen
    12. m_FrameNumberXY = m_FrameNumberX * m_FrameNumberY;
    13. }
    Alles anzeigen


    Render:

    Quellcode

    1. void lwtGraphic::Graphic::Render(sf::Sprite Sprite, sf::Image Image, int FrameNumber, int Top, int Bottom, int Right, int Left)
    2. {
    3. //Aufgabe: Noch überarbeiten und Kommentare hinzufügen
    4. int Column = FrameNumber%m_FrameNumberX;
    5. int Row = FrameNumber/m_FrameNumberY;
    6. Sprite.SetSubRect(sf::IntRect(Top, Bottom, Right, Left));
    7. }


    Render ist nicht fertig, aber ich denke Init schon. :D
    Animationen sind mein Hassthema, gefolgt von Kollisionsabfragen. ^^

    MfG
    Check
  • Änder die Parameter

    Quellcode

    1. void lwtGraphic::Graphic::Init(const string Filename, int FrameNumber,
    2. int FrameWidth, int FrameHeight, sf::Image Image)
    3. in
    4. void lwtGraphic::Graphic::Init(const string &Filename, int FrameNumber,
    5. int FrameWidth, int FrameHeight, sf::Image &Image)


    Hast du alle Variablen und Klassen die du über lwtGraphic::Graphic:: ansprichst statisch (static) definiert? Hast du dann nur ein Objekt?

    Der Render funktion brauchst du theoretisch ja nur das Sprite, das Bild und den Bildindex zu übergeben, waraus du die Position berechnen und Auswählen kannst:

    Quellcode

    1. void lwtGraphic::Graphic::Render(sf::Sprite &Sprite, sf::Image &Image, int FrameNumber)
    2. {
    3. int Top, int Bottom, int Right, int Left;
    4. //Aufgabe: Noch überarbeiten und Kommentare hinzufügen
    5. int Column = FrameNumber%m_FrameNumberX;
    6. int Row = FrameNumber/m_FrameNumberY;
    7. // Rechtec berechnen (pseudo)
    8. Left = Column * FrameWidth;
    9. Top = Row * FrameHeight;
    10. Right = Top + FrameWidth;
    11. Bottom = Top + FrameHeight;
    12. Sprite.SetSubRect(sf::IntRect(Left, Top, Right, Bottom)); // Parameter Reihenfolge ahcten
    13. // Rendern
    14. ...
    15. }
    Alles anzeigen


    Mfg Rushh0ur
  • Das ich die Positionen mit übergebe hat einen Sinn: Ich möchte gerne ein großes Tileset nutzen. Dort sind dann natürlich nicht nur Spielfiguren sondern auch Häuser usw. drauf, wodurch sich das dann nicht mehr so einfach berechnen lässt - finde ich.
    Danke jedenfalls!

    Eine Frage noch! Kann man dann einfach den Sprite dem Image zuordnen und den dann wie alle anderen auf die 'Leinwand' pinseln lassen?

    MfG
    Check
  • Naja du könntest dein Tileset in ein "globales" Image Objekt laden und daraus die einzelnen Teilbilder mittels Image::Copy rauskopieren und daraus die einzlene Framesets erstellen.

    Wenn du ein Sprite erstellst ist es, so weit ich weiß, automatisch an das Image gebunden, wird letzteres freigegeben kann auch kein das Sprite nicht mehr gerendert werden.

    Mfg Rushh0ur
  • Du machst das ganze so wie ich es früher gemacht habe, einfach drauflose programmiert ohne wirklich nach zu denken was ich überhaupt machen will.

    Ich würde dir sehr empfehlen, deine gedanken vor dem Programmschreiben niederzuschreiben auch wenn es nur Brainstorming ist, dann klappts es bei komplexene Sachen. ;)

    Wenn man nun die auf der SFML schon vorgestellte SFML Klasse nimmt und ein Größeres Tileset, dann könnte das ganze wie folgt aussehen.

    Quellcode

    1. #include "AniSprite.h"
    2. #include <SFML/Window.hpp>
    3. #include <SFML/Graphics.hpp>
    4. int main()
    5. {
    6. // Create a Window and set Frameliment to 60fps
    7. sf::RenderWindow App(sf::VideoMode(792, 192), "Sprite Animation Example");
    8. App.SetFramerateLimit(60);
    9. // Load a sprite to display
    10. sf::Image ImageWholeAnim;
    11. if (!ImageWholeAnim.LoadFromFile("anim.png"))
    12. return EXIT_FAILURE;
    13. // Create SubImages
    14. sf::Image ImageAnim[4];
    15. ImageAnim[0].Create(960, 768, sf::Color(0,0,0,0)); // first animation block
    16. ImageAnim[0].Copy(ImageWholeAnim, 0,0, sf::IntRect(0, 0, 960, 768));
    17. ImageAnim[1].Create(960, 768, sf::Color(0,0,0,0)); // second animation block
    18. ImageAnim[1].Copy(ImageWholeAnim, 0,0, sf::IntRect(0, 768, 960, 1536));
    19. ImageAnim[2].Create(960, 1152, sf::Color(0,0,0,0)); // third animation block
    20. ImageAnim[2].Copy(ImageWholeAnim, 0,0, sf::IntRect(0, 1536, 960, 2880));
    21. ImageAnim[3].Create(960, 768, sf::Color(0,0,0,0)); // fourth animation block
    22. ImageAnim[3].Copy(ImageWholeAnim, 0,0, sf::IntRect(0, 2880, 960, 3648));
    23. // Create Animation Sprites
    24. AniSprite Sprite[4];
    25. for (int i=0; i<4; ++i)
    26. {
    27. Sprite[i] = AniSprite(ImageAnim[i], 192, 192);
    28. Sprite[i].SetPosition(200 * i, 0);
    29. Sprite[i].SetLoopSpeed(20);
    30. Sprite[i].Play();
    31. }
    32. // Start the game loop
    33. while (App.IsOpened())
    34. {
    35. // Process events
    36. sf::Event Event;
    37. while (App.GetEvent(Event))
    38. {
    39. if (Event.Type == sf::Event::Closed)
    40. App.Close();
    41. }
    42. // Render Start
    43. App.Clear(sf::Color(255, 127, 0));
    44. // Update Animation and Render Sprites
    45. for (int i=0; i<4; ++i)
    46. {
    47. Sprite[i].Update();
    48. App.Draw(Sprite[i]);
    49. }
    50. // Flip Buffers
    51. App.Display();
    52. // Render End
    53. }
    54. }
    Alles anzeigen


    Das dazugehörige AnimationsSet: xup.in/dl,12246257/anim.png/

    Hoffe das bringt dich weiter. :)

    Mfg Rushh0ur