Move Object from point A to point B

I was introduced to graphics by drawing on a grid of pixels. If I wanted to move an item that is in the center of a grid to another location it was very clunky, akin to a robot that can only move in a single direction then stop and think and change direction of its movement to go to the location traveling. This was used in the first stages of the game ColorCatch as pieces fall from the top of the screen and move to the bottom. As I started to create new levels I wanted a way to move them from point A to point B so that the list of points from A to B would be preset.

Note:There are no negative pixels in the user’s view with Android. the grid has origin (0,0) at the top left and the bottom corner is (screenWidth, screenHeight).

pic 2

Moving a piece straight down, you take the Y value and increment it. Now if we are moving from 0,0 at the top left, to the bottom right corner, this can be independent of screen size, I needed to find when to move the piece on its X axis and have it appear less clunky than a few over and a few down, it has to appear to move on a nice evenly spaced diagonal line. I am moving a rectangle object that contains the color so both the top and bottom of the rectangle need to move at the same time to keep the shape of the rectangle in tact. The speed variable is changed depending on the number of pixels on a screen, a larger screen will have a larger speed so the piece moves at the same visual rate on a large screen as it will on a small screen.

This is the basic move object down code.

@Override
public void move() {
rect.top += speed;
rect.bottom += speed;
}

This is the basic move object right code

@Override
public void move() {
rect.left += speed * direction;
rect.right += speed * direction;
}

or move right and down at the same time

@Override
public void move() {
rect.left += speed * direction;
rect.top += speed;
rect.right += speed * direction;
rect.bottom += speed;
}

I decided to write a way to find the path ahead of time from point A to B. The Moveable will not just blindly move or rely on the coding to do this at run time. This will allow for a one time path determination before the level loads or before the piece is needed in the game on screen. This will allow for easier use of background threads, freeing the main thread to do the drawing and other run time logic such as piece collecting and checking for pieces to be off screen.

@Override
public void plotPoints(Point a, Point b) {
points = plot.PlotLine(a, b);
}

This is called at some point before the piece is visible to the user and it populates a list of points called points. When plotting points the number of points is based on the longes distance between A and B either horizontally or vertically.

public Point[] plotLine(Point a, Point b) {
this.a = a;
this.b = b;
// create array of points based on longer x or y distance
if (Math.abs(a.y - b.y) > Math.abs(a.x - b.x)) {
pointArr = new Point[Math.abs(a.y - b.y)];
} else {
pointArr = new Point[Math.abs(a.x - b.x)];
}

for (int i = 0; i < pointArr.length; i++) {
point = new Point();
pointArr[i] = point;
}

PlotPointsToLocation();
return pointArr;
}

Since I want this to work for any direction we are going to have to decide which direction we want the piece to move, taking into account it could be a straight line as well. Looking at the x and y values you can tell which way the next point will be heading from comparing them. Draw the points on a grid and see if you can understand this more easily if its confusing.

private void PlotPointsToLocation() {
// move object up wards
if (a.y > b.y) {
if (a.x < b.x) { plotPointsUpRight(); } else if (a.x > b.x) {
plotPointsUpLeft();
} else {
plotPointsUp();
}
// move objects downwards
} else if (a.y < b.y) {
if (a.x < b.x) { plotPointsDownRight(); } else if (a.x > b.x) {
plotPointsDownLeft();
} else {
plotPointsDown();
}
// move left or right
} else if (a.x > b.x) {
plotPointsLeft();
} else {
plotPointsRight();
}
}

Now we know the direction the pieces are moving and can plot the points and allot or changes in the x or y values in the list. We can plot points based on the number of moves before we need to move in the other direction. A perfect diagonl line will increment the x and y values at an even rate, but the lines with more horizontal or vertical moves will need some sort of way to know to take one step this way and N steps that way. We can do this by finding the distance per move variable and then plot the line and every time the distance per move is up we can allot for this change and then continue the previous direction. There is chancee we are just one pixel off in one direction or the other in this case we want the point the diagonal to move at the mid way half of the line.

private void plotPointsUpRight() {
// get the number of vertical moves
double verticalPixels = Math.abs(a.y - b.y);

// get the number of horizontal moves
double horizontalPixels = Math.abs(a.x - b.x);

// case of equal up and right moves, a perfect diagonal line
if (horizontalPixels == verticalPixels) {

// cycle through the array and fill the points
for (int i = 0; i < horizontalPixels; i++) { point = new Point(); pointArr[i] = point; pointArr[i].x = a.x + i + 1; pointArr[i].y = a.y - i - 1; } } else if (horizontalPixels >= verticalPixels) {
// more horizontal moves in the line
pointArr = new Point[(int) horizontalPixels];

// create new points in array with x values filled
// we have a certainty that the line will move along the horizontal
// axis in its direction
for (int i = 0; i < horizontalPixels; i++) {
point = new Point();
pointArr[i] = point;
pointArr[i].x = a.x + i + 1;
}

// start filling in missing values
int startValue = a.y;
double distance = Math.abs(a.y - b.y);

// every x steps we need to move up or down a step as well
float distancePerMove = (float) distance / (float) (pointArr.length - 1);

// if this is 1.0 we have a near diagonal line with only 1 offset
// the offset should be accounted for in the middle of the line
if (distancePerMove == 1.0) {
float acc = startValue;
int i = 0;
while (i < (pointArr.length)) {
if (i != pointArr.length / 2) {
acc -= distancePerMove;
}
pointArr[i].y = Math.round(acc);
i++;
}
} else {

// set first and last y this is the starting point and
// the end point
pointArr[0].y = a.y;
pointArr[pointArr.length - 1].y = b.y;

// since we have a decimal it needs to round to find the best
// pixel
// to move
// this means that it will move down if possible or stay in
// line if needed.
float acc = startValue;
int i = 1;
while (i < (pointArr.length - 1)) {
acc -= distancePerMove;
pointArr[i].y = Math.round(acc);
i++;
}
}
} else {
// more vertical moves is similar but we are basing the line off
// the fact that the vertical pixels move evenly
pointArr = new Point[(int) verticalPixels];

// create new points in array with y values filled
for (int i = 0; i < verticalPixels; i++) {
point = new Point();
pointArr[i] = point;
pointArr[i].y = a.y - i - 1;
}

// start filling in missing values
int startValue = a.x;
double distance = Math.abs(a.x - b.x);

// every N steps down we move 1 step right
// N = distancePerMove
float distancePerMove = (float) distance / (float) (pointArr.length - 1);

// with a value of 1.0 we have a near diagonal line that should be offset
// only at the halfway point, its why we don't add distance at that point.
if (distancePerMove == 1.0) {
float acc = startValue;
int i = 0;
while (i < (pointArr.length)) {
if (i != pointArr.length / 2) {
acc += distancePerMove;
}
pointArr[i].x = Math.round(acc);
i++;
}

} else {
// set first and last x
pointArr[0].x = a.x;
pointArr[pointArr.length - 1].x = b.x;

float acc = startValue;
int i = 1;
while (i < (pointArr.length - 1)) {
acc += distancePerMove;
pointArr[i].x = Math.round(acc);
i++;
}
}
}
}

Leave a Reply

Your email address will not be published. Required fields are marked *

Subscribe for Post Notifications