功能批量实现 优化 服务端 新浮动小游戏框架 新界面UI

This commit is contained in:
FloatGaming
2026-04-24 13:20:16 +08:00
parent e0bc0bbf08
commit 5eec879582
257 changed files with 38481 additions and 1288 deletions
+111
View File
@@ -0,0 +1,111 @@
using UnityEngine;
using UnityEngine.UI;
[ExecuteAlways]
[DisallowMultipleComponent]
[RequireComponent(typeof(Text))]
[RequireComponent(typeof(LayoutElement))]
public sealed class BubbleTextWidthLimiter : MonoBehaviour
{
[Min(1f)]
public float maxPreferredWidth = 224f;
private Text textComponent;
private LayoutElement layoutElement;
private string lastText;
private Font lastFont;
private int lastFontSize;
private FontStyle lastFontStyle;
private float lastMaxPreferredWidth = -1f;
private void Awake()
{
CacheComponents();
Apply();
}
private void OnEnable()
{
CacheComponents();
Apply();
}
private void OnValidate()
{
CacheComponents();
Apply();
}
private void LateUpdate()
{
if (NeedsRefresh())
{
Apply();
}
}
private void CacheComponents()
{
if (textComponent == null)
{
textComponent = GetComponent<Text>();
}
if (layoutElement == null)
{
layoutElement = GetComponent<LayoutElement>();
}
}
private bool NeedsRefresh()
{
if (textComponent == null || layoutElement == null)
{
return false;
}
return lastText != textComponent.text
|| lastFont != textComponent.font
|| lastFontSize != textComponent.fontSize
|| lastFontStyle != textComponent.fontStyle
|| !Mathf.Approximately(lastMaxPreferredWidth, maxPreferredWidth);
}
private void Apply()
{
if (textComponent == null || layoutElement == null)
{
return;
}
textComponent.horizontalOverflow = HorizontalWrapMode.Wrap;
textComponent.verticalOverflow = VerticalWrapMode.Overflow;
var generationSettings = textComponent.GetGenerationSettings(new Vector2(10000f, 0f));
var rawPreferredWidth = textComponent.cachedTextGeneratorForLayout.GetPreferredWidth(textComponent.text ?? string.Empty, generationSettings)
/ textComponent.pixelsPerUnit;
layoutElement.minWidth = 0f;
layoutElement.preferredWidth = Mathf.Min(rawPreferredWidth, Mathf.Max(1f, maxPreferredWidth));
layoutElement.flexibleWidth = -1f;
layoutElement.minHeight = -1f;
layoutElement.preferredHeight = -1f;
layoutElement.flexibleHeight = -1f;
var rectTransform = transform as RectTransform;
if (rectTransform != null)
{
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
if (rectTransform.parent is RectTransform parentRect)
{
LayoutRebuilder.MarkLayoutForRebuild(parentRect);
}
}
lastText = textComponent.text;
lastFont = textComponent.font;
lastFontSize = textComponent.fontSize;
lastFontStyle = textComponent.fontStyle;
lastMaxPreferredWidth = maxPreferredWidth;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3fb66c09204f49b4bfeb513c894b52e0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff
+7
View File
@@ -42,6 +42,8 @@ public class UI_Panel_Main : Singleton_Mono<UI_Panel_Main>
[SerializeField] GameObject ui_Panel_Story;
[SerializeField] Button button_Setting;
[SerializeField] GameObject ui_Panel_Setting;
[SerializeField] Button button_worldChat;
[SerializeField] GameObject worldChatObject;
[SerializeField] float prefab_Enter_Time = 0.35f;
[SerializeField] float prefab_Enter_Scale_From = 0.92f;
[SerializeField] Ease prefab_Enter_Ease = Ease.OutCubic;
@@ -330,6 +332,11 @@ public class UI_Panel_Main : Singleton_Mono<UI_Panel_Main>
if (button_Setting != null)
button_Setting.onClick.AddListener(
() => Try_Open_Panel(ui_Panel_Setting));
if (worldChatObject != null)
worldChatObject.SetActive(false);
if (button_worldChat != null && worldChatObject != null)
button_worldChat.onClick.AddListener(
() => worldChatObject.SetActive(true));
if (button_Select_Music != null)
@@ -3098,7 +3098,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!224 &7476805877805305379
RectTransform:
m_ObjectHideFlags: 0
@@ -3115,10 +3115,10 @@ RectTransform:
- {fileID: 2515611058996813551}
m_Father: {fileID: 7912636600211646566}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 95, y: -25}
m_SizeDelta: {x: 50, y: 50}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &8613954281550256410
CanvasRenderer:
@@ -4105,7 +4105,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!224 &3878110758398832463
RectTransform:
m_ObjectHideFlags: 0
@@ -4121,10 +4121,10 @@ RectTransform:
- {fileID: 2099305528324639673}
m_Father: {fileID: 7912636600211646566}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 25, y: -25}
m_SizeDelta: {x: 50, y: 50}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2846323317655161991
CanvasRenderer:
@@ -5113,6 +5113,7 @@ MonoBehaviour:
email_prefab: {fileID: 3756075665884320709, guid: 41f4ea31b64f18d48aeef21b79930a6c, type: 3}
notice_prefab: {fileID: 8527835049849151044, guid: 06bb6d3a45697374ab4f5ff36356d138, type: 3}
userBag_prefab: {fileID: 2826375232361138358, guid: 9e0039d3a46af1c458d7f6e2fc72bab2, type: 3}
mailRedPot: {fileID: 5835331043321630532}
back_navButton: {fileID: 0}
home_navButton: {fileID: 0}
settings_navButton: {fileID: 0}
@@ -6126,6 +6127,7 @@ RectTransform:
m_Children:
- {fileID: 7514224236584078014}
- {fileID: 4607317886706537962}
- {fileID: 1145193307346210204}
m_Father: {fileID: 7912636600211646566}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
@@ -6602,6 +6604,81 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &6847515371386411778
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1145193307346210204}
- component: {fileID: 4536071255097187218}
- component: {fileID: 5835331043321630532}
m_Layer: 5
m_Name: new
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1145193307346210204
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6847515371386411778}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8079540942653106974}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 21.9, y: 21.3}
m_SizeDelta: {x: 15.8354, y: 15.8355}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4536071255097187218
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6847515371386411778}
m_CullTransparentMesh: 1
--- !u!114 &5835331043321630532
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6847515371386411778}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 0
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: bef5646fb83a6a54f9b2720dc36259f3, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &6924915827096337323
GameObject:
m_ObjectHideFlags: 0
@@ -7,6 +7,7 @@ using System.Collections.Generic;
using UnityEngine.Audio;
using Bansonic;
using Steamworks;
using GameServer.Client;
public class btmandtopController : MonoBehaviour, ICancelHandler
{
@@ -67,6 +68,9 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
public GameObject notice_prefab;
public GameObject userBag_prefab;
[Header("mail red pot")]
public Image mailRedPot;
[Header("New Back Buttons")]
[SerializeField] private Button back_navButton;
[SerializeField] private Button home_navButton;
@@ -204,6 +208,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
button_Music.onClick.AddListener(ToggleMusicPicLocal);
UpdateSteamUserInfo();
InitializeMailRedPot();
var binder = BgmUiBinder.Instance != null ? BgmUiBinder.Instance : Object.FindAnyObjectByType<BgmUiBinder>();
if (binder != null && musicPicRoot != null)
@@ -517,6 +522,11 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
}
PlayerRksService.OnRksChanged -= HandleRksChanged;
UI_Panel_Mail.OnUnreadStateChanged -= HandleMailUnreadStateChanged;
if (MailHttpService.Instance != null)
{
MailHttpService.Instance.OnMailListChanged -= HandleMailListChanged;
}
if (ReferenceEquals(activeInstance, this))
{
@@ -539,6 +549,65 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
UpdatePlayerRksText(rksAmount);
}
private void InitializeMailRedPot()
{
if (mailRedPot == null)
{
return;
}
bool useServerMail = false;
if (email_prefab != null)
{
UI_Panel_Mail mailPanel = email_prefab.GetComponent<UI_Panel_Mail>();
if (mailPanel != null)
{
useServerMail = mailPanel.UsesServerMail;
}
}
if (useServerMail && MailHttpService.Instance != null)
{
MailHttpService.Instance.SetServerModeEnabled(true);
MailHttpService.Instance.OnMailListChanged -= HandleMailListChanged;
MailHttpService.Instance.OnMailListChanged += HandleMailListChanged;
}
UI_Panel_Mail.OnUnreadStateChanged -= HandleMailUnreadStateChanged;
UI_Panel_Mail.OnUnreadStateChanged += HandleMailUnreadStateChanged;
UpdateMailRedPot();
}
private void HandleMailUnreadStateChanged()
{
UpdateMailRedPot();
}
private void HandleMailListChanged(IReadOnlyList<MailApiEntry> _)
{
UpdateMailRedPot();
}
private void UpdateMailRedPot()
{
if (mailRedPot == null)
{
return;
}
bool useServerMail = false;
if (email_prefab != null)
{
UI_Panel_Mail mailPanel = email_prefab.GetComponent<UI_Panel_Mail>();
if (mailPanel != null)
{
useServerMail = mailPanel.UsesServerMail;
}
}
mailRedPot.enabled = UI_Panel_Mail.HasUnreadMails(useServerMail);
}
private void UpdatePlayerCoinsLegacyText(int coinAmount)
{
if (playerCoins_legacy != null)
@@ -0,0 +1,214 @@
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
[ExecuteAlways]
[DisallowMultipleComponent]
[RequireComponent(typeof(RectTransform))]
public sealed class RectChildrenHeightFitter : MonoBehaviour
{
public bool includeInactiveChildren;
public float extraTopPadding;
public float extraBottomPadding;
public bool syncLayoutElement = true;
public bool preserveDirectChildrenTopLeft = true;
private RectTransform rectTransform;
private LayoutElement layoutElement;
private float lastAppliedHeight = -1f;
private readonly Dictionary<int, ChildOffsets> childOffsets = new Dictionary<int, ChildOffsets>();
private struct ChildOffsets
{
public float LeftOffset;
public float TopOffset;
}
private void Awake()
{
CacheComponents();
Refresh();
}
private void OnEnable()
{
CacheComponents();
Refresh();
}
private void OnValidate()
{
CacheComponents();
Refresh();
}
private void LateUpdate()
{
Refresh();
}
private void CacheComponents()
{
if (rectTransform == null)
{
rectTransform = GetComponent<RectTransform>();
}
if (syncLayoutElement && layoutElement == null)
{
layoutElement = GetComponent<LayoutElement>();
}
}
private void Refresh()
{
if (rectTransform == null)
{
return;
}
CacheChildOffsetsIfNeeded();
var hasBounds = false;
var minY = float.PositiveInfinity;
var maxY = float.NegativeInfinity;
var corners = new Vector3[4];
for (var i = 0; i < rectTransform.childCount; i++)
{
if (!(rectTransform.GetChild(i) is RectTransform child))
{
continue;
}
if (!includeInactiveChildren && !child.gameObject.activeSelf)
{
continue;
}
child.GetWorldCorners(corners);
for (var c = 0; c < 4; c++)
{
var localPoint = rectTransform.InverseTransformPoint(corners[c]);
minY = Mathf.Min(minY, localPoint.y);
maxY = Mathf.Max(maxY, localPoint.y);
hasBounds = true;
}
}
var targetHeight = hasBounds
? Mathf.Max(0f, (maxY - minY) + extraTopPadding + extraBottomPadding)
: 0f;
if (!Mathf.Approximately(lastAppliedHeight, targetHeight))
{
rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, targetHeight);
RestoreDirectChildPositions();
if (syncLayoutElement)
{
if (layoutElement == null)
{
layoutElement = GetComponent<LayoutElement>();
}
if (layoutElement != null)
{
layoutElement.minHeight = -1f;
layoutElement.preferredHeight = targetHeight;
layoutElement.flexibleHeight = -1f;
}
}
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
if (rectTransform.parent is RectTransform parentRect)
{
LayoutRebuilder.MarkLayoutForRebuild(parentRect);
}
lastAppliedHeight = targetHeight;
}
}
private void CacheChildOffsetsIfNeeded()
{
if (!preserveDirectChildrenTopLeft || rectTransform == null)
{
return;
}
if (childOffsets.Count == rectTransform.childCount)
{
var allPresent = true;
for (var i = 0; i < rectTransform.childCount; i++)
{
if (!childOffsets.ContainsKey(rectTransform.GetChild(i).GetInstanceID()))
{
allPresent = false;
break;
}
}
if (allPresent)
{
return;
}
}
childOffsets.Clear();
var parentRect = rectTransform.rect;
for (var i = 0; i < rectTransform.childCount; i++)
{
if (!(rectTransform.GetChild(i) is RectTransform child))
{
continue;
}
var localPivotPosition = (Vector2)child.localPosition;
childOffsets[child.GetInstanceID()] = new ChildOffsets
{
LeftOffset = localPivotPosition.x - parentRect.xMin,
TopOffset = parentRect.yMax - localPivotPosition.y
};
}
}
private void RestoreDirectChildPositions()
{
if (!preserveDirectChildrenTopLeft || rectTransform == null)
{
return;
}
var parentRect = rectTransform.rect;
for (var i = 0; i < rectTransform.childCount; i++)
{
if (!(rectTransform.GetChild(i) is RectTransform child))
{
continue;
}
if (!childOffsets.TryGetValue(child.GetInstanceID(), out var offsets))
{
continue;
}
// Only handle fixed-anchor direct children. Stretched children should keep their own layout behavior.
if (!Mathf.Approximately(child.anchorMin.x, child.anchorMax.x)
|| !Mathf.Approximately(child.anchorMin.y, child.anchorMax.y))
{
continue;
}
var desiredLocalPivot = new Vector2(
parentRect.xMin + offsets.LeftOffset,
parentRect.yMax - offsets.TopOffset);
var anchorReference = new Vector2(
Mathf.Lerp(parentRect.xMin, parentRect.xMax, child.anchorMin.x),
Mathf.Lerp(parentRect.yMin, parentRect.yMax, child.anchorMin.y));
child.anchoredPosition = desiredLocalPivot - anchorReference;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 232307e6a44c4ca0bfe2e260dba56267
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -13,7 +13,6 @@ public class UI_UnimplementedFeatureBlocker : MonoBehaviour
"Button_STORY",
"Button_IDOL",
"Button_NOTEBOOK",
"launchEzGame",
"Button_CHARACTER_SET",
"Button_Market",
"Button_Personal_information",