周末我在家折腾独立游戏开发时,何游突然想给中世纪战争题材的戏中游戏加个可拖拽的旗帜系统。就像小时候玩战棋游戏时用手指挪动棋子那样,使用鼠标希望玩家能用鼠标把军旗「抓」起来甩到指定位置。点击的移动这个功能看似简单,控制但实际调试时遇到了不少坑。旗帜
让旗帜听懂鼠标的何游暗号
在Unity引擎里,我尝试过两种主流方案。戏中第一种是使用鼠标给旗帜对象挂载OnMouseDown
方法,就像给物品贴了个「请点击我」的点击的移动标签:
- 优点:三行代码就能实现点击检测
- 缺点:必须保证对象有Collider组件
- 隐藏bug:如果相机视角旋转后,射线检测会失灵
后来改用射线检测方案,控制通过Camera.ScreenPointToRay把鼠标位置转换成三维射线:
检测方式 | 响应速度 | 设备兼容性 |
对象事件 | 0.3秒延迟 | 仅限PC端 |
射线检测 | 即时响应 | 跨平台通用 |
物理世界的旗帜摩擦力
当旗帜开始跟着鼠标移动时,直接修改transform.position会导致「瞬移」效果。何游参考《游戏编程模式》里的戏中组件模式,我给旗帜添加了Rigidbody组件,使用鼠标用AddForce实现惯性效果:
if(isDragging){
Vector3 mouseDelta = Input.mousePosition
flagRigidbody.AddForce(mouseDelta 15f);
那些藏在细节里的魔鬼
测试时发现当鼠标移动速度超过500像素/秒时,旗帜会飞出地图边界。于是增加了速度钳制逻辑:
- 设置最大移动速度上限
- 添加屏幕边缘碰撞盒
- 用Mathf.Clamp限制坐标范围
最有趣的是处理地形起伏的问题。当把旗帜拖拽到山坡时,原本的水平移动需要转换成斜坡切线方向。这时用Vector3.ProjectOnPlane方法,把鼠标的平面移动矢量投影到地形法线垂直面:
地形类型 | 解决方案 | 运算开销 |
平坦地面 | 直接坐标转换 | 0.02ms |
复杂地貌 | 法线投影算法 | 0.15ms |
让移动更有「手感」
通过调节Damping参数模拟不同材质的拖拽感。亚麻旗面设为0.85阻尼值,金属旗杆则用0.45,这样拖动时能明显感觉旗面比旗杆更「粘手」。调试过程中意外发现,当设置Damping=1.1时,旗帜会产生反向惯性的弹簧效果,这个bug后来变成了特色功能。
窗外的麻雀在防盗窗上跳来跳去,屏幕里的旗帜终于能跟着鼠标灵活移动了。保存工程时突然想到,或许该给快速双击添加甩旗动作,让玩家能把旗帜像飞镖一样掷出去——不过那就是下一个版本的故事了。