XAvatar.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. //const log$E = new Logger$1("Avatar")
  2. import BillboardStatus from "./enum/BillboardStatus.js"
  3. import {avatarLoader} from "./XAvatarLoader.js"
  4. import XAnimationController from "./XAnimationController.js"
  5. import XAvatarComopnent from "./XAvatarComopnent.js"
  6. import XStateMachine from "./XStateMachine.js"
  7. import XAvatarBillboardComponent from "./XAvatarBillboardComponent.js"
  8. const castRayOffsetY = .01;
  9. const castRayTeleportationOffset = 10;
  10. export default class XAvatar {
  11. constructor({id, avatarType, priority, avatarManager, assets, status}) {
  12. this.isRender = !1,
  13. this.distLevel = 0,
  14. this.isInLoadingList = !1,
  15. this.isHide = !1,
  16. this.isSelected = !1,
  17. this.pendingLod = !1,
  18. this._previousReceivedPosition = new BABYLON.Vector3(0,1e4,0),
  19. this.distToCam = 1e11,
  20. this.enableNickname = !0,
  21. this.distance = 1e11,
  22. this.isCulling = !1,
  23. this.reslevel = 0,
  24. this.isInLoadingQueue = !1,
  25. this._transparent = 0,
  26. this.id = id,
  27. this._avatarManager = avatarManager,
  28. this._scene = this.avatarManager.scene,
  29. this.clothesList = assets,
  30. this._avatarType = avatarType,
  31. this.priority = priority || 0,
  32. this.controller = new XAnimationController(this),
  33. this.component = new XAvatarComopnent,
  34. this.stateMachine = new XStateMachine(this._scene),
  35. this.bbComponent = new XAvatarBillboardComponent(this._scene),
  36. this.rootNode = new BABYLON.TransformNode(id, this._avatarManager.scene),
  37. this._avatarScale = status.avatarScale == null ? 1 : status.avatarScale,
  38. this._avatarRotation = status.avatarRotation == null ? { pitch: 0, yaw: 0, roll: 0 } : status.avatarRotation,
  39. this._avatarPosition = status.avatarPosition == null ? { x: 0, y: 0, z: 0 } : status.avatarPosition,
  40. this._isRayCastEnable = avatarSetting.isRayCastEnable,
  41. this.setPosition(this._avatarPosition, !0),
  42. this.setRotation(this._avatarRotation),
  43. this.setScale(this.scale),
  44. this._isRayCastEnable = avatarSetting.isRayCastEnable,
  45. this._scene.registerBeforeRender(()=>{
  46. this.tick()
  47. })
  48. }
  49. hide = ()=>{
  50. this.isHide = !0
  51. this._hide()
  52. return !this.isRender
  53. }
  54. _show = ()=>{
  55. this.isHide || (
  56. this.setIsPickable(!0),
  57. this.bbComponent._attachmentObservers.forEach((b,k)=>{
  58. k.setEnabled(!0)
  59. }),
  60. this.priority == 0 && (
  61. this.rootNode.setEnabled(!0),
  62. this.isRender = !0,
  63. this.avatarManager._updateBillboardStatus(this, BillboardStatus.SHOW),
  64. this.component.accessories.forEach(b=>{
  65. b.rootComponent.setEnabled(!0)
  66. }),
  67. this.controller == null || this.controller.playAnimation(this.controller.onPlay, this.controller.loop)
  68. ),
  69. this.component.accessories.forEach(b=>{
  70. b.rootComponent.setEnabled(!0)
  71. })
  72. )
  73. }
  74. show = ()=>{
  75. this.isHide = !1
  76. this._show()
  77. return !!this.isRender
  78. }
  79. setAnimations = _=>{
  80. this.controller.animations = _
  81. }
  82. attachToAvatar = ( _, b=!1, k={x:0,y:0,z:0}, j=!1, $, _e ) => {
  83. this.bbComponent.attachToAvatar(this, _, b, k, j, _e)
  84. }
  85. detachFromAvatar = ( _, b=!1 )=>{
  86. this.bbComponent.detachFromAvatar(this, _, b)
  87. }
  88. getBbox = (_={})=>{
  89. this.bbComponent.getBbox(this, _)
  90. }
  91. tick() {
  92. this.cullingTick()
  93. }
  94. cullingTick() {
  95. this.isCulling && (this.rootNode == null || this.rootNode.getChildMeshes().forEach(i=>{
  96. this.distToCam < 50 ? i.visibility = 0 : i.visibility = this._transparent
  97. }))
  98. }
  99. setTransParentThresh(e) {
  100. this._transparent = e
  101. }
  102. get isNameVisible() {
  103. return this.bbComponent.isNameVisible
  104. }
  105. get isBubbleVisible() {
  106. return this.bbComponent.isBubbleVisible
  107. }
  108. get isGiftButtonsVisible() {
  109. return this.bbComponent.isGiftButtonsVisible
  110. }
  111. get words() {
  112. return this.bbComponent.words
  113. }
  114. get nickName() {
  115. return this.bbComponent.nickName
  116. }
  117. get giftButtons() {
  118. return this.bbComponent.giftButtons
  119. }
  120. get bubble() {
  121. return this.bbComponent.bubble
  122. }
  123. get nameBoard() {
  124. return this.bbComponent.nameBoard
  125. }
  126. get avatarManager() {
  127. return this._avatarManager
  128. }
  129. set withinVisibleRange(e) {
  130. this.bbComponent.withinVisualRange = e
  131. }
  132. setNicknameStatus(e) {
  133. return this.bbComponent.setNicknameStatus(e)
  134. }
  135. setBubbleStatus(e) {
  136. return this.bbComponent.setBubbleStatus(e)
  137. }
  138. setButtonsStatus(e) {
  139. return this.bbComponent.setBubbleStatus(e)
  140. }
  141. setGiftButtonsVisible(e) {
  142. return this.bbComponent.setGiftButtonsVisible(e)
  143. }
  144. get avatarType() {
  145. return this._avatarType
  146. }
  147. attachBody(e) {
  148. return this.component.addBodyComp(this, e)
  149. }
  150. attachDecoration(e) {
  151. return this.component.addClothesComp(this, e)
  152. }
  153. detachDecoration(e) {
  154. return this.component.clearClothesComp(e)
  155. }
  156. detachDecorationAll() {
  157. return this.component.clearAllClothesComps()
  158. }
  159. get skeleton() {
  160. return this.component.skeleton
  161. }
  162. get position() {
  163. return this._avatarPosition
  164. }
  165. get rotation() {
  166. return this._avatarRotation
  167. }
  168. get scale() {
  169. return this._avatarScale
  170. }
  171. _hide_culling() {
  172. this.bbComponent.updateBillboardStatus(this, BillboardStatus.HIDE),
  173. this.isCulling = !0
  174. }
  175. _show_culling() {
  176. this.isCulling && (this.rootNode && this.rootNode.getChildMeshes().forEach(e=>{
  177. e.visibility = 1
  178. }),
  179. this.bbComponent.updateBillboardStatus(this, BillboardStatus.SHOW),
  180. this.isCulling = !1)
  181. }
  182. _hide() {
  183. !this.isHide || (this.setIsPickable(!1),
  184. this.bbComponent._attachmentObservers.forEach((e,i)=>{
  185. i.setEnabled(!1)
  186. }
  187. ),
  188. this.priority == 0 ? (this.rootNode.setEnabled(!1),
  189. this.isRender = !1,
  190. this.bbComponent.updateBillboardStatus(this, BillboardStatus.HIDE),
  191. this.component.accessories.forEach(e=>{
  192. e.rootComponent.setEnabled(!1)
  193. }
  194. )) : this.isRender && (this.avatarManager.currentLODUsers[this.distLevel]--,
  195. this.removeAvatarFromScene()),
  196. this.component.accessories.forEach(e=>{
  197. e.rootComponent.setEnabled(!1)
  198. }))
  199. }
  200. rotate(e, i, o) {
  201. return this.stateMachine.roll(this, e, i, o)
  202. }
  203. set isRayCastEnable(e) {
  204. this._isRayCastEnable = e
  205. }
  206. get isRayCastEnable() {
  207. return this._isRayCastEnable
  208. }
  209. getAvatarId() {
  210. return this.id
  211. }
  212. getAvaliableAnimations() {
  213. const e = avatarLoader.avaliableAnimation.get(this.avatarType);
  214. return e || []
  215. }
  216. // todo i用于控制是否接触地面。目前设默认为true,实时检测模型地面高度
  217. setPosition(e, i=!0) {
  218. this._avatarPosition = e;
  219. if (this.rootNode) {
  220. const o = ue4Position2Xverse(this._avatarPosition);
  221. let s = !1;
  222. if(this.avatarManager.getMainAvatar() ){
  223. if(this.id == this.avatarManager.getMainAvatar().id){
  224. Math.abs(o.y - this._previousReceivedPosition.y) > castRayOffsetY && (s = !0);
  225. o.subtract(this._previousReceivedPosition).length() > castRayTeleportationOffset && (s = !0)
  226. }
  227. }
  228. if(this._isRayCastEnable)
  229. if(s || i) {
  230. // 检测模型地面高度
  231. this._castRay(e).then(c=>{
  232. this.rootNode.position = o;
  233. this.rootNode.position.y -= c;
  234. }
  235. ).catch(c=>{
  236. Promise.reject(c)
  237. })
  238. } else {
  239. // 保持人物高度不变
  240. this.rootNode.position.x = o.x
  241. this.rootNode.position.z = o.z
  242. }
  243. else this.rootNode.position = o
  244. this._previousReceivedPosition = o.clone()
  245. }
  246. return Promise.resolve(e)
  247. }
  248. setRotation(e) {
  249. if (this._avatarRotation = e,
  250. this.rootNode) {
  251. const i = {
  252. pitch: e.pitch,
  253. yaw: e.yaw + 180,
  254. roll: e.roll
  255. }
  256. , o = ue4Rotation2Xverse(i);
  257. this.rootNode.rotation = o
  258. }
  259. }
  260. setAvatarVisible(e) {
  261. this.rootNode && (this.rootNode.setEnabled(e),
  262. this.rootNode.getChildMeshes().forEach(i=>{
  263. i.setEnabled(e)
  264. }
  265. ))
  266. }
  267. setScale(e) {
  268. this._avatarScale = e,
  269. this.rootNode && (this.rootNode.scaling = new BABYLON.Vector3(e,e,e)),
  270. this.bbComponent.bbox && this.getBbox()
  271. }
  272. _removeAvatarFromScene() {
  273. var e, i;
  274. this.isRender = !1,
  275. (e = this.controller) == null || e.detachAnimation(),
  276. this.component.dispose(this),
  277. (i = this.avatarManager.sceneManager) == null || i.lightComponent.removeShadow(this),
  278. this.component.accessories.forEach(o=>{
  279. o.rootComponent.setEnabled(!1)
  280. })
  281. }
  282. removeAvatarFromScene() {
  283. this._removeAvatarFromScene(),
  284. this._disposeBillBoard()
  285. }
  286. _disposeBillBoard() {
  287. this.bbComponent.disposeBillBoard(this)
  288. }
  289. addComponent(e, i, o, s) {
  290. return i === "pendant" ? this.component.attachPendant(this, e) : this.component.changeClothesComp(this, e, i, o, s)
  291. }
  292. removeComponent(e, i) {
  293. if (e === "pendant")
  294. i ? this.component.detachPendant(i) : this.component.accessories.forEach((o,s)=>{
  295. this.component.detachPendant(s)
  296. }
  297. );
  298. else {
  299. const o = this.component.resourceIdList.find(s=>s.type == e);
  300. o && (this.detachDecoration(o),
  301. this.clothesList = this.clothesList.filter(s=>s.type != e))
  302. }
  303. }
  304. getComponentByType(e, i) {
  305. if (e === "pendant")
  306. if (i) {
  307. const o = this.component.accessories.get(i);
  308. return o || []
  309. } else
  310. return Array.from(this.component.accessories).map(o=>o[1]);
  311. else
  312. return this.component.resourceIdList.find(o=>o.type == e)
  313. }
  314. _castRay(e) {
  315. return new Promise((i,o)=>{
  316. var et;
  317. const s = ue4Position2Xverse(e)
  318. , c = new BABYLON.Vector3(0,-1,0)
  319. , d = 1.5 * this.scale
  320. , _ = 100 * d
  321. , b = d
  322. , k = new BABYLON.Vector3(s.x,s.y + b,+s.z)
  323. , j = new BABYLON.Ray(k,c,_)
  324. , $ = (et = this.avatarManager.sceneManager) == null ? void 0 : et.getGround(e);
  325. if (!$ || $.length <= 0)
  326. return log$F.warn(`\u89D2\u8272 id= ${this.id} \u627E\u4E0D\u5230\u5730\u9762\uFF0C\u5F53\u524D\u9AD8\u5EA6\u4E3A\u4E0B\u53D1\u9AD8\u5EA6`),
  327. i(0);
  328. let _e = j.intersectsMeshes($);
  329. if (_e.length > 0)
  330. return i(_e[0].distance - b);
  331. if (c.y = 1,
  332. _e = j.intersectsMeshes($),
  333. _e.length > 0)
  334. return i(-(_e[0].distance - b))
  335. })
  336. }
  337. setPickBoxScale(e) {
  338. return this.bbComponent.setPickBoxScale(e)
  339. }
  340. setIsPickable(e) {
  341. return this.bbComponent.setIsPickable(this, e)
  342. }
  343. createPickBoundingbox(e) {
  344. return this.bbComponent.createPickBoundingbox(this, e)
  345. }
  346. scaleBbox(e) {
  347. this.bbComponent.bbox && this.bbComponent.bbox.scale(e)
  348. }
  349. rotateTo(e, i, o) {
  350. return this.stateMachine.rotateTo(this, e, i, o)
  351. }
  352. faceTo(e, i) {
  353. return this.stateMachine.lookAt(this, e, i)
  354. }
  355. removeObserver() {
  356. this.stateMachine.disposeObsever()
  357. }
  358. moveHermite(e, i, o, s, c, d) {
  359. return this.stateMachine.moveToHermite(this, e, i, o, s, c, d)
  360. }
  361. moveCardinal(e, i, o, s, c, d, _=!1) {
  362. return this.stateMachine.moveToCardinal(this, e, i, o, s, c, d, _)
  363. }
  364. move(e, i, o, s, c, d=!1) {
  365. return this.stateMachine.moveTo(this, e, i, o, s, c, d)
  366. }
  367. initNameboard(e=1) {
  368. return this.bbComponent.initNameboard(this, e)
  369. }
  370. initBubble(e=1) {
  371. return this.bbComponent.initBubble(this, e)
  372. }
  373. say(e, {
  374. id, isUser, background,
  375. font="Arial", fontsize=38, fontcolor="#ffffff", fontstyle="bold", linesize=22, linelimit,
  376. offsets={x: 0, y: 0, z: 40}, scale=this._avatarScale, compensationZ=11.2, reregistAnyway=!0
  377. }) {
  378. return this.bbComponent.say(this, e, {
  379. id, isUser, background,
  380. font, fontsize, fontcolor, fontstyle, linesize, linelimit,
  381. offsets, scale, compensationZ, reregistAnyway
  382. })
  383. }
  384. silent() {
  385. return this.bbComponent.silent()
  386. }
  387. setNickName(e, {
  388. id, isUser, background,
  389. font="Arial", fontsize=40, fontcolor="#ffffff", fontstyle="bold", linesize=22, linelimit,
  390. offsets={x: 0, y: 0, z: 15}, scale=this._avatarScale, compensationZ=0, reregistAnyway=!1
  391. }) {
  392. return this.bbComponent.setNickName(this, e, {
  393. id, isUser, background,
  394. font, fontsize, fontcolor, fontstyle, linesize, linelimit,
  395. offsets, scale, compensationZ, reregistAnyway
  396. })
  397. }
  398. generateButtons(e=null, i=this._avatarScale, o=85) {
  399. return this.bbComponent.generateButtons(this, e, i, o)
  400. }
  401. clearButtons() {
  402. return this.bbComponent.clearButtons()
  403. }
  404. attachExtraProp(e, i, o, s) {
  405. return this.component.addDecoComp(this, e, i, o, s)
  406. }
  407. showExtra(e) {
  408. return this.component.showExtra(e)
  409. }
  410. hideExtra(e) {
  411. return this.component.hideExtra(e)
  412. }
  413. disposeExtra() {
  414. return this.component.disposeExtra()
  415. }
  416. getSkeletonPositionByName(e) {
  417. var i;
  418. if (this.skeleton) {
  419. const o = this.skeleton.bones.find(s=>s.name.replace("Clone of ", "") == e);
  420. if (o && o.getTransformNode() && ((i = o.getTransformNode()) == null ? void 0 : i.position)) {
  421. const s = o.getTransformNode().position;
  422. return xversePosition2Ue4({
  423. x: s.x,
  424. y: s.y,
  425. z: s.z
  426. })
  427. }
  428. }
  429. }
  430. shootTo(e, i, o=2, s=10, c={
  431. x: 0,
  432. y: 0,
  433. z: 150
  434. }) {
  435. return this.stateMachine.sendObjectTo(this, e, i, o, s, c)
  436. }
  437. }