2010-11-27 17 views
1

J'ai créé une zone plane ouverte avec des cylindres fins comme des rondelles, ils rebondissent autour de la zone et ont une détection de collision pour certains grands cylindres également placés sur l'avion. J'essaie de les amener maintenant vers un point fixe dans l'avion en utilisant une méthode de direction. La direction travaille pour éviter les obstacles en calculant la distance par rapport à l'obstacle puis en calculant l'angle entre la direction et l'obstacle, en calculant la distance de l'obstacle lorsque la rondelle est trop proche qu'elle se dirige vers la gauche ou vers la droite basé sur l'angle calculé. La même technique inversée ne fonctionne pas pour se diriger vers un point, j'ai essayé d'utiliser acos et atan2 pour calculer l'angle entre la direction et la direction de la cible et des sorties je pense que ce bit est correct mais quand j'essaie d'utiliser Pour me diriger vers la cible, j'obtiens des résultats inattendus. Parfois tournant au hasard?Implémentation du comportement de recherche d'objets sur un plan dans OpenSceneGraph?

#include "Puck.h" 
#include <iostream> 
#include <fstream> 
using namespace std; 
#include <math.h> 

ofstream fout("danna.txt"); 

#ifndef M_PI 
#define M_PI 3.1415 
#endif 

class TranslateCB : public osg::NodeCallback 
{ 
    public: 
    TranslateCB() : _dx(0.), _dy(0.), _dirx(1), _diry(0), _inc(0.1), _theta(0) {} 

    TranslateCB(Puck** pp, Obstacle** ob, int count, double r, double x, double y) : _dx(0.), _dy(0.), 
_dirx(2.0*rand()/RAND_MAX-1), _diry(2.0*rand()/RAND_MAX-1), _inc(0.3), _theta(0) 
{ 
    obstacles = ob; 
    ob_count = count; 
    _radius = r; 
    _x = x; 
    _y = y; 
    puckH = pp; 

} 

virtual void operator()(osg::Node* node,osg::NodeVisitor* nv) 
{ 
    osg::MatrixTransform* mt = 
    dynamic_cast<osg::MatrixTransform*>(node); 
    osg::Matrix mR, mT; 
    mT.makeTranslate(_dx , _dy, 0.); 
    mt->setMatrix(mT); 

    double ob_dirx; 
    double ob_diry; 
    double ob_dist; 
    double centerX=0, centerY =0; 
    _theta = 0; 
    double min = 4; 

    // location that I am trying to get the pucks to head towards 
    centerX = 1; 
    centerY = 5; 

    double tDirx = (_x+_dx) - centerX; 
    double tDiry = (_y+_dy) - centerY; 
    double tDist = sqrt(tDirx*tDirx+tDiry*tDiry); //distance to target location 

    // normalizing my target direction 
    tDirx = tDirx/tDist; 
    tDiry = tDiry/tDist; 

    double hDist = sqrt(_dirx*_dirx + _diry*_diry); //distance to next heading 
    _dirx= _dirx/hDist; 
    _diry= _diry/hDist; 

    double cAngle = acos(_dirx*tDirx+_diry*tDiry); //using inverse of cos to calculate angle between directions 
    double tAngle = atan2(centerY - (_y+_dy),centerX - (_x+_dx)); // using inverse of tan to calculate angle between directions 
    double tMin = tDist*sin(cAngle); 

    //if statement used to define when to apply steering direction 
    if(tMin > 3) 
    { 
     if(tDist < 1){ _theta = 0; }  //puck is inside target location, so keep travelling straight 
     if(cAngle > M_PI/2){ _theta = -0.1; } //turn left 
     else{ _theta = 0.1; } //turn right 
    } 
    else{ _theta = 0; } 

    ////// The collision detection for the obstacles that works on the same princables that I am using above 
    for(int i = 0; i < ob_count; i++) 
    { 
     ob_dirx = (_x+_dx) - obstacles[i]->x; 
     ob_diry = (_y+_dy) - obstacles[i]->y; 
     ob_dist = sqrt(ob_dirx*ob_dirx+ob_diry*ob_diry); 

     if (ob_dist < 3) { 

       //normalise directions 
       double ob_norm = sqrt(ob_dirx*ob_dirx+ob_diry*ob_diry); 
       ob_dirx = (ob_dirx)/ob_norm; 
       ob_diry = (ob_diry)/ob_norm; 
       double norm = sqrt(_dirx*_dirx+_diry*_diry); 
       _dirx = (_dirx)/norm; 
       _diry = (_diry)/norm; 

      //calculate angle between direction travelling, and direction to obstacle 
      double angle = acos(_dirx*ob_dirx + _diry*ob_diry); 
      //calculate closest distance between puck and obstacle if continues on same path 
      double min_dist = ob_dist*sin(angle); 

      if(min_dist < _radius + obstacles[i]->radius && ob_dist < min+obstacles[i]->radius) 
      { 
       min = ob_dist; 
       if(ob_dist < _radius + obstacles[i]->radius){ _theta = 0; } 
       else if(angle <= M_PI/2){ _theta = -0.3; } 
       else{ _theta = 0.3; } 
      } 
     } 
    } 


    //change direction accordingly 
    _dirx = _dirx*cos(_theta) + _diry*sin(_theta); 
    _diry = _diry*cos(_theta) - _dirx*sin(_theta); 

    _dx += _inc*_dirx; 
    if((_x+_dx > 20 && _dirx > 0) || (_x+_dx < -20 && _dirx < 0)) 
    { 
     _dirx = -_dirx; 
     _diry += (0.2*rand()/RAND_MAX-0.1); //add randomness to bounce 
    } 
    _dy += _inc*_diry; 
    if((_y+_dy > 20 && _diry > 0) || (_y+_dy < -20 && _diry < 0)) 
    { 
     _diry = -_diry; 
     _dirx += (0.2*rand()/RAND_MAX-0.1); //add randomness to bounce 
    } 

    traverse(node, nv); 

} 

private: 
double _dx,_dy; 
double _dirx,_diry; 
double _inc; 
double _theta; 
double _radius; 
double _x,_y; 
Obstacle** obstacles; 
Puck** puckH; 
int ob_count; 
}; 

Puck::Puck() 
{ 

} 

void Puck::createBoids (Puck** pucks, Group *root, Obstacle** obstacles, int count, double xx, double yy) 
{ 
    // geometry 
    radius = 0.2; 
    x = xx; 
    y = yy; 
    ob_count = count; 

    Cylinder *shape=new Cylinder(Vec3(x,y,0),radius,0.1); 
    ShapeDrawable *draw=new ShapeDrawable(shape); 
    draw->setColor(Vec4(1,0,0,1)); 
    Geode *geode=new Geode(); 
    geode->addDrawable(draw); 

    // transformation 
    MatrixTransform *T=new MatrixTransform(); 
    TranslateCB *tcb = new TranslateCB(pucks, obstacles,ob_count,radius,x,y); 
    T->setUpdateCallback(tcb); 
    T->addChild(geode); 

    root->addChild(T); 

} 

toute aide serait incroyable!

+0

S'il vous plaît comment il "ne fonctionne pas pour diriger vers un point". Et aussi nettoyer votre code et rendre plus lisible ... supprimer les commentaires de la ferraille, l'indentation correcte et enlever les espaces excessifs ... – ronag

+0

S'il vous plaît décrire comment il * ... – ronag

+0

désolé pour le vague, j'ai essayé de le rendre plus clair ce Cela se passe, j'ai supprimé les commentaires qui n'identifient pas les blocs de code et j'ai essayé de corriger l'indentation (lorsque la copie à partir du formatage du studio visuel semble être perdue). Merci d'avoir regardé. –

Répondre

0

Le problème ici est que la technique qui «fonctionne» pour éviter les obstacles se produira toujours lorsque la rondelle se dirige vers l'obstacle. Cette condition spéciale fait à la fois la direction de la rondelle et la direction de l'obstacle dans les quadrants adjacents. Cependant, lorsqu'on essaie de rapprocher les rondelles de l'obstacle, la technique se détériore parce que la rondelle s'éloignera probablement de l'obstacle, n'ayant plus la condition que les vecteurs cible et direction se trouvent dans les quadrants adjacents. La méthode correcte pour déterminer la direction de braquage est de faire pivoter le vecteur cible d'un angle qui rendrait le point vectoriel directionnel droit dans les quadrants (0, 1). Maintenant que le vecteur cible est relatif au vecteur de direction (0, 1), en regardant la composante x du vecteur cible, on déterminera la direction de direction. Si la composante x du vecteur cible est négative, la rondelle doit tourner à gauche pour se diriger vers la cible (augmenter l'angle). Si la composante x du vecteur cible est positive, la rondelle doit tourner à droite pour se diriger vers la cible (diminuer l'angle).

Tenir compte l'extrait suivant écrit en Python pour vérifier, il doit encore être facile à lire pour vous de saisir le concept:

from math import * 

dirX = 0.0 
dirY = 0.0 
targX = 1.0 
targY = 0.0 


def dir(): 
    global dirX, dirY, targX, targY 
    # get magnitiude of direction 
    mag1 = sqrt(dirX*dirX + dirY*dirY) 
    if mag1 != 0: 
     # normalize direction vector 
     normX = dirX/mag1 
     normY = dirY/mag1 
    # get magnitude of target vector 
    mag2 = sqrt(targX*targX + targY*targY) 
    if mag2 != 0: 
     # normalize target vector 
     targX = targX/mag2 
     targY = targY/mag2 
    # find the angle need to rotate the dir vector to (0, 1) 
    rotateAngle = (pi/2.0) - atan2(normY, normX) 
    # rotate targ vector by that angle (we only care about the x component) 
    relTargX = cos(rotateAngle) * normX + sin(rotateAngle) * normY 
    # if the target vector's x is negative 
    if relTargX < 0: 
     # turn left 
     print "Left!" 
    # otherwise the target vector is 0 or positive 
    else: 
     # turn right 
     print "Right!" 

def out(): 
    global dirX, dirY, targX, targY 
    # function just prints values to the screen 
    print "dir(%f, %f) targ(%f, %f)" % (dirX, dirY, targX, targY) 

# for values 0 to 360 
for i in range(360): 
    # pretend this is the pucks direction 
    dirX = sin(radians(i)) 
    dirY = cos(radians(i)) 
    # print dir and target vectors to screen 
    out() 
    # print the direction to turn 
    dir() 

Je suppose que je pourrais avoir écrit cela en C++, mais par rapport à lancer une invite python c'est une douleur royale. Il est aussi lisible que n'importe quel code pseudo que j'aurais pu écrire et les concepts fonctionneront indépendamment de la langue.

+0

Bien sûr, maintenant que la bonne méthode pour déterminer la direction à utiliser est utilisée, vous pouvez soit éviter, soit vous diriger vers les cibles, et cela fonctionnera correctement. – manifest