如何检测Raycast是否停止碰撞物体并实现材质切换
解决Raycast未命中时恢复物体初始材质的问题
要实现仅在Raycast命中时高亮、未命中时恢复初始材质的逻辑,核心是跟踪上一次命中的物体,并在未命中或命中非目标物体时重置它的材质。以下是具体实现方案:
1. 新增必要的变量
在你的脚本中添加以下变量,用于记录上一次命中的物体和它的初始材质:
// 你已定义的高亮材质 public Material highlightMaterial; // 记录上一次命中的BoardBlock物体 private GameObject _lastHitBlock; // 临时存储物体的初始材质,无需给每个BoardBlock单独写脚本 private Dictionary<GameObject, Material> _originalMaterials = new Dictionary<GameObject, Material>();
2. 修改OnMouseDrag方法
更新拖拽检测逻辑,加入未命中时的材质恢复处理:
private void OnMouseDrag() { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out RaycastHit hit)) { if (hit.collider.CompareTag("BoardBlock")) { // 如果当前命中的不是上一个物体,先恢复上一个的材质 if (_lastHitBlock != null && _lastHitBlock != hit.gameObject) { ResetBlockMaterial(_lastHitBlock); } // 仅在首次命中时存储物体的初始材质 if (!_originalMaterials.ContainsKey(hit.gameObject)) { _originalMaterials.Add(hit.gameObject, hit.collider.GetComponent<Renderer>().material); } // 设置当前物体为高亮材质 hit.collider.GetComponent<Renderer>().material = highlightMaterial; _lastHitBlock = hit.gameObject; } else { // 命中非BoardBlock物体,恢复上一个命中物体的材质 if (_lastHitBlock != null) { ResetBlockMaterial(_lastHitBlock); _lastHitBlock = null; } } } else { // 未命中任何物体,恢复上一个命中物体的材质 if (_lastHitBlock != null) { ResetBlockMaterial(_lastHitBlock); _lastHitBlock = null; } } }
3. 新增材质重置辅助方法
把重复的材质恢复逻辑抽成单独方法,让代码更简洁:
private void ResetBlockMaterial(GameObject block) { if (_originalMaterials.TryGetValue(block, out Material originalMat)) { block.GetComponent<Renderer>().material = originalMat; // 可选:如果不需要长期保留记录,可以移除字典中的条目 // _originalMaterials.Remove(block); } }
4. 补充OnMouseUp处理(可选但推荐)
为了避免拖拽结束后物体仍保持高亮,在鼠标抬起时也做一次材质重置:
private void OnMouseUp() { if (_lastHitBlock != null) { ResetBlockMaterial(_lastHitBlock); _lastHitBlock = null; } }
逻辑说明
- 每次拖拽检测时,先判断Raycast命中状态:
- 命中BoardBlock:先检查是否有上一个命中物体,有则重置;然后存储当前物体的初始材质(仅首次命中),再设置高亮。
- 命中非BoardBlock或未命中任何物体:如果有上一个命中物体,立即重置它的材质并清空记录。
- 使用字典存储初始材质,无需给每个BoardBlock单独编写脚本,减少代码耦合。
内容的提问来源于stack exchange,提问作者Solace
相关产品推荐
相关产品推荐

