Autor Wątek: Brak synchronizacji  (Przeczytany 3125 razy)

Offline jelcynek

  • Użytkownik

# Marzec 13, 2014, 21:49:35
Cześć warsztatowicze.
Spotkałem się z problemem z którym nie umiem sobie poradzić. Może mądre głowy wpadną na pomysł co może być nie tak. W swojej grze posiadam wrogów, którzy mają tą samą prędkość, te przesunięcie, obiekty są właściwie takie same, tylko mają inną pozycję. Powinny one się ruszać synchronicznie. Jednak w pewnym przedziale ekranu ruch traci synchronizację.
Pętla gry wykonuje update w tym samym momencie z tym samym dt. Parametry obiektów sprawdzałem i są poprawne. Nawet dodałem licznik wywołań funkcji update na każdy obiekt i liczniki są zsynchronizowane. Nie mam pomysłów co się tu może dziać. Wpadłem nawet na takie abstrakcyjne pomysły, że zachodzi problem z typem float, ale za mała różnica w częśći całkowitej by to mogło jakoś wpłynąć. Zresztą dlaczego wtedy dwaj ostatni wrogowie się poruszają poprawnie. Opis wydaje się mętny więc poniżej link do filmiku. Może spotkaliście się z czymś takim. Nie mam pomysłu co to może być.
Wątpie by to miało jakiekolwiek znaczenie, ale gra jest pisana w xna. W ogóle dziwna sytuacja. Mogę jedynie zaręczyć, że parametry obiektów są poprawne. Prędkości wszystkich jednostek są takie same. Odległości ruchu także. Funkcje update są wykonywane w tym samym czasie, z takim samym dt. Więc wtf?

youtub: http://youtu.be/RfSM_c2mAPc

Offline Mr. Spam

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

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Marzec 13, 2014, 21:57:54
Cytuj
Wpadłem nawet na takie abstrakcyjne pomysły, że zachodzi problem z typem float, ale za mała różnica w częśći całkowitej by to mogło jakoś wpłynąć.
Od kiedy to float zważa na coś takiego jak część całkowita?

Tak czy inaczej, z filmiku widać wyraźniej że felerne obiekty albo poruszają się szybciej, albo mają coś z deltą, albo z licznikiem czasu "odbijania się". Wszystko zależy od tego jak dokładnie masz to zrobione.

A jeżeli mimo wszystko podejrzewasz floaty, to przerób to na fixed point.

Offline jelcynek

  • Użytkownik

# Marzec 13, 2014, 22:05:58
Cytuj
Od kiedy to float zważa na coś takiego jak część całkowita?
Być może się mylę, ale rozumiem to tak, że wraz ze wzrostem wartości całkowitej, spada dokładność części ułamkowej. Więc teoretycznie pozycja może wpływać na dokładność zmian. Oczywiście to sytuacja abstrakcyjna bo różnice by musiały być ogromne.

Cytuj
Tak czy inaczej, z filmiku widać wyraźniej że felerne obiekty albo poruszają się szybciej, albo mają coś z deltą, albo z licznikiem czasu "odbijania się". Wszystko zależy od tego jak dokładnie masz to zrobione.
Oczywiście wszystko co piszesz wydaje się oczywiste. Jednak po sprawdzeniu to wszystkie obiekty powinny się zachowywać tak samo. Parametry mają te same. Jedynie pozycje początkową inną.

Cytuj
A jeżeli mimo wszystko podejrzewasz floaty, to przerób to na fixed point.
Nie wiem jakim cudem mogę podejrzewać floaty, ale nie mam już innych pomysłów. Nawet nie mam pomysłu jak to zdebugować. Najbardziej mnie dziwi ta "strefa" na ekranie w której jest różnica.

Offline Kyroaku

  • Użytkownik

# Marzec 13, 2014, 22:23:34
Nie wiem, jak Ty to zrobiłes, ale ja bym to zrobił tak, ze animowalbym pewien punkt, a nie każdy obiekt osobno.
Cos w stylu:
Point p(0, 0); //ten punkt to przesunięcie KAZDEGO obiektu
for(każdy obiekt)
{
obiekt.draw(obiekt.x + p.x, obiekt.y + p.y); //rysuj obiekt przesunięty o punkt p
}
Dodatkowo, jesli chcesz, aby obiekty atakowaly, lub wystepowaly z szeregu, etc, to do klasy obiekt podpiac bool freeObiekt; ktory zdecyduje, czy przesuwac obiekt o punkt p, czy nie.
Jak dla mnie, to poprostu dla części obiektów zbyt szybko zmieniasz kierunek poruszania. Ja bym nie oskarżał floata, ponieważ zwykle (w moim przypadku) kończy się to przeprosinami xD

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Marzec 13, 2014, 22:29:21
Cytuj
Być może się mylę, ale rozumiem to tak, że wraz ze wzrostem wartości całkowitej, spada dokładność części ułamkowej.
No nie dokładnie, bo nie ma tu jasnego podziału na część całkowitą i ułamkową.

Cytuj
Oczywiście to sytuacja abstrakcyjna bo różnice by musiały być ogromne.
Albo dużą liczbę razy sumować ten sam błąd. Np. co klatkę przez kilkanaście sekund. ;)

Cytuj
Nie wiem jakim cudem mogę podejrzewać floaty, ale nie mam już innych pomysłów. Nawet nie mam pomysłu jak to zdebugować. Najbardziej mnie dziwi ta "strefa" na ekranie w której jest różnica.
Jeśli to rzeczywiście floaty i precyzja, to mnie ta strefa zupełnie nie dziwi. Na części ekranu są zaokrąglenia w górę, potem na innej w dół, a potem znowu w górę.

Ale tak serio, to zrób lepiej ten fixed point. :)

Offline Veldrin

  • Użytkownik

# Marzec 13, 2014, 22:30:21
Problem nie tkwi pewnie w typach danych, a ich wykorzystywaniu. Masz błędy w kodzie. Jakie to Ci nikt nie wywróży dopóki nie zarzucisz kodem (dziwie się, że jeszcze tego nie zrobiłeś pomimo wygenerowania wielu linijek tekstu).


Offline Xirdus

  • Redaktor

# Marzec 13, 2014, 22:33:21
Ja obstawiam że walnąłeś się przy wyliczaniu punktu w którym ma się zmienić kierunek - np. kolejne obce mają współrzędne 50, 100, 150, 210, 260, 310, 350. Podaj tutaj dane na temat ścieżki obiektów - nie wiem w jakiej formie masz to napisane, więc najlepiej postnij wszystko. By zmniejszyć ilość elementów, zapodaj tylko górny rząd obcych. Na 99% podczas samego pisania swojego posta odkryjesz błąd.

Offline steckel

  • Użytkownik

# Marzec 14, 2014, 11:26:47
No nie dokładnie, bo nie ma tu jasnego podziału na część całkowitą i ułamkową.
Pewnie mu chodziło o podział na mantysę i wykładnik.

Offline jelcynek

  • Użytkownik

# Marzec 14, 2014, 22:13:21
Wychodzi na to, że nie rozumiem liczb zmiennoprzecinkowych tak dobrze jak myślałem. Z jakiegoś powodu, pomimo że każdy obiekt teoretycznie powinien się przesuwać o taką samą wartość po jakimś czasie na ostatnim miejscu po przecinku zaczynają powstawać różnice.

Funkcja update ruchu:
        public void Update(GameTime gameTime)
        {
            currentPosition.X += (float)(gameTime.ElapsedGameTime.TotalSeconds * speed.X);
            currentPosition.Y += (float)(gameTime.ElapsedGameTime.TotalSeconds * speed.Y);

            animation.Update(gameTime);

            if (speed.X > 0)
            {
                if (currentPosition.X > targetPosition.X)
                    currentPosition.X = targetPosition.X;
            }
            else
            {
                if (currentPosition.X < targetPosition.X)
                    currentPosition.X = targetPosition.X;
            }

            if (speed.Y > 0)
            {
                if (currentPosition.Y > targetPosition.Y)
                    currentPosition.Y = targetPosition.Y;
            }
            else
            {
                if (currentPosition.Y < targetPosition.Y)
                    currentPosition.Y = targetPosition.Y;
            }

            if (currentPosition.Y == targetPosition.Y && currentPosition.X == targetPosition.X)
                Bounce();
        }

Powyższy kod standardowo na początku wykonuje przesunięcie w osi X i Y. Następne ify sprawdzają, czy w którejś z osi nie został przekroczony punkt docelowy i następuje w takim wypadku dosunięcie do punktu. Jak oś x i y jest w punkcie docelowym następuje odbicie (Bounce), czyli zmiana kierunku ruchu na obu osiach).

gameTime.ElapsedGameTime.TotalSeconds jest doublem, speed.X i speed.Y to floaty. W zasadzie TotalSeconds będzie w każdej ramce taki sam bo gra jest zsynchronizowana do 30 fps.

Czy ja coś źle robię, czy może jedynym rozwiązaniem jest fixed point? Przy okazji może jakiś dobry art o zmiennoprzecinkowych posiadacie, bo właśnie się przekonałem, że ciągle tego nie "czuję" do końca.

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Marzec 14, 2014, 22:27:39
Cytuj
Z jakiegoś powodu, pomimo że każdy obiekt teoretycznie powinien się przesuwać o taką samą wartość
No nie wiem według jakiej to teorii. Według tego jak działają floaty, to i teoretycznie i praktycznie powinny się one przesuwać o tą samą wartość plus błąd zaokrąglenia.

Offline jelcynek

  • Użytkownik

# Marzec 14, 2014, 22:28:57
Czyli jedynym sensownym rozwiązaniem jest fixed point?

Offline Xirdus

  • Redaktor

# Marzec 14, 2014, 23:03:56
Zamiast iteracyjnie zmieniać pozycję, określ ich pozycję jako okresową funkcję położenia od czasu. Albo poruszaj tylko pierwszym obiektem, a resztę ustaw na pozycję pierwszego plus stałe przesunięcie.

Offline laggyluk

  • Użytkownik
    • twitter

# Marzec 14, 2014, 23:06:46
W zasadzie TotalSeconds będzie w każdej ramce taki sam bo gra jest zsynchronizowana do 30 fps.
rly? delta od ostatniej ramki będzie taka sama ale jej nie używasz. patrząc po nazwie funkcji to gameTime.ElapsedGameTime.TotalSeconds powinno zwracać za każdym razem inny (większy) rezultat

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Marzec 14, 2014, 23:14:02
Czyli jedynym sensownym rozwiązaniem jest fixed point?
Nie jedynym, ale ma realną szansę być jednym z najprostszych w implementacji.

Offline Xirdus

  • Redaktor

  • +1
# Marzec 14, 2014, 23:17:30
rly? delta od ostatniej ramki będzie taka sama ale jej nie używasz. patrząc po nazwie funkcji to gameTime.ElapsedGameTime.TotalSeconds powinno zwracać za każdym razem inny (większy) rezultat
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.gametime.elapsedgametime.aspx