5
\$\begingroup\$

I was wondering if you could help me:

In XNA I have a hexagonal map, and the size of the map currently exceeds the size of the window. There is already code in place to move the 'camera' around the map using the directional keys, which is as follows:

if (ks.IsKeyDown(Keys.Left))
        {
            Camera.Location.X = MathHelper.Clamp(Camera.Location.X - 8, 0, 
                (myMap.MapWidth - squaresAcross) * Tile.TileStepX);
        }

But I'd prefer using the mouse, like in good ol' Command and Conquer.

So basically: If mouse coords are within 5 pixels of game window edge, move map appropriately'. Any help would be greatly appreciated!

\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

You have somewhat answered your own question :) (everything after "so basically"). I don't have XNA here so YMMV with my code. Furthermore - it's (from what I can tell) usually a 1px border.

Using Rectangles

What you first need to do is determine the position in terms of your Viewport. What we do is create some rectangles and check if the mouse cursor is in each of them. If it is we use the associated Vector2 to move the camera.

private List<Tuple<Rectangle, Vector2>> _rectangles = new List<Tuple<Rectangle, Vector2>>();
private Rectangle _noActionRectangle;
private const int MouseCameraBorder = 5; // Really, this should be 1.

// ...

GraphicsDevice.DeviceReset += GraphicsDevice_Reset;
GraphicsDevice_Reset(GraphicsDevice, EventArgs.Empty);

// ...

void GraphicsDevice_Reset(object sender, EventArgs args)
{
    var vp = GraphicsDevice.Viewport;
    _rectangles.Clear();
    // Top/left
    _rectangles.Add(Tuple.Create(new Rectangle(0, 0, MouseCameraBorder, MouseCameraBorder), new Vector2(-1, -1)));
    // Left, but excluding the top/left and bottom/left.
    _rectangles.Add(Tuple.Create(new Rectangle(0, MouseCameraBorder, vp.Height - MouseCameraBorder * 2, MouseCameraBorder), new Vector2(-1, 0));
    // Add the rest of the 8 rectangles that are
    // - Corners
    // - Sides excluding the corners.
    _noActionRectangle = new Rectangle(MouseCameraBorder, MouseCameraBorder, vp.Height - MouseCameraBorder * 2, vp.Width - MouseCameraBorder * 2);
}

// ...

var ms = Mouse.GetState();
var msPt = new Point(ms.X, ms.Y);
// Make sure we are not wasting team checking each rectangle if the
// mouse is not in any of them.
if (!_noActionRectangle.Contains(msPt))
{
    foreach(var pair in _rectangles)
    {
        if (pair.Item1.Contains(msPt))
        {
           // ... Move your camera based on pair.Item2.
           break;
        }
    }
}

Using Offset

You might want to try this approach and see if it works out better than the rectangle approach. Essentially what you do is make sure the mouse cursor is not inside the _noActionRectangle and then calculate how to move the camera based off of how far away from the center of the screen the mouse cursor is.

private Vector2 _screenSizeOver2; // Should be Size technically, but we want floats.
private Rectangle _noActionRectangle;
private const int MouseCameraBorder = 5; // Really, this should be 1.

// ...

GraphicsDevice.DeviceReset += GraphicsDevice_Reset;
GraphicsDevice_Reset(GraphicsDevice, EventArgs.Empty);

// ...

void GraphicsDevice_Reset(object sender, EventArgs args)
{
    var vp = GraphicsDevice.Viewport;
    _noActionRectangle = new Rectangle(MouseCameraBorder, MouseCameraBorder, vp.Height - MouseCameraBorder * 2, vp.Width - MouseCameraBorder * 2);
    _screenSizeOver2 = new Vector2(vp.Width / 2, vp.Height / 2);
}

// ...

var ms = Mouse.GetState();
var msV = new Vector2((ms.X - _screenSizeOver2.X) / _screenSizeOver2.X, (ms.Y - _screenSizeOver2.Y) / _screenSizeOver2.Y);
var msPt = new Point(ms.X, ms.Y);
if (!_noActionRectangle.Contains(msPt))
{
   // ... Move camera based on msV - it will lie in the range [-1 ... 1]
}
\$\endgroup\$

You must log in to answer this question.

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