DrawPener.cs 20 KB

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