You are not logged in.

  • Login

1

Monday, March 21st 2011, 10:02pm

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:

C/C++ Quellcode

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

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

C/C++ Quellcode

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


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

MfG
Check

2

Tuesday, March 22nd 2011, 4:53am

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 http://www.sfml-dev.org/wiki/en/sources/anisprite):


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:

Source code

1
2
3
m_NumFramesX = m_pImage->w (191) / m_FrameWidth (47) = 4; 
m_NumFramesY = m_pImage->h (256) / m_FrameHeight(64) = 4;
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:

Source code

1
2
3
-> Zeile und Spalte aus dem Frameindex Berechnen:
spalte = fFrameNumber(6)%m_NumFramesX(4) = 2(Rest);
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:

Source code

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


Mfg Rushh0ur

This post has been edited 1 times, last edit by "Rushh0ur" (Mar 22nd 2011, 2:38pm)


3

Tuesday, March 22nd 2011, 7:44pm

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

This post has been edited 1 times, last edit by "Checkmateing" (Mar 22nd 2011, 9:50pm)


4

Wednesday, March 23rd 2011, 2:46pm

Irgendwie verstehe ich deinen letzten Post nicht, was willst du nun machen?

Um die Addresse von einer Variablen sf::Image Image zu erhalten kannst du diese mit einem UND & referenzieren (sf::Image *Image2 = &Image).

Der this Zeiger ist nur inerrhalb eines Objektes verfügbar und zeigt auf die eigene Speicheradresse.

Mfg Rushh0ur

5

Wednesday, March 23rd 2011, 3:02pm

Ich will GetHeight() usw. nutzen....
Das mit der Adresse ist ja wieder was anderes. ^.^
Ich kann ja mal den bisherigen Syntax durch kommentiert posten, wenn du brauchst....

MfG
Check

6

Wednesday, March 23rd 2011, 3:16pm

Allright, zeig mal her. (Kommentare sind mir persöhnlich relativ weine)

Mfg Rushh0ur

7

Wednesday, March 23rd 2011, 3:46pm

Init:

C/C++ Quellcode

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


Render:

C/C++ Quellcode

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


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

MfG
Check

8

Wednesday, March 23rd 2011, 6:23pm

Änder die Parameter

C/C++ Quellcode

1
2
3
4
5
6
7
void lwtGraphic::Graphic::Init(const string Filename, int FrameNumber,
								int FrameWidth, int FrameHeight, sf::Image Image)
 
in
 
void lwtGraphic::Graphic::Init(const string &Filename, int FrameNumber,
								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:

C/C++ Quellcode

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


Mfg Rushh0ur

9

Wednesday, March 23rd 2011, 7:25pm

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

10

Wednesday, March 23rd 2011, 10:01pm

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

11

Thursday, March 24th 2011, 3:52pm

Dann weiß ich nicht, wie das rendern weiter gehen sollte... ;(

MfG
Check

12

Saturday, March 26th 2011, 1:52pm

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.

C/C++ Quellcode

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


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

Hoffe das bringt dich weiter. :)

Mfg Rushh0ur

13

Monday, March 28th 2011, 4:28pm

Also wäre es im obigen Fall dann einfach App.Draw?
Das würde ich dann lieber im Spiel machen. :D Bedeutet, meine Render-Funktion wäre also fertig.

Ich merke mir: Weniger denken, mehr machen. Klappt irgendwie auch in der Schule. 1 in Mathematik bekommen. :D

MfG
Check

Social bookmarks