SamsaraGame/assets/Script/common/CustomRichText.js

497 lines
16 KiB
JavaScript
Raw Normal View History

2025-04-24 17:03:28 +08:00
import GameModel from "../ts/core/GameModel";
cc.Class({
extends: cc.Component,
properties: {
_type: 0,//0 聊天框 1遊戲右下角ui
type: {
get() {
return this._type;
},
set(t) {
this._type = t;
}
},
_string: '',
string: {
get() {
return this._string;
},
set(t) {
this._string = t;
this.showTextInfo();
}
},
_maxWidth: 0,
maxWidth: {
get() {
return this._maxWidth;
},
set(t) {
this._maxWidth = t;
if (t <= 0) {
this._maxWidth = 100;
}
this.node.width = t;
}
},
_fontSize: 20,
fontSize: {
get() {
return this._fontSize;
},
set(t) {
this._fontSize = t;
}
},
_lineHeight: 22,
lineHeight: {
get() {
return this._lineHeight;
},
set(t) {
this._lineHeight = t;
this.node.height = t;
}
},
_strColor: cc.Color.BLACK,
strColor: {
get() {
return this._strColor;
},
set(c) {
this._strColor = c;
this.node.color = c;
}
},
startX: 0,
startY: 0,
emojiAtlas: cc.SpriteAtlas,
joinTeamBg: cc.SpriteFrame,
item_detail: cc.Prefab,
fontRes: cc.Font
},
onLoad() {
this.node.setAnchorPoint(cc.v2(0, 1));
this.isLoad = true;
},
/**
* showLabInfo creator編輯是顯示用程序裡用不到
*/
showLabInfo() {
this.node.destroyAllChildren();
let lnode = new cc.Node();
lnode.parent = this.node;
lnode.width = this.maxWidth;
lnode.color = cc.Color.BLACK;
let lab = lnode.addComponent(cc.Label);
lab.fontSize = this.fontSize;
lab.lineHeight = this.lineHeight;
lab.string = this.string;
lab.horizontalAlign = cc.Label.HorizontalAlign.LEFT;
lab.verticalAlign = cc.Label.VerticalAlign.TOP;
lab.overflow = cc.Label.Overflow.RESIZE_HEIGHT;
lnode.setPosition(cc.v2(this.startX, this.startY));
lnode.setAnchorPoint(cc.v2(0, 1));
},
showTextInfo() {
if (this.isLoad == null) {
this.showLabInfo();
return;
}
this.node.destroyAllChildren();
this.startX = 0;
this.startY = 0;
if (this.type == 1) {
this.addScaleNode();
this.addNameNode();
}
let textInfo = [];
let msgstr = this.string;
// let patt = /\[(?:[0-9]{1,3}|1000)\]/;
// let pos = msgstr.search(patt);
// while (pos != -1) {
// if (pos > 0) {
// textInfo.push({ type: 'txt', data: msgstr.substring(0, pos) });
// }
// let numend = msgstr.indexOf(']', pos);
// let numstr = msgstr.substring(pos + 1, numend);
// textInfo.push({ type: 'img', data: numstr });
// msgstr = msgstr.substr(numend + 1);
// pos = msgstr.search(patt);
// }
// if (msgstr.length > 0) {
// textInfo.push({ type: 'txt', data: msgstr });
// }
let patt = /\[[\s\S]*?\]/;
// let patt = /\[(?:[0-9]{1,3}|1000)\]/;
let pos = msgstr.search(patt);
while (pos != -1) {
if (pos > 0) {
textInfo.push({ type: 'txt', data: msgstr.substring(0, pos) });
}
let numend = msgstr.indexOf(']', pos);
let numstr = msgstr.substring(pos + 1, numend);
let ppatt1 = /\[(?:[0-9]{1,3}|1000)\]/;
let pnumstr = '[' + numstr + ']';
let ppos1 = pnumstr.search(ppatt1);
if (ppos1 >= 0) {
textInfo.push({ type: 'img', data: numstr });
} else {
textInfo.push({ type: 'link', data: numstr });
}
// textInfo.push({ type: 'img', data: numstr });
msgstr = msgstr.substr(numend + 1);
pos = msgstr.search(patt);
}
if (msgstr.length > 0) {
if (!this.checkColor(textInfo, msgstr))
textInfo.push({ type: 'txt', data: msgstr });
}
for (const info of textInfo) {
if (info.type == 'txt') {
let str = info.data;
let cutPos = this.cutStringByWidth(str, this.maxWidth - this.startX);
while (cutPos != str.length) {
if (cutPos == 0) {
this.startX = 0;
this.startY -= this.lineHeight;
} else {
this.addLabelNode(str.substr(0, cutPos), info.color);
str = str.substr(cutPos);
}
cutPos = this.cutStringByWidth(str, this.maxWidth - this.startX);
}
if (str.length > 0) {
this.addLabelNode(str, info.color);
}
}
if (info.type == 'img') {
this.addImgNode(info.data);
}
if (info.type == 'link') {
this.addLinkNode(info.data);
}
}
if (this.startY < 0) {
this.node.width = this.maxWidth;
}
else {
this.node.width = this.startX;
}
this.node.height = -(this.startY - this.lineHeight) + 5;
},
checkColor(list, str) {
var hasColor = /\<color=#(?:[0-9]|[a-f]){6}[ ]\>.*?\<\/c(olor)?[ ]\>/g;
var arr = str.match(hasColor)
if (arr == null) return false
for (let i in arr) {
var color = arr[i].match(/#(?:[0-9]|[a-f]){6}/)[0]
var t = arr[i].replace(/\<color=#(?:[0-9]|[a-f]){6}[ ]\>/, "");
t = t.replace(/\<\/c(olor)?[ ]\>/, "");
list.push({ type: "txt", data: t, color: color })
}
return true
},
addNameNode() {
if (this.rolename == null || this.rolename == '') {
return;
}
if (this.startX > this.maxWidth - this.fontSize) {
this.startX = 0;
this.startY -= this.lineHeight;
}
let lnode = new cc.Node();
lnode.color = new cc.Color(24, 218, 224);
let title = `[${this.rolename}]`;
if (this.vipLevel > 0) {
title = `V${this.vipLevel}${title}`;
}
let textRT = lnode.addComponent(cc.Label);
// if (this.fontRes)
// textRT.font = this.fontRes;
// else
// textRT.font = GameModel.fontRes;
textRT.cacheMode = cc.Label.CacheMode.BITMAP
textRT.fontSize = this.fontSize;
textRT.lineHeight = this.lineHeight;
textRT.string = title;
lnode.setPosition(cc.v2(this.startX, this.startY));
lnode.setAnchorPoint(cc.v2(0, 1));
lnode.parent = this.node;
this.startX += lnode.width;
},
addLabelNode(str, color) {
let labelColor = this.node.color;
if (color) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color)
if (result)
labelColor = cc.color(parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16));
} else {
if (this.type == 1) {
if (this.scale == 0) {
labelColor = cc.color(22, 196, 88);
} else if (this.scale == 1) {
labelColor = cc.color(0, 194, 141);
} else if (this.scale == 2) {
labelColor = cc.color(54, 171, 253);
} else if (this.scale == 3) {
labelColor = cc.color(255, 90, 90);
}
}
}
if (this.startX > this.maxWidth - this.fontSize) {
this.startX = 0;
this.startY -= this.lineHeight;
}
let lnode = new cc.Node();
lnode.color = labelColor;
let lab = lnode.addComponent(cc.Label);
// if (this.fontRes)
// lab.font = this.fontRes;
// else
// lab.font = GameModel.fontRes;
lab.cacheMode = cc.Label.CacheMode.BITMAP
lab.fontSize = this.fontSize;
lab.lineHeight = this.lineHeight;
lab.string = str;
lnode.setAnchorPoint(cc.v2(0, 1));
lnode.setPosition(cc.v2(this.startX, this.startY));
lnode.parent = this.node;
this.startX += lnode.width;
},
addScaleNode() {
if (this.scale == null) {
return;
}
let scaleFrame = null;
if (this.scale == 0) {
scaleFrame = this.emojiAtlas.getSpriteFrame('font_back_all');
}
else if (this.scale == 1) {
scaleFrame = this.emojiAtlas.getSpriteFrame('font_back_team');
}
else if (this.scale == 2) {
scaleFrame = this.emojiAtlas.getSpriteFrame('font_back_bang');
}
else if (this.scale == 3) {
scaleFrame = this.emojiAtlas.getSpriteFrame('font_back_system');
}
// else if (this.scale == 7) {
// scaleFrame = this.emojiAtlas.getSpriteFrame('font_back_system');
// }
if (scaleFrame == null) {
return;
}
if (this.startX > this.maxWidth - this.fontSize) {
this.startX = 0;
this.startY -= this.lineHeight;
}
let snode = new cc.Node();
let sp = snode.addComponent(cc.Sprite);
sp.spriteFrame = scaleFrame;
snode.setAnchorPoint(cc.v2(0, 0.5));
snode.setPosition(cc.v2(this.startX, this.startY - this.lineHeight / 2));
snode.setScale(this.lineHeight / snode.height);
snode.parent = this.node;
this.startX += snode.width * snode.scaleX;
},
addImgNode(img) {
let emojiFrame = this.emojiAtlas.getSpriteFrame(('000' + img).substr(-3) + '0000');
if (emojiFrame == null) {
return;
}
let emojiFrames = [];
for (let i = 0; ; i++) {
let frame = this.emojiAtlas.getSpriteFrame(('000' + img).substr(-3) + ('0000' + i).substr(-4));
if (frame) emojiFrames.push(frame);
else break;
}
let snode = new cc.Node();
let sp = snode.addComponent(cc.Sprite);
sp.spriteFrame = emojiFrame;
snode.setAnchorPoint(cc.v2(0, 0.5));
snode.setScale(this.lineHeight / snode.height);
snode.parent = this.node;
if (this.startX + snode.width * snode.scaleX > this.maxWidth - this.fontSize) {
this.startX = 0;
this.startY -= this.lineHeight;
}
snode.setPosition(cc.v2(this.startX, this.startY - this.lineHeight / 2));
this.startX += snode.width * snode.scaleX;
if (emojiFrames.length > 0) {
let emojiClip = cc.AnimationClip.createWithSpriteFrames(emojiFrames, 10);
emojiClip.name = 'run';
emojiClip.wrapMode = cc.WrapMode.Loop;
let nodeAni = snode.addComponent(cc.Animation);
nodeAni.addClip(emojiClip);
nodeAni.play('run');
}
},
addLinkNode(link) {
let strs = link.split("@");
if (strs.length < 2) {
this.addLabelNode(link);
return;
}
if (strs[2] == 10) {
// 加入隊伍按鈕
this.addJoinTeamNode(link)
return
}
let labelColor = this.node.color;
labelColor = cc.color(0, 194, 141);
if (this.startX > this.maxWidth - this.fontSize) {
this.startX = 0;
this.startY -= this.lineHeight;
}
let lnode = new cc.Node();
lnode.color = labelColor;
let lab = lnode.addComponent(cc.Label);
// if (this.fontRes)
// lab.font = this.fontRes;
// else
// lab.font = GameModel.fontRes;
lab.cacheMode = cc.Label.CacheMode.BITMAP
lab.fontSize = this.fontSize;
lab.lineHeight = this.lineHeight;
lab.string = '[' + strs[0] + ']';
lnode.setAnchorPoint(cc.v2(0, 1));
lnode.setPosition(cc.v2(this.startX, this.startY));
lnode.parent = this.node;
let btn = lnode.addComponent(cc.Button);
btn.transition = cc.Button.Transition.NONE;
var clickEventHandler = new cc.Component.EventHandler();
clickEventHandler.target = this.node;
clickEventHandler.component = "CustomRichText";
clickEventHandler.handler = "onLinkPropClicked";
clickEventHandler.customEventData = link;
btn.clickEvents.push(clickEventHandler);
this.startX += lnode.width;
},
/**
* 加入隊伍
* @param {*} link
*/
addJoinTeamNode(link) {
if (this.startX > this.maxWidth - this.fontSize) {
this.startX = 0;
this.startY -= this.lineHeight;
}
let snode = new cc.Node();
let sp = snode.addComponent(cc.Sprite);
sp.spriteFrame = this.joinTeamBg;
snode.setAnchorPoint(cc.v2(0, 0.5));
snode.setPosition(cc.v2(this.startX, this.startY - this.lineHeight / 2));
snode.setScale(this.lineHeight / 40);
snode.parent = this.node;
let lnode = new cc.Node();
lnode.color = new cc.Color(100, 60, 60);
let title = "加入";
let textRT = lnode.addComponent(cc.Label);
// if (this.fontRes)
// textRT.font = this.fontRes;
// else
// textRT.font = GameModel.fontRes;
textRT.fontSize = this.fontSize + 6;
textRT.lineHeight = this.lineHeight;
textRT.string = title;
lnode.setPosition(cc.v2(43, 0));
lnode.setAnchorPoint(cc.v2(0.5, 0.5));
lnode.parent = snode;
this.startX += 86 * snode.scaleX;
let btn = snode.addComponent(cc.Button);
btn.transition = cc.Button.Transition.NONE;
var clickEventHandler = new cc.Component.EventHandler();
clickEventHandler.target = this.node;
clickEventHandler.component = "CustomRichText";
if (this.type != 1)
clickEventHandler.handler = "onLinkJoinTeam";
else
clickEventHandler.handler = "onLinkPropClicked";
clickEventHandler.customEventData = link;
btn.clickEvents.push(clickEventHandler);
},
onLinkJoinTeam(event, link) {
console.log(event, link)
let strs = link.split("@");
GameModel.send('c2s_requst_team', {
roleid: GameModel.player.roleid,
teamid: strs[1]
});
},
onLinkJoinTeam1(event, link) {
let strs = link.split("@");
GameModel.send('c2s_requst_team', {
roleid: GameModel.player.roleid,
teamid: strs[1]
});
},
onLinkPropClicked(event, link) {
let datas = link.split("@");
if (datas[2] == 10) datas[2] = 9
GameModel.send("c2c_goods_info", { type: datas[2], id: datas[1] });
},
cutStringByWidth(str, w) {
// TODO : 修改此方法 1 使用池管理 2 取消本方法 使用 RichText
if (w < 0) {
w = 0;
}
let lnode = new cc.Node();
let lab = lnode.addComponent(cc.Label);
lab.fontSize = this.fontSize;
lab.lineHeight = this.lineHeight;
lab.string = str;
lnode.parent = this.node;
let tempLen = str.length;
if (lab.node.width > w) {
tempLen = Math.ceil((w / lab.node.width) * str.length) + 2;
if (tempLen > str.length) {
tempLen = str.length;
}
str = str.substr(0, tempLen);
lab.string = str;
lab._forceUpdateRenderData(true);
while (lab.node.width > w) {
str = str.substr(0, tempLen - 1);
tempLen -= 1;
lab.string = str;
lab._forceUpdateRenderData(true);
}
}
lnode.parent = null;
lnode.destroy();
return tempLen;
}
});