• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed SFML - Tworzenie jednostek sfml'elo podobnych

Object Storage Arubacloud
0 głosów
281 wizyt
pytanie zadane 3 lipca 2018 w C i C++ przez Jakub 0 Pasjonat (23,120 p.)
zamknięte 8 lipca 2018 przez Jakub 0

Witam, pytanie dotyczy tego artykułu ze strony: https://www.sfml-dev.org/tutorials/2.5/graphics-vertex-array.php

A dokładnie części o nazwie jak w temacie pytania, jest tam taka klasa:

class MyEntity : public sf::Drawable, public sf::Transformable
{
public:

private:

    virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
    {
        states.transform *= getTransform();

        states.texture = &m_texture;

        target.draw(m_vertices, states);
    }

    sf::VertexArray m_vertices;
    sf::Texture m_texture;
};

Dzięki temu że dziedziczy z sf::Drawable i sf::Transformable możemy jej obiekty rysować i transformować jak by były wbudowanymi kształtami. Mam jednak uwagę do tego fragmentu:

 states.transform *= getTransform();

Niby jest na stronce wyjaśnienie że chodzi tu o połączenie jednostki transformacji z tą która została przekazana jako argument do funkcji draw. Nie jestem jednak pewien jak to zrozumieć, co się stanie jeśli tej linijki nie będzie?

Wiem że pewnie pomyślicie że nie rozumiem tego bo słabo umiem angielski, ale mam też screeny z byłego polskiego tłumaczenia tego kursu i dalej mam pustkę w głowie.

Czy dał by ktoś jakiegoś linka do strony gdzie jest to na przykładach dobrze wytłumaczone lub tu mi spróbował to wyjaśnić, bo się pogubiłem ( jeszcze to przeciążenie operatora '*' zamiast zwykłej funkcji/metody z nazwą )

Z góry wam dziękuje i pozdrawiam ;)

 

komentarz zamknięcia: już znam wytłumaczenie

1 odpowiedź

+2 głosów
odpowiedź 3 lipca 2018 przez Patrycjerz Mędrzec (192,320 p.)
wybrane 4 lipca 2018 przez Jakub 0
 
Najlepsza

Kod biblioteki jest otwarty, możesz przejrzeć implementację w każdej chwili, jeśli czegoś nie rozumiesz.

Słowem wstępu, jako że SFML używa OpenGL do renderowania grafiki, korzysta także z ogólnie wykorzystywanego modelu transformacji wierzchołków wielokątów w postaci macierzy 4x4. W telegraficznym skrócie, każda macierz oznacza pewną transformację (przesuniecie, obrót, skalowanie). Mnożąc je łączymy je razem. Dodawanie kolejnych przekształceń odbywa się poprzez umieszczenie ich po lewej stronie mnożenia, nie odwrotnie, jakby podpowiadała logika.

Tutaj znajduje się definicja operatora przypisania z mnożeniem. Jak można zauważyć, wywołuje on metodę `combine` dla lewego operandu. Przejdźmy więc do niej. Widać tutaj tworzenie nowej macierzy poprzez mnożenie obu innych. Znowu nie będę dywagował nad szczegółami (odsyłam do literatury matematycznej), ale jest tutaj zaimplementowane mnożenie macierzy argumentu funkcji i obiektu wywołującego (właśnie w takiej kolejności). Zgadza się to z powyższym stwierdzeniem, że nowe transformacje znajdują się po lewej stronie znaku mnożenia. Taka transformacja jest potem przypisywana do obiektu `state` i wykorzystywana przy renderingu.

Jeśli tej linii nie będzie, to zostanie użyta domyślna macierz klasy `sf::RenderStates`, czyli macierz jednostkowa. Taka transformacja jest jałowa, to znaczy niczego nie zmienia.

komentarz 4 lipca 2018 przez Jakub 0 Pasjonat (23,120 p.)

Wiem że wynika to pewnie z mojego niezrozumienia ale mam taką sprawę:

#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <iostream>
#include <string>

constexpr short QuadCorners{ 4 };

class Map : public sf::Drawable, sf::Transformable {
private:
	sf::Texture titlesSet;
	sf::VertexArray map;
	sf::Vector2f mapDimension;

	int m_width;
	int m_height;
	int m_titleSizeX;
	int m_titleSizeY;

public:
	bool load (std::string fileName, sf::Vector2u titleSize,
		unsigned titles[], int mapWidth, int mapHeight) {

		if (!titlesSet.loadFromFile(fileName))
			return false;

		mapDimension = sf::Vector2f(mapWidth * titleSize.x, mapHeight * titleSize.y);
		m_width = mapWidth;
		m_height = mapHeight;
		m_titleSizeX = titleSize.x;
		m_titleSizeY = titleSize.y;

		map.setPrimitiveType(sf::Quads);
		map.resize(mapWidth * mapHeight * QuadCorners);

		for (int y = 0; y < mapHeight; ++y) {
			for (int x = 0; x < mapWidth; ++x) {

				unsigned arrIndex = ( mapWidth * y ) + x;

				int locTexX = titles[arrIndex] % (titlesSet.getSize().x / titleSize.x);
				int locTexY = titles[arrIndex] / (titlesSet.getSize().x / titleSize.x);

				sf::Vertex* quad = &map[arrIndex * QuadCorners];

				quad[0].position = sf::Vector2f(x*titleSize.x, y*titleSize.y);
				quad[1].position = sf::Vector2f((x+1)*titleSize.x, y*titleSize.y);
				quad[2].position = sf::Vector2f((x+1)*titleSize.x, (y+1)*titleSize.y);
				quad[3].position = sf::Vector2f(x*titleSize.x, (y+1)*titleSize.y);

				quad[0].texCoords = sf::Vector2f(titleSize.x*locTexX, titleSize.y*locTexY);
				quad[1].texCoords = sf::Vector2f(titleSize.x*(locTexX+1), titleSize.y*locTexY);
				quad[2].texCoords = sf::Vector2f(titleSize.x*(locTexX+1), titleSize.y*(locTexY+1));
				quad[3].texCoords = sf::Vector2f(titleSize.x*locTexX, titleSize.y*(locTexY+1));
			}
		}

		return true; 
	}

	virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override {
		states.transform *= getTransform(); //temat pytania (^)
		states.texture = &titlesSet;
		target.draw(map, states);
	}

	sf::Vector2f returnDimension() {
		return mapDimension;
	}

	void changeTitle(int x, int y, int style) {
		unsigned arrIndex = (m_width * y) + x;
		sf::Vertex* quad = &map[arrIndex * QuadCorners];

		int locTexX = style % (titlesSet.getSize().x / m_titleSizeX);
		int locTexY = style / (titlesSet.getSize().x / m_titleSizeX);

		quad[0].texCoords = sf::Vector2f(m_titleSizeX*locTexX, m_titleSizeY*locTexY);
		quad[1].texCoords = sf::Vector2f(m_titleSizeX*(locTexX + 1), m_titleSizeY*locTexY);
		quad[2].texCoords = sf::Vector2f(m_titleSizeX*(locTexX + 1), m_titleSizeY*(locTexY + 1));
		quad[3].texCoords = sf::Vector2f(m_titleSizeX*locTexX, m_titleSizeY*(locTexY + 1));
	}
};

/// ---------------///
/// 0 - grass      ///
/// 1 - water      ///      
/// 2 - road       ///
/// 3 - sand       ///
/// ---------------///

int main(){

	unsigned mapInterface[]{
		0,0,1,1,0,
		0,1,1,1,1,
		2,2,2,2,2,
		1,1,1,1,1,
		3,3,1,1,1
	};

	Map map;
	if (!map.load("plik.jpg", { 88,90 }, mapInterface, 5, 5)) {
		std::cout << "Error!\n"; std::cin.get();
		return -1;
	}

	map.changeTitle(0, 0, 3);

	sf::Transform trans; 
	trans.rotate(5); // rotacja ( & )


	sf::RenderWindow window(sf::VideoMode(map.returnDimension().x,map.returnDimension().y), "Nazwa okna", sf::Style::Close); 
	window.setFramerateLimit(30);
	window.setKeyRepeatEnabled(false);

    while (window.isOpen()) { 

		   sf::Event event;
		   while (window.pollEvent(event)) {
			    if (event.type == sf::Event::Closed)
				     window.close();
				if (event.type == sf::Event::KeyPressed) {
					static bool grass = false;
					if (grass) {
						map.changeTitle(0, 0, 3);
						grass = false;
					}
					else {
						map.changeTitle(0, 0, 0);
						grass = true;
					}
				}

		   }

		   window.clear(sf::Color::Black);	
		   window.draw(map, trans); //przekazanie transformacji (*)
		   window.display(); 
		}

	return 0;
}

Tak sobie testowałem i napisałem większy programik...

Ważne są tylko miejsca po których w komentarzu są symbole: ^, &, *

 

W metodzie draw() mam napisane:

states.transform *= getTransform();

Oraz na obiekcie dokonuje rotacji ( symbol '&' i '*' )

Problem jest taki że niezależnie czy stosuje "to mnożenie" czy nie to rotacja i tak nastąpi :/

Nie wiem co źle zrozumiałem, będę bardzo wdzięczny za pomoc.

 

komentarz 4 lipca 2018 przez Patrycjerz Mędrzec (192,320 p.)

Problem jest taki że niezależnie czy stosuje "to mnożenie" czy nie to rotacja i tak nastąpi :/

Co masz na myśli? Całkowicie usuwasz tę linię kodu czy zastępujesz ją inną?

komentarz 4 lipca 2018 przez Jakub 0 Pasjonat (23,120 p.)

Mam na myśli że nawet jak usunę z kodu:

  states.transform *= getTransform();

To transformacja jaką jest rotacja przebiegnie poprawnie

1
komentarz 5 lipca 2018 przez Patrycjerz Mędrzec (192,320 p.)
To oczywiste, że następuje rotacja. Przesyłasz do metody `Map::draw` transformację, a potem używasz jej w `sf::RenderTarget::draw`. Tym mnożeniem jedynie łączysz nowe przekształcenie z wewnętrznym. Jeśli to drugie niczego nie powoduje, to efekt daje jedynie transformacja zewnętrzna.
komentarz 8 lipca 2018 przez Jakub 0 Pasjonat (23,120 p.)
Dziękuje za wszystko, musiałem trochę poeksperymentować i zerknąć do dokumentacji... ale już to zrozumiałem ;)

Podobne pytania

0 głosów
1 odpowiedź 576 wizyt
0 głosów
0 odpowiedzi 333 wizyt
pytanie zadane 12 listopada 2017 w C i C++ przez noel1402 Użytkownik (630 p.)
0 głosów
2 odpowiedzi 375 wizyt

92,568 zapytań

141,424 odpowiedzi

319,630 komentarzy

61,956 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...