LogicTransform.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. using UnityEngine;
  2. public enum LogicTransformHitType
  3. {
  4. Cylinder = 0,
  5. Box = 1,
  6. Sphere = 2,
  7. }
  8. public struct InterpolateRecord
  9. {
  10. public float time;
  11. public Vector3 pos;
  12. }
  13. public struct InterpolateCache
  14. {
  15. const int cache_size = 5;
  16. InterpolateRecord[] records;
  17. int last;
  18. public void Init (Vector3 pos)
  19. {
  20. records = new InterpolateRecord[cache_size];
  21. for (int i = 0; i < cache_size; i++) {
  22. records [i].pos = pos;
  23. records [i].time = 0;
  24. }
  25. last = 0;
  26. }
  27. public void Reset (Vector3 pos)
  28. {
  29. for (int i = 0; i < cache_size; i++) {
  30. records [i].pos = pos;
  31. records [i].time = 0;
  32. }
  33. last = 0;
  34. }
  35. public void Add (Vector3 pos)
  36. {
  37. last = (last + 1) % cache_size;
  38. records [last].time = Time.time;
  39. records [last].pos = pos;
  40. }
  41. public bool Interpolate (float time, out Vector3 pos)
  42. {
  43. if (records [last].time <= time + 1e-3f) {
  44. pos = records [last].pos;
  45. return true;
  46. }
  47. int idx = (last + cache_size - 1) % cache_size;
  48. while (idx != last) {
  49. if (records [idx].time <= time) {
  50. pos = Vector3.Lerp (records [idx].pos, records [last].pos, (time - records [idx].time) / (records [last].time - records [idx].time));
  51. return false;
  52. }
  53. idx = (idx + cache_size - 1) % cache_size;
  54. }
  55. pos = records [(last + 1) % cache_size].pos;
  56. return false;
  57. }
  58. }
  59. public class LogicTransform
  60. {
  61. const float interpolate_position_delay = 0.066f;
  62. bool mGoDirty;
  63. bool mMatrixDirty;
  64. bool mPositionDirty;
  65. Matrix4x4 mLocalToWorld;
  66. Matrix4x4 mWorldToLocal;
  67. InterpolateCache mPositionCache;
  68. LogicTransform mParent;
  69. Vector3 mLocalPosition;
  70. Vector3 mLocalForward;
  71. bool mIsSettingFromParent;
  72. public Vector3 Position { get; protected set; }
  73. public Vector3 Forward { get; private set; }
  74. public Vector3 Up { get; private set; }
  75. public Vector3 Right { get { return Vector3.Cross (Up, Forward); } }
  76. public Vector3 Back { get { return Quaternion.AngleAxis(180, Vector3.up) * Forward; } }
  77. public float Scale { get; private set; }
  78. public int Layer { get; set; }
  79. public string LayerName { get { return LayerMask.LayerToName (Layer); } set { Layer = LayerMask.NameToLayer (value); } }
  80. public Vector3 HitSize { get; set; }
  81. public LogicTransformHitType HitType { get; set; }
  82. public float HitHeight { get { return HitSize.y; } }
  83. public float HitRadius { get { return HitSize.x; } }
  84. public bool KeepHorizontalLook { get; set; }
  85. public LogicTransform Parent { get { return mParent; } }
  86. public Vector3 LocalPosition {
  87. get { return mParent == null ? Position : mLocalPosition; }
  88. set {
  89. if (mParent != null) {
  90. mLocalPosition = value;
  91. UpdateFromParent ();
  92. } else
  93. SetPosition (value);
  94. }
  95. }
  96. public Vector3 LocalForward {
  97. get { return mParent == null ? Forward : mLocalForward; }
  98. set {
  99. if (mParent != null) {
  100. mLocalForward = value;
  101. UpdateFromParent ();
  102. } else
  103. LookForward (value);
  104. }
  105. }
  106. public LogicTransform ()
  107. {
  108. Position = Vector3.zero;
  109. Forward = Vector3.forward;
  110. Up = Vector3.up;
  111. KeepHorizontalLook = true;
  112. Scale = 1;
  113. HitSize = new Vector3 (0.5f, 1.8f, 0f);
  114. HitType = LogicTransformHitType.Cylinder;
  115. mPositionCache.Init (Position);
  116. mGoDirty = true;
  117. mPositionDirty = true;
  118. UpdateMatrix ();
  119. }
  120. public LogicTransform (Vector3 position, Vector3 forward, LogicTransformHitType hitType = LogicTransformHitType.Box, Vector3 hitSize = default(Vector3))
  121. {
  122. Position = position;
  123. Forward = forward;
  124. Up = Vector3.up;
  125. KeepHorizontalLook = true;
  126. Scale = 1;
  127. HitSize = hitSize;
  128. HitType = hitType;
  129. mPositionCache.Init (Position);
  130. mGoDirty = true;
  131. mPositionDirty = true;
  132. UpdateMatrix ();
  133. }
  134. public virtual void UpdateTransform (Transform transform)
  135. {
  136. if (mPositionDirty) {
  137. Vector3 pos;
  138. mPositionDirty = !mPositionCache.Interpolate(Time.time - interpolate_position_delay, out pos);
  139. transform.position = pos;
  140. }
  141. if (mGoDirty) {
  142. transform.LookAt (transform.position + Forward, Up);
  143. transform.localScale = Vector3.one * Scale;
  144. mGoDirty = false;
  145. }
  146. }
  147. public void ForceSync (Transform transform)
  148. {
  149. transform.position = Position;
  150. transform.LookAt (transform.position + Forward, Up);
  151. transform.localScale = Vector3.one * Scale;
  152. mPositionCache.Reset (Position);
  153. mGoDirty = false;
  154. mPositionDirty = false;
  155. }
  156. public virtual void SetPosition (Vector3 position)
  157. {
  158. mPositionCache.Add (position);
  159. mPositionDirty = true;
  160. mMatrixDirty = true;
  161. if (mParent != null && !mIsSettingFromParent)
  162. UpdateLocal ();
  163. }
  164. public virtual void SetRotation(Quaternion rot)
  165. {
  166. mMatrixDirty = true;
  167. if (mParent != null && !mIsSettingFromParent)
  168. UpdateLocal();
  169. }
  170. public virtual void LookForward (Vector3 forward, Vector3 up = default(Vector3))
  171. {
  172. if (KeepHorizontalLook) {
  173. forward = forward.SetY (0).normalized;
  174. if (forward.FEqual (Forward, 1e-3f))
  175. return;
  176. Forward = forward.normalized;
  177. Up = Vector3.up;
  178. } else {
  179. if (forward.FEqual (Forward, 1e-3f))
  180. return;
  181. Forward = forward.normalized;
  182. if (up != default(Vector3))
  183. Up = up.normalized;
  184. FixUpDir ();
  185. }
  186. mGoDirty = true;
  187. mMatrixDirty = true;
  188. if (mParent != null && !mIsSettingFromParent)
  189. UpdateLocal ();
  190. }
  191. public virtual void SetScale (float s)
  192. {
  193. Scale = s;
  194. mGoDirty = true;
  195. mMatrixDirty = true;
  196. }
  197. public void LookAt (Vector3 lookAt, Vector3 up = default(Vector3))
  198. {
  199. if (lookAt.FEqual (Position, 1e-2f))
  200. return;
  201. LookForward ((lookAt - Position).normalized, up);
  202. }
  203. public Vector3 TransformPoint (Vector3 v)
  204. {
  205. if (mMatrixDirty)
  206. UpdateMatrix ();
  207. return mLocalToWorld.MultiplyPoint (v);
  208. }
  209. public Vector3 InverseTransformPoint (Vector3 v)
  210. {
  211. if (mMatrixDirty)
  212. UpdateMatrix ();
  213. return mWorldToLocal.MultiplyPoint (v);
  214. }
  215. public Vector3 TransformDirection (Vector3 d)
  216. {
  217. if (mMatrixDirty)
  218. UpdateMatrix ();
  219. return mLocalToWorld.MultiplyVector (d);
  220. }
  221. public Vector3 InverseTransformDirection (Vector3 d)
  222. {
  223. if (mMatrixDirty)
  224. UpdateMatrix ();
  225. return mWorldToLocal.MultiplyVector (d);
  226. }
  227. public bool CheckHitBox (Vector3 pos, Vector3 dir, Vector3 size)
  228. {
  229. Vector3 offset = Position - pos;
  230. if (Mathf.Abs (Vector3.Dot (offset, Up) + 0.5f * HitHeight) > 0.5f * (size.y + HitHeight))
  231. return false;
  232. if (Mathf.Abs (Vector3.Dot (offset, dir)) > (0.5f * size.z + HitRadius))
  233. return false;
  234. return Mathf.Abs (Vector3.Dot (offset, Vector3.Cross (Up, dir))) <= (0.5f * size.x + HitRadius);
  235. }
  236. public bool CheckHitBoxUnscrict(Vector3 linkPos, Vector3 pos, Vector3 dir, Vector3 size)
  237. {
  238. Vector3 offset = linkPos - pos;
  239. if (Mathf.RoundToInt(Mathf.Abs(Vector3.Dot(offset, Up) + 0.5f * HitHeight) * 1e5f) > Mathf.RoundToInt(0.5f * (size.y + HitHeight)) * 1e5f)
  240. return false;
  241. if (Mathf.RoundToInt(Mathf.Abs(Vector3.Dot(offset, dir)) * 1e5f) > Mathf.RoundToInt((0.5f * size.z + HitRadius) * 1e5f))
  242. return false;
  243. return Mathf.RoundToInt(Mathf.Abs(Vector3.Dot(offset, Vector3.Cross(Up, dir))) * 1e5f) <= Mathf.RoundToInt((0.5f * size.x + HitRadius) * 1e5f);
  244. }
  245. public bool CheckHitBoxUnscrict (Vector3 pos, Vector3 dir, Vector3 size)
  246. {
  247. Vector3 offset = Position - pos;
  248. if (Mathf.RoundToInt (Mathf.Abs (Vector3.Dot (offset, Up) + 0.5f * HitHeight) * 1e5f) > Mathf.RoundToInt (0.5f * (size.y + HitHeight)) * 1e5f)
  249. return false;
  250. if (Mathf.RoundToInt (Mathf.Abs (Vector3.Dot (offset, dir)) * 1e5f) > Mathf.RoundToInt((0.5f * size.z + HitRadius) * 1e5f))
  251. return false;
  252. return Mathf.RoundToInt (Mathf.Abs (Vector3.Dot (offset, Vector3.Cross (Up, dir))) * 1e5f) <= Mathf.RoundToInt((0.5f * size.x + HitRadius) * 1e5f);
  253. }
  254. public bool CheckHitCylinder (Vector3 pos, float radius, float height)
  255. {
  256. Vector3 offset = Position - pos;
  257. if (offset.SetY (0).sqrMagnitude > (radius + HitRadius) * (radius + HitRadius))
  258. return false;
  259. return Mathf.Abs (offset.y + 0.5f * HitHeight) <= 0.5f * (height + HitHeight);
  260. }
  261. public void SetParent (LogicTransform parent, bool keepWorldTransform = false)
  262. {
  263. mParent = parent;
  264. if (mParent != null) {
  265. if (keepWorldTransform) {
  266. UpdateLocal ();
  267. } else {
  268. LocalPosition = Vector3.zero;
  269. LocalForward = Vector3.forward;
  270. }
  271. }
  272. }
  273. void UpdateLocal ()
  274. {
  275. mLocalPosition = mParent.InverseTransformPoint (Position);
  276. mLocalForward = mParent.InverseTransformDirection (Forward);
  277. }
  278. public void UpdateFromParent ()
  279. {
  280. mIsSettingFromParent = true;
  281. SetPosition (mParent.TransformPoint (mLocalPosition));
  282. LookForward (mParent.TransformDirection (Forward));
  283. mIsSettingFromParent = false;
  284. }
  285. void UpdateMatrix ()
  286. {
  287. mLocalToWorld.SetColumn (0, Right * Scale);
  288. mLocalToWorld.SetColumn (1, Up * Scale);
  289. mLocalToWorld.SetColumn (2, Forward * Scale);
  290. mLocalToWorld.SetColumn (3, new Vector4(Position.x, Position.y, Position.z, 1));
  291. mWorldToLocal = mLocalToWorld.inverse;
  292. mMatrixDirty = false;
  293. }
  294. void FixUpDir ()
  295. {
  296. float dot = Mathf.Abs (Vector3.Dot (Forward, Up));
  297. if (dot > 1 - 1e-4f) {
  298. if (Forward.FEqual (Vector3.up))
  299. Up = Vector3.Cross (Forward, Vector3.right);
  300. else
  301. Up = Vector3.Cross (Forward, Vector3.Cross (Vector3.up, Forward));
  302. } else if (dot > Mathf.Epsilon)
  303. Up = Vector3.Cross (Forward, Vector3.Cross (Up, Forward));
  304. }
  305. }