赞
踩
公司经营的软件与绘图相关,这天,客户提出来一个需求,希望能在绘图的任意位置添加备注,方便厂家之间沟通。
客户要求:可以在任意位置添加、修改、删除。
实现过程:
1、如何创建?
这个问题很简单,UI界面添加一个Button,绑定一个事件,点击的时候创建一个游戏物体专门用来显示文字。显示文字使用TextMesh组件,如下图:
2、如何修改文字?
这个问题也很容易解决,添加一个inputfiled组件,获取用户输入的文本,然后再将用户输入的内容传递给TextMesh即可。
3、如何实现移动这些文字?
给每个物体添加一个脚本,跟随鼠标或者手势滑动的位置。代码如下:
public class Move : MonoBehaviour { Ray ray; Vector3 position; RaycastHit hit; //判断当前是否被选中 public bool isSelect=true; void LateUpdate() { if (Input.GetMouseButton(0)&& isSelect) { ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out hit)) { if (hit.transform.gameObject.tag == "Note") { transform.position = hit.point; } } } if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved&& isSelect) { ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out hit)) { if (hit.transform.gameObject.tag == "Note") { transform.position = hit.point; } } } } }
4、如何知道客户想修改的是哪一个文本?
创建一个控制脚本,里面定义一个空物体,作为当前物体的引用。使用射线,获取当前用户点击到的文本,拿到当前用户点击的物体,当用户点击另一个的时候,将当前物体的引用改为新点击的即可。代码细节如下:
public class Test : MonoBehaviour { GameObject currentObj; Ray ray; RaycastHit hit; public GameObject parentObj; public InputField InputField; public Button OKButton; public Button createButton; public Button delButton; private Color black; //当前被选中的为黄色 private Color yellow; void Start () { black = new Color(0, 0, 0); yellow = new Color(215, 215, 0); OKButton.onClick.AddListener(() => ReviseText()); createButton.onClick.AddListener(() => CreateNote()); delButton.onClick.AddListener(()=>Del()); } void CreateNote() { Resert(); GameObject obj = new GameObject("Test"); currentObj = obj; var textMesh = obj.AddComponent<TextMesh>(); textMesh.text = "测试字体"; textMesh.fontSize = 100; obj.transform.SetParent(transform); obj.transform.localPosition = new Vector3(0, 0, 100); obj.transform.SetParent(parentObj.transform); obj.tag = "Note"; obj.GetComponent<TextMesh>().color = yellow; obj.GetComponent<TextMesh>().anchor = TextAnchor.MiddleCenter; obj.AddComponent<Move>(); obj.GetComponent<Move>().isSelect = true; //TextMeshPro插件添加碰撞体不会随着字体改变而改变,所以最后添加 obj.AddComponent<BoxCollider>(); } //重置上一个选中的状态 private void Resert() { //将先前选中的备注设置为黑色 if (currentObj != null) { currentObj.GetComponent<TextMesh>().color = black; currentObj.GetComponent<Move>().isSelect = false; } } void ReviseText() { if (currentObj!=null) { currentObj.GetComponent<TextMesh>().text = InputField.text; //TextMeshPro插件添加碰撞体不会随着字体改变而改变,所以需要删除后重新添加 Destroy(currentObj.GetComponent<BoxCollider>()); currentObj.AddComponent<BoxCollider>(); } } void Del() { if (currentObj != null) Destroy(currentObj); } private void Update() { if (Input.GetMouseButtonDown(0)) { ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out hit)) { if (hit.transform.gameObject.tag == "Note") { if (currentObj != null) { currentObj.GetComponent<TextMesh>().color = black; currentObj.GetComponent<Move>().isSelect = false; } currentObj = hit.transform.gameObject; currentObj.GetComponent<TextMesh>().color = yellow; currentObj.GetComponent<Move>().isSelect = true; } } } if(Input.touchCount==1&&Input.GetTouch(0).phase == TouchPhase.Began) { ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position); if (Physics.Raycast(ray, out hit)) { if (hit.transform.gameObject.tag == "Note") { Resert(); currentObj = hit.transform.gameObject; currentObj.GetComponent<TextMesh>().color = yellow; currentObj.GetComponent<Move>().isSelect = true; } } } } }
效果如下:
总结:总的来说还是一个比较简单易实现的小功能,主要用到Input类、射线类
后续:实际应用的时候可以创建一个空物体作为预制件,提前添加好需要用到的脚本,实际开发调用的时候可以减少代码量,提高阅读效率。
2020.8.26后续更新,客户画的图有大有小,希望可以自定义字体的大小,看起来更搭配。
新增一个Slider组件,通过这个滑动轴来定义大小。
在测试脚本中给Slider组件添加事件。
slider.onValueChanged.AddListener((value)=>
{
if (currentObj != null)
currentObj.transform.localScale = new Vector3(value,value,value);
});
为了客户的更好使用,客户点击到每一个字体的时候,这个时候Slider的value应该改为当前值。
分别在创建新字体和点击字体时候调用。
//重置滑块的Value值
private void ResetSliderValue()
{
slider.value = currentObj.transform.localScale.x;
}
实际效果:
客户在提完改变大小的要求后,希望能增加多种颜色自由选择。简单想了一下,解决方法有俩。
1:调用调色板(比较复杂,而且不知道手机上是否支持,暂且放弃,百度可以搜索到相关方法,是可行的)
2:使用DropDown组件。将常用颜色放入到下拉框中,供客户选择。
UI界面设置如下:
代码添加事件即可。
dropdown.onValueChanged.AddListener((value) => { if (currentObj != null) { switch (value) { case 0: currentObj.GetComponent<TextMesh>().color = Color.green; break; case 1: currentObj.GetComponent<TextMesh>().color = Color.blue; break; case 2: currentObj.GetComponent<TextMesh>().color = Color.red; break; } } });
实际效果:
但是UGUI默认的DropDown有若干个问题。
1、下拉菜单弹出时,首选项(即第一个)是被选中的状态。此时调用首选项无效。
2、如果上次选择了某一项,下一次还是选择这个,不会执行OnVlaueChanged事件。(这个很致命,用户有时候会挨个设置一样的颜色,结果发现无效)。
改进方法:看UGUI源码,自己做一个DropDown组件。(挖个坑,有空的时候回来填坑)。
9.3后续更新。
选中字体的时候,字体的position会直接改为点击的位置,这就造成了点击字体的位置不是中心位置的时候会造成便宜,需要优化,优化代码如下。
移动脚本中增加一个偏移量。
public Vector3 pianyi;
点击的时候计算下偏移量,然后用点击的位置减去原来的位置再减去偏移量,就可以得到鼠标移动的距离,用原来的坐标位置加上移动的距离即可。
移动脚本代码,写在lateupdate中
transform.position += new Vector3(hit.point.x - transform.position.x - pianyi.x, hit.point.y - transform.position.y - pianyi.y, 0);
测试脚本代码
currentObj.GetComponent<Move>().pianyi = hit.point - currentObj.transform.position;
优化后的效果:
Demo
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。