tBane Temat założony przez niniejszego użytkownika |
[SFML 2.X] Cienie w grze 2D RPG » 2024-11-05 18:40:29 Witam. Mam problem. Nie wiem jak obliczyć pozycję cienia. Próbowałem na wiele sposobów i nic mi nie wychodzi. Może ktoś ma jakiś pomysł ? virtual void draw() { if( isAlive ) { sf::Sprite shadow; shadow = sprite; shadow.setColor( sf::Color( 0, 0, 0, 128 ) ); shadow.setOrigin( currentTexture->cx, currentTexture->cy ); shadow.setScale( 1.0f, 1.5f ); sf::Vector2f p; p.x = position.x; p.y = position.y -( float( currentTexture->texture->getSize().y ) - currentTexture->cy ) * shadow.getScale().y / 2.0f; shadow.setPosition( p ); window->draw( shadow ); window->draw( sprite ); window->draw( lifeBarBackground ); window->draw( lifeBar ); Unit::draw(); } }
|
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-11-05 18:52:30 Eh zagalopowałem się i za dużo kombinowałem a tu wystarczyło odjąć 10 od pozycji xD virtual void draw() { if( isAlive ) { sf::Sprite shadow; shadow = sprite; shadow.setColor( sf::Color( 0, 0, 0, 128 ) ); shadow.setOrigin( currentTexture->cx, currentTexture->cy ); shadow.setScale( 1.0f, 1.5f ); sf::Vector2f p; p.x = position.x; p.y = position.y - 10; shadow.setPosition( p ); window->draw( shadow ); window->draw( sprite ); window->draw( lifeBarBackground ); window->draw( lifeBar ); Unit::draw(); } }
|
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-11-05 19:01:48 Teraz zauważyłem swój błąd logiczny. Cienie mogą być rzucane także na inne obiekty. I teraz zastanawiam się jak to zaimplementować. Jak na razie mam takie coś ale wiem, że to nie spełnia swojej roli, gdyż cienie jako Sprajty mogą na siebie nachodzić. Mam wstępny pomysł, żeby użyć dwóch tekstur jedna do renderowania gry, a druga do renderowania cieni i na końcu tę z cieniem dodawać do tej pierwszej. Ale czy to dobry pomysł ? |
|
DejaVu |
» 2024-11-05 20:41:16 GPT 4o: Masz rację – właściwe podejście polega na **najpierw renderowaniu wszystkich cieni**, a dopiero potem renderowaniu obiektów. Dzięki temu unikniesz sytuacji, w której cień jednego obiektu zasłania inny obiekt, co może wyglądać nieestetycznie. Poniżej wyjaśnię szczegółowo, dlaczego i jak to zrobić w praktyce. ### Poprawne podejście: Cienie najpierw, potem obiekty 1. **Koncepcja cienia „pod obiektem”**: W tradycyjnej perspektywie 2D cień powinien znajdować się **pod wszystkimi obiektami**. Dzięki temu cienie będą widoczne na powierzchni "podłogi" lub tła, ale nie będą zasłaniać obiektów, które są "przed" nimi na osi \( Y \). 2. **Unikanie zasłaniania**: Jeśli najpierw narysujesz wszystkie cienie, a potem same obiekty, unikniesz efektu, w którym cień jednego obiektu zasłania inny obiekt znajdujący się z tyłu. ### Przykład implementacji w SFML – krok po kroku W poprzedniej wersji kodu dokonamy drobnej modyfikacji, aby rozdzielić rysowanie cieni i obiektów. Poniżej znajduje się przykład z poprawionym renderowaniem: #### 1. Rozszerzenie klasy `GameObject` Dodamy dwie oddzielne metody do rysowania: jedną do rysowania cienia, a drugą do rysowania obiektu. #include <SFML/Graphics.hpp>
class GameObject { public: sf::Sprite sprite; sf::Sprite shadow; GameObject( const sf::Texture & texture ) { sprite.setTexture( texture ); shadow.setTexture( texture ); shadow.setColor( sf::Color( 0, 0, 0, 128 ) ); } void setPosition( float x, float y ) { sprite.setPosition( x, y ); shadow.setPosition( x + 10, y + 10 ); } void drawShadow( sf::RenderWindow & window ) { window.draw( shadow ); } void drawObject( sf::RenderWindow & window ) { window.draw( sprite ); } };
#### 2. Funkcja renderująca: Rysowanie najpierw cieni, potem obiektów W funkcji renderującej najpierw rysujemy cienie wszystkich obiektów, a następnie rysujemy same obiekty w odpowiedniej kolejności. #include <vector> #include <algorithm>
bool compareYPosition( const GameObject & a, const GameObject & b ) { return a.sprite.getPosition().y < b.sprite.getPosition().y; }
void renderScene( sf::RenderWindow & window, std::vector < GameObject > & objects ) { std::sort( objects.begin(), objects.end(), compareYPosition ); for( auto & obj: objects ) { obj.drawShadow( window ); } for( auto & obj: objects ) { obj.drawObject( window ); } }
#### 3. Główna pętla gry Kod głównej pętli gry pozostaje bez zmian. Rysowanie obiektów odbywa się przez wywołanie `renderScene` w odpowiedniej kolejności. int main() { sf::RenderWindow window( sf::VideoMode( 800, 600 ), "2D Shadows Example" ); sf::Texture texture; texture.loadFromFile( "path/to/texture.png" ); std::vector < GameObject > objects; for( int i = 0; i < 50; ++i ) { GameObject obj( texture ); obj.setPosition( rand() % 800, rand() % 600 ); objects.push_back( obj ); } while( window.isOpen() ) { sf::Event event; while( window.pollEvent( event ) ) { if( event.type == sf::Event::Closed ) window.close(); } window.clear( sf::Color::White ); renderScene( window, objects ); window.display(); } return 0; }
### Dlaczego to działa 1. **Separacja renderowania cieni i obiektów**: Dzięki rozdzieleniu rysowania cieni i obiektów mamy pewność, że każdy cień jest „pod” obiektem, a nie go zasłania. 2. **Kolejność osi Y**: Sortowanie po osi \( Y \) gwarantuje, że obiekty bliżej dołu ekranu (czyli „bliżej” kamery) będą narysowane później, co daje efekt zasłaniania dla obiektów znajdujących się wyżej na osi \( Y \). ### Efekt końcowy Taki sposób renderowania sprawia, że obiekty zasłaniają się nawzajem tylko na podstawie swojej pozycji, a cienie wyglądają naturalnie, tworząc iluzję głębi bez skomplikowanego kodu czy problemów z zasłanianiem. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-11-05 21:19:39 Ok. Mam jeszcze jedno pytanie. A mianowicie znikają mi cienie w dolnej części ekranu. Z kodem jest wszystko ok raczej. Myśle, że to wina SFML. Gdy główny sprite jest niewidoczny wtedy i sprajt cienia zanika. Tu mam jeszcze link do git'a jak kod będzie niewystarczający .. https://github.com/tBane1995/test#ifndef NatureObjects_hpp #define NatureObjects_hpp
class Nature : public GameObject { public: Texture * texture; sf::Sprite sprite; sf::Sprite shadow; Nature( string name, float width, float length, float height ) : GameObject( name, 0, 0, width, length, height, true, false ) { type = GameObjectType::Nature; this->texture = getTexture( name ); sprite = sf::Sprite(); sprite.setTexture( * texture->texture ); sprite.setOrigin( texture->cx, texture->cy ); sprite.setPosition( position ); shadow = sf::Sprite(); shadow.setTexture( * texture->texture ); shadow.setColor( sf::Color( 0, 0, 0, 48 ) ); shadow.setOrigin( texture->cx, texture->cy ); sf::Vector2f scale; scale.x = 1.0f + 0.15f * float( texture->texture->getSize().x ) / 256.0f; scale.y = 1.0f + 0.30f * float( texture->texture->getSize().y ) / 256.0f; shadow.setScale( scale ); shadow.setPosition( position ); } Nature( GameObject * object, float x, float y ) : GameObject( object, x, y ) { type = GameObjectType::Nature; this->texture = getTexture( name ); sprite = sf::Sprite(); sprite.setTexture( * texture->texture ); sprite.setOrigin( texture->cx, texture->cy ); sprite.setPosition( position ); shadow = sf::Sprite(); shadow.setTexture( * texture->texture ); shadow.setColor( sf::Color( 0, 0, 0, 48 ) ); shadow.setOrigin( texture->cx, texture->cy ); sf::Vector2f scale; scale.x = 1.0f + 0.15f * float( texture->texture->getSize().x ) / 256.0f; scale.y = 1.0f + 0.30f * float( texture->texture->getSize().y ) / 256.0f; shadow.setScale( scale ); shadow.setPosition( position ); } virtual ~Nature() { } virtual void setPosition( sf::Vector2f position ) { this->position = position; sprite.setPosition( position ); shadow.setPosition( position ); } virtual void update( float dt ) { } virtual void draw() { if( mouseIsHover ) GameObject::draw(); window->draw( shadow ); window->draw( sprite ); } };
std::vector < Nature * > natures;
#endif
|
|
DejaVu |
» 2024-11-05 21:42:59 Zapewne masz warunek ograniczający, aby nie renderować obiektów 'poza' sceną, co jest dobrą optymalizacją. Jeżeli renderowanie 'cieni' jest powiązane z renderowaniem 'obiektów' to musisz zadbać o to, aby renderować obiekty 'poza sceną', których 'cień' wejdzie na scenę. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-11-05 22:30:15 No właśnie mój warunek ograniczający jest z przedziału [-2*screenWidth, -2*screenHeight] [2*screenWidth, 2*screenHeight]. Więc on na pewno nie wpływa na ten render. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-11-05 22:38:46 Dobra. Miałeś rację :-) Znalazłem fragment kodu odpowiedzialny za to renderowanie.
Dzięki za pomoc! :-) |
|
« 1 » 2 |