Click here to Skip to main content
15,891,184 members
Articles / Desktop Programming / Windows Forms
Article

A Joystick Control

Rate me:
Please Sign up or sign in to vote.
3.14/5 (6 votes)
31 May 20053 min read 54.3K   2.7K   23   1
A joystick control using a simplified polar coordinate system to return an orientation and magnitude, and a custom Vehicle UserControl with an Offset method that uses the said coordinate system.

Image 1

Introduction

This project provides a joystick control that uses a simplified polar coordinate system (i.e., only the eight grossest compass points for directions — north, northeast, east, southeast, etc.). It also provides a custom vehicle class that can take an offset in the compass coordinate system that the joystick uses.

Background

The control uses a trig function to arrive at the angle of the joystick-- FindOrientation uses Math.Atan2(double, double) to get the angle in radians that the joystick ray makes to the x axis. Don't be frightened though--the Joystick actually returns a member of the enumeration below instead of an angle for its orientation, and you can use simple Euclidean geometry to translate that and the magnitude (radial distance of the mouse pointer from the center of the joystick) into x and y offsets to feed to some (hopefully) moving object. Of course, if I go on and produce version 0.2 that returns orientation in radians, you'll need some more trig to deal with it.

There are actually two custom controls in the project--the Joystick and the Vehicle. The latter is just a UserControl that has a custom Offset method that takes an orientation and a magnitude rather than the usual x and y components of motion. A vector, if you will, and are thinking calculus and not STL.

Using the code

If you want to use the JoyStickControl in your own project, you will have to deal with the polar coordinate system that it uses. Perhaps I should mention here that the control is the result of a school assignment—left to my own, I would have used either plain x-y coordinates, or a full polar coordinate system, with the orientation being passed in radians. As it is, the joystick contains a public enumeration:

C#
public enum compassPoints
{
    north,
    northeast,
    east,
    southeast,
    south,
    southwest,
    west,
    northwest
}

which has all the possible values for orientation that it may pass through its MouseMoving event. In my own use of the thing, I had the main form subscribe to the custom event; the form then calls the Vehicle's Offset method, which deals with the coordinates like so:

C#
public void Offset(Joystick.compassPoints orientation, int magnitude)
{
    this.orientation = orientation;
    this.magnitude = (double)magnitude;
    switch (orientation)
    {
        case Joystick.compassPoints.north :
            this.Location = new Point(this.Location.X, 
                            this.Location.Y - (int)this.magnitude);
            break;
        case Joystick.compassPoints.northeast :
            this.Location = new Point(this.Location.X + 
               ((int)Math.Round(Math.Sqrt((Math.Pow(this.magnitude, 2))/2), 0)), 
               this.Location.Y + 
               (int)-Math.Round((Math.Sqrt((Math.Pow(this.magnitude, 2))/2)), 0));
            break;
        case Joystick.compassPoints.east :
            this.Location = 
                 new Point(this.Location.X + magnitude, this.Location.Y);
            break;
        case Joystick.compassPoints.southeast :
            this.Location = new Point(this.Location.X + 
                 (int)Math.Round(Math.Sqrt((Math.Pow(this.magnitude, 2))/2), 0), 
                 this.Location.Y + 
                 (int)Math.Round(Math.Sqrt((Math.Pow(this.magnitude, 2)/2)), 0));
            break;
        case Joystick.compassPoints.south :
            this.Location = 
                 new Point(this.Location.X, this.Location.Y + (magnitude));
            break;
        case Joystick.compassPoints.southwest :
            this.Location = new Point(this.Location.X + 
                 (int)-Math.Round(Math.Sqrt(Math.Pow(this.magnitude, 2)/2), 0), 
                 this.Location.Y + 
                 (int)Math.Round((Math.Sqrt((Math.Pow(this.magnitude, 2))/2)), 0));
            break;
        case Joystick.compassPoints.west :
            this.Location = 
                 new Point(this.Location.X - (magnitude), this.Location.Y);
            break;
        case Joystick.compassPoints.northwest :
            this.Location = new Point(this.Location.X + 
                 (int)-Math.Round(Math.Sqrt((Math.Pow(this.magnitude, 2))/2), 0), 
                 this.Location.Y + 
                 (int)-Math.Round(Math.Sqrt((Math.Pow(this.magnitude, 2))/2), 0));
            break;
        default :
            break;
    }
}

In other words, we just use the compass points and a bit of simple Euclidean geometry, (opposite)2 + (adjacent)2 = (hypotenuse)2, to arrive at a new location. Simplicity itself, though with lots of typing for me. For reasons of precision, I do all my calculations using doubles, and then carefully round them before casting them to ints, since the cast would otherwise simply strip the decimal places off without rounding, producing sloppy results.

Points of Interest

While working on this, I discovered that the Joystick.MouseMove event fired continuously while the mouse was over the control. I don't know whether or not this is intentional on Microsoft's part, or whether I've found a bug. The MSDN simply states "Occurs when the mouse pointer is moved over the control," which sounds like it should mean that it either fires when the mouse moves over, or enters the control (but this of course would be redundant, since controls already have a MouseEnter event), or that it fires when the mouse moves over the control--moves while within the control. Instead, the thing just fires continuously while the mouse is inside the thing. I ended up having the Joystick screen out the noise by checking to see that the mouse had actually moved before firing its custom MouseMovingEvent, which the form listens to. Movement of the Vehicle is controlled by a timer on the main form, the form calling the Vehicle's Offset method every 18 ms while the mouse is over the Joystick, and what with the Joystick.MouseMovingEvent originally firing continuously in response to its own MouseMove event (firing 87 bazillion times a second) the poor timer never had a chance to do anything until I added my screening code.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
General"Points of interest" Pin
sabrown1006-Oct-07 13:27
sabrown1006-Oct-07 13:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.