| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- import { AppKernel } from '@scripts/app/AppKernel';
- import { CURRENCY_TYPE } from '@scripts/define/Define';
- import { IBigWinItem } from '@scripts/store/mainStore/data';
- import { formatMaskNickName, formatSCNum } from '@scripts/utils/Helper';
- import { _decorator, Component, Input, input, instantiate, isValid, KeyCode, Label, Node, NodePool, tween, Tween, UITransform, Vec3 } from 'cc';
- const { ccclass, property } = _decorator;
- const MIN_MESSAGE_GAP = 50;
- const SCROLL_SPEED = 120;
- const NEXT_NOTICE_DELAY = 2;
- interface INoticeNode {
- label: Label,
- trans: UITransform,
- }
- @ccclass('HomeNotices')
- export class HomeNotices extends Component {
- @property(Node)
- itemNode: Node = null;
- @property(UITransform)
- content: UITransform = null;
- private readonly pool = new NodePool('HomeNotices');
- private readonly activeItems: Node[] = [];
- private readonly noticeNodes = new WeakMap<Node, INoticeNode>();
- private timerID: number = 0;
- private waitingForNext = false;
- private readonly playNextNotice = () => {
- this.waitingForNext = false;
- this.startNotify();
- };
- protected onLoad(): void {
- if (this.itemNode) this.itemNode.active = false;
- this.node.active = false;
- // input.on(Input.EventType.KEY_DOWN, (event) => {
- // if (event.keyCode === KeyCode.KEY_W) {
- // let data: INoticeData = {
- // nickName: `User${Math.floor(Math.random() * 8999 + 1000)}`,
- // value: Math.random() * 10000
- // }
- // const mainStore = AppKernel.stores.mainStore;
- // mainStore['_noticesList'].push(data);
- // this.startNotify();
- // }
- // })
- }
- protected onDestroy(): void {
- this.unschedule(this.playNextNotice);
- for (let index = 0; index < this.activeItems.length; index += 1) {
- Tween.stopAllByTarget(this.activeItems[index]);
- }
- this.activeItems.length = 0;
- this.stopTimer();
- }
- private stopTimer() {
- if (this.timerID === 0) return;
- clearTimeout(this.timerID);
- this.timerID = 0;
- }
- startNotify(): void {
- // 外部刷新或旧消息播放结束不能跳过下一条消息的等待时间。
- if (this.waitingForNext) return;
- this.stopTimer();
- const mainStore = AppKernel.stores.mainStore;
- const data = mainStore.getNoticeData();
- if (!data) {
- // 队列已空且没有正在移动的消息时,隐藏整个公告区域。
- if (this.activeItems.length === 0) {
- this.node.active = false;
- }
- this.timerID = setTimeout(async () => {
- this.timerID = 0;
- await AppKernel.stores.mainStore.reqBigWinNotices()
- if (isValid(this.node)) this.startNotify();
- }, 5000);
- return;
- }
- this.node.active = true;
- this.onNotify(data);
- }
- onNotify(data: IBigWinItem): void {
- if (!this.itemNode || !this.content) return;
- const msg = `${formatMaskNickName(data.username)} won ${CURRENCY_TYPE.SC} ${formatSCNum(data.amount)}`;
- const item = this.pool.get() || instantiate(this.itemNode);
- const noticeNode = this.getNoticeNode(item);
- const lblNotices = noticeNode.label;
- const itemTransform = noticeNode.trans;
- Tween.stopAllByTarget(item);
- item.setParent(this.content.node);
- item.active = true;
- lblNotices.string = msg;
- lblNotices.updateRenderData(true);
- const itemWidth = itemTransform.width * Math.abs(item.scale.x);
- if (itemWidth <= 0) {
- this.recycle(item);
- return;
- }
- const startX = this.getStartX(this.content.width);
- const endX = -itemWidth;
- item.setPosition(startX, 0, item.position.z);
- this.activeItems.push(item);
- // 消息右边缘进入 content 右边界,表示整条消息已经滑入。
- // 超长消息也以尾部进入作为判定,不要求全文同时出现在可视区。
- const fullyEnteredTime = Math.max(0, startX + itemWidth - this.content.width) / SCROLL_SPEED;
- this.waitingForNext = true;
- this.unschedule(this.playNextNotice);
- this.scheduleOnce(this.playNextNotice, fullyEnteredTime + NEXT_NOTICE_DELAY);
- tween(item)
- .to((startX - endX) / SCROLL_SPEED, {
- x: endX,
- }, { easing: 'linear' })
- .call(() => {
- this.recycle(item);
- this.startNotify();
- })
- .start();
- }
- private getNoticeNode(item: Node) {
- let notices = this.noticeNodes.get(item);
- if (!notices) {
- notices = {
- label: item.getComponent(Label),
- trans: item.getComponent(UITransform),
- }
- this.noticeNodes.set(item, notices);
- }
- return notices;
- }
- private getStartX(contentWidth: number): number {
- let startX = contentWidth;
- for (let index = 0; index < this.activeItems.length; index += 1) {
- const item = this.activeItems[index];
- if (!item.isValid) continue;
- const transform = this.noticeNodes.get(item)?.trans;
- if (!transform) continue;
- const rightX = item.position.x + transform.width * Math.abs(item.scale.x);
- startX = Math.max(startX, rightX + MIN_MESSAGE_GAP);
- }
- return startX;
- }
- private recycle(item: Node): void {
- Tween.stopAllByTarget(item);
- const index = this.activeItems.indexOf(item);
- if (index !== -1) this.activeItems.splice(index, 1);
- if (!item.isValid) return;
- item.active = false;
- item.removeFromParent();
- this.pool.put(item);
- }
- async updateNotices() {
- await AppKernel.stores.mainStore.reqBigWinNotices();
- if (!isValid(this.node)) return;
- this.startNotify();
- }
- }
|