Autor Wątek: [SOLVED] SDL - problem z przesuwaniem obiektu  (Przeczytany 3357 razy)

Offline Dethas

  • Użytkownik

# Luty 03, 2014, 15:02:19
Witam, mam problem z którym od dłuższego czasu nie mogę sobie poradzić, chodzi o to że obiekt "kulka" ma poruszać się za myszką, problem polega na tym że kiedy myszka jest po lewej stronie wszystko jest ok, obiekt porusza się płynnie( kiedy odejmuje pixele od pozycji obiektu), jednak gdy jest po prawej stronie( pixele się dodaje do pozycji obiektu ) to kulka po prostu porusza się bardzo powoli i zupełnie bez ładu i składu oto kod odpowiadający za poruszanie się kulki względem myszki:

if( !( ( MouseX < 30 || MouseX > SCREEN_SIZE_X || MouseY < 30 || MouseY > SCREEN_SIZE_Y ) || ( ( MouseX - PlayerPosition.x - SizeR ) * ( MouseX - PlayerPosition.x - SizeR ) + ( MouseY - PlayerPosition.y - SizeR ) * ( MouseY - PlayerPosition.y - SizeR ) < 12 * 12 ) ) )
{
if( MouseX > PlayerPosition.x - SizeR )
{
PlayerPosition.x += ( Speed * DeltaTime );
}
if( MouseX < PlayerPosition.x + SizeR )
{
PlayerPosition.x -= ( Speed * DeltaTime );
}
if( MouseY > PlayerPosition.y - SizeR )
{
PlayerPosition.y += ( Speed * DeltaTime );
}
if( MouseY < PlayerPosition.y + SizeR )
{
PlayerPosition.y -= ( Speed * DeltaTime );
}

Speed - prędkość obiektu
DeltaTime - czas między klatką
SizeR - połowa długości obiektu, wyznaczam tym po prostu środek
« Ostatnia zmiana: Marzec 04, 2015, 21:28:32 wysłana przez Dethas »

Offline Mr. Spam

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

Offline Super Vegeta

  • Użytkownik
    • SV Games

# Luty 03, 2014, 16:07:46
Obstawiam źle sformułowane liczenie odległości w warunku. Gdy masz ( MouseX - PlayerPosition.x - SizeR ), co się dzieje:
a) mysz po lewej na x = 100, gracz na x = 200, sizer = 10. Wyliczona odległość X = abs(100 - 200 - 10) = abs(-110) = 110.
b) mysz po prawej na x = 200, gracz na x = 100, sizer = 10; Wyliczona odległość X = abs(200 - 100 - 10) = abs(90) = 90.

Offline Dethas

  • Użytkownik

# Luty 03, 2014, 16:39:22
W tym miejscu kodu nie ma na pewno błędu, ponieważ on liczy tylko kiedy kulka ma się zatrzymać czyli w odległości 12 pixeli od myszki, ale dla pewności wyciąłem ten kod tak aby ten warunek nie był sprawdzany i to nic nie zmieniło :/

Offline Super Vegeta

  • Użytkownik
    • SV Games

# Luty 03, 2014, 16:46:37
Między parami warunków nie masz else -  czy nie jest przypadkiem tak, że najpierw następuje przesunięcie w prawo z racji PlayerPosition.x += ( Speed * DeltaTime );, a potem drugi warunek jest spełniony i odpala się przesunięcie w lewo?

Offline Dethas

  • Użytkownik

# Luty 03, 2014, 17:01:17
Speed * DeltaTime to wielkości bardzo małe, jeśli myszka będzie o 200 pixeli na prawo od pozycji obiektu to jeśli warunek pójścia w prawo jest spełniony to niemożliwym jest aby warunek pójścia w lewo też się spełnił bo myszka musiała by się wtedy znajdować po lewej stronie obiektu, dodałem else tak jak zaproponowałeś ale niestety kulka teraz nawet przestała dążyć do myszki, idzie gdzieś niedaleko niej ale nie bezpośrednio tak że to niestety nie jest to, dziwnym jest że w lewo i w górę wszystko działa, czyli wtedy kiedy się spełni warunek w którym odejmuję pixele od pozycji, tylko w przypadku dodawania się tak dzieje, nie na odwrót

Offline Dethas

  • Użytkownik

# Luty 05, 2014, 00:41:15
Wklejam całą klasę "Player" i wszystko co z nią związane
class CPlayer
{
private:

public:
int SizeR, Speed;
SDL_Texture *PlayerTexture;
SDL_Rect PlayerPosition;
bool PlayerIsDead, PlayerIsHold, GameOn;
int Points, Range, Multiplayer;
CPlayer( int Size )
{
PlayerTexture = NULL;
Points = 0;
Range = 0;
PlayerPosition.x = 0;
PlayerPosition.y = 500;
PlayerPosition.w = Size * 2;
PlayerPosition.h = Size * 2;
Speed = 300;
PlayerIsHold = false;
PlayerIsDead = false;
GameOn = false;
SizeR = Size;
}
void ChaseMouse( int MouseX, int MouseY, double DeltaTime, CObjectsContainer *Container );
void CountPoints( int x );
void Reset();
};

Tutaj implementacja metod:

void CPlayer::ChaseMouse( int MouseX, int MouseY, double DeltaTime, CObjectsContainer *Container )
{
if( !PlayerIsDead )
{
if( Container->CheckColisions( PlayerPosition.x, PlayerPosition.y, SizeR )) PlayerIsDead = true;
}
if( !PlayerIsDead )
{
if( !( ( MouseX < 30 || MouseX > SCREEN_SIZE_X - 30 || MouseY < 30 || MouseY > SCREEN_SIZE_Y - 30 ) || ( ( MouseX - PlayerPosition.x - SizeR ) * ( MouseX - PlayerPosition.x - SizeR ) + ( MouseY - PlayerPosition.y - SizeR ) * ( MouseY - PlayerPosition.y - SizeR ) < 12 * 12 ) ) )
{
if( MouseX > PlayerPosition.x - SizeR )
{
PlayerPosition.x += ( Speed * DeltaTime );
}
if( MouseX < PlayerPosition.x + SizeR )
{
PlayerPosition.x -= ( Speed * DeltaTime );
}
if( MouseY > PlayerPosition.y - SizeR )
{
PlayerPosition.y += ( Speed * DeltaTime );
}
if( MouseY < PlayerPosition.y + SizeR )
{
PlayerPosition.y -= ( Speed * DeltaTime );
}
if( GameOn == true )
{
Multiplayer = Container->Container.size();
CountPoints( Speed * DeltaTime );
}
}
}
}

void CPlayer::CountPoints( int x )
{
Range += x;
if( Range >= 50 )
{
Points += 1 * Multiplayer;
Range -= 50;
}
}

void CPlayer::Reset()
{
Range = 0;
Points = 0;
PlayerIsDead = false;
GameOn = false;
}

No i pętla główna:
int CMainWindow::Events()
{

while( !WindowQuit )
{
if( SDL_PollEvent( &ActualEvent ) )
{
ActiveGame();
}
else
{
SDL_RenderClear( Renderer->Renderer );
TrueDelta = Frame->DeltaTime( Player->Points );
Player->ChaseMouse( MouseX, MouseY, TrueDelta, Container );
Container->Render( MainScreen, TrueDelta );
SDL_RenderCopy( Renderer->Renderer, BackGroundT, NULL, NULL );
SDL_RenderCopy( Renderer->Renderer, Player->PlayerTexture, NULL, &Player->PlayerPosition );
Renderer->RenderCopy( Container->Container );
Renderer->RenderPresent();
}
}
return 1;
}

int CMainWindow::ActiveGame()
{
if( ActualEvent.type == SDL_QUIT )
{
WindowQuit = true;
}
if( ActualEvent.type == SDL_KEYDOWN )
{
switch( ActualEvent.key.keysym.sym )
{
case SDLK_ESCAPE:
{
WindowQuit = true;
break;
}
case SDLK_q:
{
Tryb = true;
break;
}
case SDLK_w:
{
Tryb = false;
break;
}
case SDLK_n:
{
Container->AddBall( Renderer );
Player->GameOn = true;
break;
}
case SDLK_1:
{
Container->ClearContainer();
Player->Reset();
break;
}
}
}
if( ActualEvent.type = SDL_MOUSEMOTION )
{
MouseX = ActualEvent.motion.x;
MouseY = ActualEvent.motion.y;
}
return 1;
}

Offline Super Vegeta

  • Użytkownik
    • SV Games

# Luty 05, 2014, 10:22:47
Hm. Jeśli PlayerPosition to SDL_Rect, to X i Y są intami. Jeśli, jak mówisz, (Speed * DeltaTime) to wartości bardzo małe, to w takim razie, dla x = 100 i (speed * delta) = 0.1, co następuje:
przy odejmowaniu: x = int(100 - 0.1) = int(99.9) = 99
przy dodawaniu: x = int(100 + 0.1) = int(100.1) = 100

Offline Dethas

  • Użytkownik

# Luty 05, 2014, 14:29:30
No są bardzo małe bo gra osiąga ponad 400fps czyli muszę wyrównać fps na przykład do 100? Ale czy na pewno tak następuje zaokrąglenie przez program?
« Ostatnia zmiana: Luty 05, 2014, 14:31:36 wysłana przez Dethas »

Offline Super Vegeta

  • Użytkownik
    • SV Games

# Luty 05, 2014, 14:45:16
Trzymaj pozycję gracza jako floaty czy double i przy rysowaniu konwertuj sobie na inty.
A zaokrąglenie, duh, napisz sobie czterolinijkowy program i sprawdź, u mnie g++ daje dokładnie takie rezultaty.

Offline Dethas

  • Użytkownik

# Luty 05, 2014, 17:54:20
Ok, dzięki za pomoc, prawdopodobnie to jest to co mówisz ale jak coś to jeszcze napiszę ;]

Offline Dethas

  • Użytkownik

# Luty 06, 2014, 00:12:22
Zrobiłem jak napisałeś, trzymam teraz pozycję gracza we float i wszystko działa doskonale, dziękuje za pomoc,
problem został rozwiązany ;]