Skip to main content
gamedev.net
🔒 Locked

2D vector problem

Started by TinyGameDev Feb 23, 2007 at 6:08 AM 4 replies 750+ views
Original Post
TinyGameDev
TinyGameDev
OK, so I have a round UFO which fires off shots from its center towards a point where the mouse is clicked. My problem is that the shots don't get fired off in the right direction. It's in the correct quadrant at least and the deviation is small. Actually it's based on the speed of the shot. The faster the shot goes, the more accurate is its direction. Here are my calculations:

int mx = event.button.x; //get x-coordiante of mouse
int my = event.button.y; //get y-coordinate of mouse

//this line calculates the vector length from the center of the ship
//to the point where the mouse is clicked		
float vec = sqrt(pow(mx-(offset.x+32), 2) + pow(my-(offset.y+32),2));

//normalise the vector components
float cx = (mx-(offset.x+32)) / vec;
float cy = (my-(offset.y+32)) / vec;

//multiply the vector components to a constant shot speed
xVel = cx * SHOT_VEL;
yVel = cx * SHOT_VEL;

//calculate the new positions based on a timer
//to get fps independant movement
x += xVel * (delta.get_ticks() / 1000.f); 
y += yVel * (delta.get_ticks() / 1000.f); 

I'm not really sure if this is the problem but delta.get_ticks() / 1000.f seem t be around 0.008 and I think it might be too low. SHOT_VEL is around 300. It seems that when I raise the SHOT_VEL value to a higher value like 3000 the shots' directiong et more accurate, not 100% though. Also, when the ship shoots att exactly 45 degree angle the shots move in the correct direction. I hate these kind of problems and I'm sure it's just some small thing I've overlooked. Anyone got any ideas? Thanx a lot
Bob Janova
Bob Janova
yvel = <font size=5>cy</font> * SHOT_VEL


:)

Why the +32? The origin of the UFO should be its centre, really.
haegarr
haegarr
The shown snippet seems me okay (besides the typo, of course). Although the +32 offsets in both x and y direction seem me spurious, too. It is correct that using very small _and_ very big numbers (w.r.t. the used variable type) leads to imprecision. However, your values doesn't seem me too extreme for float. If you want you can check this if running the stuff with doubles.

What isn't visible from the OPs code is how x,y are initialized. Since you increment x,y up to the target, starting at a wrong position typically yields in ending at a wrong position, of course.

Last but not least, there may be too many rounding errors, since perhaps x,y and xVel,yVel are integer numbers?

You may consider to re-organize your code like so:
// initializing start position (w/ that 32 pixel offsets)float x = offset.x+32;float y = offset.y+32;// velocity initialized w/ difference vectorfloat xVel = event.button.x - x;float yVel = event.button.y - y;// notice that here xVel,yVel must not disappear to avoid division by zerofloat scale = ((float)SHOT_VEL) / sqrt(xVel*xVel+yVel*yVel);xVel *= scale;yVel *= scale;// iterationsx += xVel * (delta.get_ticks() / 1000.f); y += yVel * (delta.get_ticks() / 1000.f); // when used for renderingxPos = (int)(x+0.5f);yPos = (int)(y+0.5f);

Please notice the use of float type at appropriate places.
oliii
oliii
I dont see anything wrong really, either a floating point error, or it's not doing what you thought it would do.

You should really use a 2D vector class with overload operators. Then those kind of problem tend to dissapear. Plus a reusable vector class is well useful for that sort of things.

/////////////////////////////////////////////////////////////////////////////// Class       : Vector2D//---------------------------------------------------------------------------// Created By  : // Created On  : // Description : /////////////////////////////////////////////////////////////////////////////class Vector2D{public:	float x, y;	// constructors	Vector2D() {}	Vector2D(float _x, float _y) : x(_x), y(_y) {}	Vector2D(const Vector2D& v) : x(v.x), y(v.y) {}	// operators	Vector2D& operator += (const Vector2D& v) { x += v.x; y += v.y; return *this; }	Vector2D& operator -= (const Vector2D& v) { x -= v.x; y -= v.y; return *this; }	Vector2D& operator *= (float k) { x*= k; y *= k; return *this; }	Vector2D& operator /= (float k) { return (*this) *= (1.0f / k); }	// const operators	Vector2D operator + (const Vector2D& v) const { Vector2D temp(*this); return temp += v; } 	Vector2D operator - (const Vector2D& v) const { Vector2D temp(*this); return temp -= v; } 	Vector2D operator * (float k) const { Vector2D temp(*this); return temp *= k; } 	Vector2D operator / (float k) const { Vector2D temp(*this); return temp /= k; } 	// uniform scaling	Vector2D& operator *=(const Vector2D& v) { x *= v.x; y *= v.y; return *this; }	Vector2D  operator * (const Vector2D& v) const { Vector2D temp(*this); return temp * v; }	Vector2D& operator /=(const Vector2D& v) { x /= v.x; y /= v.y; return *this; }	Vector2D  operator / (const Vector2D& v) const { Vector2D temp(*this); return temp / v; }	// unary operator	Vector2D  operator-() const { return Vector2D(-x, -y); }	// length	float     LengthSquared	() const { return (*this) | (*this);  }	float     Length		() const { return (float) sqrt(LengthSquared()); }	// normalisation	float	  Normalise		() { float l = Length(); if (l < 0.000000001f) return 0.0f; (*this) /= l; return l; }	Vector2D  Direction     () const { Vector2D temp(*this); temp.Normalise(); return temp; }	// products 	float     operator |  (const Vector2D& v) const { return x*v.x + y*v.y; } // dot   product operator	float     operator ^  (const Vector2D& v) const { return x*v.y - y*v.x; } // cross product operator	// friends	friend Vector2D operator*(float k, const Vector2D& v) { return v * k; }	// constants	static const Vector2D& Zero()		{ static const Vector2D  zero(0.0f, 0.0f); return  zero; }	static const Vector2D& Identity()	{ static const Vector2D    id(1.0f, 1.0f); return    id; }	static const Vector2D& Xaxis()		{ static const Vector2D xaxis(1.0f, 0.0f); return xaxis; }	static const Vector2D& Yaxis()		{ static const Vector2D yaxis(0.0f, 1.0f); return yaxis; }};


then it becomes

Vector 2D gunOrigin = Vector2D(offset.x, offset.y) + Vector2D(32, 32);Vector 2D gunTarget(mx, my);Vector 2D gunDir = (gunTarget - gunOrigin).Direction();Vector 2D bulletVel = gunDir * SHOT_VEL;Vector 2D bulletPos = gunOrigin;//...bulletPos += bulletVel * (delta.get_ticks() / 1000.f);
Everything is better with Metal.
TinyGameDev
TinyGameDev
haegarr: You were totally right, it was rounding errors. x and y where integers and that seemed to have messed up quite a lot.

Thanx a lot for your time

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.