There is a Geode whose Geometry is a ball with a MatrixTransform() assigned above it. It's callback function makes it falls. When the ball intersects with the ground, I hope to remove it from the scene.
The following code throws exception:
//inside the ball's callback
virtual void operator()(osg::Node* node ,osg::NodeVisitor* nv)
{
using namespace osg;
MatrixTransform* matrix_node = dynamic_cast<MatrixTransform*>(node);
Matrix matrix = matrix_node->getMatrix();
velocity += Vec3(0, 0, -0.002);
matrix.postMultTranslate(velocity);
matrix_node->setMatrix(matrix);
Vec3 now_position = start_position * matrix;
osgUtil::IntersectVisitor ivXY;
osg::ref_ptr<osg::LineSegment> lineXY = new osg::LineSegment(now_position, now_position+velocity);
ivXY.addLineSegment(lineXY);
GAME.main_camera->m_pHostViewer->getSceneData()->accept(ivXY) ;
if(ivXY.hits())
{
node->getParent(0)->removeChild(node);
}
return;
}
How to do it correctly? Thank you!
This is an excerpt from the OpenSceneGraph Group class (from which MatrixTransform inherits):
void Group::traverse(NodeVisitor& nv)
{
for(NodeList::iterator itr=_children.begin();
itr!=_children.end();
++itr)
{
(*itr)->accept(nv);
}
}
bool Group::removeChild( Node *child )
{
unsigned int pos = getChildIndex(child);
if (pos<_children.size()) return removeChildren(pos,1);
else return false;
}
Your code (which is called from traverse) throws an exception probably because the iterator gets invalidated in the middle of the loop, when removeChild is called. To remove the node you would have to wait at least until your node callback returns.
To resolve this I would just use a node mask to control whether the ball is displayed or not. Initially, set the ball node mask to the "visible" value. When the ball hits the ground, set the node mask to the "hidden" value. The node will not be traversed/rendered, but will still be in memory.
If memory is an issue, you can move the code to the parent node or outside the update traversal (e.g. use a modified Viewer::run method).
Related
I am working on a game project, and I am stuck with a situation. So I have a game object that if moves towards right and then enters again into the screen on the left (pacman effect) there is a new screen, I mean the screen is the same, but there should be with new other objects, but if the game object goes back, I should be able to see the older version of objects on the screen. So I have a list of lists of planets. I created them, and the thing I would like to "print" the the first element of the list if move forward, and if I move backwards I would like to see the previous element. I did think to try to use a circular version, but I decided I will not do that.
https://imgur.com/a/vCjk9iW
class planet {
//an shape planet has these charateristics
sf::CircleShape shape;
//etc
};
struct nodeplanet
{
planet Planet;
nodeplanet *planet;
}
typedef nodeplanet *ptr_listplanet;
//here I make a list with planet
class listofplanets
{
private:
ptr_listplanet head;
public:
listofplanets()
{
head = NULL;
}
ptr_listofplanets create ()
//etc;
};
//then i create a system of planets;
struct nodeSystem
{
listofplanets ListOfPlanets;
nodeSystem*next;
nodeSystem *prev;
}
ptr_listSystem GenerateNode()
{
ptr_listSystem tmp;
tmp = new nodeSystem;
tmp->ListOfPlanets = ListOfPlanets();
tmp->ListOfPlanets.create(randomnumber());
tmp->prev = NULL;
tmp->next = NULL;
return tmp;
}
ptr_listSystem GenerateSystem ()
{
for (int i=0; i<3; i=i+1){ //just a trial, creating three systems
ptr_listSistema newNode = GenerateNode();
newNode->prev = NULL;
newNode->next = head;
if (head!=NULL)
head->prev = newNode;
head = newNode;
}
return this->head;
}
void Visualize(sf::RenderWindow &window, Player player)
{
ptr_listSistema current = this->head;
float x;
//while (current!=NULL){
x = player.shape.getPosition().x;
current->ListOfPlanet.draw(window);
//if ((player.shape.getPosition().x > 1269))
if (x>1269)
{
//current = GenerateSystem();
current = current->next;
window.clear();
current->ListaPianeta.draw(window);
}
//if ((player.shape.getPosition().x< 3) && (Keyboard::isKeyPressed(Keyboard::Left)))
{
if ((x<3) && (Keyboard::isKeyPressed(Keyboard::Left)))
//p = current->prev;
current = current->prev;
if (current == NULL)
{
current = current->next; //in the case I am in the "head" screen, I should see the head screen;
}
window.clear();
current->ListOfPlanet.draw(window);
}
// }
}
the visualize function is the classic printing function of the list. at least I think, the list is already generated, if the player moves forward i should be able to see the planets generated in the next node, and if the player moves backwards i should be able to see the the previous node. I tried with the loop, using the while, but it's not that i should keep "printing", it depends. (I don't know if my idea is logically corrected)
Think you can simplify everything a lot. Just draw everything where it actually is. Then use a sf::View to represent the current visible screen and move that around accordingly:
// setup done only once, we'll reposition it later
sf::View screen(sf::Vector2(0,0), sf::Vector2(screen_width, screen_height));
// before drawing
screen.setCenter((std::floor(player.shape.getPosition().x / screen_width) + 0.5f) * screen_width, screen_height / 2);
window.setView(screen);
What this basically does is calculating the intended left border position of the screen (by dividing, rounding, then multiplying the screen width) and adjusting this with an offset for the screen center (the + 0.5f).
Obviously you could also duplicate the code for the X coordinate and reuse it for Y as well, allowing up/down transitions as well:
screen.setCenter((std::floor(player.shape.getPosition().x / screen_width) + 0.5f) * screen_width, (std::floor(player.shape.getPosition().y / screen_height) + 0.5f) * screen_height);
I have a scene and inside the scene I have the ellipses (circles) to which I change the position with setPos() so when I ask for its position later I will not get 0,0 coordinates, but now when I want to delete the object, the member function contains() does not ever evaluate to true understandably. The question is, how can I get to the scene coordinates or object coordinates so when I click on the object I get the true evaluation of contains() member function. I have tried the mapToScene(), mapFromScene() which do not help. (still kinda lost in Qt coordinate system)
Code sample:
void MyQGraphicsView::mousePressEvent(QMouseEvent * e)
{
QPointF pt = mapToScene(e->pos());
if(e->button()==Qt::RightButton)
{
// remove point
QList<QGraphicsItem *> listIt = scene->items();
QList<QGraphicsItem *>::const_iterator stlIter;
QGraphicsItem * itemToRemove = NULL;
QGraphicsEllipseItem it; // for type checking
for(stlIter = listIt.begin(); stlIter != listIt.end(); ++stlIter)
{
// if it has the expected type and the point is inside (type checking is redundant)
if(((*stlIter)->type() == it.type()) && ((*stlIter)->contains(pt))){
// contains(pt) is never true - understandably
itemToRemove = *stlIter;
break;
}
}
if(itemToRemove != NULL) scene->removeItem(itemToRemove);
}else{ // leftClick to add ellipse
double rad = 10;
QGraphicsEllipseItem* pEllipse = scene->addEllipse(-rad, -rad, rad*2.0, rad*2.0, QPen(Qt::red,0), QBrush(Qt::red,Qt::SolidPattern));
pEllipse->setPos(pt.x(), pt.y()); // set the postion so it does not return 0,0
}
}
The QGraphicsItem::contains method takes points in local coordinates, that is in coordinates with (0, 0) being the center of the QGraphicsItem.
You are using points in global scene coordinates.
To get a point in local coordinates of a given QGprahicsItem you can use the QGraphicsItem::mapFromScene(const QPointF & point) method.
You might want to do something like :
for(Object& obj : objects)
if(obj.contains(obj.mapFromScene(point)))
// do stuf because point is inside obj
Sources :
http://doc.qt.io/qt-4.8/graphicsview.html#item-coordinates
http://doc.qt.io/qt-4.8/qgraphicsitem.html#contains
I'm implementing A* path planning algorithm for my main robots exploration behavior in C++. As the robot moves, it maps the environment around itself as a 2D graph. From this graph, I have set a Vector2D Tuple {x, y} which holds the location of this waypoint, where I want the robot to navigate too.
The first thing I do with A* is to have a Node class, which holds information about the current node;
double f; // F, final score
double g; // Movement cost
double h; // Hueristic cost (Manhatten)
Node* parent;
Vector2d position;
As A* starts, I have my starting node as my Robots starting position (I also hold this position as a Vector for easy access). Then, I enter a while loop until the end goal is found. The first thing I do in this loop is to generate eight adjacent Nodes (Left, Bottom, Right, Top, Top-left, Top-Right, Bottom-Left, Bottom Right), I then return this in a OpenList vector.
// Open List is current nodes to check
std::vector positions;
positions.push_back(Vector2d(current->position.getX() - gridSize, current->position.getY())); // Left of my current grid space (parent node)
positions.push_back(Vector2d(current->position.getX() + gridSize, current->position.getY())); // right of my current grid space (parent node)
positions.push_back(Vector2d(current->position.getX(), current->position.getY() + gridSize)); // Top of my current grid space (parent node)
positions.push_back(Vector2d(current->position.getX(), current->position.getY() - gridSize)); // Bottom of my current grid space (parent node)
positions.push_back(Vector2d(current->position.getX() + gridSize,current->position.getY() + gridSize)); // Top Right of my current grid space (parent node)
positions.push_back(Vector2d(current->position.getX() - gridSize,current->position.getY() + gridSize)); // Top Left of my current grid space (parent node)
positions.push_back(Vector2d(current->position.getX() + gridSize,current->position.getY() - gridSize)); // Bottom Right of my current grid space (parent node)
positions.push_back(Vector2d(current->position.getX() - gridSize,current->position.getY() - gridSize)); // Bottom Left of my current grid space (parent node)
// moving diagnolly has a bigger cost
int movementCost[8] = { 10, 10, 10, 10, 14, 14, 14, 14 };
// loop through all my positions and calculate their g, h and finally, f score.
for (int i = 0; i < positions.size(); i++)
{
Node* node = new Node(positions[i]);
node->parent = current;
node->movementCost = movementCost[i];
if (!presentInClosedList(node))
{
// if the probability value of the current node is less then 0.5 (not an obstacle) then add to the open list, else skip it as an obstacle
// Set astar grid occupancy
if (grid->getProbabilityValue(node->position) < 0.51)
{
node->g = current->g + movementCost[i];
node->h = (abs(positions[i].getX() - wantedLocation.getX())) + (abs(positions[i].getY() - wantedLocation.getY()));
node->f = node->g + node->h;
openList.push_back(node);
}
}
}
This is the code to see if the current node is present in my closedList
bool exists = false;
for (int i = 0; i < closedList.size(); i++)
{
if (closedList[i]->position == currentNode->position)
{
closedList[i]->f = currentNode->f;
closedList[i]->g = currentNode->g;
closedList[i]->h = currentNode->h;
closedList[i]->parent = currentNode->parent;
exists = true;
break;
}
}
return exists;
This returns an openlist of possible routes. Next, I select the one with the smallest F score, and add this to my closedList. I keep doing this routine until the end goal has been found. Finally, once found I go back down the list using the parent objects. Here is the rest of the code
// If my parents location is the same as my wanted location, then we've found our position.
if (locationFound(current, wantedLocation))
{
// Now we need to backtrack from our wantedNode looking at the parents of each node to reconstruct the AStar path
Node* p = current->parent;
rollingDist = p->g;
while (!wantedFound)
{
if (p->position == startLocation)
{
wantedFound = true;
wantedNodeFound = true;
break;
}
path.push_back(p);
p = p->parent;
}
}
Now this is my issue. On every attempt it always finds the wanted location, but never the shortest path. See figure one below.
Figure one. Where the yellow marker is the wanted location, and the red darts is the "Path" to my wanted location, and finally, the "Blue" marker is where A star began.
This is my issue. I can't seem to reconstruct this path.
To recap the comments, there are two important problems
Manhattan distance is not admissible for your movement costs, since the actual shortest path can take a diagonal shortcut that Manhattan distance wouldn't take into account.
Before adding a new node to the Open list, it not only necessary to check whether it is in the Closed list, but also whether it is already in the Open list. If it is already in the Open list, the G's have to be compared and the smallest must be chosen (together with the corresponding parent pointer).[1]
Since you have octile movement with 10/14 costs, your heuristic function could be (from http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html)
function heuristic(node) =
dx = abs(node.x - goal.x)
dy = abs(node.y - goal.y)
return D * (dx + dy) + (D2 - 2 * D) * min(dx, dy)
With D = 10, D2 = 14. Of course you can also use anything else admissible but this formula already reflects the actual distance on an open plain so it can't easily be improved.
Finding and updating nodes in the Open list is an annoying part of A* that I'm sure many people would like to pretend isn't necessary, since it means you can't reasonably use any pre-defined priority queue (they lack efficient lookup). It can be done by having a manually implemented binary heap and a hash table that maps coordinates to their corresponding indexes in the heap. The hash table has to be updated by the heap whenever a node is moved.
[1]: the relevant snippet of pseudo code from the wikipedia article is:
tentative_gScore := gScore[current] + dist_between(current, neighbor)
if neighbor not in openSet // Discover a new node
openSet.Add(neighbor)
else if tentative_gScore >= gScore[neighbor]
continue // This is not a better path.
// This path is the best until now. Record it!
cameFrom[neighbor] := current
gScore[neighbor] := tentative_gScore
fScore[neighbor] := gScore[neighbor] + heuristic_cost_estimate(neighbor, goal)
I have search but can't find a anything specific to my case.
I wanna implement a graph in c++ using linked list only. My structure is as below:
class Vertex
{
public:
Vertex(std::string name = "none");
private:
std::string name;
Edge *edges;
Vertex *next;
Runnable *runnables;
};
class Edge
{
public:
Edge();
private:
Vertex *connectsTo;
Edge *next;
};
class TaskGraph{
public:
TaskGraph();
private:
Vertex *head;
};
I have a method to add vertices to the graph
void addVertex(TaskGraph* taskGraph, const std::string&);
This method works well as I can print out all the vertices in the graph. On the otherhand, to add directed edge, I did something like this:
void MyGraph::addEdge(TaskGraph* taskGraph, const string& src, const string& dest){
//get to the source vertex: this is ok
//get to the destination vertex: this is also ok
//add edge : the problem is here // s is source vertex while d is destination vertex.
Edge *e = new Edge;
e->connectsTo = d;
if(s->edges == 0){
s->edges = e;
}else{
s->edges->next = e;
}
}
After adding say 5 edges, only two is actually added (i.e. the first and list edges, others are being replaced). I figure out it's because of this line: "s->edges->next = e;" but can't figure out how to implement it correctly. Please help!!!
Thanks
You are breaking your list. when you insert the edge. So you first case always works. you just add e are your edge.
The other case will add e as second edge but will loose all other edges previously added.
try this instead:
//add edge : the problem is here
Edge *e = new Edge;
e->connectsTo = d;
//If there is already a list node pointing to in s->edges...
if(s->edges != 0){
//Then apply the existing list to the back of the new node.
// this add the exiting edges to the new one so you do not break the list.
e->next = s->edges;
}
//Apply e as the head of the list (pointing to it via s->edges).
s->edges = e;
This algorithm adds the new edge at the front of the list so they will appear in reverse order as the order you added them in.
To keep edges in the same order as they were inserted you can do as suggested below looping or adding a tail pointer for the last edge in the list..
The most important here is that you understand what you where doing wrong.
You started with
S->edges->NULL
you added an edge E1 you you get
S->edges->E1.next->NULL
Now you added the second edge E2 and:
S->edges->E1.next->E2.next->NULL
So far so good. But when you add E3 this what what happened:
S->edges->E1.next->E3.next->NULL lost link to E2.next->NULL
This is why you only had 2 edges in your list no matter how many edges you tried to add. It is also called a memory leak because you have lost all references to the E2 instance and you cannot clean up those objects.
Ok, that said this is and example implementation for what the others where talking about in the comments below about how to keep the list in the same order as the edges you added. So E1 is first E2 second, etc...:
class Vertex
{
public:
Vertex(std::string name = "none");
private:
std::string name;
Edge *edges;
Edge *lastEdge; // this will keep track of the last edge in the list.
// with this pointer you avoid having to loop through all
// the edges every time to add to the end.
Vertex *next;
Runnable *runnables;
};
void MyGraph::addEdge(TaskGraph* taskGraph, const string& src, const string& dest)
{
//get to the source vertex: this is ok
//get to the destination vertex: this is also ok
//add edge : the problem is here // s is source vertex while d is destination vertex.
Edge *e = new Edge;
e->connectsTo = d;
if(s->edges == 0)
{
s->edges = e;
// set the last edge to point to the first item.
s->lastEdge = e;
}
else
{
// In this case the logic is simple you already know that
// the list is not empty and that lastEdge is pointing at the
// last edge in the list so just make the current lastEdge
// point to the new edge. This will grow your list with e at
// the end.
// Then update lastEdge to point to the new edge you just added.
// so that is it pointing to the end of the list again.
s->lastEdge->next = e;
s->lastEdge = e;
}
}
I've realized that CCPhysicsSprite is different in a few ways from CCSprite. For example, you must set the body before you set the position of the sprite. I believe it is one of these differences that is causing an EXC_BAD_ACCESS error when I try destroying the body. I call the scheduleSprite method in the update method.
-(void)scheduleSprite {
if ([testSprite physicsSprite].b2Body != NULL) {
b2Vec2 force = b2Vec2(-5, 10.0 * [testSprite physicsSprite].b2Body->GetMass());
[testSprite physicsSprite].b2Body->ApplyForce(force, [testSprite physicsSprite].b2Body->GetWorldCenter() );
if ([testSprite physicsSprite].position.x < 0) {
world->DestroyBody([testSprite physicsSprite].b2Body);
[testSprite physicsSprite].b2Body = NULL;
}
}
}
I get an EXC_BAD_ACCESS pointing to line
b2Vec2 pos = _b2Body->GetPosition();
in the
-(CGAffineTransform) nodeToParentTransform
method, within the class
CCPhysicsSprite.mm
Thanks.
Despite you destroyed the body, the sprite will keep doing its stuff, so you may remove the sprite from its parent also, something like.-
if ([testSprite physicsSprite].position.x < 0) {
world->DestroyBody([testSprite physicsSprite].b2Body);
[[testSprite physicsSprite] removeFromParentAndCleanup:YES];
}
- (void) killBody:(cpBody*)body
{
cpBodyEachShape_b(body, ^(cpShape *shape) {
cpSpaceRemoveShape( _space, shape );
cpShapeFree(shape);
});
cpSpaceRemoveBody( _space, body );
cpBodyFree(body);//edited to include this line
CCPhysicsSprite* sprite = (__bridge CCPhysicsSprite*) body->data;
[sprite removeFromParentAndCleanup:true];
}
I was getting the same thing, the method above seemed to fix it.
First, remove the shapes attached to the body from the space. I'm using _space as a instance variable pointing to a cpSpace object. Next, remove the body from the space. Finally, remove the sprite from the parent.
When I make a CCPhysicsSprite object, I connect its body to the sprite using body->data. You can see that in the method above.
If you are starting with a CCPhysicsSprite object, you would first get the cpBody object from the sprite, then remove the body and shape as shown above.