Reputation: 283043
I'm trying to implement camera movement for an FPS game. I think I've almost got it, but there's just a few more kinks to work out. I've got my mouse movement set up like this:
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;
}
Which seems to work pretty well when the mouse is actually inside the window, but as soon as I leave the window it doesn't work. I think what I have to do is somehow constrain the mouse to be inside the window, because even if it triggered a mouse move when my mouse was outside of the window, and still run into the same issue, just at the bounds on my desktop coords instead.
So...how do I do that -- lock my mouse to inside the window? Do I essentially just keep setting the mouse position to the center? If so...how do I set the mouse position? I'm using Windows, but I'd prefer a non-native solution if OpenTK provides it.
Upvotes: 2
Views: 8571
Reputation: 46
Quite simple in OpenTK 3.2
OpenTK.GameWindow window = new OpenTK.GameWindow();
window.CursorGrabbed = true;
You can additionally use this snippet to hide the cursor. Just implement it as needed.
window.Cursor = MouseCursor.Empty;
Upvotes: 3
Reputation: 283043
This is my solution right now...it's specific to windows though.
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);
}
Upvotes: 1
Reputation: 25773
One practice that I have done, and that the old Quake games used (and half-life 1), is every frame you reset the cursor position to be the middle of the screen, then you calculate the delta from the middle of the screen.
EDIT: And to move the cursor, check out Cursor.Position
Upvotes: 2