float g_TextChatExpandRate = 1.0; float g_TextChatOffsetX = 0; float g_TextChatMessageExpandRate = 1.0; float g_TextChatMessageOffsetX = 0; float g_TextChatMaskExpandRate = 1.0; float g_TextChatMaskOffsetX = 0; bool g_TextChatIsXShare = false; class TCView { const string DEFAULT_LAYER_NAME = "textchat_common"; const string WEBXR_LAYER_NAME = "mainmenu_webxr"; const string WEBXR_INPUT_FIELD_NAME = "chat_text_inputfield"; string m_textchat_HTMLElementID; string m_textchat_Text_HTMLElementID; string m_WebXRInputText; public TCView() { m_textchat_HTMLElementID = "textchat"; m_textchat_Text_HTMLElementID = "textchat-text"; m_WebXRInputText = ""; string ParamXShare = hsWebGetQueryParam("xshare"); g_TextChatIsXShare = (ParamXShare == "1"); // Xで開いているのでGUIをX用にリサイズする if(g_TextChatIsXShare) { g_TextChatExpandRate = 1.65; g_TextChatOffsetX = 100.0; g_TextChatMessageExpandRate = 1.65; g_TextChatMessageOffsetX = 100.0; g_TextChatMaskExpandRate = 1.65; g_TextChatMaskOffsetX = 105.0; Resize(false); } // ShowInputField(false); _LoadMessageListLayer(CHAT_TYPE_PUBLIC, false, TAB_TYPE_TEXT_CHAT); _LoadMessageListLayer(CHAT_TYPE_PUBLIC, true, TAB_TYPE_TEXT_CHAT); _LoadMessageListLayer(CHAT_TYPE_PRIVATE, false, TAB_TYPE_TEXT_CHAT); _LoadMessageListLayer(CHAT_TYPE_PRIVATE, true, TAB_TYPE_TEXT_CHAT); _LoadMessageListLayer(CHAT_TYPE_SYSTEM, false, TAB_TYPE_SYSTEM_MESSAGE); _LoadMessageListLayer(CHAT_TYPE_SYSTEM, true, TAB_TYPE_SYSTEM_MESSAGE); } // GUIの整列 // 毎回レイアウト替えの対応で.jsonだと1つ変えたら5個手打ちでやらないといけないの面倒すぎるのでここでオフセット型整理を行う public void OnLoaded() { InputTextLengthGUISort(); } private string GetLayerName(){ string layerName = DEFAULT_LAYER_NAME; if(hsSystemIsVRMode()) layerName = WEBXR_LAYER_NAME; return layerName; } void Resize(bool IsPortrait) { string layerName = GetLayerName(); // Expand hsCommonResizeGUI(layerName, IsPortrait, "chat_base", g_TextChatExpandRate); hsCommonResizeGUI(layerName, IsPortrait, "chat_tab_txt_chat_off", g_TextChatExpandRate); hsCommonResizeGUI(layerName, IsPortrait, "chat_tab_txt_chat_on", g_TextChatExpandRate); hsCommonResizeGUI(layerName, IsPortrait, "chat_tab_system_off", g_TextChatExpandRate); hsCommonResizeGUI(layerName, IsPortrait, "chat_tab_system_on", g_TextChatExpandRate); hsCommonResizeGUI(layerName, IsPortrait, "common_btn_close", g_TextChatExpandRate); hsCommonResizeGUI(layerName, IsPortrait, "chat_btn_send", g_TextChatExpandRate); hsCommonResizeGUI(layerName, IsPortrait, "chat_input_base", g_TextChatExpandRate); hsCommonResizeGUI(layerName, IsPortrait, "chat_scroll_base_chat", g_TextChatExpandRate); hsCommonResizeGUI(layerName, IsPortrait, "chat_scroll_slider_chat", g_TextChatExpandRate); hsCommonResizeGUI(layerName, IsPortrait, "chat_scroll_base_system", g_TextChatExpandRate); hsCommonResizeGUI(layerName, IsPortrait, "chat_scroll_slider_system", g_TextChatExpandRate); hsCommonResizeGUI(layerName, IsPortrait, "chat_text_inputfield", g_TextChatExpandRate); // Offset hsCommonSetGUIOffset(layerName, IsPortrait, "chat_base", g_TextChatOffsetX, 0.0); hsCommonSetGUIOffset(layerName, IsPortrait, "chat_tab_txt_chat_off", g_TextChatOffsetX, 0.0); hsCommonSetGUIOffset(layerName, IsPortrait, "chat_tab_txt_chat_on", g_TextChatOffsetX, 0.0); hsCommonSetGUIOffset(layerName, IsPortrait, "chat_tab_system_off", g_TextChatOffsetX, 0.0); hsCommonSetGUIOffset(layerName, IsPortrait, "chat_tab_system_on", g_TextChatOffsetX, 0.0); hsCommonSetGUIOffset(layerName, IsPortrait, "common_btn_close", g_TextChatOffsetX, 0.0); hsCommonSetGUIOffset(layerName, IsPortrait, "chat_btn_send", g_TextChatOffsetX, 0.0); hsCommonSetGUIOffset(layerName, IsPortrait, "chat_input_base", g_TextChatOffsetX, 0.0); hsCommonSetGUIOffset(layerName, IsPortrait, "chat_scroll_base_chat", g_TextChatOffsetX, 0.0); hsCommonSetGUIOffset(layerName, IsPortrait, "chat_scroll_slider_chat", g_TextChatOffsetX, 0.0); hsCommonSetGUIOffset(layerName, IsPortrait, "chat_scroll_base_system", g_TextChatOffsetX, 0.0); hsCommonSetGUIOffset(layerName, IsPortrait, "chat_scroll_slider_system", g_TextChatOffsetX, 0.0); hsCommonSetGUIOffset(layerName, IsPortrait, "chat_text_inputfield", g_TextChatOffsetX, 0.0); } void _LoadMessageListLayer(string ChatType, bool IsPortrait, string TabType) { bool IsSystemChatTab = (TabType == TAB_TYPE_SYSTEM_MESSAGE); hsCanvasSetLayerShow(ChatType, true); // Layerの生成 system.Canvas_AddLayer(ChatType, IsPortrait, true, 18); if(IsPortrait) { if(IsSystemChatTab) { system.Canvas_SetLayerMask(ChatType, IsPortrait, "gui2024/NoButton.png", -32,-148, 1195,1566, 0.5, 0.5, "CM", 0, 0.0, 0.0, 0.0, 0.0, false, true, false, 80); } else { system.Canvas_SetLayerMask(ChatType, IsPortrait, "gui2024/NoButton.png", -32,-181, 1195,1274, 0.5, 0.5, "CM", 0, 0.0, 0.0, 0.0, 0.0, false, true, false, 80); } system.Canvas_SetLayerSeekBarVertical(ChatType,IsPortrait,"gui2024/clear.png","gui2024/clear.png","gui2024/chat/chat_scroll_slider_po.png","gui2024/chat/chat_scroll_slider_po.png",70,70,70,70,70); } else { if(IsSystemChatTab) { system.Canvas_SetLayerMask(ChatType, IsPortrait, "gui2024/NoButton.png", -266 * g_TextChatMaskExpandRate + g_TextChatMaskOffsetX, -15 * g_TextChatMaskExpandRate, 320 * g_TextChatMaskExpandRate, 545 * g_TextChatMaskExpandRate, 0.5, 0.5, "RM", 0, 0.0, 0.0, 0.0, 0.0, false, true, false, 50); } else { system.Canvas_SetLayerMask(ChatType, IsPortrait, "gui2024/NoButton.png", -266 * g_TextChatMaskExpandRate + g_TextChatMaskOffsetX, -60 * g_TextChatMaskExpandRate, 320 * g_TextChatMaskExpandRate, 375 * g_TextChatMaskExpandRate, 0.5, 0.5, "RM", 0, 0.0, 0.0, 0.0, 0.0, false, true, false, 50); } system.Canvas_SetLayerSeekBarVertical(ChatType,IsPortrait,"gui2024/clear.png","gui2024/clear.png","gui2024/chat/chat_scroll_slider.png","gui2024/chat/chat_scroll_slider.png",25,25,25,25,25); } system.Canvas_SetLayerComponentNameList(ChatType, IsPortrait, "TCController"); system.Canvas_SetLayerSeekBarRate(ChatType, IsPortrait, 0.0, 1.0); hsCanvasSetLayerShow(ChatType, false); } public void ShowClickableTextChatHUD() { hsCanvasResetToggleDefault("Toggle_OpenClose_TextChat"); } public void ResizeCallback() { _ResizeInputField(); } void _ResizeInputField() { hel_setText(ETextParamType_OperateCanvas, "ResizeInputFieldGeneric" + "," + "textchat_common" + "," + "chat_text_inputfield" + "," + m_textchat_HTMLElementID + "," + m_textchat_Text_HTMLElementID); } public void OpenTextChatBase(bool Flag) { string layerName = GetLayerName(); hsCanvasSetLayerShow(layerName, Flag); } public void ShowTextChat(string ChatType, bool Show, bool UseInput) { if(Show) { // 表示状態の時だけまず全てをいったん非表示にしてリセットする CloseMessageList(); } hsCanvasSetLayerShow(ChatType, Show); ShowInputField(Show && UseInput); } public void CloseMessageList() { hsCanvasSetLayerShow(CHAT_TYPE_PUBLIC, false); hsCanvasSetLayerShow(CHAT_TYPE_PRIVATE, false); hsCanvasSetLayerShow(CHAT_TYPE_SYSTEM, false); } public void ShowInputField(bool show) { if(!show) ClearInputFieldText(); hel_set_HTMLElement_visibility(m_textchat_HTMLElementID, show); hel_set_HTMLElement_visibility(m_textchat_Text_HTMLElementID, show); _ResizeInputField(); } public string GetInputFieldText() { //VRの場合はGUIの内容を返す if(hsSystemIsVRMode()){ return m_WebXRInputText; } return hel_get_HTMLElement_value(m_textchat_Text_HTMLElementID); } public void ClearInputFieldText() { hel_set_HTMLElement_value(m_textchat_Text_HTMLElementID, ""); } public bool IsInputLengthOverLimit(){ return GetInputFieldText().Length() > TEXTCHAT_MAX_TEXT_LENGTH; } // 文字数上限のGUIを動的に整列 // 縦画面:テキストボックス合わせ // 横画面:送信ボタン合わせ private void InputTextLengthGUISort(){ bool usePortraitFlag = true; bool useLandscapeFlag = false; // ---縦画面------------------------ string textBoxGUIName = "chat_input_base"; HS2DI textBoxPos = GetGUIPos(GetLayerName(), textBoxGUIName, usePortraitFlag); HS2DI textBoxSize = GetGUISize(GetLayerName(),textBoxGUIName, usePortraitFlag); // 上限表示テキストGUIの座標計算 int limiterOffsetHeight = 10; int limiterOffsetWidth = -20; HS2DI poTextLimiterPos = MakeHS2DI(textBoxPos.x() + textBoxSize.x() + limiterOffsetWidth, textBoxPos.y() + textBoxSize.y() + limiterOffsetHeight); // 入力文字数テキストGUIの座標計算 int counterOffsetHeight = -15; int counterOffsetWidth = -100; HS2DI poTextCounterPos = MakeHS2DI(poTextLimiterPos.x() + counterOffsetWidth, poTextLimiterPos.y() + counterOffsetHeight); string inputCounterGUIName = "chat_text_input_counter"; string inputLimiterGUIName = "chat_text_input_limiter"; // 縦画面の文字数カウンターGUIの座標更新 SetGUIPos(GetLayerName(), inputLimiterGUIName, poTextLimiterPos, usePortraitFlag); SetGUIPos(GetLayerName(), inputCounterGUIName, poTextCounterPos, usePortraitFlag); // ---横画面------------------------ string sendButtonGUIName = "chat_btn_send"; HS2DI sendButtonPos = GetGUIPos(GetLayerName(), sendButtonGUIName, useLandscapeFlag); // 上限表示テキストGUIの座標計算 int laLimiterOffsetWidth = -135; int laLimiterOffsetHeight = 15; HS2DI laTextLimiterPos = MakeHS2DI(sendButtonPos.x() + laLimiterOffsetWidth, sendButtonPos.y() +laLimiterOffsetHeight); // 入力文字数テキストGUIの座標計算 int laCounterOffsetWidth = -40; int laCounterOffsetHeight = -7; HS2DI laTextCounterPos = MakeHS2DI(laTextLimiterPos.x() + laCounterOffsetWidth, laTextLimiterPos.y() + laCounterOffsetHeight); // 縦画面の文字数カウンターGUIの座標更新 SetGUIPos(GetLayerName(), inputLimiterGUIName, laTextLimiterPos, useLandscapeFlag); SetGUIPos(GetLayerName(), inputCounterGUIName, laTextCounterPos, useLandscapeFlag); // 文字上限を表示 string limitText = "/%d" % TEXTCHAT_MAX_TEXT_LENGTH; SetGUIText(GetLayerName(), inputLimiterGUIName, limitText); } public void ApplyInputTextLengthLimit(){ int inputTextLength = GetInputFieldText().Length(); string limitText = "%d" % inputTextLength; int maxLength = 999; // レイアウト崩壊を回避する為、999以上はカウントしない if(inputTextLength > maxLength){ inputTextLength = maxLength; limitText = "%d" % inputTextLength; } string inputCounterGUIName = "chat_text_input_counter"; SetGUIText(GetLayerName(), inputCounterGUIName, limitText); string limitLampGUIName = "chat_text_input_limit_lamp"; HSColor limitTextColor = GetGradientColor(inputTextLength); SetGUIColor(limitLampGUIName, HSGUIType_Image, limitTextColor); if(IsInputLengthOverLimit()){ SetGUIColor(inputCounterGUIName, HSGUIType_Text, limitTextColor); }else{ //rgba(204, 204, 204, 0.9) HSColor white = MakeHSColorbyHex(204, 204, 204, 0.9); SetGUIColor(inputCounterGUIName, HSGUIType_Text ,white); } } private void SetGUIColor(string guiName, int guiType, HSColor color){ bool usePortraitFlag = true; bool useLandscapeFlag = false; hsCanvasSetGUIMulColor(GetLayerName(), usePortraitFlag, guiName, guiType, color); hsCanvasSetGUIMulColor(GetLayerName(), useLandscapeFlag, guiName, guiType, color); } // RGB の線形補間 private HSColor GetGradientColor(int nowTextLength) { // 文字数に応じて色をグラデさせる float fillRage = float(nowTextLength) / TEXTCHAT_MAX_TEXT_LENGTH; if(fillRage > 1){ fillRage = 1; } // 0% rgba(35, 255, 215, 0.9) HSColor turquoise = MakeHSColorbyHex(35, 255, 215, 0.9); // 25% rgba( 0, 255, 30, 0.9) HSColor green = MakeHSColorbyHex(0, 255, 30, 0.9); // 50% rgba(255, 250, 0, 0.9) HSColor yellow = MakeHSColorbyHex(255, 250, 0, 0.9); // 75% rgba(255, 165, 0, 0.9) HSColor orange = MakeHSColorbyHex(255, 165, 0, 0.9); //100% rgba(255, 20, 20, 0.9) HSColor red = MakeHSColorbyHex(255, 20, 20, 0.9); HSColor nowTextLimitColor = new HSColor(); float quarter = 0.25; float harlf = quarter * 2; float threeQuarters = quarter * 3; if(fillRage <= quarter){ nowTextLimitColor = LerpColor(turquoise, green, fillRage / quarter); }else if(fillRage <= harlf){ nowTextLimitColor = LerpColor(green, yellow, (fillRage - quarter) / quarter); }else if(fillRage <= threeQuarters){ nowTextLimitColor = LerpColor(yellow, orange, (fillRage - harlf) / quarter); }else{ nowTextLimitColor = LerpColor(orange, red, (fillRage - threeQuarters) / quarter); } return nowTextLimitColor; } private HSColor LerpColor(HSColor start, HSColor end, float percent) { float r = start.r() + (end.r() - start.r()) * percent; float g = start.g() + (end.g() - start.g()) * percent; float b = start.b() + (end.b() - start.b()) * percent; float a = 0.9; return MakeHSColor(r, g, b, a); } private HSColor MakeHSColor(float r, float g, float b, float a){ HSColor hsColor = new HSColor(); hsColor.SetRGBA(r, g, b, a); return hsColor; } private HSColor MakeHSColorbyHex(float r, float g, float b, float a){ HSColor hsColor = new HSColor(); hsColor.SetRGBA(HexColor2DecColor(r), HexColor2DecColor(g), HexColor2DecColor(b), a); return hsColor; } // 256表記の色コードのを0~1に変換する private float HexColor2DecColor(float hexColorValue){ if(hexColorValue > 255){ hexColorValue = 255; } if(hexColorValue < 0){ hexColorValue = 0; } return hexColorValue / 255; } private HS2DI MakeHS2DI(int x, int y){ HS2DI hs2di = new HS2DI(); hs2di.SetXY(x, y); return hs2di; } private void SetGUIText(string layerName, string guiName, string text){ Layer laTextChatLayer = hsLayerGetLandscape(layerName); Layer poTextChatLayer = hsLayerGetPortrait(layerName); if(laTextChatLayer !==null){ laTextChatLayer.CanvasSetGUIText(guiName, text); } if(poTextChatLayer !==null){ poTextChatLayer.CanvasSetGUIText(guiName, text); } } // GUI座標の変更 private void SetGUIPos(string layerName, string guiName, HS2DI position, bool usePrtraitFlag){ Layer layer = new Layer(); if(usePrtraitFlag){ layer = hsLayerGetPortrait(layerName); }else{ layer = hsLayerGetLandscape(layerName); } layer.SetGUIPos(guiName, position.x(), position.y()); } // GUIの座標取得 private HS2DI GetGUIPos(string layerName, string guiName, bool usePrtraitFlag){ Layer layer = new Layer(); if(usePrtraitFlag){ layer = hsLayerGetPortrait(layerName); }else{ layer = hsLayerGetLandscape(layerName); } Vector3 pos = new Vector3(); layer.GetGUIPos(guiName, pos.x, pos.y); return MakeHS2DI(pos.x, pos.y); } // GUIサイズの変更 private void SetGUISize(string layerName, string guiName, HS2DI size, bool usePrtraitFlag){ Layer layer = new Layer(); if(usePrtraitFlag){ layer = hsLayerGetPortrait(layerName); }else{ layer = hsLayerGetLandscape(layerName); } layer.SetGUISize(guiName, size.x(), size.y()); } // GUIのスケール取得 private HS2DI GetGUISize(string layerName, string guiName, bool usePrtraitFlag){ Layer layer = new Layer(); if(usePrtraitFlag){ layer = hsLayerGetPortrait(layerName); }else{ layer = hsLayerGetLandscape(layerName); } Vector3 size = new Vector3(); layer.GetGUISize(guiName, size.x, size.y); return MakeHS2DI(size.x, size.y); } public void SetPlaceHolder(){ string input = hel_get_HTMLElement_value(m_textchat_Text_HTMLElementID); hsCanvasResetToggleDefault("Toggle_ph_show"); if(input != ""){ return; } //プレースホルダーの設定 hsCanvasToggleChange("Toggle_ph_show"); } public void SwitchTextChatTab(string TabType) { if(TabType == TAB_TYPE_TEXT_CHAT) { hsCanvasResetToggleDefault("Toggle_TextChat_Tab"); } else if(TabType == TAB_TYPE_SYSTEM_MESSAGE) { hsCanvasResetToggleDefault("Toggle_TextChat_Tab"); hsCanvasToggleChange("Toggle_TextChat_Tab"); } } // テキストチャットを送信可能かどうか public void SwitchSendable(bool sendableFlag) { hsCanvasResetToggleDefault("Toggle_TextChat_Sendable"); if(!sendableFlag) { hsCanvasToggleChange("Toggle_TextChat_Sendable"); } } // テキストチャットタブの有効化 public void EnabledIndividualChatTab(bool Enabled) { hsCanvasResetToggleDefault("Toggle_PrvTextChat_Enabled_Disabled"); if(Enabled) { hsCanvasToggleChange("Toggle_PrvTextChat_Enabled_Disabled"); } } public void ToggleIndividualChat(bool toggle) { hsCanvasResetToggleDefault("Toggle_PrvTextChat_Tab"); if(toggle){ hsCanvasToggleChange("Toggle_PrvTextChat_Tab"); } } public void ShowBadge(bool Flag, string ChatType) { if(ChatType == CHAT_TYPE_PUBLIC) { hsCanvasResetToggleDefault("Toggle_TextChat_Badge_Public"); if(Flag) { hsCanvasToggleChange("Toggle_TextChat_Badge_Public"); } } else if(ChatType == CHAT_TYPE_SYSTEM) { hsCanvasResetToggleDefault("Toggle_TextChat_Badge_System"); if(Flag) { hsCanvasToggleChange("Toggle_TextChat_Badge_System"); } } } // 個別チャットのバッジだけ未読法則が違うためメソッド分け public void ControlIndivisualBadge(bool Flag){ hsCanvasResetToggleDefault("Toggle_TextChat_Badge_Private"); if(Flag) { hsCanvasToggleChange("Toggle_TextChat_Badge_Private"); } } public void ControlTextChatBadge(bool Flag){ hsCanvasResetToggleDefault("Toggle_TextChat_Badge_Chat"); if(Flag){ hsCanvasToggleChange("Toggle_TextChat_Badge_Chat"); } } public void ShowPrvChatPulldown(bool show) { hsCanvasResetToggleDefault("Toggle_PrvTextChat_Pulldown_OpenClose"); if(show) { hsCanvasToggleChange("Toggle_PrvTextChat_Pulldown_OpenClose"); } } // WebXRモードに入った際にテキストチャットを表示するマスクとシークバーの調整 public void ResizeWebXRUI() { system.Canvas_SetLayerMaskAnchor(CHAT_TYPE_PUBLIC, false, 4); system.Canvas_SetLayerMaskAnchor(CHAT_TYPE_SYSTEM, false, 4); system.Canvas_SetLayerMaskPivot(CHAT_TYPE_PUBLIC, false, 0.5, 0.5); system.Canvas_SetLayerMaskPivot(CHAT_TYPE_SYSTEM, false, 0.5, 0.5); system.Canvas_SetLayerMaskPos(CHAT_TYPE_PUBLIC, false, 29, 0 ); system.Canvas_SetLayerMaskPos(CHAT_TYPE_SYSTEM, false, 29, 50 ); system.Canvas_SetLayerMaskSize(CHAT_TYPE_PUBLIC, false, 320, 380); system.Canvas_SetLayerMaskSize(CHAT_TYPE_SYSTEM, false, 320, 500); hsCanvasSetLayerShow(CHAT_TYPE_PUBLIC, false); hsCanvasSetLayerShow(CHAT_TYPE_SYSTEM, false); } // WebXRモード終了時に通常モードのテキストチャットマスクサイズに戻す public void RestoreNormalHUD() { system.Canvas_SetLayerMaskAnchor(CHAT_TYPE_PUBLIC, false, 5); system.Canvas_SetLayerMaskAnchor(CHAT_TYPE_SYSTEM, false, 5); system.Canvas_SetLayerMaskPivot(CHAT_TYPE_PUBLIC, false, 0.5, 0.5); system.Canvas_SetLayerMaskPivot(CHAT_TYPE_SYSTEM, false, 0.5, 0.5); system.Canvas_SetLayerMaskPos(CHAT_TYPE_PUBLIC, false, -266 * g_TextChatMaskExpandRate + g_TextChatMaskOffsetX, -60 * g_TextChatMaskExpandRate ); system.Canvas_SetLayerMaskPos(CHAT_TYPE_SYSTEM, false, -266 * g_TextChatMaskExpandRate + g_TextChatMaskOffsetX, -15 * g_TextChatMaskExpandRate ); system.Canvas_SetLayerMaskSize(CHAT_TYPE_PUBLIC, false, 320 * g_TextChatMaskExpandRate, 375 * g_TextChatMaskExpandRate); system.Canvas_SetLayerMaskSize(CHAT_TYPE_SYSTEM, false, 320 * g_TextChatMaskExpandRate, 545 * g_TextChatMaskExpandRate); ShowInputField(false); } public void SetWebXRInputText(string text) { m_WebXRInputText = text; } public void SetWebXRPlaceholderText(string layerName, string guiName, string text) { hsCanvasSetGUIText(layerName, guiName, text); } }