Jump to content

  • Log In with Google      Sign In   
  • Create Account

Get a points coordinate


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
15 replies to this topic

#1 P0jahn   Members   -  Reputation: 270

Like
0Likes
Like

Posted 25 December 2012 - 07:20 PM

Look at these three pictures:

example1.png

example2.png

example3.png

 

So the red object is some sort of watcher. It watches the green object. However, I do not want the coordinates of the green object, but the black circle. Is there any way to calculate this? 

 

Some more info about my game, the top left corner is point 0,0, x increases while moving to the right and y is increasing when moving down, just like any other java coordinate system. The black circle is always going to be at the edge of the map.



Sponsor:

#2 Nyssa   Members   -  Reputation: 426

Like
1Likes
Like

Posted 25 December 2012 - 10:57 PM

So you want the direction to the green object from the red object?

 

direction = normalize(greenPos - redPos)

 

Then you can multiply the direction by the distance from the red object to the black circle. So if you wanted the black circle to appear 10 units away from the red object you would write:


blackCirclePos = direction * 10

 

 

 

Does that answer your question or have I misunderstood?



#3 Álvaro   Crossbones+   -  Reputation: 13368

Like
1Likes
Like

Posted 26 December 2012 - 05:24 AM

Well, I am afraid he doesn't know the distance to the black circle a priori. The black circle is wherever the ray intersects the edge of the map.

 

Consider a structure called a "ray" that contains the position of the red dot (the ray's "origin") and the direction (as defined in Nyssa's post). You can find a point along the ray as ray.origin + t*ray.direction. I would write a function that finds the intersection of a ray with a line, and returns the value of the parameter t where the intersection happens (use the dot product for this). Then call it four times for the edges of the map and pick the lowest non-negative value of the parameter. That should give you the position of the black dot.

 

I may post some easy-to-read C++ code to solve this later.


Edited by Álvaro, 26 December 2012 - 05:26 AM.


#4 Nyssa   Members   -  Reputation: 426

Like
0Likes
Like

Posted 26 December 2012 - 07:37 AM

The black circle is always going to be at the edge of the map.

 

Ah, right, missed that bit. Thanks for clearing that up Alvaro.



#5 Álvaro   Crossbones+   -  Reputation: 13368

Like
0Likes
Like

Posted 26 December 2012 - 08:47 AM

Here's some C++ code to solve the problem. I tried to not use references or static variables, to not confuse matters. But I couldn't get myself to not overload a few operators... Let me know if you have a hard time understanding what it's doing. But the function find_black_dot() is the key to it all, and it should be fairly easy to follow.
 
#include <iostream>
#include <cmath>
struct Vector {
  float x, y;
 
  Vector(float x, float y) : x(x), y(y) {
  }
};

Vector operator*(Vector v, float s) {
  return Vector(v.x*s, v.y*s);
}

float dot_product(Vector v, Vector w) {
  return v.x*w.x + v.y*w.y;
}

Vector normalize(Vector v) {
  return v * (1.0 / std::sqrt(dot_product(v, v)));
}

struct Point {
  float x, y;
 
  Point(float x, float y) : x(x), y(y) {
  }
};

std::ostream &operator<<(std::ostream &os, Point p) {
  return os << '(' << p.x << ',' << p.y << ')';
}

Vector operator-(Point p, Point q) {
  return Vector(p.x-q.x, p.y-q.y);
}

Point operator+(Point p, Vector v) {
  return Point(p.x+v.x, p.y+v.y);
}

struct Ray {
  Point origin;
  Vector direction;
 
  Ray(Point origin, Vector direction) : origin(origin), direction(direction) {
  }
};

// If dot_product(p-origin,normal)==constant, p is in the line
struct Line {
  Vector normal;
  float constant;
  
  Line(Vector normal, float constant) : normal(normal), constant(constant) {
  }
};

float find_intersection_parameter(Ray ray, Line line) {
  return (line.constant - dot_product(ray.origin-Point(0.0f,0.0f), line.normal))
    / dot_product(ray.direction, line.normal);
}

Point find_black_dot(Point red_point, Point green_point) {
  Line lines[4] = {
    Line(Vector(1.0f,0.0f), 0.0f),
    Line(Vector(1.0f,0.0f), 30.0f),
    Line(Vector(0.0f,1.0f), 0.0f),
    Line(Vector(0.0f,1.0f), 20.0f)
  };
 
  Ray ray(red_point, normalize(green_point-red_point));
  double min_non_negative_intersection_parameter = 1.0e20f;
  for (int i=0; i<4; ++i) {
    float intersection_parameter = find_intersection_parameter(ray, lines[i]);
    if (intersection_parameter >= 0.0f
        && intersection_parameter < min_non_negative_intersection_parameter)
      min_non_negative_intersection_parameter = intersection_parameter;
  }
 
  return ray.origin + ray.direction * min_non_negative_intersection_parameter;
}

int main() {
  Point red(16.5,10.5);
  Point green(11.5,15.5);
 
  std::cout << find_black_dot(red, green) << '\n';
}

Edited by Álvaro, 26 December 2012 - 08:57 AM.


#6 superman3275   Crossbones+   -  Reputation: 2061

Like
0Likes
Like

Posted 26 December 2012 - 11:20 AM

I would use the Pythagorean theorem and slope, however I'm just now getting into linear algebra tongue.png.


I'm a game programmer and computer science ninja ph34r.png!

Here's my 2D RPG-Ish Platformer Programmed in Python + Pygame, with a Custom Level Editor and Rendering System!

 

Here's my Custom IDE / Debugger Programmed in Pure Python and Designed from the Ground Up for Programming Education!

Want to ask about Python, Flask, wxPython, Pygame, C++, HTML5, CSS3, Javascript, jQuery, C++, Vimscript, SFML 1.6 / 2.0, or anything else? Recruiting for a game development team and need a passionate programmer? Just want to talk about programming? Email me here:

hobohm.business@gmail.com

or Personal-Message me on here smile.png!


#7 Álvaro   Crossbones+   -  Reputation: 13368

Like
1Likes
Like

Posted 26 December 2012 - 12:52 PM

You don't really need the Pythagorean theorem for this, and the method I proposed is also kind of overkill.

This is much simpler code that does the same thing. I should probably posted this solution before:
#include <iostream>

struct Point {
  float x, y;

  Point(float x, float y) : x(x), y(y) {
  }
};

Point find_black_dot(Point red_point, Point green_point) {
  float vertical_intersection_time = 1.0e20f;
  if (green_point.x > red_point.x)
    vertical_intersection_time = (30.0f-red_point.x)/(green_point.x-red_point.x);
  else if (green_point.x < red_point.x)
    vertical_intersection_time = (0.0f-red_point.x)/(green_point.x-red_point.x);

  float horizontal_intersection_time = 1.0e20f;
  if (green_point.y > red_point.y)
    horizontal_intersection_time = (20.0f-red_point.y)/(green_point.y-red_point.y);
  else if (green_point.y < red_point.y)
    horizontal_intersection_time = (0.0f-red_point.y)/(green_point.y-red_point.y);

  float time = std::min(horizontal_intersection_time,vertical_intersection_time);
  return Point(red_point.x + time * (green_point.x-red_point.x), red_point.y + time * (green_point.y-red_point.y));
}

int main() {
  Point red(16.5,10.5);
  Point green(11.5,15.5);

  Point black = find_black_dot(red, green);
  std::cout << '(' << black.x << ',' << black.y << ")\n";
}


#8 P0jahn   Members   -  Reputation: 270

Like
0Likes
Like

Posted 26 December 2012 - 03:06 PM

Thanks Alvaro. May I ask what type of data the returned point actually contains? If it is the black circle as you described, how can it find it without knowing the dimension of the map?
Also, can you suggest some sort of professional name for this method? :)

Edited by P0jahn, 26 December 2012 - 03:15 PM.


#9 Khatharr   Crossbones+   -  Reputation: 3007

Like
0Likes
Like

Posted 26 December 2012 - 04:13 PM

I didn't understand what you did the second time there (I need to copy it into SciTE and look at it more closely), but this is what I came up with (just because I like messing with this kind of problem).

 

struct Vector2 {
  int x;
  int y;
};

Vector2 findTargetAlignedBoundaryIntersection(Vector2 obsever, Vector2 target) {
  Vector2 targetDelta = { //vector to the target from the obserer
    target.x - observer.x,
    target.y - observer.y
  };
  
  //position of the relevant boundaries (will also be abused as a retval later)
  //start by assuming max bounds (lower right)...
  Vector2 boundary = {
    X_MAXIMUM_BOUND,
    Y_MAXIMUM_BOUND
  };
  //and then correct by axis when wrong
  if(targetDelta.x < 0) {boundary.x = X_MINIMUM_BOUND;}
  if(targetDelta.y < 0) {boundary.y = Y_MINIMUM_BOUND;}
  
  //vector from observer to relevant map corner
  Vector2 boundaryDelta = {
    boundary.x - observer.x,
    boundary.y - observer.y
  };
  
  //find ratio of boundary vs target deltas per-axis
  //(Edit - corrected against div-by-zero)
  //(Note - behavior is undefined if observer and target are equal)
  float xRatio = std::numeric_limits<float>::max();
  if(targetDelta.x) {xRatio = (float)(boundaryDelta.x) / targetDelta.x;}
  float yRatio = std::numeric_limits<float>::max();
  if(targetDelta.y) {yRatio = (float)(boundaryDelta.y) / targetDelta.y;}
  
  if(xRatio > yRatio) { //slope collides with y bound first
    boundary.x = observer.x + (targetDelta.x * yRatio);
  }
  else { //slope collides with x bound first
    boundary.y = observer.y + (targetDelta.y * xRatio);
  }
  
  return boundary;
}

 

Edit - Ah, I see. Same solution. Cool.

 

@P0jahn - He's just using 30.0f and 20.0f as map bounds there. You'd have to fill in the actual bounds where he uses the constants.


Edited by Khatharr, 27 December 2012 - 02:26 AM.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

#10 P0jahn   Members   -  Reputation: 270

Like
0Likes
Like

Posted 26 December 2012 - 05:23 PM

I guess 30.0f is the width and 20.0f is the height? So what is vertical_intersection_time and horizontal_intersection_time?

And as I am not a C++er, I guess std::min is Math.min in java?



#11 Álvaro   Crossbones+   -  Reputation: 13368

Like
0Likes
Like

Posted 26 December 2012 - 05:40 PM

Yes, 30.0 is the width and 20.0 is the height (as in the examples in the first post). I think of the ray as being a particle starting at the red point, moving at constant velocity so that at time 1 it is at the green point. I use vertical_intersection_time and horizontal_intersection_time to see when that particle would hit the edges of the map. Whichever one happens first is where the black dot will be.

 

std::min does what you expect: Return the minimum of two values. I don't know how you say that in Java.



#12 P0jahn   Members   -  Reputation: 270

Like
0Likes
Like

Posted 26 December 2012 - 07:10 PM

Hmmmm. I did not get it to work for some reason.

Watch the result:

error.png

 

The position is wrong as well.

 

The code:

public static Point findEdgePoint(GameObject observer, GameObject target) //TODO:
{
 float vertical_intersection_time = 1.0e20f;


 if (target.posX > observer.posX) vertical_intersection_time = (observer.stage.width-observer.posX)/(target.posX-observer.posX);
 else if (target.posX < observer.posX) vertical_intersection_time = (0.0f-observer.posX)/(target.posX-observer.posX);


 float horizontal_intersection_time = 1.0e20f;


 if (target.posY > observer.posY) horizontal_intersection_time = (observer.stage.height-observer.posY)/(target.posY-observer.posY);
 else if (target.posY < observer.posY) horizontal_intersection_time = (0.0f-observer.posY)/(target.posY-observer.posY);


 float time = Math.min(horizontal_intersection_time, vertical_intersection_time);


 return new Point((int)(observer.posY + time * (target.posY-observer.posY)), (int)(observer.posY + time * (target.posY-observer.posY)));
}

Where did it go wrong?



#13 Khatharr   Crossbones+   -  Reputation: 3007

Like
0Likes
Like

Posted 26 December 2012 - 08:37 PM

Whoa, I just realized we've got some div-by-zero time-bombs hangin' out in here. Better factor those out.

 

Meanwhile, look closely at the args you've passed to 'new Point()'.


Edited by Khatharr, 26 December 2012 - 08:57 PM.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

#14 P0jahn   Members   -  Reputation: 270

Like
0Likes
Like

Posted 27 December 2012 - 09:37 AM

Ops, my bad. Fixed it. Works perfect now, almost...

There seems to be some inconsistency  when the black circle is at the bottom. The circle is not at the bottom-most position, instead, it is about 40 pixels above it.

The problem is probably because the provided method use float as coordinates while my game only use ints as coordinates.

Is there a way around this?



#15 Álvaro   Crossbones+   -  Reputation: 13368

Like
0Likes
Like

Posted 27 December 2012 - 09:42 AM

Ops, my bad. Fixed it. Works perfect now, almost...
There seems to be some inconsistency  when the black circle is at the bottom. The circle is not at the bottom-most position, instead, it is about 40 pixels above it.
The problem is probably because the provided method use float as coordinates while my game only use ints as coordinates.
Is there a way around this?

That doesn't sound like a int-vs-float problem at all. Pick a particular example where the code does the wrong thing and follow it step by step, using a debugger. You should be able to see at what point the computation departs from what you expect.

#16 P0jahn   Members   -  Reputation: 270

Like
0Likes
Like

Posted 27 December 2012 - 09:59 AM

I fixed it somehow. I think that it... Actually I have no idea how I fixed it. But the problem is solved, big thanks to all the help.

I am going to test this ingame, as see how it works. I will report back if there is anything that do not work well.






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS