DrawPener.cs 18 KB

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