1
\$\begingroup\$

I am making a library of GUI controls for games I make with XNA. I am currently developing the library as I make a game so I can test the features and find errors/bugs and hopefully smash them right away.

My current issue is on a slide feature I want to implement for my base class that all controls inherit. My goal is to get the control to slide to a specified point over a specified amount of time. Here is the #region containing the code

#region Slide
    private bool sliding;
    private Vector2 endPoint;
    private float slideTimeLeft;
    private float speed;
    private bool wasEnabled;
    private Vector2 slideDirection;
    private float slideDistance;

    public void Slide(Vector2 startPoint, Vector2 endPoint, float slideTime) {
        this.location = startPoint;
        Slide(endPoint,slideTime);
    }

    public void Slide(Vector2 endPoint, float slideTime) {
        this.wasEnabled = this.enabled;
        this.enabled = false;
        this.sliding = true;
        Vector2 tempLength = endPoint - this.location;
        this.slideDistance = tempLength.Length(); //Was this.slideDistance = (float)Math.Sqrt(tempLength.LengthSquared());
        this.speed = slideTime / this.slideDistance;
        this.endPoint = endPoint;
        this.slideTimeLeft = slideTime;
    }

    private void UpdateSlide(GameTime gameTime) {
        if (this.sliding) {
            this.slideTimeLeft -= gameTime.ElapsedGameTime.Milliseconds;
            if (this.slideTimeLeft >= 0 ) {
                if ((this.endPoint-this.location).Length() != 0){//Was if (this.endPoint.LengthSquared() > 0 || this.location.LengthSquared() > 0) {
                    this.slideDirection = Vector2.Normalize(this.endPoint - this.location);
                }
                this.location += this.slideDirection * speed * gameTime.ElapsedGameTime.Milliseconds;//This is where I believe the issue is, but I'm not sure. It seems right to me... (Even though it doesn't work)
            }
            else {
                this.enabled = this.wasEnabled;
                this.location = this.endPoint;//After time, the controls position will get set to be the endpoint.
                this.sliding = false;   
            }
        }
    }
    #endregion 

this.location is the location of the control elsewhere defined in the class. I have looked at this blog as a huge reference and have googled around quite and have looked on many forums but can't find anything that shows how to implement it.

Please and Thanks for your time!

EDIT:

I have switched this line "this.location += this.slideDirection * speed * gameTime.ElapsedGameTime.Milliseconds;" several times to see what it does. My issue is getting the control to smoothly move to the end location. It moves after the time has expired, but It doesn't move other then that except flash in my face.

EDIT2:

I have used the first slide method with 3 parameters and it works except it doesn't do it in a period of time and once it gets to its destination, it starts moving randomly towards the previous location and the end location.

\$\endgroup\$
2
  • \$\begingroup\$ What, exactly, is your question? What have you tried and what about it didn't work? Please update your question with those updates. \$\endgroup\$
    – House
    Oct 2, 2012 at 16:54
  • \$\begingroup\$ Possibly silly, but important, question. Where are you calling UpdateSlide? \$\endgroup\$
    – Ray Dey
    Oct 2, 2012 at 19:13

3 Answers 3

0
\$\begingroup\$

Well, for stableness I advice you to integrate it. (instead of working with the velocity/speed of the widget location += set its position location =)

Well, one of the ways to do it is using LERP (linear Interpolation)

For this, you have to first store the startPoint, the endPoint, the currentTime and the endTime(startTime we know is zero). So your code will be looking something like this: the LERP #region Slide private bool sliding; private Vector2 startPoint private Vector2 endPoint; private float currentSlideTime; private float endTime; private float speed; private bool wasEnabled;

public void Slide(Vector2 startPoint, Vector2 endPoint, float slideTime) {
    this.startPoint = startPoint;
    this.wasEnabled = this.enabled;
    this.enabled = false;
    this.sliding = true;
    this.endPoint = endPoint;
    this.endTime = slideTime;
}

public void Slide(Vector2 endPoint, float slideTime) {
    this.Slide(this.Location, endPoint, slideTime); 
}

private void UpdateSlide(GameTime gameTime) {
    if (sliding) {
        currentTime += gameTime.ElapsedGameTime.Milliseconds;
        if (currentTime < endTime ) {
            float t = currentTime / endTime;
            location = Vector2.Lerp(startPoint, endPoint, t);
        }
        else {
            this.enabled = this.wasEnabled;
            this.location = this.endPoint;
            this.sliding = false;   
        }
    }
}
#endregion 

The key is here: Vector2.Lerp(startPoint, endPoint, t); It get a point between startPoint and endPoint with the percentage t. You could make it more smooth using Vector2.Smoothstep(startPoint, endPoint, t); It's pretty the same logic, but it smooths t value gradually, you just have to change this line.

And if you want even more control, you can use Vector2.Hermite or Vector2.Spline, but they are complicated and I'm pretty sure that if you don't understand them, you don't need them :P

\$\endgroup\$
2
  • \$\begingroup\$ I had to make a couple changes to the code since I'm assuming "this.endSlideTime" is supposed to be "endTime". I also switched out the lerp with smoothstep and it works. Very nicely actually. Also thanks a bunch for explaining it aswell as you did! \$\endgroup\$ Oct 3, 2012 at 3:13
  • \$\begingroup\$ Yeah, you are right, I didn't see this :P and you're welcome :D \$\endgroup\$ Oct 3, 2012 at 3:15
0
\$\begingroup\$

Speed normally is distance per time. You divide time by distance.

Why (float)Math.Sqrt(tempLength.LengthSquared()); Instead of just tempLength.Length();

Why do you check whether the "endPoint" or the "location" is at (0,0) before calculating the "slideDirection"? You probably want to check if this.endPoint - this.location has length 0.

\$\endgroup\$
1
  • \$\begingroup\$ I have modified the code to what you have questioned me about. Unfortunately I still run into the same issue. \$\endgroup\$ Oct 2, 2012 at 18:11
0
\$\begingroup\$

You mention that you want this to smoothly slide from one location to another. Using a simplistic linear function, aka velocity/speed will not accomplish this. It will result in a jerky start/stop.

If you want to have a smooth slide transition you will need to implement a cubic curve or something similar. The Microsoft.Xna.Framework.MathHelper class provides an implementation of this curve through the SmoothStep method. All you will need to do is provide it your start and end values and a float between 0.0f and 1.0f representing the elapsed time of your animation. It will return the appropriate intermediate value.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .