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

Flocking Algorithm ( organizacja obiektowego projektu, dziedziczenie czy szablony? )

Object Storage Arubacloud
0 głosów
82 wizyt
pytanie zadane 16 lutego 2019 w C i C++ przez Jakub 0 Pasjonat (23,120 p.)

Witam, mój projekt dotyczy tego: https://en.wikipedia.org/wiki/Flocking_(behavior)

Sam algorytm już dawno napisałem, początkowo miało być to tylko dla mnie jakieś wyzwanie, teraz jednak stwierdziłem że zrobię z tego małą bibliotekę którą będę mógł wykorzystać w moich przyszłych projektach. Kod musiałem kilka razy bardzo przebudować. Jak na razie wygląda on tragicznie... Zanim go pokaże może przejdę najpierw do tego co właściwie chce osiągnąć:

No wiec początkowo klasy generowały stado rysując zwykłe trójkąty, oczywiście chciałem to rozwinąć, w ich miejsce można wstawić ryby, ptaki, antylopy, ludzi, Początkowo miałem zrobić abstrakcyjną klasę bazową o nazwie EntityShape a kolejne klasy miały z niej dziedziczyć. Zaletą takiego rozwiązania jest to że użytkownik jest zmuszony napisać definicje dla wszystkich czysto wirtualnych  metod klasy bazowej, jakie są wymagane dla algorytmu. Relacja wygląda tak:

class EntityShape : public sf::Drawable {
public:
	virtual void setRotationBasedVelocity(sf::Vector2f velocity) = 0;
	virtual sf::Vector2f getSize() const = 0;
	virtual sf::Vector2f getPosition() const = 0;
	virtual void setSize(sf::Vector2f size) = 0;
	virtual void setPosition(sf::Vector2f position) = 0; 
	virtual void setPosition(float x, float y) = 0;
	virtual void move(sf::Vector2f vec) = 0;
	virtual void setRotation(float angle) = 0;
	virtual void setOrigin(sf::Vector2f vec) = 0;
	virtual void setFillColor(sf::Color color) = 0;
};

class FishShape : public EntityShape {
private:
	sf::RectangleShape m_fish;
	static sf::Texture m_texture;
	static bool isTextureLoaded;
public:

	FishShape(float a, float b) {
		if (!isTextureLoaded) { 
			m_texture.loadFromFile("fish.png");
			isTextureLoaded = true; 
		}

		m_fish.setTexture(&m_texture);
	}

	virtual void setRotationBasedVelocity(sf::Vector2f velocity) {
		m_fish.setRotation(atan2(velocity.y, velocity.x)*(180.f / 3.14159265359f) + 90.f);
	}

	virtual sf::Vector2f getSize() const {
		return m_fish.getSize();
	}

	virtual sf::Vector2f getPosition() const {
		return m_fish.getPosition(); 
	}

	virtual void setSize(sf::Vector2f size) {
		m_fish.setSize(size);
	}

	virtual void setPosition(sf::Vector2f position) {
		m_fish.setPosition(position); 
	}

	virtual void setPosition(float x, float y) {
		m_fish.setPosition(x, y);
	}

	virtual void move(sf::Vector2f vec) {
		m_fish.move(vec);
	}

	virtual void setRotation(float angle) {
		m_fish.setRotation(angle);
	}

	virtual void setOrigin(sf::Vector2f vec) {
		m_fish.setOrigin(vec);
	}

	virtual void setFillColor(sf::Color color) {
		m_fish.setFillColor(color);
	}

public:

	virtual void  draw(sf::RenderTarget& target, sf::RenderStates states) const override {
		target.draw(m_fish);
	}
};

sf::Texture FishShape::m_texture;
bool FishShape::isTextureLoaded = false;

( oczywiście trzeba wiele rzeczy poprawić bo na razie jest to tylko prowizorka, dlatego proszę... nie zwracajcie uwagi na ten konstruktor co przyjmuje dwa argumenty a nic z nimi nie robi )

Wadą jest tu bardzo wysoki poziom powtarzalnej abstrakcji ( taki mój termin ;) ). Sami widzicie o co chodzi, wywołujemy metody składowej o takiej samej nazwie jak metody aktualnej klasy, nwm czy to jest w ogóle wydajne ale też nie mam pojęcia jak to obejść...

Największy problem w całym projekcie jest taki że wykorzystuje i dziedziczenie i szablony, oto klasy mające związek z samym algorytmem:

///-------------------------------------------------------------------------

template <typename DrawableObject> class SingleEntity : public sf::Drawable {
private:
	EntityShape* m_entity;
	sf::Vector2f m_velocity;
private:
	const long double m_SeparationCubedZone; 
	const int m_ID;
public:
	SingleEntity(float angle, sf::Vector2f size, sf::Color color, float separationSquareRootZone, int ID, sf::Vector2f position);
public:
	long double getSeparationSquaredZone() const;
	float getSeparationSquareRootZone() const;
	bool operator!=(const SingleEntity& otherEntity) const;
	long double getDistanceSquared(sf::Vector2f position) const;
	sf::Vector2f getVelocity() const;
	sf::Vector2f getPosition() const;
public:
	void operator+=(sf::Vector2f velocity);
	void operator=(sf::Vector2f velocity);
	void update(float speed, float elapedTime, sf::Vector2f windowSize);
public:
	virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
};

///-------------------------------------------------------------------------

template <typename DrawableObject> class Flock : public sf::Drawable {
private:
	const float m_TimeToStartFlocking;
private:
	bool m_mathMode = false; 
private:
	sf::Vector2f m_windowSize;
private:
	const float m_speed;
	const long double m_NeighborhoodSquaredZone;

	const float m_CohereWeight = 1.f;
	const float m_SeparateWight = 6.f; 
	const float m_AlignmentWeight = 1.f;
	const float m_MouseCursorSeparateWeight = 20.f;
	const float m_MouseCursorCohereWeight = 3.f;
private:
	std::list<SingleEntity<DrawableObject>> m_entities;
private:
	//---------------------------------------------------------------------------------
	sf::Vector2f cohere(const SingleEntity<DrawableObject>& currentEntity);
	sf::Vector2f separate(const SingleEntity<DrawableObject>& currentEntity);
	sf::Vector2f alignment(const SingleEntity<DrawableObject>& currentEntity);
	
	sf::Vector2f mouseCursorSeparate(const SingleEntity<DrawableObject>& currentEntity, sf::Vector2f mouseCursor);
	sf::Vector2f mouseCursorCohere(const SingleEntity<DrawableObject>& currentEntity, sf::Vector2f mouseCursor);

	sf::Vector2f Flock::obstacleSeparate(const SingleEntity<DrawableObject>& currentEntity, std::list<FlockingObstacle>& obstacles);

	sf::Vector2f flocking(const SingleEntity<DrawableObject>& currentEntity, sf::Vector2f mouseCursor, std::list<FlockingObstacle>& obstacles);
	//---------------------------------------------------------------------------------
public:
	Flock(std::list<SingleEntity<DrawableObject>>& entities, float speed, float neighborhoodSquareRootZone, sf::Vector2f windowSize, float timeToStartFlocking );
	void update(float elapedTime, float realProgramTime, sf::Vector2f mouseCursor, std::list<FlockingObstacle>& obstacles);
	virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;

public:
	void setMathMode(bool mathMode);
};

Używam tu szablony do tego celu:

template <typename DrawableObject>
SingleEntity<DrawableObject>::SingleEntity(float angle, sf::Vector2f size, sf::Color color, float separationSquareRootZone, int ID, sf::Vector2f position)
	: m_SeparationCubedZone(std::pow(separationSquareRootZone, 2)), m_ID(ID) {
	m_entity = new DrawableObject(0,0);
	angle *= (3.14159265359f / 180.f);
	m_velocity = sf::Vector2f(std::cos(angle), std::sin(angle));
	m_entity->setSize(size);
	m_entity->setOrigin(m_entity->getSize() / 2.f);
	m_entity->setFillColor(color);
	m_entity->setPosition(position);
}

Tak wygląda konstruktor dla pojedynczej jednostki, szablon jest użyty żeby była możliwość przekazania jakiego typu klasy pochodnej chcemy użyć:

m_entity = new DrawableObject(0,0);

Nie wiem co zrobić, zrezygnować z szablonów a obiekt jednostki skonstruować zewnętrznie, zrezygnować z dziedziczenia? Nie podaję całego kodu bo problem dotyczy tylko możliwości wstawienia w miejsce jednostki dowolnego typu, który zawiera niezbędne metody.

Z góry dziękuje za pomoc :)

Zaloguj lub zarejestruj się, aby odpowiedzieć na to pytanie.

Podobne pytania

0 głosów
1 odpowiedź 451 wizyt
0 głosów
1 odpowiedź 116 wizyt
pytanie zadane 31 października 2018 w C i C++ przez oksent Nowicjusz (150 p.)
0 głosów
0 odpowiedzi 312 wizyt
pytanie zadane 18 lutego 2017 w C i C++ przez delta_pavonis Początkujący (300 p.)

92,570 zapytań

141,422 odpowiedzi

319,643 komentarzy

61,958 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!

...