Keeping constant speed overtime

OK so I have a scenario where i can interact with NPCs, and send them to a position that I decided beforehand, the path that this NPC will take comes from the A* pathfinding algorythm in the form of a list of what i call “nodes” which are essentially Points to get to that final destination.

That being said, what I think is the correct way to do this is loop through all these points and move the character’s position until it’s reached this point’s x and y. But it doesn’t behave like that especially when the path has multiple turns or directional changes…

Anyway, my problem here is that the NPC’s speed isn’t constant during it’s journey, maybe this is related to timers and stuff, i have troubles understanding this aspect.
Here’s a gif of what’s happening:
movement behaviour
the NPC is the one on the right, as you can see it starts fast and then slows down.

now a bit of code:

move method in NPC class:

    public const int millisecondsPerFrame = 200;

    .....

    public void Move(GameTime gameTime)
    {
        foreach (var node in nodesToEnd)
        {
           
                timeSinceLastUpdate += (int)(gameTime.ElapsedGameTime.Milliseconds);
                if (timeSinceLastUpdate >= millisecondsPerFrame)
                {
                timeSinceLastUpdate = 0;

                if (Sprite.Hitbox.X < node.X)//right
                {                       
                    Sprite.Direction = Direction.RIGHT;
                    Sprite.MoveHitbox(gameTime, node.hitbox, Direction.RIGHT);
                }

                else if (Sprite.Hitbox.Y < node.Y)//down
                {                       
                    Sprite.Direction = Direction.DOWN;
                    Sprite.MoveHitbox(gameTime, node.hitbox, Direction.DOWN);
                }                
            }                  
        }
    }

MoveHitbox method:

  public void MoveHitbox(GameTime gameTime, Rectangle destination, Direction direction)
    {
        double delta = Globals.Speed * (gameTime.ElapsedGameTime.TotalMilliseconds / speedAdjustment);
        int newX = 0;
        int newY = 0;
      
        if (direction == Direction.RIGHT)
        {
            newX = (int)(_hitbox.X + delta);
            if (newX > destination.X)
            {
                _hitbox.X = destination.X;
                state = State.Idle;
            }            
            else
                _hitbox.X += (int)(delta);
        }             
        if (direction == Direction.LEFT)
        {
            newX = (int)(_hitbox.X - delta);
            if (newX < destination.X)
            {
                _hitbox.X = destination.X;
                state = State.Idle;
            }               
            else
                _hitbox.X -= (int)(delta);
        }               
        if (direction == Direction.DOWN)
        {
            newY = (int)(_hitbox.Y + delta);
            if (newY > destination.Y)
            {
                _hitbox.Y = destination.Y;
                State = State.Idle;
            }
            else
                _hitbox.Y += (int)(delta);
        }              
        if (direction == Direction.UP)
        {
            newY = (int)(_hitbox.Y - delta);
            if (newY < destination.Y)
            {
                _hitbox.Y = destination.Y;
                State = State.Idle;
            }
            else
                _hitbox.Y -= (int)(delta);
        }    
    }

Check your speedAdjustment, isnt it affected in any way over time?

Seems like two separate problems to me.

With a decent A* algorithm you should get a path out of it e.g. a node path list. With a number of nodes from the current position to the ending position. Such that as you traverse each point of the resulting node list path, you simply set the course for the next till you hit the last node or the target position changes or you wish to stop your character ect…

The movement speed or smoothness of it, is a completely separate matter and you should think of it in speed per second. This helps to simplify things alot.

(though which ever time measurement you use … use it for everything be it per second or per milliseconds as all speed variables relate to some such relative timing, don’t mix them)

For example.

Lets say a tile is 50x50 units in your world if this is 2d you can just say pixels. You have a traversal node list produced by the A* function that is used to set your characters new direction to head towards as you reach each node. You want your character to move about 1/2 a tile per second or about 25 units or pixels per second. So you create that variable.

float MySpeedPerSecond = 25.0; // world pixels per second or about 1/2 of a 50x50 tile per second.

Now thats nice and all but lets say you have a frame rate of 60 frames per second you might convert that to the equivalent speed per sixtieth of a second (.0166 seconds ).

float MySpeedPerSixtiethSeconds = MySpeedPerSecond / 60;

Perfect each frame we go the speed we want to go with a fixed timed frame rate… ?

However…

Lets say for some reason we lag and we cant or the users old comp cant handle 60 fps and runs at say 45 fps or we just have a un-fixed frame rate.

Better yet lets say the time that elapsed between every two frames is variable and that’s the way we like it because we want to be different.

for example.

frame time elapsed in seconds (0) = 0;
frame time elapsed in seconds (1) = .0166;
frame time elapsed in seconds (2) = .0266;
frame time elapsed in seconds (3) = .0080;

Now the real key to keeping things sane…

As long as we measure time elapsed in the same way as we define our time for our speed variable no matter what we had set it. (our variable 25 world pixels per second).

Then we can straight multiply the elapsed time by our speed to find just how far we can move this frame.

for example… frame time elapsed in seconds (2) = .0266;

currentDistanceMovedThisFrame = MySpeedPerSecond * frame_time_elapsed_in_seconds;

The number one rule is to perform your timings in the same frame of reference as your variable for distance over time , which of course is MySpeedPerSecond. The part that is important is the ________PerSecond , don’t mix per second with per millisecond measurements of elapsed time or nanosecond because then transformations become requisite.

One final note is that when you are not moving directly up down left right, you have to realize that speed is not a velocity its a magnitude or scalar.
To transform a 2 element x,y direction such as up and right (diagonal) into the equivalent of your speed you take the target position - the current position and normalize the result (in this case your position and the target nodes position) then multiply it by your desired speed and then multiply that by the elapsed time.
Such that

currentXyVelocityThisFrame = MySpeedPerSecond * frame_time_elapsed_in_seconds * Vector2.Normalize(MyTargetLocation - MyPosition);

Provided you don’t have your speed in milliseconds or something and are measuring elapsed time in seconds you will be ok. So make sure to measure elapsed time the same way you do for your characters speed in time (per seconds for both or per milliseconds for both ect).

I don’t get it, why is it that the speed isn’t constant like with player, it’s using the same move method, also i can only move up, down, right and left so no need to take into account diagonals.

I’m assuming node.hitbox is the tile your NPC is moving towards? Maybe the hitbox coordinates are not correct, I.e. only moved slightly every frame and then capping the movement. You could draw the hitbox rectangle to easily debug this.

This is probably why you shouldn’t double post on the same problem.

See my reply here in the other thread.

We didn’t catch it because we couldn’t see his declarations of the variables or most of the guys who looked at this would have immediately spotted this.

newY = (int)(_hitbox.Y + delta);

_hitbox.Y -= (int)(delta);

He was casting float / doubles to a int position variable to accumulate his floating point positions this is rounding his positional accumulations off.

There maybe other problems however this bug could cause that, in fact it could cause his sprite player to simply not move at all.

So you are suggesting that I store the positions as floats? i never would have thought of that. And I won’t be able to use rectangles to represent my objects anymore

Make a struct with xywh values and a method that returns a Rectangle from it. or just returns the xy part in a new vector2 or point.

mystructvariable.ToRectangle();
mystructvariable.ToVector2();
draw(…, mystructvariable.ToRectangle() …, …);

If you want something more fancy i have a old class that does that as well its pretty big.
But it can do all that stuff and then some you can use it as is or cut out the extra junk…

public class VirtRect
    {
        #region variables fields
        /// <summary>
        /// only a couple methods use this were ...
        /// its so easy to type a mistake and so hard to track down
        /// they throw a exception if a typical mistake or typo is made
        /// if this call is set to true that check will not be made but it
        /// must be explicity set before each iffy method there is only a couple
        /// and they are commented , basically you ignore this unless you want
        /// a virtrect with a negative w h by corners
        /// </summary>
        public static bool allow_A_Unsafe_Operation = false;
        private float left = 0.0f;     // x
        private float top = 0.0f;      // y
        private float right = 0.0f;    // ex
        private float bottom = 0.0f;   // ey
        private float width = 0.0f;    // w
        private float height = 0.0f;   // h
        private float center_x = 0.0f; // cx
        private float center_y = 0.0f; // cy
        #endregion
        #region properties
        //setters getters
        /// <summary>
        /// set or get the starting x postition 
        /// here width can be a negative number
        /// moves the rectangle to x the width is preserved
        /// right = left + width;
        /// center is always left + .5f * width
        /// </summary>
        public float X
        {
            get
            {
                return left;
            }
            set
            {
                left = value;
                right = left + width;
                center_x = width * .5f + left;
            }
        }
        /// <summary>
        /// set or get the starting y postition
        /// moves the rectangle height is preserved
        /// bottom = top + height;
        /// here height can be a negative number
        /// center is always top + .5f * height 
        /// </summary>
        public float Y
        {
            get
            {
                return top;
            }
            set
            {
                top = value;
                bottom = top + height;
                center_y = height * .5f + top;
            }
        }
        /// <summary>
        /// set or get the ending x postition 
        /// here width is preserved  left = right - width
        /// center x is always left + .5f * width
        /// </summary>
        public float EX
        {
            get
            {
                return right;
            }
            set
            {
                right = value;
                left = right - width;
                //width = right - left;
                center_x = width * .5f + left;
            }
        }
        /// <summary>
        /// set or get the ending y postition 
        /// here height is preserved top = right - height
        /// center is always top + .5f * height 
        /// </summary>
        public float EY
        {
            get
            {
                return bottom;
            }
            set
            {
                bottom = value;
                top = bottom - height;
                //height = bottom - top;
                center_y = height * .5f + top;
            }
        }
        /// <summary>
        /// set or get
        /// a virt rect  
        /// width is set from right - left
        /// center is always left + .5f * width or height respectively
        /// </summary>
        public float Left
        {
            get
            {
                return left;
            }
            set
            {
                left = value;
                width = right - left;
                center_x = width * .5f + left;
            }
        }
        /// <summary>
        /// set or get
        /// center is always top + .5f * height
        /// </summary>
        public float Top
        {
            get
            {
                return top;
            }
            set
            {
                top = value;
                height = bottom - top;
                center_y = height * .5f + top;
            }
        }
        /// <summary>
        /// set or get 
        /// center x is always left + .5f * width 
        /// width = right - left;
        /// </summary>
        public float Right
        {
            get
            {
                return right;
            }
            set
            {
                right = value;
                width = right - left;
                center_x = width * .5f + left;
            }
        }
        /// <summary>
        /// set or get 
        /// center is always right + .5f * height respectively
        /// height = bottom - top ;
        /// </summary>
        public float Bottom
        {
            get
            {
                return bottom;
            }
            set
            {
                bottom = value;
                height = bottom - top;
                center_y = height * .5f + top;
            }
        }
        /// <summary>
        /// set or get width
        /// width is added to the left coordinate to find the right
        /// the center x is then recalculated
        /// </summary>
        public float Width
        {
            get
            {
                return width;
            }
            set
            {
                width = value;
                right = left + width;
                center_x = width * .5f + left;
            }
        }
        /// <summary>
        /// set or get height
        /// height is added to the top coordinate to find the bottom
        /// the center y is then recalculated
        /// </summary>
        public float Height
        {
            get
            {
                return height;
            }
            set
            {
                height = value;
                bottom = top + height;
                center_y = height * .5f + top;
            }
        }
        /// <summary>
        /// normally you dont set the center
        /// however if you do in this case
        /// the width and height remain unchanged
        /// the left right and top bottom coordinates will
        /// move with the center though
        /// </summary>
        public float CenterX
        {
            get
            {
                return center_x;
            }
            set
            {
                float r = (right - left) * .5f;
                left = value - r;
                right = value + r;
                center_x = value;
            }
        }
        /// <summary>
        /// normally you dont set the center
        /// however if you do in this case
        /// the width and height remain unchanged
        /// the left right and top bottom coordinates will
        /// move with the center though
        /// </summary>
        public float CenterY
        {
            get
            {
                return center_y;
            }
            set
            {
                float r = (bottom - top) * .5f;
                top = value - r; // y
                bottom = value + r; // ey
                center_y = value;
                //float d = value - center_y;
                //center_y = value;
                //top = top + d;
                //bottom = bottom + d;
            }
        }
        /// <summary>
        /// get set center as a vector 2
        /// </summary>
        public Vector2 Center
        {
            get{return new Vector2(center_x,center_y);}
            set { CenterX = value.X; CenterY = value.Y; }
        }
        /// <summary>
        /// gets the virtual location as a vector2
        /// </summary>
        public Vector2 LocationVirt
        {
            get { return new Vector2(top, left); }
        }
        /// <summary>
        /// gets the screen location as a vector2
        /// </summary>
        //public Vector2 LocationScreen
        //{
        //    get{return new Vector2((int)(X * (float)(BxEngine.client_screen_width)), (int)(Y * (float)(BxEngine.client_screen_height)));}
        //}
        // static properties
        /// <summary>
        /// gets a virtual rectangle zero 
        /// </summary>
        public static VirtRect Zero
        {
            get
            {
                return default(VirtRect);
            }
        }
        public static VirtRect Whole
        {
            get
            {
                return new VirtRect(0f, 0f, 1f, 1f);
            }
        }
        #endregion
        #region constructors and polymorphic constructs methods
        /// <summary>
        /// Primary constructor 
        /// creates a new virtrect with zero parameters
        /// AS of now this constructor shouldn't be used in favor of VirtRect.Zero
        /// so that this can be depreciated however untill i do a bit more test ill leave this in
        /// to boot this is a old class allot of my apps use this so it will be a real bitch to do that
        /// the reason for this to be depreciated is i need to do so in order to turn this class into a struct
        /// which should give me a bit of a boost 
        /// </summary>
        public VirtRect()
        {
            Left = 0.0f;
            Top = 0.0f;
            Width = 0.0f;
            Height = 0.0f;
        }
        /// <summary>
        /// primary constructor
        /// </summary>
        /// <param name="x">x left position of rect</param>
        /// <param name="y">y right position of rect</param>
        /// <param name="w">Width of rect</param>
        /// <param name="h">Height of rect</param>
        public VirtRect(float x, float y, float w, float h)
        {
            Left = x;
            Top = y;
            Width = w;
            Height = h;
        }
        /// <summary>
        /// Construct a VirtRect from a normal rectangle
        /// </summary>
        /// <param name="r">Takes a Rectangle Object</param>
        public VirtRect(Rectangle r)
        {
            Left = r.X;
            Top = r.Y;
            Width = r.Width;
            Height = r.Height;
        }
        /// <summary>
        /// Construct a VirtRect from a normal rectangle and a screen W H to place it as a screen percentage
        /// </summary>
        /// <param name="r">Takes a Rectangle Object</param>
        public VirtRect(Rectangle r, int ofWidth, int ofHeight)
        {
            Left = (float)(r.X) / (float)(ofWidth);
            Top = (float)(r.Y) / (float)(ofHeight);
            Width = (float)(r.Width) / (float)(ofWidth);
            Height = (float)(r.Height) / (float)(ofHeight);
        }
        /// <summary>
        /// nearly the same as ofwidth height
        /// </summary>
        /// <param name="_inner_rect"></param>
        /// <param name="_of_outer_rectangle"></param>
        public VirtRect(Rectangle _inner_rect, Rectangle _of_outer_rectangle)
        {
            Left = (float)(_inner_rect.X - _of_outer_rectangle.X) / (float)(_of_outer_rectangle.Width);
            Top = (float)(_inner_rect.Y - _of_outer_rectangle.Y) / (float)(_of_outer_rectangle.Height);
            Width = (float)(_inner_rect.Width) / (float)(_of_outer_rectangle.Width);
            Height = (float)(_inner_rect.Height) / (float)(_of_outer_rectangle.Height);
        }
        
        // polymorphic constructor methods
        /// <summary>
        /// Creates a Virtual rectangle Object
        /// <para>this allows you to set the virtrect by its corner positions</para>
        /// <para>Throws a exception and logs if width or height is negative</para>
        /// </summary>
        /// <param name="Start_X">Left</param>
        /// <param name="Start_Y">Top</param>
        /// <param name="End_X">Right</param>
        /// <param name="End_Y">Bottom</param>
        /// <returns>a new VirtRect object</returns>
        public static VirtRect NewVirtRectByCorners(float Start_X, float Start_Y, float End_X, float End_Y)
        {
            VirtRect n = new VirtRect(Start_X, Start_Y, End_X - Start_X, End_Y - Start_Y);
            if (allow_A_Unsafe_Operation == false && (n.width < 0 || n.height < 0)) { BxLog.writeThrownExceptionStackMsg("Error Loged new Virt Rectangle By corners is improperly set"); }
            else { allow_A_Unsafe_Operation = false; }
            return n; 
        }
        /// <summary>
        /// Creates a Virtual rectangle Object 
        /// using the center as the position from which to create it
        /// and useing the Width Height to find the sides of the rectangle
        /// </summary>
        /// <param name="_centerx">x position to base the rectangle on</param>
        /// <param name="_centery">y position to base the rectangle on</param>
        /// <param name="_w">half the width  +- x = left and right</param>
        /// <param name="_h">half the height +- y = top  and bottom</param>
        /// <returns>a new VirtRect object</returns>
        public static VirtRect NewVirtRectByCenterAndWH(float _center_x, float _center_y, float _w, float _h)
        {
            return new VirtRect(_center_x - (_w * .5f), _center_y - (_h * .5f), _w, _h);
        }
        // static method    
        /// <summary>
        /// <para>given an outer virt rectangle (b)</para>
        /// <para>and a portion of it (vr_in_b) (i)</para>
        /// the value returned will be the relation to the virtual screen w,h (1.0,1.0) as
        /// <para>vrX  =  ix * bw + bx  ,</para>
        /// <para>vrW  =  iw * bw </para>
        /// </summary>
        /// <param name="vr_in_b">this vr will be a percentage within b</param>
        /// <param name="b">this is a vr in relation to a whole for example e.g. a screen</param>
        /// <returns>a new virtual screen rectangle</returns>
        public static VirtRect GetVrOfVr(VirtRect vr_in_b, VirtRect b)
        {
            return new VirtRect
                (
                vr_in_b.X * b.Width + b.X,
                vr_in_b.Y * b.Height + b.Y,
                vr_in_b.Width * b.Width,//+ b.X,
                vr_in_b.Height * b.Height);//+ b.Y);             
        }
        #endregion
        // Class Object Methods
        /// <summary>
        /// returns a new instance of this virtual rectangle
        /// </summary>
        /// <returns></returns>
        public VirtRect Copy
        {
            get { return new VirtRect(this.X, this.Y, this.Width, this.Height); }
            set { this.X = value.X; this.Y = value.Y; this.Width = value.Width; this.Height = value.Height; }
        }
        /// <summary>
        /// Returns a Rectangle from this Virtual Rectangle
        /// note this method rounds down the decimal point
        /// </summary>
        /// <returns>a Rectangle Class Object</returns>
        public Rectangle GetRectangle()
        {
            return new Rectangle((int)X, (int)Y, (int)Width, (int)Height);
        }
        /// <summary>
        /// <para>this version returns a rectangle based on a width and height value and this virtual rectangle</para>
        /// <para>example vr.X = .5  ofwidth = 800 then .5 * 800 = 400 </para>
        /// note this method rounds down the decimal point
        /// </summary>
        /// <param name="ofWidth"></param>
        /// <param name="ofHeight"></param>
        /// <returns>returns a rectangle</returns>
        public Rectangle GetRectangle(int ofWidth, int ofHeight)
        {
            return new Rectangle((int)(X * ofWidth), (int)(Y * ofHeight), (int)(Width * ofWidth), (int)(Height * ofHeight));
        }
        /// <summary>
        /// <para>Example...use this were...</para> 
        /// <para> this virtual rectangle represents a portion of another rectangle that you pass to this method</para>
        /// <para> this method rounds down the decimal point</para>
        /// </summary>
        /// <param name="ofRectangle">a rectangle that will be used</param>
        /// <returns>a new Rectangle</returns>
        public Rectangle GetRectangle(Rectangle ofRectangle)
        {
            return new Rectangle(
                (int)(X * ofRectangle.Width + ofRectangle.X), 
                (int)(Y * ofRectangle.Height + ofRectangle.Y), 
                (int)(Width * ofRectangle.Width), 
                (int)(Height * ofRectangle.Height)
                );
        }
        /// <summary>
        /// call to the engien to get a screen rectangle 
        /// used when the virt rectangle represents a uv portion of the screen itself
        /// </summary>
        /// <returns></returns>
        //public Rectangle GetScreenRectangle()
        //{
        //    return new Rectangle(
        //        (int)(X * (float)(BxEngine.client_screen_width)), 
        //        (int)(Y * (float)(BxEngine.client_screen_height)), 
        //        (int)(Width * (float)(BxEngine.client_screen_width)), 
        //        (int)(Height* (float)(BxEngine.client_screen_height))
        //        );
        //}
        
        /// <summary>
        /// same as getRectangle
        /// <para>static general use method</para>
        /// <para> allows you to find a new rectangle using the given percentages within the given rectangle</para>
        /// </summary>
        /// <param name="x">0 to 1</param>
        /// <param name="y">0 to 1</param>
        /// <param name="ex">0 to 1 typically</param>
        /// <param name="ey">0 to 1 typically</param>
        /// <param name="rect">the rectangle to base the new rectangle from</param>
        /// <returns>a new rectangle based on the floats given for the corners within the inputed rectangle</returns>
        public static Rectangle GetRectanglePortionOfRectangle(float x,float y,float ex,float ey,Rectangle rect)
        {
            return new Rectangle(
                (int)(x * rect.Width) + rect.X, 
                (int)(y * rect.Height) + rect.Y, 
                (int)((ex - x) * rect.Width), 
                (int)((ey - y) * rect.Height));
        }
        
        /// <summary>
        /// inner is a rectangle in a whole texture(0,0,W,H) the rectangle you get back fits on the screen
        /// in the same proportion to the rectangle to the texture , that said the rule of thumb is inner rect
        /// right bottom should be lower then outer rectangles wh 
        /// if the _screen_window_rect is just a portion of the screen 
        /// we get a rectangle that fits in it as though it were a window to the texture itself
        /// 
        /// note this method does not ensure the rectangle is in bounds of the texture_pixelsize_rectangle
        /// 
        ///  EXAMPLE)
        ///        large rectangle is (0,0,4000,4000)  inner is (0,0,4000,4000)   the screen is (0,0,800,600)
        ///        the result returned will be a rectangle the size of the screen
        ///        (the returned rectangle / divided by the screen rectangle) will give a virtual rectangle of (0,0,1f,1f)
        /// </summary>
        /// <param name="_inner_texture_rect"></param>
        /// <param name="_larger_texture_pixsize_rect"></param>
        /// <param name="ScreenRect"></param>
        /// <returns></returns>
        public static Rectangle GetRectOfTextureRectToScrWindowRectangle(Rectangle _inner_texture_rect, Rectangle _larger_texture_pixsize_rect,Rectangle _screen_window_rect)
        {
            Rectangle r = new Rectangle
                (
                (int)(((float)_inner_texture_rect.X / (float)_larger_texture_pixsize_rect.Width) * (float)_screen_window_rect.Width + _screen_window_rect.X),
                (int)(((float)_inner_texture_rect.Y / (float)_larger_texture_pixsize_rect.Height) * (float)_screen_window_rect.Height + _screen_window_rect.Y),
                (int)(((float)_inner_texture_rect.Width / (float)_larger_texture_pixsize_rect.Width) * (float)_screen_window_rect.Width),
                (int)(((float)_inner_texture_rect.Height / (float)_larger_texture_pixsize_rect.Height) * (float)_screen_window_rect.Height)
                );
            int rx = r.X; int ry = r.Y; int rex = r.Right; int rey = r.Bottom;
            if (rx < _screen_window_rect.X) { rx = _screen_window_rect.X; }
            if (ry < _screen_window_rect.Y) { ry = _screen_window_rect.Y; }
            if (rex < _screen_window_rect.Right) { rex = _screen_window_rect.Right; }
            if (rey < _screen_window_rect.Bottom) { rey = _screen_window_rect.Bottom; }
            if (rx >= _screen_window_rect.Right) { rx = -1; ry = -1; rex = -1; rey = -1; }
            if (ry >= _screen_window_rect.Bottom) { rx = -1; ry = -1; rex = -1; rey = -1; }
            if (rex <= _screen_window_rect.X) { rx = -1; ry = -1; rex = -1; rey = -1; }
            if (rey <= _screen_window_rect.Y) { rx = -1; ry = -1; rex = -1; rey = -1; }
            return new Rectangle(rx, ry, rex, rey);
        }
        /// <summary>
        /// the reverse of getRectOfTextureRectToScrWindowRectangle
        /// turns a inner selection rectangle ussualy a mouse drag rectanlge in comparision to a window on screen and turns that into coordinates
        /// </summary>
        /// <param name="mouse_drag_rect"></param>
        /// <param name="screen_window_rect"></param>
        /// <param name="texture_rect"></param>
        /// <returns></returns>
        public static Rectangle GetRectInScrWindowRectToTextureRect(Rectangle mouse_drag_rect,Rectangle screen_window_rect,Rectangle texture_rect)
        {
            Rectangle r = new Rectangle
                (
                    (int)(Math.Round((float)(texture_rect.Width) * (float)((float)(mouse_drag_rect.X - screen_window_rect.X) / (float)(screen_window_rect.Width)),MidpointRounding.ToEven)),
                    (int)(Math.Round((float)(texture_rect.Height) * (float)((float)(mouse_drag_rect.Y - screen_window_rect.Y) / (float)(screen_window_rect.Height)),MidpointRounding.ToEven)),
                    (int)(Math.Round((float)(texture_rect.Width) * (float)((float)(mouse_drag_rect.Width) / (float)(screen_window_rect.Width)),MidpointRounding.ToEven)),
                    (int)(Math.Round((float)(texture_rect.Height) * (float)((float)(mouse_drag_rect.Height) / (float)(screen_window_rect.Height)), MidpointRounding.ToEven))
                 );
            // if r.width is within 1 of texture_rect width we might want to just set it to the width because floating point rounding errors can
            // actually throw off this calculation or maybe there is a math.rounding or something
            int rx = r.X; int ry = r.Y; int rex = r.Right; int rey = r.Bottom;
            if (rx < texture_rect.X) { rx = texture_rect.X; }
            if (ry < texture_rect.Y) { ry = texture_rect.Y; }
            if (rex < texture_rect.Right) { rex = texture_rect.Right; }
            if (rey < texture_rect.Bottom) { rey = texture_rect.Bottom; }
            if (rx >= texture_rect.Right) { rx = -1; ry = -1; rex = -1; rey = -1; }
            if (ry >= texture_rect.Bottom) { rx = -1; ry = -1; rex = -1; rey = -1; }
            if (rex <= texture_rect.X) { rx = -1; ry = -1; rex = -1; rey = -1; }
            if (rey <= texture_rect.Y) { rx = -1; ry = -1; rex = -1; rey = -1; }
            return new Rectangle(rx, ry, rex, rey);
        }
        /// <summary>
        /// this is used to check button positions for clicks on them
        /// in addition if the click occurs then we set a small pause duration
        /// ... this takes a virtual position in relation to a virtrectangle
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public bool HasWithin(Vector2 vp)
        {
            if (vp.X > left && vp.X < right && vp.Y > top && vp.Y < bottom)
                return true;
            else
                return false;
        }
        /// <summary>
        /// An overloaded ToString method
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return 
                " [ X=" + X.ToString()+", Y=" + Y.ToString() +" ]" +
                "[ CenterX=" + center_x.ToString() + ", CenterY=" + center_y.ToString() + " ]" +
                "[ Right=" + Right.ToString() + ", Bottom=" + Bottom.ToString() +" ]" +
                "[ Width=" + width.ToString() +", Height=" + height.ToString() + " ]" 
                ;
        }
    }