You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# SharpDX如何锁定光标并持续检测鼠标移动以旋转相机

实现类似Unity锁定光标式的FPS相机旋转(解决屏幕边缘无法继续旋转问题)

要解决光标到屏幕/窗口边缘后无法继续旋转相机的问题,核心思路是模拟Unity的CursorLockMode.Locked效果:隐藏光标,持续捕获鼠标相对移动量,每次读取后将光标重置到窗口中心,这样就能无限获取鼠标偏移,不受边界限制。

实现步骤与修改后的代码

  1. 新增必要变量:记录窗口中心位置、锁定状态
  2. 替换原MouseMove逻辑,改用持续捕获光标偏移+重置位置的方式
  3. 处理窗口焦点变化,避免光标丢失
float rotationX = 0;
float rotationY = 0;
float dist = 1;
float moveFactor = 0.01f; // 根据需求调整灵敏度
Point windowCenter;
bool isCursorLocked = false;

float clmp(float val, float min, float max)
{
    return Math.Clamp(val, min, max); // 直接用系统自带的Math.Clamp更简洁
}

// 初始化时设置窗口中心,并绑定必要事件
void InitializeCameraControl(Control gameControl)
{
    windowCenter = new Point(gameControl.ClientSize.Width / 2, gameControl.ClientSize.Height / 2);
    // 绑定鼠标按下事件触发锁定(示例:右键锁定,可根据游戏设定调整)
    gameControl.MouseDown += (s, e) =>
    {
        if (e.Button == MouseButtons.Right)
        {
            isCursorLocked = true;
            Cursor.Hide();
            // 先把光标移到窗口中心
            Cursor.Position = gameControl.PointToScreen(windowCenter);
        }
    };

    // 绑定鼠标释放事件解锁
    gameControl.MouseUp += (s, e) =>
    {
        if (e.Button == MouseButtons.Right)
        {
            isCursorLocked = false;
            Cursor.Show();
        }
    };

    // 绑定窗口失焦事件解锁,避免光标丢失
    gameControl.LostFocus += (s, e) =>
    {
        if (isCursorLocked)
        {
            isCursorLocked = false;
            Cursor.Show();
        }
    };

    // 处理鼠标移动逻辑
    gameControl.MouseMove += (s, e) =>
    {
        if (!isCursorLocked) return;

        // 获取当前光标相对于窗口中心的偏移
        Point currentPos = gameControl.PointToClient(Cursor.Position);
        int deltaX = currentPos.X - windowCenter.X;
        int deltaY = currentPos.Y - windowCenter.Y;

        // 立刻把光标重置回窗口中心
        Cursor.Position = gameControl.PointToScreen(windowCenter);

        // 更新旋转角度
        rotationX += deltaY * moveFactor;
        rotationY -= deltaX * moveFactor;

        // 限制X轴旋转(避免抬头/低头过度)
        rotationX = clmp(rotationX, -1.5f, 1.5f);

        // 计算相机目标点
        float h = MathF.Cos(rotationX) * dist;
        Vector3 cameraTarget = new Vector3(
            MathF.Cos(rotationY) * h,
            MathF.Sin(rotationX) * dist,
            MathF.Sin(rotationY) * h
        );

        viewMatrix = Matrix.LookAtRH(cameraPosition, cameraPosition + cameraTarget, cameraUp);
    };
}

关键说明

  • 为什么不用Clip模式?Clip模式只是把光标限制在窗口范围内,当光标碰到窗口边缘后,就不会再产生偏移量,自然无法继续旋转相机。而重置光标到中心的方式,能持续获取鼠标的相对移动,完全不受边界限制。
  • 推荐用游戏主循环处理:如果你的游戏有固定帧率的主循环(比如每帧更新),可以把鼠标偏移的读取和处理放在循环里,比MouseMove事件更稳定,避免事件触发的延迟问题。
  • 焦点处理必须加:如果窗口失去焦点(比如切到其他程序),一定要解锁光标并显示,否则光标会一直隐藏,影响用户操作。

内容的提问来源于stack exchange,提问作者user19815545

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 11:31:11