Agent.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /** @format */
  2. import {cBody} from './Body'
  3. import {Line, RVOMath, Vector2} from './Maths'
  4. export class ObserverObj<T> {
  5. public value: T
  6. constructor(val?: T) {
  7. if (val) this.value = val
  8. }
  9. }
  10. export class KeyValuePair<K, V> {
  11. public Key: K
  12. public Value: V
  13. constructor(key: K, value: V) {
  14. this.Key = key
  15. this.Value = value
  16. }
  17. }
  18. export class RVOConfig {
  19. /**代理对象总数 */
  20. public static agentCount = 10
  21. /**代理对象之间的距离 */
  22. public static neighborDist = 0.75 //25;
  23. /**代理对象的半径 */
  24. public static radius = 0.5 //10;
  25. /**代理对象的最大移动速度 */
  26. public static maxSpeed = 1
  27. /**代理对象的初始速度 */
  28. public static velocity: cc.Vec3 = new cc.Vec3()
  29. /**最大邻居数 */
  30. public static maxNeighbors = 10
  31. /**安全单位时间,值越大,就会越早做出避让行为 */
  32. public static timeHorizon = 5 //25;
  33. /**与timeHorizon类似,只针对障碍物 */
  34. public static timeHorizonObst = 0
  35. /**步骤帧 */
  36. public static timeStep = 0.05 //0.25
  37. }
  38. export class Agent {
  39. private static _inst: Agent = null
  40. static get inst() {
  41. if (this._inst == null) {
  42. this._inst = new Agent()
  43. }
  44. return this._inst
  45. }
  46. check(a: cBody, b: cBody) {
  47. let invTimeHorizon = 1.0 / RVOConfig.timeHorizon
  48. let relativePosition = Vector2.subtract(b.getCenter(), a.getCenter())
  49. let relativeVelocity = Vector2.subtract(a.newVelocity, b.newVelocity)
  50. let combinedRadius = a.neighborDist + b.neighborDist
  51. let combinedRadiusSq = RVOMath.sqr(combinedRadius)
  52. let distSq = RVOMath.absSq(relativePosition)
  53. let u = new Vector2()
  54. let direction = new Vector2()
  55. if (distSq > combinedRadiusSq) {
  56. let w = Vector2.subtract(relativeVelocity, Vector2.multiply2(invTimeHorizon, relativePosition))
  57. let wLengthSq = RVOMath.absSq(w)
  58. let dotProduct1 = Vector2.multiply(w, relativePosition)
  59. if (dotProduct1 < 0 && RVOMath.sqr(dotProduct1) > combinedRadiusSq * wLengthSq) {
  60. let wLength = RVOMath.sqrt(wLengthSq)
  61. let unitW = Vector2.division(w, wLength)
  62. direction = new Vector2(unitW.y, -unitW.x)
  63. u = Vector2.multiply2(combinedRadius * invTimeHorizon - wLength, unitW)
  64. } else {
  65. let leg = RVOMath.sqrt(distSq - combinedRadiusSq)
  66. if (RVOMath.det(relativePosition, w) > 0) {
  67. direction = Vector2.division(
  68. new Vector2(
  69. relativePosition.x * leg - relativePosition.y * combinedRadius,
  70. relativePosition.x * combinedRadius + relativePosition.y * leg,
  71. ),
  72. distSq,
  73. )
  74. } else {
  75. direction = Vector2.division(
  76. new Vector2(
  77. relativePosition.x * leg + relativePosition.y * combinedRadius,
  78. -relativePosition.x * combinedRadius + relativePosition.y * leg,
  79. ),
  80. -distSq,
  81. )
  82. }
  83. let dotProduct2 = Vector2.multiply(relativeVelocity, direction)
  84. u = Vector2.subtract(Vector2.multiply2(dotProduct2, direction), relativeVelocity)
  85. }
  86. } else {
  87. let invTimeStep = 1.0 / RVOConfig.timeStep
  88. let w = Vector2.subtract(relativeVelocity, Vector2.multiply2(invTimeStep, relativePosition))
  89. let wLength = RVOMath.abs(w)
  90. let unitW = Vector2.division(w, wLength)
  91. direction = new Vector2(unitW.y, -unitW.x)
  92. u = Vector2.multiply2(combinedRadius * invTimeStep - wLength, unitW)
  93. }
  94. let lineA = new Line()
  95. lineA.direction = new Vector2(direction.x, direction.y)
  96. lineA.point = Vector2.addition(a.newVelocity, Vector2.multiply2(0.5, u))
  97. a.orcaLines.push(lineA)
  98. }
  99. process(bodys: Array<cBody>) {
  100. for (let i = 0, j = bodys.length; i < j; i++) {
  101. let body = bodys[i]
  102. if (body.isAgent && body.orcaLines.length > 0) {
  103. if (!body.isRemove && body.object) {
  104. let numObstLines = 0 //默认0wh
  105. let tempVelocity_ = new ObserverObj<Vector2>(new Vector2(body.newVelocity.x, body.newVelocity.y))
  106. let lineFail = this.linearProgram2(
  107. body.orcaLines,
  108. body.maxVelocity,
  109. body.prefVelocity,
  110. false,
  111. tempVelocity_,
  112. )
  113. if (lineFail < body.orcaLines.length) {
  114. this.linearProgram3(body.orcaLines, numObstLines, lineFail, body.maxVelocity, tempVelocity_)
  115. }
  116. let value = tempVelocity_.value
  117. body.prefVelocity.x = body.newVelocity.x
  118. body.prefVelocity.y = body.newVelocity.y
  119. // body.newVelocity.x = value.x;
  120. // body.newVelocity.y = value.y;
  121. if (body.object) {
  122. let v = body.object.velocity
  123. v.x = value.x
  124. v.y = value.y
  125. v.z = 0
  126. }
  127. }
  128. body.orcaLines.length = 0
  129. }
  130. }
  131. }
  132. private linearProgram1(
  133. lines: Array<Line>,
  134. lineNo: number,
  135. radius: number,
  136. optVelocity: Vector2,
  137. directionOpt: boolean,
  138. result: ObserverObj<Vector2>,
  139. ): boolean {
  140. let dotProduct = Vector2.multiply(lines[lineNo].point, lines[lineNo].direction)
  141. let discriminant = RVOMath.sqr(dotProduct) + RVOMath.sqr(radius) - RVOMath.absSq(lines[lineNo].point)
  142. if (discriminant < 0) {
  143. return false
  144. }
  145. let sqrtDiscriminant = RVOMath.sqrt(discriminant)
  146. let tLeft = -dotProduct - sqrtDiscriminant
  147. let tRight = -dotProduct + sqrtDiscriminant
  148. for (let i = 0; i < lineNo; ++i) {
  149. let denominator = RVOMath.det(lines[lineNo].direction, lines[i].direction)
  150. let numerator = RVOMath.det(lines[i].direction, Vector2.subtract(lines[lineNo].point, lines[i].point))
  151. if (RVOMath.fabs(denominator) <= RVOMath.RVO_EPSILON) {
  152. if (numerator < 0) {
  153. return false
  154. }
  155. continue
  156. }
  157. let t = numerator / denominator
  158. if (denominator > 0) {
  159. tRight = Math.min(tRight, t)
  160. } else {
  161. tLeft = Math.max(tLeft, t)
  162. }
  163. if (tLeft > tRight) {
  164. return false
  165. }
  166. }
  167. if (directionOpt) {
  168. if (Vector2.multiply(optVelocity, lines[lineNo].direction) > 0) {
  169. result.value = Vector2.addition(lines[lineNo].point, Vector2.multiply2(tRight, lines[lineNo].direction))
  170. } else {
  171. result.value = Vector2.addition(lines[lineNo].point, Vector2.multiply2(tLeft, lines[lineNo].direction))
  172. }
  173. } else {
  174. let t = Vector2.multiply(lines[lineNo].direction, Vector2.subtract(optVelocity, lines[lineNo].point))
  175. if (t < tLeft) {
  176. result.value = Vector2.addition(lines[lineNo].point, Vector2.multiply2(tLeft, lines[lineNo].direction))
  177. } else if (t > tRight) {
  178. result.value = Vector2.addition(lines[lineNo].point, Vector2.multiply2(tRight, lines[lineNo].direction))
  179. } else {
  180. result.value = Vector2.addition(lines[lineNo].point, Vector2.multiply2(t, lines[lineNo].direction))
  181. }
  182. }
  183. return true
  184. }
  185. private linearProgram2(
  186. lines: Array<Line>,
  187. radius: number,
  188. optVelocity: Vector2,
  189. directionOpt: boolean,
  190. result: ObserverObj<Vector2>,
  191. ): number {
  192. if (directionOpt) {
  193. result.value = Vector2.multiply2(radius, optVelocity)
  194. } else if (RVOMath.absSq(optVelocity) > RVOMath.sqr(radius)) {
  195. result.value = Vector2.multiply2(radius, RVOMath.normalize(optVelocity))
  196. } else {
  197. result.value = optVelocity
  198. }
  199. for (let i = 0; i < lines.length; ++i) {
  200. if (RVOMath.det(lines[i].direction, Vector2.subtract(lines[i].point, result.value)) > 0) {
  201. let tempResult = new Vector2(result.value.x, result.value.y)
  202. if (!this.linearProgram1(lines, i, radius, optVelocity, directionOpt, result)) {
  203. result.value = tempResult
  204. return i
  205. }
  206. }
  207. }
  208. return lines.length
  209. }
  210. private linearProgram3(
  211. lines: Array<Line>,
  212. numObstLines: number,
  213. beginLine: number,
  214. radius: number,
  215. result: ObserverObj<Vector2>,
  216. ) {
  217. let distance = 0
  218. for (let i = beginLine; i < lines.length; ++i) {
  219. if (RVOMath.det(lines[i].direction, Vector2.subtract(lines[i].point, result.value)) > distance) {
  220. let projLines: Array<Line> = []
  221. for (let ii = 0; ii < numObstLines; ++ii) {
  222. projLines[projLines.length] = lines[ii]
  223. }
  224. for (let j = numObstLines; j < i; ++j) {
  225. let line = new Line()
  226. let determinant = RVOMath.det(lines[i].direction, lines[j].direction)
  227. if (RVOMath.fabs(determinant) <= RVOMath.RVO_EPSILON) {
  228. if (Vector2.multiply(lines[i].direction, lines[j].direction) > 0.0) {
  229. continue
  230. } else {
  231. line.point = Vector2.multiply2(0.5, Vector2.addition(lines[i].point, lines[j].point))
  232. }
  233. } else {
  234. line.point = Vector2.addition(
  235. lines[i].point,
  236. Vector2.multiply2(
  237. RVOMath.det(lines[j].direction, Vector2.subtract(lines[i].point, lines[j].point)) /
  238. determinant,
  239. lines[i].direction,
  240. ),
  241. )
  242. }
  243. let d = Vector2.subtract(lines[j].direction, lines[i].direction)
  244. if (RVOMath.absSq(d) > 0) {
  245. line.direction = RVOMath.normalize(d)
  246. projLines[projLines.length] = line
  247. }
  248. }
  249. let tempResult = new Vector2(result.value.x, result.value.y)
  250. if (
  251. this.linearProgram2(
  252. projLines,
  253. radius,
  254. new Vector2(-lines[i].direction.y, lines[i].direction.x),
  255. true,
  256. result,
  257. ) < projLines.length
  258. ) {
  259. result.value = tempResult
  260. }
  261. distance = RVOMath.det(lines[i].direction, Vector2.subtract(lines[i].point, result.value))
  262. }
  263. }
  264. }
  265. }