DrawPener.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using XRTool.Util;
  5. using SC.XR.Unity.Module_InputSystem;
  6. using System;
  7. using System.Linq;
  8. using ShadowStudio.Model;
  9. using UnityEngine.EventSystems;
  10. using TriLib.Extras;
  11. namespace ShadowStudio.Tool
  12. {
  13. /// <summary>
  14. /// 画笔功能
  15. /// </summary>
  16. public class DrawPener : UnitySingleton<DrawPener>
  17. {
  18. /// <summary>
  19. /// 笔的材质
  20. /// </summary>
  21. public Material penMate;
  22. /// <summary>
  23. /// 笔颜色的名称
  24. /// </summary>
  25. public string colorName;
  26. /// <summary>
  27. /// 最小间距
  28. /// </summary>
  29. public float minDis = 0.01f;
  30. /// <summary>
  31. /// 默认笔头的粗细
  32. /// </summary>
  33. public float radius = 0.005f;
  34. /// <summary>
  35. /// 笔的颜色
  36. /// </summary>
  37. public Color penColor = Color.white;
  38. /// <summary>
  39. /// 线的预制体
  40. /// </summary>
  41. public LineSegment linePrefab;
  42. /// <summary>
  43. /// 每根线段最多100点
  44. /// </summary>
  45. public int maxPointOfLine = 100;
  46. /// <summary>
  47. /// 所有线段加起来最多500个点
  48. /// </summary>
  49. public int maxPointOfSegment = 500;
  50. /// <summary>
  51. /// 有可能要撤销对应的组件
  52. /// </summary>
  53. private Queue<LineSegment> lines;
  54. private LineSegment currentLine;
  55. private Coroutine drawCoroutine;
  56. private InputDevicePartBase part;
  57. private Vector3 lastPosition = Vector3.zero;
  58. public string defaultShader = "Mixed Reality Toolkit/Standard";
  59. private int currentPoint;
  60. /// <summary>
  61. /// 资源的id
  62. /// </summary>
  63. public static string artLineId = "ArtId_GameObject";
  64. /// <summary>
  65. /// 线与对应的名字的集合
  66. /// </summary>
  67. private Dictionary<string, LineSegment> lineMap;
  68. /// <summary>
  69. /// 请他用户的线段id
  70. /// 仅房主使用此数据
  71. /// </summary>
  72. private List<int> otherUserList;
  73. private List<int> userList;
  74. private DrawPlaneContainer drawPlane;
  75. public List<int> OtherUserList
  76. {
  77. get
  78. {
  79. if (otherUserList == null)
  80. {
  81. otherUserList = new List<int>();
  82. }
  83. return otherUserList;
  84. }
  85. }
  86. public List<int> UserList
  87. {
  88. get
  89. {
  90. if (userList == null)
  91. {
  92. userList = new List<int>();
  93. }
  94. return userList;
  95. }
  96. }
  97. public LineSegment GetLine(string lineName)
  98. {
  99. if (lineMap != null && lineMap.ContainsKey(lineName))
  100. {
  101. return lineMap[lineName];
  102. }
  103. return null;
  104. }
  105. protected override void Awake()
  106. {
  107. base.Awake();
  108. DisActiveDrawPen();
  109. }
  110. public void ActiveDrawPen()
  111. {
  112. gameObject.SetActive(true);
  113. }
  114. /// <summary>
  115. /// 添加老线
  116. /// </summary>
  117. /// <param name="line"></param>
  118. public void AddOldLine(LineSegment line)
  119. {
  120. if (line)
  121. {
  122. if (lineMap == null)
  123. {
  124. lineMap = new Dictionary<string, LineSegment>();
  125. }
  126. if (!lineMap.ContainsKey(line.name))
  127. {
  128. lineMap.Add(line.name, line);
  129. }
  130. if (lines == null)
  131. {
  132. lines = new Queue<LineSegment>();
  133. }
  134. if (line.Line.positionCount > 0 && !lines.Contains(line))
  135. {
  136. currentPoint += line.Line.positionCount;
  137. lines.Enqueue(line);
  138. }
  139. }
  140. }
  141. public void DisActiveDrawPen()
  142. {
  143. gameObject.SetActive(false);
  144. }
  145. public void OnEnable()
  146. {
  147. DispatcherBase.KeyDownDelegateRegister(OnKeyDownAction);
  148. DispatcherBase.KeyUpDelegateRegister(OnKeyUpAction);
  149. //caoting 2021/6/11 合并新的sdk
  150. if (SCInputModule.Instance)
  151. {
  152. SCInputModule.Instance.CanDrag = false;
  153. }
  154. }
  155. private void OnDisable()
  156. {
  157. DispatcherBase.KeyDownDelegateUnRegister(OnKeyDownAction);
  158. DispatcherBase.KeyUpDelegateUnRegister(OnKeyUpAction);
  159. //caoting 2021/6/11 合并新的sdk
  160. if (SCInputModule.Instance)
  161. {
  162. SCInputModule.Instance.CanDrag = true;
  163. }
  164. }
  165. /// <summary>
  166. /// 抬起按钮时
  167. /// </summary>
  168. /// <param name="keyCode"></param>
  169. /// <param name="part"></param>
  170. private void OnKeyUpAction(InputKeyCode keyCode, InputDevicePartBase part)
  171. {
  172. drawPlane = null;
  173. lastPosition = Vector3.zero;
  174. ClearPen();
  175. isHandlerobj = false;
  176. distance = 0;
  177. isNoCheck = false;
  178. }
  179. public void ClearPen()
  180. {
  181. if (drawCoroutine != null)
  182. {
  183. StopCoroutine(drawCoroutine);
  184. }
  185. drawCoroutine = null;
  186. if (lines == null)
  187. {
  188. lines = new Queue<LineSegment>();
  189. }
  190. if (currentLine)
  191. {
  192. if (currentLine.Line.positionCount > 1)
  193. {
  194. if (!lines.Contains(currentLine))
  195. {
  196. currentLine.StopSyn();
  197. lines.Enqueue(currentLine);
  198. }
  199. }
  200. else
  201. {
  202. Destroy(currentLine.gameObject);
  203. }
  204. }
  205. currentLine = null;
  206. }
  207. private bool isHandlerobj;
  208. private bool isNoCheck;
  209. private float distance;
  210. /// <summary>
  211. /// 按下按钮时
  212. /// </summary>
  213. /// <param name="keyCode"></param>
  214. /// <param name="part"></param>
  215. private void OnKeyDownAction(InputKeyCode keyCode, InputDevicePartBase part)
  216. {
  217. if (lines == null)
  218. {
  219. lines = new Queue<LineSegment>();
  220. }
  221. ///当前的还存在上一个画笔
  222. if (currentLine || drawCoroutine != null || this.part != part)
  223. {
  224. ClearPen();
  225. }
  226. ///当大于线段时,清除掉相关的线段
  227. while (currentPoint >= maxPointOfSegment - maxPointOfLine)
  228. {
  229. ClearOldLine();
  230. }
  231. this.part = part;
  232. var tmp = part.inputDataBase.SCPointEventData.pointerCurrentRaycast.gameObject;
  233. if (tmp)
  234. {
  235. ///如果点击了某个UI按钮,触发对应的点击事件,不绘制图形
  236. var tmpbutton = tmp.GetComponentInParent<IPointerClickHandler>();
  237. if (tmpbutton != null)
  238. {
  239. if (!isNoCheck)
  240. {
  241. isHandlerobj = true;
  242. if (isHandlerobj)
  243. {
  244. if (distance == 0)
  245. {
  246. distance = GetDis();
  247. }
  248. }
  249. }
  250. //tmpbutto n.OnPointerClick(part.inputDataBase.SCPointEventData);
  251. //return;
  252. }
  253. var downHandler = tmp.GetComponentInParent<IPointerDownHandler>();
  254. if (downHandler != null)
  255. {
  256. if (!isNoCheck)
  257. {
  258. isHandlerobj = true;
  259. if (isHandlerobj)
  260. {
  261. if (distance == 0)
  262. {
  263. distance = GetDis();
  264. }
  265. }
  266. }
  267. //downHandler.OnPointerDown(part.inputDataBase.SCPointEventData);
  268. //return;
  269. }
  270. ///在画板上绘制
  271. else if (drawPlane = tmp.GetComponentInParent<DrawPlaneContainer>())
  272. {
  273. }
  274. else
  275. {
  276. drawPlane = null;
  277. }
  278. }
  279. drawCoroutine = StartCoroutine(DrawLine(keyCode));
  280. }
  281. private float helpAngle = 1f;
  282. /// <summary>
  283. /// 画线功能的实现
  284. /// 如果画在画线板上时,不计入总点数
  285. /// </summary>
  286. /// <param name="keyCode"></param>
  287. /// <returns></returns>
  288. private IEnumerator DrawLine(InputKeyCode keyCode)
  289. {
  290. var obj = part.inputDataBase.SCPointEventData.pointerCurrentRaycast.gameObject;
  291. currentLine = CreateLine();
  292. currentLine.IsSingleLine = !drawPlane;
  293. if (lineMap == null)
  294. {
  295. lineMap = new Dictionary<string, LineSegment>();
  296. }
  297. if (!lineMap.ContainsKey(currentLine.name))
  298. {
  299. lineMap.Add(currentLine.name, currentLine);
  300. }
  301. yield return currentLine;
  302. Vector3 pointPos = part.detectorBase.pointerBase.cursorBase.transform.position;
  303. //Vector3 pointPos = part.pointerBase.cursorBase.transform.position;
  304. if (API_Module_InputSystem.InputDeviceStatus(InputDeviceType.KS))
  305. {
  306. pointPos = API_Module_InputSystem_KS.KSPosition(API_Module_InputSystem_KS.GCType.Right);
  307. pointPos += API_Module_InputSystem_KS.KSTransform(API_Module_InputSystem_KS.GCType.Right).forward.normalized * SystemSettingMgr.Instance.settings.RayDis;
  308. }
  309. if (lastPosition != Vector3.zero)
  310. {
  311. GameNode.Instance.SetParent(ObjNode.World, currentLine.transform,
  312. GameNode.Instance.LocalPosition(ObjNode.World, lastPosition, 1), Vector3.zero, Vector3.one, true);
  313. currentLine.AddPosition(lastPosition);
  314. currentPoint++;
  315. }
  316. else
  317. {
  318. GameNode.Instance.SetParent(ObjNode.World, currentLine.transform,
  319. GameNode.Instance.LocalPosition(ObjNode.World, pointPos, 1), Vector3.zero, Vector3.one, true);
  320. }
  321. while (currentLine && part)
  322. {
  323. //if (obj != part.inputDataBase.SCPointEventData.pointerCurrentRaycast.gameObject)
  324. //{
  325. // OnKeyUpAction(keyCode, part);
  326. // yield break;
  327. //}
  328. Vector3 posks = part.detectorBase.pointerBase.cursorBase.transform.position;
  329. if (API_Module_InputSystem.InputDeviceStatus(InputDeviceType.KS))
  330. {
  331. posks = API_Module_InputSystem_KS.KSPosition(API_Module_InputSystem_KS.GCType.Right);
  332. posks += API_Module_InputSystem_KS.KSTransform(API_Module_InputSystem_KS.GCType.Right).forward.normalized * SystemSettingMgr.Instance.settings.RayDis;
  333. }
  334. if (currentLine.Line.positionCount < 1 || Vector3.Distance(posks, pointPos) >= (obj ? (minDis / 5f) : minDis))
  335. {
  336. bool addPoint = true;
  337. if (currentLine.Line.positionCount > 1)
  338. {
  339. Vector3 lastDir = currentLine.transform.TransformPoint(currentLine.Line.GetPosition(currentLine.Line.positionCount - 1)) -
  340. currentLine.transform.TransformPoint(currentLine.Line.GetPosition(currentLine.Line.positionCount - 2));
  341. Vector3 curDir = posks -
  342. currentLine.transform.TransformPoint(currentLine.Line.GetPosition(currentLine.Line.positionCount - 1));
  343. if (Vector3.Angle(lastDir, curDir) < helpAngle)
  344. {
  345. UnityLog.Instance.Log(Vector3.Angle(lastDir, curDir), 4);
  346. addPoint = false;
  347. if (isHandlerobj)
  348. {
  349. pointPos = GameSession.Instance.GetHeadForwadPos(distance, false);
  350. currentLine.SetPosition(pointPos);
  351. }
  352. else
  353. {
  354. currentLine.SetPosition(posks);
  355. }
  356. }
  357. }
  358. if (addPoint)
  359. {
  360. if (isHandlerobj)
  361. {
  362. pointPos = GameSession.Instance.GetHeadForwadPos(distance, false);
  363. }
  364. else
  365. {
  366. pointPos = posks;
  367. }
  368. currentLine.AddPosition(pointPos);
  369. currentPoint++;
  370. }
  371. }
  372. if (currentLine.Line.positionCount >= maxPointOfLine)
  373. {
  374. lastPosition = pointPos;
  375. isNoCheck = true;
  376. OnKeyDownAction(keyCode, part);
  377. yield break;
  378. }
  379. yield return new WaitForFixedUpdate();
  380. //part.inputDataBase.SCPointEventData.pointerCurrentRaycast.gameObject;
  381. //part.pointerBase.cursorBase.transform.position;
  382. }
  383. }
  384. /// <summary>
  385. /// 创建线段
  386. /// </summary>
  387. /// <returns></returns>
  388. public LineSegment CreateLine()
  389. {
  390. LineSegment line;
  391. var lineName = UnityEngine.Random.Range(100000000, 999999999).ToString(); // DateTime.Now.ToString("MMddHHmmssf");
  392. if (linePrefab)
  393. {
  394. line = Instantiate(linePrefab);
  395. line.name = lineName;
  396. }
  397. else
  398. {
  399. GameObject obj = new GameObject(lineName, typeof(LineRenderer));
  400. line = obj.AddComponent<LineSegment>();
  401. //if (!line.Line.sharedMaterial)
  402. //{
  403. // line.Line.sharedMaterial = penMate;
  404. //}
  405. }
  406. if (line)
  407. {
  408. ///如果设置了默认的材质,则使用默认材质
  409. if (penMate)
  410. {
  411. line.SetLine(penMate);
  412. }
  413. line.SetLine(penColor, radius, colorName);
  414. }
  415. line.Line.positionCount = 0;
  416. line.Line.useWorldSpace = false;
  417. ///如果存在物体,则改变对齐模式,使线段看起来平整圆滑
  418. if (part != null && part.inputDataBase.SCPointEventData.pointerCurrentRaycast.gameObject)
  419. {
  420. line.Line.alignment = LineAlignment.TransformZ;
  421. }
  422. GameNode.Instance.SetParent(ObjNode.World, line.transform,
  423. Vector3.zero, Vector3.zero, Vector3.one, true);
  424. return line;
  425. }
  426. /// <summary>
  427. /// 清除本地自己的老线段
  428. /// 为什么不在线发送确认清除?因为延时问题造成的不流畅问题
  429. /// 主动删除并释放本地内存,然后发送同步信息删除线段
  430. /// </summary>
  431. public void ClearOldLine()
  432. {
  433. ///如果此条线段尚未同步,则禁止本地删除
  434. if (lines.Count > 0)
  435. {
  436. var line = lines.Dequeue();
  437. if (line)
  438. {
  439. currentPoint -= line.Line.positionCount;
  440. lineMap.Remove(line.name);
  441. ///删除线段
  442. line.DelLine();
  443. Destroy(line.gameObject);
  444. }
  445. }
  446. }
  447. /// <summary>
  448. /// 清除指定的线,删除此线段
  449. /// 如果此线段属于用户自己创建的,则清空对应的内存
  450. /// </summary>
  451. /// <param name="line"></param>
  452. public void ClearOldLine(LineSegment line)
  453. {
  454. if (line)
  455. {
  456. if (lineMap != null && lineMap.ContainsKey(line.name))
  457. {
  458. currentPoint -= line.Line.positionCount;
  459. lineMap.Remove(line.name);
  460. }
  461. Destroy(line.gameObject);
  462. }
  463. }
  464. /// <summary>
  465. /// 清除所有线段
  466. /// </summary>
  467. public void ClearAllLine(bool isClearAll = false)
  468. {
  469. if (UserList != null)
  470. {
  471. ArtInfoMgr.Instance.DelGoodsByIds(UserList);
  472. }
  473. if (isClearAll)
  474. {
  475. ClearOtherLine();
  476. }
  477. }
  478. /// <summary>
  479. /// 删除
  480. /// </summary>
  481. /// <param name="id"></param>
  482. public void AddLineId(int id, bool isOther = true)
  483. {
  484. if (isOther)
  485. {
  486. OtherUserList.Add(id);
  487. }
  488. else
  489. {
  490. UserList.Add(id);
  491. }
  492. }
  493. /// <summary>
  494. /// 清空其他用户的线段
  495. /// </summary>
  496. public void ClearOtherLine()
  497. {
  498. ArtInfoMgr.Instance.DelGoodsByIds(OtherUserList);
  499. }
  500. public float GetDis()
  501. {
  502. Vector3 posks = part.detectorBase.pointerBase.cursorBase.transform.position;
  503. if (API_Module_InputSystem.InputDeviceStatus(InputDeviceType.KS))
  504. {
  505. posks = API_Module_InputSystem_KS.KSPosition(API_Module_InputSystem_KS.GCType.Right);
  506. posks += API_Module_InputSystem_KS.KSTransform(API_Module_InputSystem_KS.GCType.Right).forward.normalized * SystemSettingMgr.Instance.settings.RayDis;
  507. }
  508. float dis= Vector3.Distance(posks, GameSession.Instance.gameHead.position);
  509. return dis;
  510. }
  511. }
  512. }