周末我在家折腾独立游戏开发时,何游突然想给中世纪战争题材的戏中游戏加个可拖拽的旗帜系统。就像小时候玩战棋游戏时用手指挪动棋子那样,使用鼠标希望玩家能用鼠标把军旗「抓」起来甩到指定位置。点击的移动这个功能看似简单,控制但实际调试时遇到了不少坑。旗帜

让旗帜听懂鼠标的何游暗号

在Unity引擎里,我尝试过两种主流方案。戏中第一种是使用鼠标给旗帜对象挂载OnMouseDown方法,就像给物品贴了个「请点击我」的点击的移动标签:

  • 优点:三行代码就能实现点击检测
  • 缺点:必须保证对象有Collider组件
  • 隐藏bug:如果相机视角旋转后,射线检测会失灵

后来改用射线检测方案,控制通过Camera.ScreenPointToRay把鼠标位置转换成三维射线:

  • 在表格添加结构化数据 -->
  • 检测方式响应速度设备兼容性
    对象事件0.3秒延迟仅限PC端
    射线检测即时响应跨平台通用

    物理世界的旗帜摩擦力

    当旗帜开始跟着鼠标移动时,直接修改transform.position会导致「瞬移」效果。何游参考《游戏编程模式》里的戏中组件模式,我给旗帜添加了Rigidbody组件,使用鼠标用AddForce实现惯性效果:

    if(isDragging){

    Vector3 mouseDelta = Input.mousePosition

  • lastMousePosition;
  • flagRigidbody.AddForce(mouseDelta 15f);

    那些藏在细节里的魔鬼

    测试时发现当鼠标移动速度超过500像素/秒时,旗帜会飞出地图边界。于是增加了速度钳制逻辑:

    • 设置最大移动速度上限
    • 添加屏幕边缘碰撞盒
    • 用Mathf.Clamp限制坐标范围

    最有趣的是处理地形起伏的问题。当把旗帜拖拽到山坡时,原本的水平移动需要转换成斜坡切线方向。这时用Vector3.ProjectOnPlane方法,把鼠标的平面移动矢量投影到地形法线垂直面:

  • 在表格添加结构化数据 -->
  • 地形类型解决方案运算开销
    平坦地面直接坐标转换0.02ms
    复杂地貌法线投影算法0.15ms

    让移动更有「手感」

    通过调节Damping参数模拟不同材质的拖拽感。亚麻旗面设为0.85阻尼值,金属旗杆则用0.45,这样拖动时能明显感觉旗面比旗杆更「粘手」。调试过程中意外发现,当设置Damping=1.1时,旗帜会产生反向惯性的弹簧效果,这个bug后来变成了特色功能。

    窗外的麻雀在防盗窗上跳来跳去,屏幕里的旗帜终于能跟着鼠标灵活移动了。保存工程时突然想到,或许该给快速双击添加甩旗动作,让玩家能把旗帜像飞镖一样掷出去——不过那就是下一个版本的故事了。