kubawal Temat założony przez niniejszego użytkownika |
[SFML] [Fizyka 2D] Fizyka platformówki - problem » 2014-01-11 18:06:32 Witam! Pisze platformówkę i mam kłopoty z fizyką. Kolizja góra-dół z platformami działają, ale ludzik, gdy najdzie z boku na platformę, nagle przeskakuje na jej dół lub górę. Oto fragment fizyki mojego programu: #define ENUM_ADDVAL(e, val) e = (decltype(e)) ((unsigned)e | (unsigned)(val)) #define ENUM_REMOVEVAL(e, val) e = (decltype(e)) ((unsigned)e & ~((unsigned)(val))) #define ENUM_ISVAL(e, val) ((unsigned)e & (unsigned) (val))
class Collision { public: private: FloatRect r1, r2; bool coll; void collision(); public: Collision( FloatRect rr1, FloatRect rr2 ); Collision( Sprite & t1, Sprite & t2 ); Collision( Object & ob1, Object & ob2 ); operator bool() const { return coll; } FloatRect get1Rect() const { return r1; } FloatRect get2Rect() const { return r2; } void recompute() { collision(); } };
class Player { public: class Jump { float jmpH; float jmpG; Time cmlT; float startY; float currY; float relativeY; public: Jump( float starty, float jmph, float gravity = 1200.0f ); void update( Time elapsed ); float getY() const { return currY; } float getStartY() const { return startY; } float getJmpH() const { return jmpH; } float getRelativeY() const { return relativeY; } }; class Fall { float falG; Time cmlT; float startY; float currY; public: Fall( float starty, float gravity = 1200.0f ); void update( Time elapsed ); float getY() const { return currY; } float getStartY() const { return startY; } Time getCmlTime() const { return cmlT; } }; enum Move { Left, Right, }; enum class Dir { Up = 1, Down = 1 << 1, Left = 1 << 2, Right = 1 << 3, None = 0, }; private: Jump * jmp; Fall * fall; unsigned dir; bool onGround; bool onGroundCall; void stopJmp() { if( jmp ) { delete jmp; jmp = NULL; ENUM_REMOVEVAL( dir, Dir::Up ); ENUM_REMOVEVAL( dir, Dir::Down ); } } void stopFall() { if( fall ) { delete fall; fall = NULL; ENUM_REMOVEVAL( dir, Dir::Down ); } } void startFall() { fall = new Fall( getPosition().y ); } public: Player( Vector2f pos ); Vector2f getPosition() const { return sp.getPosition(); } void setPosition( Vector2f pos ) { sp.setPosition( pos ); } Vector2f getSize() const { return Vector2f( sp.getGlobalBounds().width, sp.getGlobalBounds().height ); } void onCollision( Collision & c ); };
void Player::onCollision( Collision & c ) { Vector2f pos = getPosition(); if( ENUM_ISVAL( dir, Dir::Down ) || onGround ) { if( jmp ) { delete jmp; jmp = NULL; } if( fall ) { delete fall; fall = NULL; } ENUM_REMOVEVAL( dir, Dir::Down ); onGround = true; pos.y = c.get1Rect().top - getSize().y; } if( ENUM_ISVAL( dir, Dir::Up ) ) { if( jmp ) { delete jmp; jmp = NULL; } ENUM_REMOVEVAL( dir, Dir::Up ); ENUM_ADDVAL( dir, Dir::Down ); pos.y = c.get1Rect().top + c.get1Rect().height; fall = new Fall( pos.y ); } setPosition( pos ); }
Chcę, żeby gracz po wpadnięciu na bok platformy spadał, a nie wskakiwał na nią. Próbowałem jakoś to zaimplementować, ale się mi nie udawało. Postaram się zaraz wrzucić filmik, żeby zobrazować problem. PS. Czy opłaca się pisać własna fizykę do platformówki? Czy może lepiej użyć jakiegoś gotowego silnika(np.Box2d)? |
|
kubawal Temat założony przez niniejszego użytkownika |
» 2014-01-11 19:28:53 Na serio, nikt tutaj nie pisał platformówki? |
|
MrPoxipol |
» 2014-01-11 19:30:41 Może nikomu się nie chce szukać błędów w Twoim kodzie? Może niektórzy nie mają czasu? :) |
|
RazzorFlame |
» 2014-01-12 12:16:10 Zapisuj przejście między klatkami danego obiektu do jakiegoś vectora: sf::Vector2f a = obiekt.getPosition(); obiekt.wykonajRuch(); sf::Vector2f b = obiekt.getPosition();
Teraz: bool czyKolizja =[]( klasaObiekt ob1, klasaObiekt ob2 )->bool { if( ob1.x >= ob2.x && ob1.x <= ob2.x + ob2.w && ob1.y >= ob2.y && ob1.y <= ob2.y + ob2.h ) return true; else return false; }( obiekt, platforma );
Aby sprawdzić czy dir = Up lub dir = Left lub dir = Right: Jeżeli: czyKolizja = true oraz a.y+obiekt.h <= platforma.y oraz b.y >= platforma.y oraz b.y <= platforma.y + platforma.h TO obiekt koliduje górną krawędzią (lub jednym z boków po górnej stronie). Teraz aby dokładnie sprawdzić który bok koliduje z platformą musisz sprawdzić czy abs(a.x-b.x) < abs(a.y-b.y). Jeżeli tak to znaczy że obiekt nachodzi z góry. Przykład: if( abs( a.x - b.x ) < abs( a.y - b.y ) ) { } else { sf::Vector2f offset; offset.x = b.x - platforma.x; offset.y = b.y - platforma.y; if( offset.x < platforma.w / 2 ) { } else }
Podobnie dla kolizji następującej od dołu. Pamiętaj że w przykładzie otrzymujesz czy kolizja nastąpiła po górnej stronie, dzięki temu możesz wykryć 8 kolizji (góra, prawy górny róg, lewy górny róg, dół, prawy dolny róg, lewy dolny róg, lewa strona (lewy górny && lewy dolny) i prawa strona (prawy górny && prawy dolny)). |
|
kubawal Temat założony przez niniejszego użytkownika |
» 2014-01-12 19:34:39 Nie działa. Ludzik po próbie chodzenia po platformie "teleportuje" się za lewą lub prawą stronę platformy. Kod: if( ENUM_ISVAL( dir, Dir::Up ) ) { if( jmp ) { delete jmp; jmp = NULL; } ENUM_REMOVEVAL( dir, Dir::Up ); ENUM_ADDVAL( dir, Dir::Down ); pos.y = c.get1Rect().top + c.get1Rect().height; fall = new Fall( pos.y ); }
else if( abs( old.x - pos.x ) < abs( old.y - pos.y ) ) { onGroundCall = true; stopJmp(); stopFall(); ENUM_REMOVEVAL( dir, Dir::Down ); onGround = true; pos.y = c.get1Rect().top - getSize().y; } else { sf::Vector2f offset; offset.x = pos.x - obj.left; offset.y = pos.y - obj.top; if( offset.x < obj.width / 2 ) { ENUM_REMOVEVAL( dir, Dir::Right ); startFall(); st = NoMove; pos.x = obj.left - this->getSize().x; } else { ENUM_REMOVEVAL( dir, Dir::Left ); startFall(); st = NoMove; pos.x = obj.left + obj.width; } }
PS. jak miałby wyglądać ten algorytm dla kolizji od dołu? PPS. pisząc Podobnie dla kolizji następującej od dołu |
masz na myśli dół gracza czy platformy? |
|
« 1 » |