Autor Wątek: Problem ze spritem  (Przeczytany 1238 razy)

Offline Aloneman4

  • Użytkownik

# Grudzień 15, 2010, 23:43:19
Witam, jestem tu nowy.
Mam pewien problem i zdecydowałem się poprosić o radę.
      Od pewnego czasu, uczę się SDL w C++, idzie mi całkiem nieźle gdyby nie fakt że się zatrzymałem na pewnym problemie... :-\
Mianowicie, mam tło, ładnie się przewija kiedy chodzę moim spritem(taka kuleczka:D), ale sprite porusza się bardzo niekontrolowanie...Tzn. Kiedy wciskam np. prawą strzałkę przyjmując że sprite znajduje się na pozycji 0,0, to nagle przechodzi on kilka kroków i po prostu nagle przyspiesza i pojawia się po drugiej stronie mapy, czyli bardzo szybko tam przebiega...Wygląda to beznadziejnie i jest beznadziejne... Nie na tym koniec problemu...Kiedy podczas jego ruchu np. w tą prawą stronę wcisnę strzałkę w dół sprite przez sekundę może dwie nie reaguje na wciśniętą strzałkę w dół mimo iż strzałki w prawo już nie trzymam i jedzie dalej po czym po tej... jak mówiłem sekundzie, dwóch zjeżdża po skosie w dół i w prawo... :-[ Kto wie czym to może być spowodowane?! Słyszałem o jakiś "Timerach" ale nie wiem czy to przez to że ich u mnie nie ma tak się dzieje czy przez co... eh nie wiem, w każdym bądź razie, proszę o pomoc!

Offline Mr. Spam

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

Offline Xirdus

  • Redaktor

# Grudzień 15, 2010, 23:49:01
Pokaż pętlę główną gry oraz obsługę klawiszy.

Offline Lerhes

  • Użytkownik

# Grudzień 16, 2010, 00:12:01
A jak przetwarzasz zdarzenie kliknięcia klawisza? Używasz pętli przetwarzania? Jeżeli nie, to ją napisz, to bardzo proste! Tutaj masz jak:
http://xion.org.pl/productions/texts/coding/game-programming/real-time-loop/

Lerhes

Offline Aloneman4

  • Użytkownik

# Grudzień 16, 2010, 08:54:34
^^ Widzę że odpowiedzi tutaj przychodzą natychmiastowo: D
to moja pętla:

while(running)
    {
if(SDL_PollEvent(&event))
                  {
                                       mySprite.handle_input();
                                       if(event.type == SDL_QUIT)
                                       {
                                                     running = false;
                                       }
                                       mySprite.move();
                                       
                                       mySprite.set_camera();
                                       
                                       apply_surface(0,0,background,screen,&camera);
                                       
                                       mySprite.show();
                  }
    //apply_surface
    SDL_Flip(screen);
    }
    SDL_Quit();
    return 0;
}


a tu obsługa klawiszy:

void Sprite::handle_input()
{
    //If a key was pressed
    if( event.type == SDL_KEYDOWN )
    {
   
                key[event.key.keysym.sym] = true;
                if(key[SDLK_UP])
                  {
                                    dstY -= 0.2;
                                    yVel -= height / 2;
                  }
                if(key[SDLK_DOWN])
                  {
                                    dstY += 0.2;
                                    yVel += height / 2;
                  }
                if(key[SDLK_LEFT])
                  {
                                    dstX -= 0.2;
                                    xVel -= width / 2;
                  }
                if(key[SDLK_RIGHT])
                  {
                                    dstX += 0.2;
                                    xVel += width / 2;
                  } 
    }
    //If a key was released
    else if( event.type == SDL_KEYUP )
    {
                key[event.key.keysym.sym] = false;     
                if(key[SDLK_UP])
                  {
                                    dstY -= 0;
       
                  }
                if(key[SDLK_DOWN])
                  {
                                    dstY += 0;
                  }
                if(key[SDLK_LEFT])
                  {
                                    dstX -= 0;
                  }
                if(key[SDLK_RIGHT])
                  {
                                    dstX += 0;
                  } 
    }
}

Pisałem to sam a jestem nowy w SDL'u więc nie wiem czy jest dobrze ale pewnie pochrzaniłem... :P
No...Może nie do końca sam bo cały kod to pozmieniana wersja kilku tutoriali w tym lazyfoo bo jak sam mówiłem to dopiero się uczę SDL.
« Ostatnia zmiana: Grudzień 16, 2010, 09:02:55 wysłana przez Aloneman4 »

Offline Pomnico

  • Użytkownik
    • Magic-Ars

# Grudzień 16, 2010, 10:34:58
Nie znam się co prawda na SDL'u (i nie widzę reszty kodu), ale patrząc na to co podałeś widzę następujące problemy:
a) pętla główna aktualizuje sprite'a tylko jeśli przyszedł jakiś event (da się to tak zrobić, ale na pewno będzie trudniej zaimplementować poprawną synchronizację z czasem) - PollEvent zwraca 1 jeśli jest jakiś event, 0 w przeciwnym przypadku
b) nigdzie nie wykorzystujesz info o rzeczywistym upływie czasu
c) nie wiem jak używasz dst i vel (każde z nich z osobna można się domyślić, razem - nie mam pojęcia), ale problemem może być to że np. prędkości w żaden sposób nie ograniczasz (więc może rosnąć w nieskończoność)

Teraz sugestie:
a) przeczytaj artykuł, który podesłał Ci Lerhes (ale naprawdę go przeczytaj)
b) zmień pętlę na analogiczną do tej opisanej w tym artykule (aktualizuj pozycję sprite'a i odrysowuj klatkę tylko jeśli aktualnie nie ma żadnego zadania, czyli gdy PollEvent zwróci 0)
c) dodaj obsługę czasu (timer'y)
d) w obsłudze klawiszy tylko oznaczaj sobie że dany klawisz jest wciśnięty
e) w aktualizacji pozycji sprite'a używaj dwóch informacji: upływu czasu (jak dużo czasu upłynęło od ostatniej aktualizacji) i info o wciśniętych klawiszach; używając ich obu wiesz w którym kierunku przesunąć sprite'a (info o klawiszach) a także jak bardzo (ino o czasie - im więcej czasu upłynęło tym bardziej trzeba sprite'a przesunąć)
f) na początku zaimplementuj przesuwanie bez przyspieszania (czyli np. x_diff = time * const_speed)

Offline Lerhes

  • Użytkownik

# Grudzień 16, 2010, 11:55:18
Pomnico Ci wszystko wyjaśnił. Ja tylko jeszcze dodam, że gdy już zrobisz wszystko co ci zasugerował, to jeżeli potrzebujesz sprawdzać co obieg pętli, czy użytkownik nadal trzyma klawisz (przydatne w niektórych grach) wtedy SDL_PollEvent nie będzie dostawał nowych komunikatów. Mógłbyś w sumie zapamiętać to tak jak zrobiłeś (ale to niewygodne). Lepiej zrobić sobie coś takiego:

//Poza petla, najlepiej na poczatku funkcji main wpisz
Uint8 *keystate = SDL_GetKeyState(NULL);
//A potem w pętli (nie komunikatów, gdzieś w pętli głównej)
if(keystate[SDLK_RIGHT])
{
//Klawisz nadal jest wcisniety, wiec tutaj nadal przesuwaj obiekt. Tylko synchronizuj to przesuniecie z deltaT
}

Lerhes

Offline Aloneman4

  • Użytkownik

# Grudzień 16, 2010, 16:33:01
Dziękuję wam za te wyczerpujące odpowiedzi!:) Postaram się zastosować do tych uwag i porad ^^

Offline lastseeds

  • Użytkownik

# Grudzień 16, 2010, 16:42:10
caly czas zwiekszasz predkosc a nie polozenie.

Offline Aloneman4

  • Użytkownik

# Grudzień 16, 2010, 16:48:32
Dodam jeszcze cały mój kod to moglibyście mi troszkę doradzić co w nim pozmieniać żeby działało bo próbuje i w dalszym ciągu nie łapie jak to się dzieje że ludzik porusza się jak pijany :P Powiem Wam jeszcze że przed dodaniem scrollingu nie było takiego problemu;/ a kiedy dodałem scrolling to pojawiły mi się (przy pierwszej kompilacji po dodaniu) 2 sprite'y na sobie tzn. te same i kiedy jakiś klawisz np. prawa strzałka została wciśnięta to jeden sprite poruszał się szybko a drugi wolno...Eh... podobnie w OpenGL'u zauważyłem że po dodaniu tekstury na obiekt obserwator zaczyna raz zwalniać a raz przyspieszać chód

Oto i kod:
//Includy
#include <SDL/SDL.h>
#include <windows.h>
//Integers
const int WIDTH = 640;
const int HEIGHT = 480;
const int BPP = 32;

int width = 32;
int height = 32;

int srcX = 0;
int srcY = 0;

int dstX = 2;
int dstY = 2;

int SPRITE_WIDTH = 1661;
int SPRITE_HEIGHT = 1246;

const int FPS = 60;

int frame = 0;

bool cap = true;

bool running = true;

bool key[323] = {false};

SDL_Event event;
//Powierzchnie
SDL_Surface *screen = NULL;
SDL_Surface *background = NULL;
SDL_Surface *sprite = NULL;
//Funkcje
void Init_And_Video()
{
     SDL_Init(SDL_INIT_EVERYTHING);
     screen = SDL_SetVideoMode(WIDTH,HEIGHT,BPP,SDL_SWSURFACE);
     SDL_WM_SetCaption("SDLTutorial",NULL);
}
void ImagesLoad()
{
     background = SDL_LoadBMP("Data/Images/Backgrounds/Background.bmp");
     sprite = SDL_LoadBMP("Data/Images/CharacterImages/Ball.bmp");
     SDL_SetColorKey(sprite,SDL_SRCCOLORKEY,SDL_MapRGB(sprite->format,255,0,255));
}
void M_B()
{
     MessageBox(NULL,"Program rozpoczyna dzialanie!","Uwaga!",MB_OK);
     if(!SDL_LoadBMP("Data/Images/Backgrounds/Background.bmp"))
     {
                     MessageBox(NULL,"Nie znaleziono obrazu", "Blad!",MB_OK);
     }
     if(!SDL_LoadBMP("Data/Images/CharacterImages/Ball.bmp"))
     {
                                                             
                     MessageBox(NULL,"Nie znaleziono obrazu", "Blad!",MB_OK);
     }
}
void draw_sprite(int srcX, int srcY,int dstX,int dstY,int width,int height,SDL_Surface *source, SDL_Surface *destination)
{
     SDL_Rect src;
     src.x = srcX;
     src.y = srcY;
     src.w = width;
     src.h = height;
     
     SDL_Rect dst;
     dst.x = dstX;
     dst.y = dstY;
     dst.w = width;
     dst.h = height;
     
     SDL_BlitSurface(source,&src,destination,&dst);
}
void apply_surface(int x, int y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *clip = NULL)
{
     SDL_Rect rect;
     rect.x = x;
     rect.y = y;
     
     SDL_BlitSurface(source,clip,destination,&rect);
}
//kamera
SDL_Rect camera = {0,0,WIDTH,HEIGHT};
//klasa kamery
class Sprite {
      private:
              int xVel, yVel;
              public:
                     Sprite();
                     
                     void handle_input();
                     
                     void move();
                     
                     void show();
                     
                     void set_camera();
};
//Zdefiniowanie Sprite'a
Sprite::Sprite()
{
                dstX = 0;
                dstY = 0;
                xVel = 0;
                yVel = 0;
}
void Sprite::handle_input()
{
    //If a key was pressed
    if( event.type == SDL_KEYDOWN )
    {
   
                key[event.key.keysym.sym] = true;
                if(key[SDLK_UP])
                  {
                                    dstY -= 0.2;
                                    yVel -= height / 2;
                  }
                if(key[SDLK_DOWN])
                  {
                                    dstY += 0.2;
                                    yVel += height / 2;
                  }
                if(key[SDLK_LEFT])
                  {
                                    dstX -= 0.2;
                                    xVel -= width / 2;
                  }
                if(key[SDLK_RIGHT])
                  {
                                    dstX += 0.2;
                                    xVel += width / 2;
                  } 
    }
    //If a key was released
    else if( event.type == SDL_KEYUP )
    {
                key[event.key.keysym.sym] = false;     
                if(key[SDLK_UP])
                  {
                                    dstY -= 0;
       
                  }
                if(key[SDLK_DOWN])
                  {
                                    dstY += 0;
                  }
                if(key[SDLK_LEFT])
                  {
                                    dstX -= 0;
                  }
                if(key[SDLK_RIGHT])
                  {
                                    dstX += 0;
                  } 
    }
}
//Sprite ruch
void Sprite::move()
{
     dstX += xVel;
     if((dstX < 0)||(dstX + width > SPRITE_WIDTH))
     {
          dstX -= xVel;
     }
     dstY += yVel;
     if((dstY < 0)||(dstY + height > SPRITE_HEIGHT))
     {
          dstY -= yVel;
     }
}
//Umieszczamy kamere nad sprite
void Sprite::set_camera()
{
     camera.x = (dstX + width/2)-WIDTH/2; camera.y = (dstY + height/2)-HEIGHT/2;
     
     if(camera.x < 0)
     {
                 camera.x = 0;
     }
     if(camera.y < 0)
     {
                 camera.y = 0;
     }
     if(camera.x > SPRITE_WIDTH - camera.w)
     {
                 camera.x = SPRITE_WIDTH - camera.w;
     }
     if(camera.y > SPRITE_HEIGHT - camera.h)
     {
                 camera.y = SPRITE_HEIGHT - camera.h;
     }
}
void Sprite::show()
{
     apply_surface(dstX - camera.x, dstY - camera.y, sprite, screen );
}
//Funkcja glowna
int main(int argc, char *argv[])
{
    //Deklaracja Sprite'a
    Sprite mySprite;
    //Errors and messages
    M_B();
    //Init and video func
    Init_And_Video();
   
    DTTicks = SDL_GetTicks();
      //Image Load
    ImagesLoad();
    //Game loop
    while(running)
    {
                  if(SDL_PollEvent(&event))
                  {
                                       if(event.type == SDL_QUIT)
                                       {
                                                     running = false;
                                       }
                                       mySprite.move();
                                       
                                       mySprite.set_camera();
                                       
                                       apply_surface(0,0,background,screen,&camera);
                                       
                                       mySprite.show();
                                       
                                       mySprite.handle_input();
                  }
    //apply_surface
    SDL_Flip(screen);
    }
    SDL_Quit();
    return 0;
}


Będę wdzięczny jak pomożecie mi to ogarnąć: )