Algorithm for movement along linear line

五迷三道 提交于 2019-12-11 04:16:45

问题


Code:

I have a function as follows:

bool Action::approach (img_comp &mover, sf::Vector2f start, sf::Vector2f end, int speed)
{
    //Get the change in x and y
    float delta_x = (end.x - start.x) / speed;
    float delta_y = (end.y - start.y) / speed;

    //Move the sprite
    mover.sprite.move(delta_x, delta_y);

    //Check if the sprite has met the end
    if (mover.sprite.getPosition() == end)
        return true;

    return false;
}

(Where sf::Vector2f is basically a struct with an x and y float parameter, e.g. a point on an x-y grid)

Question:

Unsurprisingly, this function has a possibility to never return true after passing the end point due to the rounding of float. What algorithm do I use in this scenario to have my sprite land exactly on the end point, regardless of rounding?

Note: Tolerance is not an answer to my question. It is merely a compromise. I want the algorithm that picks the points perfectly the first time, regardless of any rounding. If this is impossible, let me know.


回答1:


i think you have the answer already, because of the rounding of float you should not do mover.sprite.getPosition() == end but to see if mover.sprite.getPosition() - end is smaller then some number, lets say

 float diff = mover.sprite.getPosition() - end;

 if (diff < 0)
    diff *= -1;

 //Check if the sprite has met the end
 if (diff > 0.01)
        return true;

that way you check not if you are on the spot but if you are close enough to the spot. to improve that you can also do:

 float diff = mover.sprite.getPosition() - end;

 if (diff < 0)
    diff *= -1;

 //Check if the sprite has met the end
 if (diff > 0.01){
        mover.sprite.getPosition() = end; //this might not be the exact syntax but the idea is clear i hope
        return true;
 }



回答2:


Your sprite can go to the left or to the right, so you should consider to use absolute difference between current position and end point.

Epsilon = 1e-9

deltaX = (end.x - start.x) / speed
deltaY = (end.y - start.y) / speed

dirX = Math.sgn(deltaX)
dirY = Math.sgn(deltaY)

mover.sprite.move(deltaX, deltaY);

crossedEndX = dirX * (mover.sprite.getPosition().x - end.x) > Epsilon
crossedEndY = dirY * (mover.sprite.getPosition().y - end.y) > Epsilon

if(crossedEndX && crossedEndY)
  return true



回答3:


Instead of a direct compare, you could do something like "if point is close to end then point = end"

/* Set TOLERANCE to whatever makes sense.
 * Could have different X and Y values too...
 */
#define TOLERANCE 0.01
sf::Vector2f &newPos = mover.sprite.getPoition();
if (abs(newPos[0] - end[0]) < TOLERANCE &&
    abs(newPos[1] - end[1]) < TOLERANCE) {
{
    mover.sprite.setPosition(end);
    result = true;
}


来源:https://stackoverflow.com/questions/17906535/algorithm-for-movement-along-linear-line

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!