Autor Wątek: Obrazek o innych rozmiarach w projekcie, a jego pozycja rysowania  (Przeczytany 467 razy)

Offline zajmundov

  • Użytkownik

# Wrzesień 29, 2018, 11:58:09
Problem chyba prosty, tylko ja jakiś niekumaty. U mnie tile ma rozmiary 50x50, w ogóle to było główne załozenie mojej gry top-down. Postanowiłem do gry wprowadzić większe obrazki, np. ludzika tylko, że jest on rysowany za nisko, fakt postać w programie jest na swojej pozycji tylko obrazek źle rysowany.
Myślałem nad tym aby po prostu dopisać do pozycji Y -50 ale wtedy reszta obrazków co ma 50x50 też się przesunie..




Tak wygląda kod:
void Sprite::Draw( SDL_Surface* screen, Position& position )
{
if( m_surface )
{
SDL_Rect rect;

rect.x = position.x * Globals::tilesize - Globals::camera->GetCameraX();
rect.y = position.y * Globals::tilesize - Globals::camera->GetCameraY();

SDL_BlitSurface( m_surface, NULL, screen, &rect );
}
}

edit:
Dopisałem - m_sprite.GetSDLSurface()->h + Globals::tilesize
narazie coś działa, zrobię więcej testów


I wygląda to tak:
void Sprite::Draw( SDL_Surface* screen, Position& position )
{
if( m_surface )
{
SDL_Rect rect;

rect.x = position.x * Globals::tilesize - Globals::camera->GetCameraX();
rect.y = position.y * Globals::tilesize - Globals::camera->GetCameraY() - m_surface->h + Globals::tilesize;

SDL_BlitSurface( m_surface, NULL, screen, &rect );
}
}
« Ostatnia zmiana: Wrzesień 30, 2018, 20:26:54 wysłana przez zajmundov »

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline ChristopherTa...

  • Użytkownik

# Wrzesień 30, 2018, 05:26:18
Nie wiem co prawda jak wygląda kod Twojego silnika, ale ten pseudo zapis powinien coś Tobie dać:
Position position;
...
if( sprite->type == CHARACTER )
    position.y -= 1;
sprite->Draw( screen, position );

Z poważaniem,
Krzysztof.
« Ostatnia zmiana: Wrzesień 30, 2018, 05:37:56 wysłana przez ChristopherTaivaus »

Offline Kyroaku

  • Użytkownik

# Wrzesień 30, 2018, 13:22:18
Cytuj
Nie wiem co prawda jak wygląda kod Twojego silnika, ale ten pseudo zapis powinien coś Tobie dać:
Position position;
...
if( sprite->type == CHARACTER )
    position.y -= 1;
sprite->Draw( screen, position );
Powinien dać do zrozumienia, czego nie powinno się robić. Rozwiązanie, które dopisał OP jest miliard razy lepsze, bo jest ogólne, nie szczególne.

Offline ChristopherTa...

  • Użytkownik

# Październik 11, 2018, 14:16:14
Nie wiem co prawda jak wygląda kod Twojego silnika, ale ten pseudo zapis powinien coś Tobie dać:
Position position;
...
if( sprite->type == CHARACTER )
    position.y -= 1;
sprite->Draw( screen, position );
Z poważaniem,
Krzysztof.
Powinien dać do zrozumienia, czego nie powinno się robić. Rozwiązanie, które dopisał OP jest miliard razy lepsze, bo jest ogólne, nie szczególne.
Dziękuję szanownemu koledze Kyroaku'owi, że przypomniał mi jak działa system edukacyjny w Polsce.
Dla wszystkich innych, którzy chcieliby się dostać do gamedev'u lub do korpo na jakieś dobre stanowisko, lub chce podwyższyć swoje kwalfikacje, wytłumacze swoją opinię.
Sprawa pierwsza: umiejętność czytania ze zrozumieniem.
Jeśli ktoś pisze pseudo kod lub przedstawia schemat blokowy istotną rzeczą jest interpretacja, a nie odczyt dosłowny (jeśli ktoś czytający przygotowuje się do matury z informatyki - i chce ją zdać -, lub w firmie, do której się wybiera, dział HR robi test - i chce się dostać do tej firmy - to radzę to zapamietać).
Stosując powyższą zasadę, następujące:
Position position;
...
if( sprite->type == CHARACTER )
    position.y -= 1;
sprite->Draw( screen, position );
powinno być przekształcone mniej więcej w:
Position position;
...
for( int _y_ = ymin; _y_ <= ymax; _y_++ )
{
for( int _x_ = xmin; _x_ <= xmax; _x_++ )
{
position.x = _x_;
position.y = _y_;
tile[ _y_ * tilesw + _x_ ].sprite->Draw( screen, position );
}
}
for( int _character_ = 0; _character_ < maxchars; _charakter_++ )
{
position = character[ _character_ ].pos;
position.y--;
character[ _character_ ].sprite->Draw( screen, position );
}
gdyż:
if( sprite->type == CHARACTER )
    position.y -= 1;
wyraźnie mówi: sprite o typie bohatera ma być potraktowany inaczej!.
Sprawa druga: kompilator i zasada działania procesora.
Po pierwsze kompilator (zależy jak bardzo inteligentny) działania
x = a * b - c;
y = d * e - f;
może przekompilować na następujące instrukcje:
pomnoż:  x = a * b
pomnoż:  y = d * e
odejmij: x = x - c
odejmij: y = y - f
ponieważ w procesorach architektury x86 szybciej wykona się: mnożenie po mnożeniu, niż dodawanie po mnożeniu. Architektura ta ma dwa rodzaje czasu odpowiedzialnego za wykonywanie instrukcji:
 - latencje - rzeczywisty czas wykonania instrukcji w cyklach (może posiadać zakres);
 - throughput - czas w cyklach po którym ta sama instrukcja może rozpoczać wykonanie (np. mnożenie liczb całkowitych po mnożeniu liczb całkowitych), który jest mniejszy od latencji;
więc dwie te same instrukcje arytmetyczne pod rząd mogą się wykonać (w najgorszym wypadku) w czasie maksymalna latencja + throuput, zamiast maksymalna latencja + maksymalna latencja. Nawet w dzisiejszych architekturach, gdzie wykonanie nie nastepuję w koleności (out-of-order), dosłowna kompilacja:
pomnoż:  x = a * b
odejmij: x = x - c
pomnoż:  y = d * e
odejmij: y = y - f
wykona się w koleności: pomnoż, pomnoż, odejmij, odejmij (ponieważ żeby odjąć c i f muszą być znane wyniki mnożeń).
Dostawienie:
- m_surface->h + Globals::tilesizemoże spowodować skompilowanie obliczania wartości rect.y do postaci (zależnie czy kompilator układa obliczenia idąc od końca czy od początku - w lewo lub w prawo):
rect.y = ( position.y * SIZE - cam.y ) - ( surface->h + SIZE );
rect.y = ( position.y * SIZE ) - ( cam.y - surface->h + SIZE );
zależnie od wybranego kompilatora. Pomijam przeniesienie argumentu cam.y które może wystąpić w tym drugim przypadku (przyp. najpierw dodawanie, później odejmowanie). Może to być ważna informacja jeśli kod w przyszłości ma być upubliczniony i ktoś spróbuje skompilować go dość ciekawym kompilatorem.
( 10 * 32 - 64 ) - ( 32 + 32 ) = 192
( 10 * 32 ) - ( 64 - 32 + 32 ) = 320
Sprawa trzecia: optymalizacja.
W profesjonalnych silnikach operacje arytmetyczne na wektorach danych są wykonywane zbiorczo (w C++ poprzez przeciążenie operatora), więc orginalne:
x = a * b - c;
y = d * e - f;
można przekształcić w
p = pos * SIZE - cam;
rect.x = p.x;
rect.y = p.y;
co jest równe zapisowi z poprzedniego punktu, z tą różnicą, że jeśli dany procesor (nie musi to być procesor architektury x86) posiada zestaw instrukcji do operowania na wektorze danych, złożonego z dwóch 32-bitowych liczb całkowitych, kompilator może w tym wypadku ich użyć. Używając stareńkiego już zestawu MMX, procesorów x86, całość możnaby było wykonać w 6-7 instrukcjach (dodatkową instrukcją byłaby kopiująca SIZE jeśli zrobiłby to ktoś nie umiejętnie, gdyż z tą stałą możnaby było stworzyć stały wektor). W normalnych okolicznościach polecałbym zmiane odejmowania na dodawanie ze względu na szybkość wykonania, to dobra praktyka w przypadku liczb zmiennoprzecinkowych, ale w tym przypadku (wektorowym) nie ma to znaczenia. Wspomniana dobra praktyka dodawania po mnożeniu, przy liczbach zmiennoprzecinkowych, odzwierciedlić można przez istniejące pojedyncze instrukcje operujące na wektorach danych wykonujące te dwie operacje. Mnożenie możnaby było zmienić na operacje przesunięcia bitowego w lewo (jest szybsze o 1 cykl od mnożenia, a w przypadku niewektorowym prawie 2 razy wolniejsze od mnożenia). Dekrementacja position.y też ma nikłe benefity względem odejmowania jeśli jest w rejestrze i sytuację odwrotną jeśli jest w pamięci.
Zmieniłbym jeszcze układ klasy Sprite. Ale zapewne ta sugestia i powyższe sztuczki/uwagi to za dużo dla prostej gry. Powtarzam: przedstawiłem tylko mój punkt widzenia, reprezentowany przez kryptyczny zapis, skrytykowany poprzez wcześniej wspomnianego jegomościa. Mam nauczkę na przyszłość: pisać referaty, a nie skróty myśliowe...
Pozdrawiam.
Krzysztof.

Offline Kyroaku

  • Użytkownik

# Październik 11, 2018, 15:14:31
Napisałeś taki referat i nawet się nie zastanowiłeś, co miałem na myśli. Nie wiem, co chciałeś udowodnić, ale pod względem tego, o co mi chodziło, twój "przekształcony" kod jest tak samo kiepski, jak jego pierwsza wersja. Zadziała tylko dla obrazów o konkretnej, stałej wielkości. Serio, nic więcej nie miałem na myśli :)