+ Reply to Thread
Page 1 of 2 1 2 LastLast
Results 1 to 30 of 34

Thread: Useful trigonometry functions!

  1. #1
    Junior Member
    Join Date
    Oct 2006
    Posts
    28

    Default Useful trigonometry functions!

    Some useful angle functions:

    GetAngle: Returns the angle between point x,y - x2,y2 (360º = 360000)

    GetDist: Returns euclidian distance between 2 points

    GetDistX: X increment for given angle in given distance

    GetDistY: Same for GetDistX, but for Y.

    The only issue i'm having is that GetAngle gives a slightly incorrect angle, anyone trigonometric-wise can give me some advice about this?

    Code:
    int GetAngle(int x, int y, int x2, int y2)
    	{
    		int distx = x2 - x;
    		int disty = y2 - y;
    		int ang;
                             
    		if ( distx == 0 )
    		{
    			if (disty < 0)
    				ang = 270000;
    			else
    				ang = 90000;
    	
    			return ang;
    		}
    		else
    		{
    			ang = ( int )( atan( disty / distx ) * 180000 / M_PI);
    	                         
    			if (distx > 0)
    				ang = -ang + 180000;
    			else
    				ang = -ang;
    
    			return ang;
    		}    
    	}
    
    	int GetDist(int x, int y, int x2, int y2)
    	{
    		int distx = x2 - x;
    		int disty = y2 - y;
    
    		return ( int )sqrt( ( distx * distx ) 
    		              + ( disty * disty ) );
    	}
    
    	float GetDistX(int angle, float distance)
    	{
    		return (float)(cos(angle * M_PI / 180000) * distance); 
    	}
    
    	float GetDistY(int angle, float distance)
    	{
    		return (float)(-sin(angle * M_PI / 180000) * distance); 
    	}
    EDIT: Removed some useless casting o_O i dont know what the heck was i thinking...

    EDIT2: Added this function

    NearAngle: Does a smooth transition between 2 angles, returning the next logical angle in the transition, given the proper "smoothness" (i.e.: 10 is a good number)

    Code:
    	int NearAngle(int angle, int dest, int smoothness)
    	{
     
                    if (smoothness < 1) 
                         smoothness = 1;
    		int temp;
    
    		if (angle < dest && dest-angle > 180000)
    		{
    			angle += 360000;
    		}
    
    		if (angle > dest && angle-dest > 180000)
    		{
    			angle -= 360000;
    		}
    
    		if (angle < dest)
    		{
    			temp = dest-angle;
    			angle += temp / smoothness;
    			if (angle > dest) angle = dest;
    		}
    		else
    		{
    			temp = angle-dest;
    			angle -= temp / smoothness;
    			if (angle < dest) angle = dest;
    		}
    
    		if (angle < 0) return angle + 360000 ;
    		if (angle >= 360000) return angle - 360000 ;
    
    		return angle ;
    	}

    Hope someone finds this useful...
    If you find a bug don't hesitate to tell me!
    Thanks!
    Last edited by Therion; 04-18-2007 at 08:34 AM.

  2. #2
    Senior Member
    Join Date
    Jul 2006
    Location
    France
    Posts
    1,325

    Default

    You should use floating point precision and radian.
    It might have been wise 10 years ago to use integer instead of float for CPU saving but you shouldn't bother now. Floating point calculation are really fast now and so much more natural to use.

    JC

  3. #3
    Junior Member
    Join Date
    Oct 2006
    Posts
    28

    Default

    Thanks for the advice!... I tend to make these useless optimizations often, i think i should start thinking the fact that my code will run in something faster than a 486 .

  4. #4
    Senior Member
    Join Date
    Aug 2006
    Location
    Paterson, NJ
    Posts
    667

    Default

    Another useful function is a function to return the distance between two angles.

    For instance, what's the distance between 5 degrees and 355 degrees? 10 degrees. The way I figured out (which seems to work, although it's probably not the simplest way) is:

    angle_difference = abs((angle1 mod 360) - (angle2 mod 360));
    if (angle_difference > 180)
    then angle_difference = 360 - angle_difference;
    return (angle_difference);

  5. #5
    Senior Member
    Join Date
    Jan 2007
    Location
    NYC
    Posts
    486

    Default

    it's also kinda dangerous to be dividing ints, passing ints into functions that take floats/doubles, etc... at any moment the compiler could round your values to integers and you'd lose precision (which would cause errors)

    for example: atan( disty / distx ) is going to have problems if disty and distx are integers and the compiler passes an int into atan() -- imagine what happens when distx and disty are small

  6. #6
    Senior Member
    Join Date
    May 2005
    Location
    Warsaw, Poland
    Posts
    2,707

    Default

    Depends on what you're doing actually. If you do lots of muls and divs, using floating point is faster, but if you do subs and adds using fixed point arithmetic is not only faster but more precise. You might have more precise results using doubles or long doubles instead of floats -and internally the CPU converts all floating point numbers to 80bit anyway- but moving doubles and long doubles around in memory is slower than moving floats and from experiments i've found that although computationally they might be the same in cycles, due to the memory bottleneck they're slower.

    The ideal method is to break your operations in batches of integers and floats where needed, and convert between these between the batches.

    Of course you have to worry about all these only if you experience slowdowns in your game because of the CPU usage and only if you cannot manage to figure out a better algorithm :-).

  7. #7
    Senior Member
    Join Date
    Jul 2004
    Location
    Isle of Wight, UK
    Posts
    3,773

    Default

    Another useful function is a function to return the distance between two angles.
    God yeah, the trouble I remember having trying to figure this one out with no conditionals! Gave up in the end and have something very similar looking to yours now. It's one of those bits of code I make sure to never lose!
    Regards,
    Paul Johnson

    [Great BIG War Game: iOS | Android] [Great Little War Game: iOS | Android] [Fruit Blitz: iOS | Android] [Yachty Deluxe: iOS | Android]

  8. #8
    Senior Member
    Join Date
    Jan 2007
    Location
    NYC
    Posts
    486

    Default

    Quote Originally Posted by Bad Sector View Post
    Depends on what you're doing actually. If you do lots of muls and divs, using floating point is faster, but if you do subs and adds using fixed point arithmetic is not only faster but more precise. You might have more precise results using doubles or long doubles instead of floats -and internally the CPU converts all floating point numbers to 80bit anyway- but moving doubles and long doubles around in memory is slower than moving floats and from experiments i've found that although computationally they might be the same in cycles, due to the memory bottleneck they're slower.
    Right, but a float is the same size as an int... it's fairly rare to have to use doubles unless there is an explicit need for super-precision (i.e. physics engines)

    In general, I couldn't imagine that there's any reason to go through the hassle of fixed point these days unless you are SERIOUSLY cpu-bound. The algorithm itself should always be the first place to look for speedup. For these sorts of simple 2D math functions, unless you're calling them 100000000 times a second, there's not much point in making your life difficult...

    Also, you're probably losing more time doing float to int casts than the actual math takes... (with code like: x = (int) atan2(some_int / some_int2)).

  9. #9
    Senior Member
    Join Date
    Oct 2006
    Location
    Scotland
    Posts
    265

    Default

    Does anyone know of code that can approximate tangents? I use a simplified language that doesn't have any trig functions. It doesn't need to be very precise, it's just used for situations like "is ego standing close to X." Right now I just use a long series of "if" statements but there must surely be a better way?

  10. #10
    Senior Member
    Join Date
    Feb 2005
    Location
    Slovenia
    Posts
    996

    Default

    I think it's the best approach to make or get a 2d Vector library and put all this things in-there (distances, angles, inclusions, addition, scalar, rotate...) and move it from the core up. Working with vectors to move, accelerate, position..... stuff is so much neat than allways changing x and y to me. I had such library in c++ that I got on net and then added my stuff. I can post it if anyone wishes...

  11. #11
    Senior Member
    Join Date
    May 2005
    Location
    Warsaw, Poland
    Posts
    2,707

    Default

    Quote Originally Posted by andrew View Post
    Also, you're probably losing more time doing float to int casts than the actual math takes... (with code like: x = (int) atan2(some_int / some_int2)).
    Yeah, that's why i said that the ideal case (if you really need this sort of optimization) is to split the operations in int and float batches.

    But really, with the emerge of multi-core CPUs, it's much better to find parallelizing algorithms and work with threads than try to get yet another cycle. At the future, the CPU speed won't be measured in how many operations per sec a single thread can do, but how many cores it will have any how many operations can per second can be performed in all these cores. So the ideal code in such systems will be the code that takes advantage of the multicore environment.

    @tolworthy:
    Isn't something like abs((ego.x - other.x)*(ego.x - other.x) + (ego.y - other.y)*(ego.y*other.y)) < min_distance*min_distance enough?

  12. #12
    Senior Member
    Join Date
    Feb 2007
    Location
    Canberra, Australia
    Posts
    958

    Default

    Quote Originally Posted by Bad Sector View Post
    @tolworthy:
    Isn't something like abs((ego.x - other.x)*(ego.x - other.x) + (ego.y - other.y)*(ego.y*other.y)) < min_distance*min_distance enough?
    That's more or less what I'd use, though I'd modify it to (ego.x-other.x)*(ego.x-other.x) + (ego.y-other.y)*(ego.y-other.y) < min_distance*min_distance. (You had a multiplication instead of a subtraction, and the absolute value isn't necessary since the LHS will always be positive anyway, assuming there are no complex numbers involved.)

  13. #13
    Member
    Join Date
    Aug 2005
    Location
    London
    Posts
    75

    Default

    Our engine is all fixed point based very useful if your not just targeting desktop computers

  14. #14
    Senior Member
    Join Date
    Oct 2006
    Location
    Scotland
    Posts
    265

    Default

    Quote Originally Posted by Bad Sector View Post
    Isn't something like abs((ego.x - other.x)*(ego.x - other.x) + (ego.y - other.y)*(ego.y*other.y)) < min_distance*min_distance enough?
    That's good for distances, but something I forgot to mention (sorry!) is that this is a 2D game with a different sprite for each direction that ego might face. So the angle is important. Using real trig (or at least a fake version) is not essential for my game, but would just be more elegant and would avoid those irritating "face the wrong way" or "spin around" bugs.

  15. #15
    Senior Member
    Join Date
    May 2005
    Location
    Warsaw, Poland
    Posts
    2,707

    Default

    Quote Originally Posted by Inventive Dingo View Post
    That's more or less what I'd use, though I'd modify it to (ego.x-other.x)*(ego.x-other.x) + (ego.y-other.y)*(ego.y-other.y) < min_distance*min_distance. (You had a multiplication instead of a subtraction, and the absolute value isn't necessary since the LHS will always be positive anyway, assuming there are no complex numbers involved.)
    Oops! Yeah, you are right, i just had the "function(square + square)" writing in my mind (with function being "sqrt") and "abs" just popped out :-P.

  16. #16
    Senior Member
    Join Date
    Feb 2007
    Location
    Canberra, Australia
    Posts
    958

    Default

    Quote Originally Posted by tolworthy View Post
    That's good for distances, but something I forgot to mention (sorry!) is that this is a 2D game with a different sprite for each direction that ego might face. So the angle is important. Using real trig (or at least a fake version) is not essential for my game, but would just be more elegant and would avoid those irritating "face the wrong way" or "spin around" bugs.
    I'm not sure exactly what you mean, but if you mean that you want to test "is ego facing the object?" as well as "is ego close to the object?", then look into the dot product. You need to obtain two vectors: One that points from ego to the object (I'll call it A) and one that has the direction that the ego is facing (I'll call it B). The length of these vectors is not important.

    Then compute: A_x*B_x + A_y*B_y. If the result is zero, then the vectors are perpendicular (so ego is facing exactly 90 degrees to the left or the right of the object). If the result is positive, then ego is facing more-or-less towards the object (within a 180-degree arc). If it's negative, then ego is facing away from the object.

    Note that the X component of A is just (object.x-ego.x), and similarly the Y component of A is (object.y-ego.y). So the above is equivalent to (object.x-ego.x)*B_x + (object.y-ego.y)*B_y. How you calculate the vector B will depend on how you're encoding the sprite's direction.

    This happens because the dot product of two vectors is closely related to the cosine between those two vectors. The MathWorld page I linked to above has further explanation (if you don't mind that it's a bit technical).

  17. #17
    Senior Member
    Join Date
    Oct 2006
    Location
    Scotland
    Posts
    265

    Default

    Quote Originally Posted by Inventive Dingo View Post
    If the result is positive, then ego is facing more-or-less towards the object (within a 180-degree arc).
    Thanks, that's interesting. I'll have to experiment. Ego can face in eight possible directions, and usually being one direction off is not a huge problem. But occasionally, in close-up shots, facing 45 degrees to the wrong direction looks completely wrong. I'll have a look at dot product stuff. Thanks again.

  18. #18
    Senior Member
    Join Date
    Feb 2005
    Location
    Finland
    Posts
    478

    Default

    Quote Originally Posted by tolworthy View Post
    Does anyone know of code that can approximate tangents?
    Taylor series..

    tan(x) = x + x^3/3 + 2x^5/15 + 17x^7/315 + ...

    Google for Taylor series. You can approximate just about anything with taylor, and the more work you do the better the approximation gets.
    My schtuphh: http://iki.fi/sol/

  19. #19
    Senior Member
    Join Date
    Feb 2005
    Location
    Slovenia
    Posts
    996

    Default

    this is the library I said... it has dot product amongst things.. it's very simple but gives a lot of power.

    Code:
    #ifndef NVECTOR_NOMIND_TECH_001_INCLUDED_
    #define NVECTOR_NOMIND_TECH_001_INCLUDED_
    
    /*
    The author of this Vector class in Olivier renault who made exceptionaly great 
    polycolly tutorial/demo. I (janko metelko) used this lib and changed it to what I 
    needed / renamed it and stuff... but the 99.9% of thanks is to **Olivier Renault**.
    
    This NVector is made to work with PTK (phelios) 
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include "NMath.h"
    #include "KInput.h" 
    
    #define PI			3.141592f	// the venerable pi
    #define PITIMES2	6.283185f	// 2 * pi 
    #define PIOVER2		1.570796f	// pi / 2 
    #define E			2.718282f	// the venerable e
    #define SQRT2		1.414214f	// sqrt(2)
    #define SQRT3		1.732051f	// sqrt(3)
    #define GOLDEN		1.618034f	// the golden ratio
    #define DEGTORAD	0.017453f	// convert degrees to radians
    #define RADTODEG	57.29578f	// convert radians to degrees
    
    typedef unsigned char   u_char;
    typedef unsigned short  u_short;
    typedef unsigned int    u_int;
    typedef unsigned long   u_long;
    
    //#define for if(0); else for
    #define for if(0){} else for
    
    class NMatrix;
    
    class NVector
    {
    public:
    	float x,y;
    
    	static const NVector& Blank() { static const NVector V(0, 0); return V; }
    public:
    	inline NVector(void)
    	{}
    
    	inline NVector(float Ix,float Iy)
    	: x(Ix)
    	, y(Iy)
    	{}
    
    	inline NVector &operator /=(const float Scalar)	{ x /= Scalar; y /= Scalar;		return *this; }
    
    	inline NVector &operator *=(const float Scalar)	{ x *= Scalar; y *= Scalar;		return *this; }
    	
    	inline NVector &operator +=(const NVector &Other) { x += Other.x;	y += Other.y;	return *this; }
    
    	inline NVector &operator -=(const NVector &Other) { x -= Other.x;	y -= Other.y;	return *this;	}
    
    	inline float operator ^ (const NVector &V)	const	{	return (x * V.y) - (y * V.x); } // cross product
    
    	inline float operator * (const NVector &V)	const	{	return (x*V.x) + (y*V.y); } // dot product
    
    	inline NVector operator * (float  s)			const	{	return NVector(x*s, y*s); }
    	
    	inline NVector operator / (float  s)			const	{	return NVector(x/s, y/s); }
    	
    	inline NVector operator + (const NVector &V)	const	{	return NVector(x+V.x, y+V.y); }
    		
    	inline NVector operator - (const NVector &V)	const	{	return NVector(x-V.x, y-V.y); }
    
    	friend NVector operator * (float k, const NVector& V) {	return NVector(V.x*k, V.y*k); }
    
    	NVector operator * (const NMatrix& M) const;
    	
    	NVector operator ^ (const NMatrix& M) const;
    	
    	NVector& operator *=(const NMatrix& M);
    	
    	NVector& operator ^=(const NMatrix& M);
    
    	inline NVector operator -(void) const { return NVector(-x, -y); }
    	
    	inline float Length(void) const { return (float) sqrt(x*x + y*y); }
    
    	float Normalise(void) 
    	{	
    		float fLength = Length();	
    		
    		if (fLength == 0.0f) 
    			return 0.0f; 
    		
    		(*this) *= (1.0f / fLength); 
    	
    		return fLength;	
    	}
    
    	NVector Direction(void) const
    	{
    		NVector Temp(*this);
    
    		Temp.Normalise();
    
    		return Temp;
    	}
    
    	float Angle(const NVector& xE)
    	{
    		float dot = (*this) * xE;
    		float cross = (*this) ^ xE;
    		
    		// angle between segments
    		float angle = (float) atan2(cross, dot);
    
    		return angle;
    	}
    
    	NVector& Rotate(float angle)
    	{
    		float tx = x;
    		x = (float)x * (float)cos(angle) - y * (float)sin(angle);
    		y = (float)tx * (float)sin(angle) + y * (float)cos(angle);
    
    		return *this;
    	}
    
    	NVector& Rotate(const NVector& xCentre, float fAngle)
    	{
    		NVector D = *this - xCentre;
    		D.Rotate(fAngle);
    
    		*this = xCentre + D;
    
    		return *this;
    	}
    
    	void Clamp(const NVector& min, const NVector& max)
    	{
    		x = (x < min.x)? min.x : (x > max.x)? max.x : x;
    		y = (y < min.y)? min.y : (y > max.y)? max.y : y;
    	}
    
    	void Randomise(const NVector& xMin, const NVector& xMax)
    	{
    		x = NMath::frand(xMax.x - xMin.x) + xMin.x;
    		y = NMath::frand(xMax.y - xMin.y) + xMin.y;
    	}
    
    	static NVector getRandom(const NVector& xMin, const NVector& xMax){
    		NVector Temp(0, 0);
    		Temp.Randomise(xMin, xMax);
    		return Temp;
    	}
    
    	static NVector getMouse(){
    		//i return mouse pos as NVector (this func is bind with PTK)
    		return NVector(KInput::getMouseX(), KInput::getMouseY());
    	}
    
    	bool isInRect(NVector edge, NVector size){
    		//i return mouse pos as NVector (this func is bind with PTK)
    		if (x > edge.x && y > edge.y){ //in two steps so it is a little faster 
    			if (x < edge.x + size.x   && y < edge.y + size.y)
    				return true;
    		}
    		return false;
    	}
    
    	/*void Render(void) const
    	//TODO: make it render with PTK
    	{
    		glColor3f(1.0f, 1.0f, 0.1f);
    		glPointSize(3.0f);
    		glBegin(GL_POINTS);
    		glVertex2f(x, y);
    		glEnd();
    	}*/
    };
    
    #endif

  20. #20
    Senior Member
    Join Date
    Sep 2004
    Location
    Perth, Australia
    Posts
    179

    Default

    You know you don't need all those inline keywords if the function is defined in the class (like the operators)
    </pedant>

  21. #21
    Senior Member
    Join Date
    Feb 2005
    Location
    Slovenia
    Posts
    996

    Default

    99.9% thanks fo to Olivier Renault... so does the blame . I stopped programing in c++ since then and went to java. I wasn't too good in c++. The language was quite ok, but I hated the compiler "bureaucracy".

  22. #22
    Senior Member
    Join Date
    Jul 2004
    Location
    Isle of Wight, UK
    Posts
    3,773

    Default

    Quote:
    Another useful function is a function to return the distance between two angles.
    God yeah, the trouble I remember having trying to figure this one out with no conditionals! Gave up in the end and have something very similar looking to yours now. It's one of those bits of code I make sure to never lose!
    Now I remember what I got stuck on, coz I'm here again.

    What I'd kill for is for someone to post code that actually gives the shortest direction to move in, to get to a given angle.

    My actual problem: I want to rotate from a given angle to another one in the correct (shortest) direction, ie by determining to add on some scalar or subtract it, to reach my desired angle, iyswim.
    Regards,
    Paul Johnson

    [Great BIG War Game: iOS | Android] [Great Little War Game: iOS | Android] [Fruit Blitz: iOS | Android] [Yachty Deluxe: iOS | Android]

  23. #23
    Senior Member
    Join Date
    Jul 2006
    Location
    France
    Posts
    1,325

    Default

    This is my angle class, it keeps all the values beetween -pi and pi.
    The function your are looking for is interpolate, it will interpolate beetween 2 angles and the result is what you expect: the shortess direction.

    class Angle
    {
    public:
    static const float NOTANANGLE;
    float value;

    float SetBounds(float f)
    {
    if (f>0)
    {
    float k = float(int(f/(2*PI)));
    f = (f-k*2*PI);
    if (f>PI)
    f = f-2*PI;
    return f;
    }
    else
    {
    f = -f;
    float k = float(int(f/(2*PI)));
    f = (f-k*2*PI);
    if (f>PI)
    f = f-2*PI;
    return -f;
    }
    }

    Angle(){value=0;};
    Angle(float f) {value = SetBounds(f);};
    operator float () const {return value;};
    void operator+=(const Angle &a) {value = SetBounds(value+a.value);};

    static Angle Interpolate(Angle aa1, Angle aa2, float k)
    {
    float a1 = aa1;
    float a2 = aa2;

    if (fabsf(a1-a2)>=PI)
    {
    if (a1<a2) a2-=2*PI;
    else a1-=2*PI;
    }
    float angle = a1*(1-k)+a2*k;
    return angle;
    }

    };

    JC

  24. #24
    Senior Member
    Join Date
    Jul 2004
    Location
    Isle of Wight, UK
    Posts
    3,773

    Default

    OMG! Is this a record reply time ?

    Many thanks - saved me some major hair pulling, hopefully
    Regards,
    Paul Johnson

    [Great BIG War Game: iOS | Android] [Great Little War Game: iOS | Android] [Fruit Blitz: iOS | Android] [Yachty Deluxe: iOS | Android]

  25. #25
    Senior Member
    Join Date
    Jul 2004
    Location
    Isle of Wight, UK
    Posts
    3,773

    Default

    But I still can't get my hack and slash of that to work.

    I'm working in degrees and I can't seem to port it. This seems like it should be so damned easy, but I just get a mental block.

    My angles are also any-sized, so I call a clip routine to get them back into 0-360 range beforehand. It's really sophisticated, not!

    Code:
    tF32	CMath::KeepAnglePositive (tF32 Angle)
    {
    	while (Angle<0)
    		Angle+=360;
    	return Mod(Angle,360.0F);
    }
    
    tF32	CMath::AngleInterpolate (tF32 Angle1,tF32 Angle2,tF32 Scalar)
    {
    	Angle1=KeepAnglePositive(Angle1);
    	Angle2=KeepAnglePositive(Angle2);
    
    	return Angle1*(1-Scalar)+Angle2*Scalar;
    }
    Regards,
    Paul Johnson

    [Great BIG War Game: iOS | Android] [Great Little War Game: iOS | Android] [Fruit Blitz: iOS | Android] [Yachty Deluxe: iOS | Android]

  26. #26
    Senior Member
    Join Date
    Jul 2006
    Location
    France
    Posts
    1,325

    Default

    to works, it has to be between -PI and PI,


    so I guess it need to be beetween -180 and 180 degrees not 0 and 360

    JC

  27. #27
    Senior Member
    Join Date
    Jul 2006
    Location
    France
    Posts
    1,325

    Default

    Take off 180 from your angle and use my function : just change PI into 180.
    In theroy, it should work. Then put it back into your units [0-360].

    JC

  28. #28
    Senior Member
    Join Date
    Jul 2004
    Location
    Isle of Wight, UK
    Posts
    3,773

    Default

    D'oh, thanks again. Now I look again I see I trimmed off to much stuff - thought it was all bounds checking.

    This is damned handy, thanks. The solution I came up with wayback was nothing like as elegant as this iirc.
    Regards,
    Paul Johnson

    [Great BIG War Game: iOS | Android] [Great Little War Game: iOS | Android] [Fruit Blitz: iOS | Android] [Yachty Deluxe: iOS | Android]

  29. #29
    Senior Member
    Join Date
    Jul 2006
    Location
    Wellington
    Posts
    136

    Default

    On a related note, something I find very useful is to have a separate 'degrees' and 'radians' class, rather than one 'angle'. That way you can have comprehensible angles in your data, the system libraries can take their radians, opengl can take its degrees, and the compiler type checking handles any converting that needs to take place.

  30. #30
    Senior Member
    Join Date
    Jul 2004
    Location
    Isle of Wight, UK
    Posts
    3,773

    Default

    I'm coming around to that way of thinking myself tbh. All my engine is classed up with this exception as I don't really use angles much - I'm more of a vector man at heart.

    Doing what I'm doing now though, I'm starting to feel the need.
    Regards,
    Paul Johnson

    [Great BIG War Game: iOS | Android] [Great Little War Game: iOS | Android] [Fruit Blitz: iOS | Android] [Yachty Deluxe: iOS | Android]

+ Reply to Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts