HomeNotices.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import { AppKernel } from '@scripts/app/AppKernel';
  2. import { CURRENCY_TYPE } from '@scripts/define/Define';
  3. import { INoticeData } from '@scripts/store/mainStore/data';
  4. import { formatMaskNickName, formatSCNum } from '@scripts/utils/Helper';
  5. import { _decorator, Component, Input, input, instantiate, KeyCode, Label, Node, NodePool, tween, Tween, UITransform, Vec3 } from 'cc';
  6. const { ccclass, property } = _decorator;
  7. const MIN_MESSAGE_GAP = 50;
  8. const SCROLL_SPEED = 120;
  9. interface INoticeNode {
  10. label: Label,
  11. trans: UITransform,
  12. }
  13. @ccclass('HomeNotices')
  14. export class HomeNotices extends Component {
  15. @property(Node)
  16. itemNode: Node = null;
  17. @property(UITransform)
  18. content: UITransform = null;
  19. private readonly pool = new NodePool('HomeNotices');
  20. private readonly activeItems: Node[] = [];
  21. private readonly noticeNodes = new WeakMap<Node, INoticeNode>();
  22. protected onLoad(): void {
  23. if (this.itemNode) this.itemNode.active = false;
  24. this.node.active = false;
  25. // input.on(Input.EventType.KEY_DOWN, (event) => {
  26. // if (event.keyCode === KeyCode.KEY_W) {
  27. // let data: INoticeData = {
  28. // nickName: `User${Math.floor(Math.random() * 8999 + 1000)}`,
  29. // value: Math.random() * 10000
  30. // }
  31. // const mainStore = AppKernel.stores.mainStore;
  32. // mainStore['_noticesList'].push(data);
  33. // this.startNotify();
  34. // }
  35. // })
  36. }
  37. protected onDestroy(): void {
  38. for (let index = 0; index < this.activeItems.length; index += 1) {
  39. Tween.stopAllByTarget(this.activeItems[index]);
  40. }
  41. this.activeItems.length = 0;
  42. }
  43. startNotify(): void {
  44. if (this.activeItems.length > 0) {
  45. const last = this.activeItems[this.activeItems.length - 1];
  46. if (last.x >= this.content.width) return;
  47. }
  48. const mainStore = AppKernel.stores.mainStore;
  49. const data = mainStore.getNoticeData();
  50. if (!data) {
  51. // 队列已空且没有正在移动的消息时,隐藏整个公告区域。
  52. if (this.activeItems.length === 0) this.node.active = false;
  53. return;
  54. }
  55. this.node.active = true;
  56. this.onNotify(data);
  57. }
  58. onNotify(data: INoticeData): void {
  59. if (!this.itemNode || !this.content) return;
  60. const msg = `${formatMaskNickName(data.nickName)} won ${CURRENCY_TYPE.SC} ${formatSCNum(data.value)}`;
  61. const item = this.pool.get() || instantiate(this.itemNode);
  62. const noticeNode = this.getNoticeNode(item);
  63. const lblNotices = noticeNode.label;
  64. const itemTransform = noticeNode.trans;
  65. Tween.stopAllByTarget(item);
  66. item.setParent(this.content.node);
  67. item.active = true;
  68. lblNotices.string = msg;
  69. lblNotices.updateRenderData(true);
  70. const itemWidth = itemTransform.width * Math.abs(item.scale.x);
  71. if (itemWidth <= 0) {
  72. this.recycle(item);
  73. return;
  74. }
  75. const startX = this.getStartX(this.content.width);
  76. const endX = -itemWidth;
  77. item.setPosition(startX, 0, item.position.z);
  78. this.activeItems.push(item);
  79. tween(item)
  80. .to((startX - endX) / SCROLL_SPEED, {
  81. position: new Vec3(endX, 0, item.position.z),
  82. }, { easing: 'linear' })
  83. .call(() => {
  84. this.recycle(item);
  85. this.startNotify();
  86. })
  87. .start();
  88. }
  89. private getNoticeNode(item: Node) {
  90. let notices = this.noticeNodes.get(item);
  91. if (!notices) {
  92. notices = {
  93. label: item.getComponent(Label),
  94. trans: item.getComponent(UITransform),
  95. }
  96. this.noticeNodes.set(item, notices);
  97. }
  98. return notices;
  99. }
  100. private getStartX(contentWidth: number): number {
  101. let startX = contentWidth;
  102. for (let index = 0; index < this.activeItems.length; index += 1) {
  103. const item = this.activeItems[index];
  104. if (!item.isValid) continue;
  105. const transform = this.noticeNodes.get(item)?.trans;
  106. if (!transform) continue;
  107. const rightX = item.position.x + transform.width * Math.abs(item.scale.x);
  108. startX = Math.max(startX, rightX + MIN_MESSAGE_GAP);
  109. }
  110. return startX;
  111. }
  112. private recycle(item: Node): void {
  113. Tween.stopAllByTarget(item);
  114. const index = this.activeItems.indexOf(item);
  115. if (index !== -1) this.activeItems.splice(index, 1);
  116. if (!item.isValid) return;
  117. item.active = false;
  118. item.removeFromParent();
  119. this.pool.put(item);
  120. }
  121. }