kubawal Temat założony przez niniejszego użytkownika |
[SFML] Precyzyjna kolizja (z których stron nachodzą na siebie obiekty) » 2013-12-10 17:29:03 Witam! Robię platformówkę i potrzebuję algorytmu na kolizję ze stronami, tzn. że podczas kolizji wiem, z których stron nachodzą na siebie obiekty. Doszedłem mniej więcej do takiego kodu: class Collision { public: enum Side { Top = 1, Bottom = 1 >> 1, Left = 1 >> 2, Right = 1 >> 3, All = Top | Bottom | Left | Right, None = 0 }; private: FloatRect r1, r2; Side s1, s2; bool coll; bool a; bool collision(); public: Collision( FloatRect rr1, FloatRect rr2, bool adv = false ); Collision( Sprite t1, Sprite t2, bool adv = false ); bool operator bool() const { return coll; } Side get1Side() const { return s1; } Side get2Side() const { return s2; } };
Player::Collision::Collision( FloatRect rr1, FloatRect rr2, bool adv ) { r1 = rr1; r2 = rr2; s1 = s2 = None; a = adv; collision(); }
Player::Collision::Collision( Sprite t1, Sprite t2, bool adv ) { r1 = t1.getGlobalBounds(); r2 = t2.getGlobalBounds(); s1 = s2 = None; a = adv; collision(); }
Player::Collision::collision() { coll = r1.intersects( r2 ); if( !a ) return; else { if( !coll ) return; Vector2f v11( r1.left, r1.top ), v12( r1.left + r1.width, r1.top ), v13( r1.left, r1.top + r1.height ), v14( r1.left + r1.width, r1.top + r1.height ); Vector2f v21( r2.left, r2.top ), v22( r2.left + r2.width, r2.top ), v23( r2.left, r2.top + r2.height ), v24( r2.left + r2.width, r2.top + r2.height ); } }
Wierzchołki są w układzie v1---------------v2 | | | | | | v3---------------v4
Algorytmika nigdy nie była moją mocną stroną, więc prosiłbym o nakierowanie bądź gotowca(z wytłumaczeniem). Zaznaczam, że nie chcę używać żadnej z dostępnych bibliotek fizycznych. |
|
maly |
» 2013-12-11 12:44:48 Kiedyś ktoś wrzucił prosty kod z kolizją trochę się nim wtedy bawiłem i powstało coś takiego, może się przyda. Komentarze odnośnie poprawności kodu jak i jego stylu niemile widziane;P #include <SFML/Graphics.hpp> #include <iostream> #include <vector> #include <cmath>
std::vector < sf::RectangleShape *> Walls; sf::RectangleShape player;
bool drawMap = true;
enum { SideLeft = 1, SideRight = 2, SideTop = 4, SideBottom = 8 };
sf::Vector2f getInterpolated( const sf::Vector2f & v1, const sf::Vector2f & v2, float d ) { float i = 1.0f - d; return sf::Vector2f(( v1.x * i + v2.x * d ),( v1.y * i + v2.y * d ) ); }
float getLength( const sf::Vector2f & v1, const sf::Vector2f & v2 ) { sf::Vector2f t = v1 - v2; return std::sqrt( t.x * t.x + t.y * t.y ); }
void setIf( sf::Vector2f & v, float len ) { v.x = v.x < 0 ? - len: v.x > 0 ? len: 0; v.y = v.y < 0 ? - len: v.y > 0 ? len: 0; }
bool isCollision( const sf::RectangleShape & rect, const std::vector < sf::RectangleShape *> & walls ) { const sf::FloatRect frect = rect.getGlobalBounds(); for( int i = 0; i <( int ) walls.size(); ++i ) if( frect.intersects( walls[ i ]->getGlobalBounds() ) ) return true; return false; }
void movePlayer( const sf::Vector2f & oldPos, const sf::Vector2f & newPos, bool & coll, int & collSide ) { const float steplen = 1.0; const float len = getLength( oldPos, newPos ); const int div = len / steplen; sf::Vector2f vstep = -( oldPos - newPos ); setIf( vstep, steplen ); #define tWalls Walls for( int i = 0; i < div; ++i ) { sf::Vector2f lp = player.getPosition(); player.move( vstep ); if( isCollision( player, tWalls ) ) { player.setPosition( lp ); coll ^= true; break; } } float alen = getLength( oldPos, player.getPosition() ); if( alen < len ) { int div = steplen; for( int i = 0; i <= div; ++i ) { sf::Vector2f nPos = player.getPosition(); player.move( vstep.x, 0 ); if( isCollision( player, tWalls ) ) { player.setPosition( nPos ); if( vstep.x < 0 ) collSide ^= SideLeft; else collSide ^= SideRight; break; } } for( int i = 0; i <= div; ++i ) { sf::Vector2f nPos = player.getPosition(); player.move( 0, vstep.y ); if( isCollision( player, tWalls ) ) { player.setPosition( nPos ); if( vstep.y < 0 ) collSide ^= SideTop; else collSide ^= SideBottom; break; } } } }
int main() { sf::RenderWindow window( sf::VideoMode( 800, 600 ), "" ); window.setFramerateLimit( 60 ); player.setSize( sf::Vector2f( 32, 32 ) ); sf::Vector2f orig = player.getSize(); player.setOrigin( orig.x *.5, orig.y *.5 ); player.setPosition( 400, - 100 ); srand( time( NULL ) ); int cnt = 0; const int maxcnt = 200; for( int y = 0; y < 60; ++y ) { for( int x = 0; x < 60; ++x ) { float sx = rand() %(( int ) player.getSize().x * 4 ) + 10; float sy = rand() %(( int ) player.getSize().y * 4 ) + 10; float px = x * player.getSize().x * 4 + sx; float py = y * player.getSize().y * 4 + sy; sf::RectangleShape tmp( sf::Vector2f( sx, sy ) ); tmp.setPosition( px, py ); std::cout << "gen map:" << maxcnt << "/" << cnt << "\r"; if( !isCollision( tmp, Walls ) ) { sf::RectangleShape * w = new sf::RectangleShape( sf::Vector2f( sx, sy ) ); w->setFillColor( sf::Color( sx, sy, px ) ); w->setPosition( px, py ); Walls.push_back( w ); ++cnt; if( cnt == maxcnt ) goto fuck; } } } fuck: std::cout << "total shapes " << cnt << std::endl; sf::Vector2f campos = window.getView().getCenter(); while( window.isOpen() ) { sf::Event event; while( window.pollEvent( event ) ) { if( event.type == sf::Event::KeyPressed ) { if( event.type == sf::Event::Closed || event.key.code == sf::Keyboard::Escape ) window.close(); if( event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::D ) drawMap = !drawMap; } } sf::Vector2f dir( 0, 0 ); bool playerMove = false; if( sf::Keyboard::isKeyPressed( sf::Keyboard::Left ) ) { dir.x = - 1; playerMove = true; } else if( sf::Keyboard::isKeyPressed( sf::Keyboard::Right ) ) { dir.x = 1; playerMove = true; } if( sf::Keyboard::isKeyPressed( sf::Keyboard::Up ) ) { dir.y = - 1; playerMove = true; } else if( sf::Keyboard::isKeyPressed( sf::Keyboard::Down ) ) { dir.y = 1; playerMove = true; } int collSide = 0; bool coll = false; if( playerMove ) { const float speed = 2.0; dir.x *= speed; dir.y *= speed; movePlayer( player.getPosition(), player.getPosition() + dir, coll, collSide ); } window.clear( sf::Color( 200, 200, 200 ) ); if( drawMap ) for( int i = 0; i <( int ) Walls.size(); ++i ) window.draw( * Walls[ i ] ); window.draw( player ); window.display(); std::string str; str += "[Simple collision 3] "; if( collSide & SideLeft ) str += " z lewej "; if( collSide & SideRight ) str += " z prawej "; if( collSide & SideTop ) str += " z gory "; if( collSide & SideBottom ) str += " z dolu "; window.setTitle( str ); sf::View view = window.getDefaultView(); sf::Vector2f inetr = getInterpolated( player.getPosition(), campos, 0.95 ); view.setCenter( inetr ); view.zoom(.8 ); window.setView( view ); campos = inetr; } return 0; } |
|
kubawal Temat założony przez niniejszego użytkownika |
» 2014-01-07 16:56:12 Odświeżam temat, bo nadal tego potrzebuję(nie chcę zakładać nowego tematu)- Zakodziłem trochę i doszedłem do wniosku, że potrzebuje wzoru na obliczenie, jaki kąt stanowi wektor przesunięcia do osi pionowej Niby czytałem coś o tych azymutach i innych szajstwach, ale nadal tego nie rozumiem. class Offset { Vector2f curr; Vector2f next; public: Offset( Vector2f c, Vector2f n ) : curr( c ) , next( n ) { } float getAngle() { float getLength() { return distance( curr, next ); } Vector2f getCurr() const { return curr; } Vector2f getNext() const { return next; } void setCurr( Vector2f c ) { curr = c; } void setNext( Vector2f n ) { next = n; } };
|
|
pekfos |
» 2014-01-07 17:36:06 Bottom = 1 >> 1, Left = 1 >> 2, Right = 1 >> 3,
|
Zły operator. |
|
kubawal Temat założony przez niniejszego użytkownika |
» 2014-01-07 17:39:49 No tak.
Ale to nadal nie rozwiązuje głównego problemu. |
|
pekfos |
» 2014-01-07 17:44:45 potrzebuje wzoru na obliczenie, jaki kąt stanowi wektor przesunięcia do osi pionowej |
Poczytaj o atan2(). |
|
DejaVu |
» 2014-01-07 18:35:20 Podobnych tematów było sporo:
http://cpp0x.pl/forum/temat/?id=5268
Poza tym jeden temat = jeden problem. Pomyśl jak zmienić temat, aby niósł jakąś wartość (adekwatną do rozwiązywanego problemu), bo obecnie jego nazwa nadaje się do kosza... (nazwa nie mówi krótko i precyzyjnie czego wątek dotyczy). |
|
« 1 » |