1

I am on a Tron Lightbike. I want to go to a point but I can only make 90-degree turns. This prevents line shapes like this: Bresenham Line Algorithm And only alows lines like this:

enter image description here

Storing these moves I have a Queue implementation (FIFO) that stores the moves as Integers.

UP:    0
RIGHT: 1
DOWN:  2
LEFT:  3

I have the enemy's X and Y position, and I have my X and Y position. I want to make a line where all points are connected (no diagonals) that goes from me to the enemy, and store the direction numbers in my Queue.

What is the way to generate this type of line?

Aly
  • 847
  • 1
  • 6
  • 30
  • I believe you would have to define the drawing behavior for whenever each turn is hit. So, assuming you have some grid and say you are at [2][3], and you hit UP, then you must update your position to [2][4], and then draw a rectangle in that position. At least that's how I would go about implementing something like this in say JavaFX – SomeStudent Aug 04 '16 at 17:50
  • @SomeStudent I am not drawing a line, I am trying to fill a queue with move directions that makes the line as straight as it can. – Aly Aug 04 '16 at 17:52
  • I suppose a similar logic would still apply? adds the move command to said Queue? So you said you know your position, and you know your enemies. Then say you are at [2][3] and enemy is at [1][7], you could do 4 moves to the Right, and one Down; unless I am misunderstanding. Your directions will aways update either your X or Y only, only way to create a diagonal is if your move will update both positions at once. Since it is a 90 degree turn, it only updates one position at a time; at least that's how i am seeing it – SomeStudent Aug 04 '16 at 17:54
  • @SomeStudent I know how to fill/read from the queue, and I know I can get there by going straight up and then straight right, but I am trying to do it in what looks like a straight line. – Aly Aug 04 '16 at 17:55
  • So you want to make a bunch of smaller moves that approximate a straight line. You probably want something like [Brezenham's line algorithm](https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm) to compute the points, and then make small adjustments based on your 90-degree turn restriction. This question might be of some help to you: http://stackoverflow.com/questions/4672279/bresenham-algorithm-in-javascript – Jim Mischel Aug 04 '16 at 19:45
  • @Jim My question specifically asks HOW to turn that line into one with 90 degree angles – Aly Aug 04 '16 at 19:50
  • You start by generating the points with Brezenham's algorithm. Then you'll have to do some post processing to add the squares that make the diagonal moves into two 90-degree turns. If I had a full answer, I would have posted it. I gave you what I think is a good starting place from which you should be able to make progress. In the line you showed, for example, all you have to do is add another square to each of the horizontal line segments, except the last one. If you experiment with that idea, you should be able to develop a general algorithm. – Jim Mischel Aug 04 '16 at 23:56
  • @m69 wouldn't on a 67.5 degree angle I would go right for a while then go at a 45 degree angle up? – Aly Aug 05 '16 at 16:23
  • I gave it some more thought and posted what I think is a better method. – m69's been on strike for years Aug 05 '16 at 19:41

1 Answers1

3

I assume you want a result like this:

grid line

This can be achieved by moving from the source cell to the target cell, going e.g. right and down one cell at a time, and deciding each step based on the vertical distance from the ideal line to the center point of the grid cell:

enter image description here

If x is half the size of a grid cell, and α is the slope of the ideal line, then the threshold vertical distance from the center point to the ideal line is x.(1 - tan(α)). If the distance is smaller than this, move horizontally, if it is larger than this, move vertically.

You can also look at it like this: if the ideal line only goes through the left and right edge of the current cell, move horizontally; if it goes through the top/bottom edge of the current cell, move up/down.

If the ideal line is more vertical than horizontal (tangent > 1) use a similar method, but turned 90°: measure the horizontal distance from the cell center to the ideal line, and move vertically for a smaller distance, and horizontally for a greater distance.


This JavaScript code snippet shows the algorithm for mainly horizontal lines, like in the example, and the equivalent method for mainly vertical lines, using the cotangent:

function tronPath(a, b) {
    var path = [a];
    var x = a.x, y = a.y;                         // starting cell
    var dx = a.x == b.x ? 0 : b.x > a.x ? 1 : -1; // right or left
    var dy = a.y == b.y ? 0 : b.y > a.y ? 1 : -1; // up or down
    if (dx == 0 || dy == 0) {
        // STRAIGHT LINE ...
    }
    else if (Math.abs(b.x - a.x) > Math.abs(b.y - a.y)) {
        // MAINLY HORIZONTAL
        var tan = (b.y - a.y) / (b.x - a.x);      // tangent
        var max = (1 - Math.abs(tan)) / 2;        // distance threshold
        while (x != b.x || y != b.y) {            // while target not reached
            var ideal = a.y + (x - a.x) * tan;    // y of ideal line at x
            if ((ideal - y) * dy >= max) y += dy; // move vertically
            else x += dx;                         // move horizontally
            path.push({x:x, y:y});                // add cell to path
        }
    }
    else {
        // MAINLY VERTICAL
        var cotan = (b.x - a.x) / (b.y - a.y);    // cotangent
        var max = (1 - Math.abs(cotan)) / 2;      // distance threshold
        while (x != b.x || y != b.y) {            // while target not reached
            var ideal = a.x + (y - a.y) * cotan;  // x of ideal line at y
            if ((ideal - x) * dx >= max) x += dx; // move horizontally
            else y += dy;                         // move vertically
            path.push({x:x, y:y});                // add cell to path
        }
    }
    return path;
}
var a = {x:1, y:1}, b = {x:11, y:5};
var path = tronPath(a, b);
document.write(JSON.stringify(path));