Как привязать курсор к окну игры?

Я пытаюсь реализовать движение камеры для игры FPS. Я думаю, что у меня почти получилось, но осталось проработать еще несколько изгибов. У меня настроено движение мыши следующим образом:

protected override void OnLoad(EventArgs e)
{
    Mouse.Move += OnMouseMove;
}

void OnMouseMove(object sender, MouseMoveEventArgs e)
{
    _lookDir.X += e.XDelta * _mouseSensitivity;
    _lookDir.Y -= e.YDelta * _mouseSensitivity;
}

Кажется, что это работает довольно хорошо, когда мышь находится внутри окна, но как только я выхожу из окна, это не работает. Я думаю, что мне нужно каким-то образом ограничить мышь, чтобы она находилась внутри окна, потому что даже если она вызывала движение мыши, когда моя мышь была за пределами окна, и все равно сталкивалась с той же проблемой, только на границах моего рабочего стола вместо этого координаты.

Итак... как мне это сделать - заблокировать мышь внутри окна? По сути, я просто продолжаю устанавливать положение мыши в центре? Если да... как мне установить положение мыши? Я использую Windows, но я бы предпочел неродное решение, если OpenTK предоставляет его.


person mpen    schedule 12.02.2012    source источник
comment
SDL предлагает правильное решение этой проблемы. Я пишу для него оболочку, но она будет готова не сразу (если вообще будет).   -  person mpen    schedule 13.08.2013


Ответы (3)


Довольно просто в OpenTK 3.2

OpenTK.GameWindow window = new OpenTK.GameWindow();
window.CursorGrabbed = true;

Вы можете дополнительно использовать этот фрагмент, чтобы скрыть курсор. Просто реализуйте его по мере необходимости.

window.Cursor = MouseCursor.Empty;
person Wilke Schröder    schedule 30.07.2020

Одна практика, которую я применил и которую использовали старые игры Quake (и Half-Life 1), заключается в том, что в каждом кадре вы сбрасываете положение курсора на середину экрана, а затем вычисляете дельту от середины экрана.

РЕДАКТИРОВАТЬ: И чтобы переместить курсор, проверьте Cursor .Позиция

person Matthew    schedule 12.02.2012
comment
System.Windows.Forms == Для Windows != Не родной. Думаю, мне придется использовать это сейчас. Спасибо. - person mpen; 12.02.2012
comment
Извините, я не знаком с OpenTK, для .net можно использовать Cursor.Position, а для win32 можно использовать Set/GetCursorPos. Для Linux / Mac я понятия не имею, как это сделать на кросс-платформенной платформе. - person Matthew; 12.02.2012

Это мое решение прямо сейчас... оно специфично для окон.

protected void ResetCursorPosition()
{
    Cursor.Position = WindowCenter;
    _lastMousePos = Cursor.Position;
}

protected void LockMouse()
{
    _lockMouse = true;
    _origCursorPosition = Cursor.Position;
    CursorVisible = false;
    ResetCursorPosition();
}

protected void UnlockMouse()
{
    _lockMouse = false;
    CursorVisible = true;
    Cursor.Position = _origCursorPosition;
}

void OnMouseDown(object sender, MouseButtonEventArgs e)
{
    if (!_lockMouse) LockMouse();
}

void OnKeyDown(object sender, KeyboardKeyEventArgs e)
{
    if(e.Key == Key.Escape)
    {
        if (_lockMouse) UnlockMouse();
        else Exit();
    }
}

protected override void OnUpdateFrame(FrameEventArgs e)
{
    Title = string.Format("{0} - {1:0.0} FPS", _windowTitle, RenderFrequency);

    float moveSpeed = Keyboard[RunKey] ? 0.9f : 0.4f;

    if (Keyboard[MoveForwardKey])
    {
        _pos.X += (float)Math.Cos(_lookDir.X) * moveSpeed;
        _pos.Z += (float)Math.Sin(_lookDir.X) * moveSpeed;
    }

    if (Keyboard[StrafeLeftKey]) // FIXME: holding W + A gives extra speed (also, perhaps strafing should be slower?)
    {
        _pos.X -= (float) Math.Cos(_lookDir.X + Math.PI / 2) * moveSpeed;
        _pos.Z -= (float) Math.Sin(_lookDir.X + Math.PI / 2) * moveSpeed;
    }

    if (Keyboard[StrafeRightKey])
    {
        _pos.X += (float)Math.Cos(_lookDir.X + Math.PI / 2) * moveSpeed;
        _pos.Z += (float)Math.Sin(_lookDir.X + Math.PI / 2) * moveSpeed;
    }

    if (Keyboard[MoveBackKey])
    {
        _pos.X -= (float)Math.Cos(_lookDir.X) * moveSpeed;
        _pos.Z -= (float)Math.Sin(_lookDir.X) * moveSpeed;
    }

    if(Keyboard[JumpKey])
    {
        _pos.Y += moveSpeed;
    }

    if (Keyboard[CroucKey])
    {
        _pos.Y -= moveSpeed;
    }

    if (_lockMouse)
    {
        var mouseDelta = Cursor.Position - new Size(_lastMousePos);
        if (mouseDelta != Point.Empty)
        {
            _lookDir.X += mouseDelta.X * _mouseSensitivity;
            _lookDir.Y -= mouseDelta.Y * _mouseSensitivity;
            ResetCursorPosition();
        }
    }

    var target = _pos + new Vector3((float)Math.Cos(_lookDir.X), (float)Math.Sin(_lookDir.Y / 2), (float)Math.Sin(_lookDir.X));
    _viewMat = Matrix4.LookAt(_pos, target, _up);
    _projUniform.Mat4(_viewMat * _projMat);
}
person mpen    schedule 12.02.2012