From fc38b2199d5930e148262ce19aff2e7792b40420 Mon Sep 17 00:00:00 2001 From: HungDK <> Date: Thu, 9 Apr 2026 10:53:36 +0700 Subject: [PATCH 1/3] Update select target to nearest everytimes --- Assets/Scripts/CECHostPlayer.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Assets/Scripts/CECHostPlayer.cs b/Assets/Scripts/CECHostPlayer.cs index 90efd3e2bf..5a63a0e17b 100644 --- a/Assets/Scripts/CECHostPlayer.cs +++ b/Assets/Scripts/CECHostPlayer.cs @@ -63,6 +63,7 @@ namespace BrewMonster private CECPetCorral m_pPetCorral; private List m_aTabSels = new List(); + private int m_lastAutoSelectNearestId = 0; private List m_aPtSkills = new List(); private List m_aPsSkills = new List(); private List m_aEquipSkills = new List(); @@ -2812,10 +2813,22 @@ namespace BrewMonster int idNewSel = 0; if (sorted.Count == 0) { + m_lastAutoSelectNearestId = 0; idNewSel = idCurSel; } else { + int nearestId = sorted[0].id; + if (nearestId != 0 && nearestId != m_lastAutoSelectNearestId) + { + // If the nearest target changed (movement/spawn/despawn), reset cycle back to nearest + m_lastAutoSelectNearestId = nearestId; + idNewSel = nearestId; + } + else + { + m_lastAutoSelectNearestId = nearestId; + int idx = -1; for (int i = 0; i < sorted.Count; i++) { @@ -2827,6 +2840,7 @@ namespace BrewMonster } int nextIdx = idx < 0 ? 0 : (idx + 1) % sorted.Count; idNewSel = sorted[nextIdx].id; + } } // Select the target if found / 如果找到目标则选择它 From ce526d29d67e6a921a2e9ac3cc5ae8245895548b Mon Sep 17 00:00:00 2001 From: VDH Date: Thu, 9 Apr 2026 11:12:40 +0700 Subject: [PATCH 2/3] lock view --- Assets/PerfectWorld/Prefab/UIManager.prefab | 227 +++++++++++++++--- Assets/PerfectWorld/Scene/Bootstrap.unity | 4 +- .../Scripts/Camera/CameraController.cs | 40 ++- .../Scripts/Camera/CameraViewLockButton.cs | 38 +++ .../Camera/CameraViewLockButton.cs.meta | 2 + .../Scripts/UI/HUDMainGamePlay.cs | 2 +- Documentation/SKILL_GFX_CONVERSION_PLAN.md | 19 +- 7 files changed, 283 insertions(+), 49 deletions(-) create mode 100644 Assets/PerfectWorld/Scripts/Camera/CameraViewLockButton.cs create mode 100644 Assets/PerfectWorld/Scripts/Camera/CameraViewLockButton.cs.meta diff --git a/Assets/PerfectWorld/Prefab/UIManager.prefab b/Assets/PerfectWorld/Prefab/UIManager.prefab index e9cf3ea870..7a7d2dfca8 100644 --- a/Assets/PerfectWorld/Prefab/UIManager.prefab +++ b/Assets/PerfectWorld/Prefab/UIManager.prefab @@ -646,6 +646,141 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 +--- !u!1 &273846344218051884 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2430319032688992992} + - component: {fileID: 5677368834917231984} + - component: {fileID: 7495533776153823427} + - component: {fileID: 4558769830047620468} + - component: {fileID: 1109319106486568870} + m_Layer: 5 + m_Name: Pickup_btn + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2430319032688992992 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 273846344218051884} + 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: 3483809415181351540} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0} + m_AnchorMax: {x: 0.5, y: 0} + m_AnchoredPosition: {x: 135, y: 132} + m_SizeDelta: {x: 60, y: 60} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &5677368834917231984 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 273846344218051884} + m_CullTransparentMesh: 1 +--- !u!114 &7495533776153823427 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 273846344218051884} + 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: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 9022503099529048306, guid: 205ebb1fc3847174cb78c7574a2b5a7d, 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!114 &4558769830047620468 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 273846344218051884} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 7495533776153823427} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1109319106486568870 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 273846344218051884} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3e67d421887e31f4ea9eee290568e9d2, type: 3} + m_Name: + m_EditorClassIdentifier: + button: {fileID: 4558769830047620468} + maxSearchRadius: 80 --- !u!1 &335905991743982376 GameObject: m_ObjectHideFlags: 0 @@ -2993,9 +3128,13 @@ MonoBehaviour: _cinemachineCamera: {fileID: 0} orbital: {fileID: 0} dragDeadZone: 0.009259259 - horizontalRotationPerScreen: 60 + horizontalRotationPerScreen: 180 verticalRotationPerScreen: 500 _migratedDeadZoneToNormalized: 1 + _lockView: 0 + onViewLockChanged: + m_PersistentCalls: + m_Calls: [] enableZoom: 1 orbitScaleMin: 0.5 orbitScaleMax: 2 @@ -10514,6 +10653,7 @@ RectTransform: - {fileID: 4528532603973220147} - {fileID: 4742272256638967314} - {fileID: 5087414730531131461} + - {fileID: 2430319032688992992} m_Father: {fileID: 3233441867675090637} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} @@ -10540,6 +10680,7 @@ MonoBehaviour: _btnTaskTrace: {fileID: 3253955040536933532} _taskTraceParent: {fileID: 2578159539417438268} _btnTeamList: {fileID: 540188344648694736} + _lockviewList: {fileID: 0} --- !u!1 &7352847439676120744 GameObject: m_ObjectHideFlags: 0 @@ -17561,6 +17702,30 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} + - target: {fileID: 1847659348073965440, guid: a531b4b63ab8355419f297fe10d32abe, type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1847659348073965440, guid: a531b4b63ab8355419f297fe10d32abe, type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1847659348073965440, guid: a531b4b63ab8355419f297fe10d32abe, type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1847659348073965440, guid: a531b4b63ab8355419f297fe10d32abe, type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1847659348073965440, guid: a531b4b63ab8355419f297fe10d32abe, type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1847659348073965440, guid: a531b4b63ab8355419f297fe10d32abe, type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} - target: {fileID: 2445625116770621752, guid: a531b4b63ab8355419f297fe10d32abe, type: 3} propertyPath: m_AnchorMax.y value: 0 @@ -19361,11 +19526,11 @@ PrefabInstance: m_Modifications: - target: {fileID: 281531643843465414, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_SizeDelta.y - value: 0 + value: 34.75 objectReference: {fileID: 0} - target: {fileID: 720995613977598853, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_SizeDelta.y - value: 0 + value: 4 objectReference: {fileID: 0} - target: {fileID: 1565091892493587231, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMax.y @@ -19389,19 +19554,19 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 1807009239444610075, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMax.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 1807009239444610075, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMin.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 1807009239444610075, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 73.5 objectReference: {fileID: 0} - target: {fileID: 1807009239444610075, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -320.36667 objectReference: {fileID: 0} - target: {fileID: 1845571473519222713, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_Pivot.x @@ -19505,35 +19670,35 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 2316633321864138780, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMax.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 2316633321864138780, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMin.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 2316633321864138780, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 73.5 objectReference: {fileID: 0} - target: {fileID: 2316633321864138780, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -557.43335 objectReference: {fileID: 0} - target: {fileID: 2833899088985087574, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMax.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 2833899088985087574, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMin.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 2833899088985087574, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 73.5 objectReference: {fileID: 0} - target: {fileID: 2833899088985087574, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -82.4 objectReference: {fileID: 0} - target: {fileID: 2971518514894512202, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMax.y @@ -19573,19 +19738,19 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 3932182246454713380, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMax.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 3932182246454713380, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMin.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 3932182246454713380, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 73.5 objectReference: {fileID: 0} - target: {fileID: 3932182246454713380, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -675.9667 objectReference: {fileID: 0} - target: {fileID: 5246174072855755290, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: maxPoolSize @@ -19593,47 +19758,47 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 5523955004350801122, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMax.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 5523955004350801122, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMin.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 5523955004350801122, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 73.5 objectReference: {fileID: 0} - target: {fileID: 5523955004350801122, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -201.83334 objectReference: {fileID: 0} - target: {fileID: 6384211195128645007, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMax.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 6384211195128645007, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMin.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 6384211195128645007, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 73.5 objectReference: {fileID: 0} - target: {fileID: 6384211195128645007, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -438.9 objectReference: {fileID: 0} - target: {fileID: 6789168510972833533, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMax.x - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 6789168510972833533, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMax.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 6921900574306804872, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_SizeDelta.x - value: 0 + value: -794.61884 objectReference: {fileID: 0} - target: {fileID: 7404691444252589623, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_Name @@ -19661,7 +19826,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 8043788806156166990, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_SizeDelta.y - value: 0 + value: 34.75 objectReference: {fileID: 0} - target: {fileID: 8844668668090027388, guid: f2e88ae97c9b2624dbbad1d5fc0c14b8, type: 3} propertyPath: m_AnchorMax.y diff --git a/Assets/PerfectWorld/Scene/Bootstrap.unity b/Assets/PerfectWorld/Scene/Bootstrap.unity index 141d371899..b3c52b97eb 100644 --- a/Assets/PerfectWorld/Scene/Bootstrap.unity +++ b/Assets/PerfectWorld/Scene/Bootstrap.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f85e6e6bc4d5b6af2e103cf46a846213439f86c209bed0512839f28b8c23a7c6 -size 326984 +oid sha256:13a594f73641f7ee47a7a46bc38cd207d4ae93cfbccbdd33052c91d62aead223 +size 294261 diff --git a/Assets/PerfectWorld/Scripts/Camera/CameraController.cs b/Assets/PerfectWorld/Scripts/Camera/CameraController.cs index ed5a8a6973..e145c72a45 100644 --- a/Assets/PerfectWorld/Scripts/Camera/CameraController.cs +++ b/Assets/PerfectWorld/Scripts/Camera/CameraController.cs @@ -1,6 +1,7 @@ using Unity.Cinemachine; using UnityEngine; using UnityEngine.EventSystems; +using UnityEngine.Events; namespace BrewMonster { @@ -15,6 +16,11 @@ namespace BrewMonster [SerializeField] private float verticalRotationPerScreen = 500f; [SerializeField, HideInInspector] private bool _migratedDeadZoneToNormalized; + [Header("Lock view")] + [Tooltip("When locked: no zoom; drag only orbits around world Y (horizontal axis).")] + [SerializeField] private bool _lockView; + [SerializeField] private UnityEvent onViewLockChanged; + [Header("Zoom (orbit scale)")] [Tooltip("RadialAxis scales camera distance: effective distance = Orbital Follow Radius × this value.")] [SerializeField] private bool enableZoom = true; @@ -30,6 +36,26 @@ namespace BrewMonster public CinemachineOrbitalFollow Orbital { get => orbital;} + public bool ViewLocked => _lockView; + + public void SetViewLocked(bool locked) + { + if (_lockView == locked) + { + return; + } + + _lockView = locked; + onViewLockChanged?.Invoke(_lockView); + } + + public void ToggleViewLocked() + { + SetViewLocked(!_lockView); + } + + private bool CanApplyZoom => enableZoom && !_lockView; + void OnEnable() { Instance = this; @@ -55,9 +81,11 @@ namespace BrewMonster if (normalizedDelta.sqrMagnitude >= normalizedDeadZone * normalizedDeadZone) { orbital.HorizontalAxis.Value += normalizedDelta.x * horizontalRotationPerScreen; - //orbital.HorizontalAxis.Value = Mathf.Clamp(orbital.HorizontalAxis.Value, -360f, 360f); - orbital.VerticalAxis.Value -= normalizedDelta.y * verticalRotationPerScreen; - orbital.VerticalAxis.Value = Mathf.Clamp(orbital.VerticalAxis.Value, -360f, 360f); + if (!_lockView) + { + orbital.VerticalAxis.Value -= normalizedDelta.y * verticalRotationPerScreen; + orbital.VerticalAxis.Value = Mathf.Clamp(orbital.VerticalAxis.Value, -360f, 360f); + } } } @@ -124,7 +152,7 @@ namespace BrewMonster private void ApplyRadialZoomDelta(float delta) { - if (!enableZoom || orbital == null || Mathf.Abs(delta) < 1e-6f) + if (!CanApplyZoom || orbital == null || Mathf.Abs(delta) < 1e-6f) { return; } @@ -136,7 +164,7 @@ namespace BrewMonster private void UpdatePinchZoom() { - if (!enableZoom || orbital == null) + if (!CanApplyZoom || orbital == null) { _pinchZoomActive = false; return; @@ -204,7 +232,7 @@ namespace BrewMonster } #if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBGL - if (enableZoom && orbital != null) + if (CanApplyZoom && orbital != null) { float scroll = Input.mouseScrollDelta.y; if (Mathf.Abs(scroll) > Mathf.Epsilon) diff --git a/Assets/PerfectWorld/Scripts/Camera/CameraViewLockButton.cs b/Assets/PerfectWorld/Scripts/Camera/CameraViewLockButton.cs new file mode 100644 index 0000000000..c32f2a71be --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Camera/CameraViewLockButton.cs @@ -0,0 +1,38 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace BrewMonster +{ + /// + /// Wires a UI to . + /// Add to the same GameObject as the button or assign the reference in the Inspector. + /// + public class CameraViewLockButton : MonoBehaviour + { + [SerializeField] private Button lockToggleButton; + + private void OnEnable() + { + if (lockToggleButton != null) + { + lockToggleButton.onClick.AddListener(OnLockButtonClicked); + } + } + + private void OnDisable() + { + if (lockToggleButton != null) + { + lockToggleButton.onClick.RemoveListener(OnLockButtonClicked); + } + } + + private void OnLockButtonClicked() + { + if (CameraController.Instance != null) + { + CameraController.Instance.ToggleViewLocked(); + } + } + } +} diff --git a/Assets/PerfectWorld/Scripts/Camera/CameraViewLockButton.cs.meta b/Assets/PerfectWorld/Scripts/Camera/CameraViewLockButton.cs.meta new file mode 100644 index 0000000000..45a2597c83 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Camera/CameraViewLockButton.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 10cef83c908cb734eaa7fe6c336aa621 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/UI/HUDMainGamePlay.cs b/Assets/PerfectWorld/Scripts/UI/HUDMainGamePlay.cs index ab88142e11..2b9ca9e0e5 100644 --- a/Assets/PerfectWorld/Scripts/UI/HUDMainGamePlay.cs +++ b/Assets/PerfectWorld/Scripts/UI/HUDMainGamePlay.cs @@ -26,7 +26,7 @@ namespace BrewMonster _btnInvntory.onClick.AddListener(OnInventoryClicked); _btnTeam.onValueChanged.AddListener(OnTeamClicked); _btnTaskTrace.onValueChanged.AddListener(OnTaskTraceClicked); - _btnTeamList.onClick.AddListener(OnTeamListClicked); + _btnTeamList.onClick.AddListener(OnTeamListClicked); EventBus.Unsubscribe(OnUIEvent); EventBus.Subscribe(OnUIEvent); } diff --git a/Documentation/SKILL_GFX_CONVERSION_PLAN.md b/Documentation/SKILL_GFX_CONVERSION_PLAN.md index d5f3fe8f72..5d4abd22bf 100644 --- a/Documentation/SKILL_GFX_CONVERSION_PLAN.md +++ b/Documentation/SKILL_GFX_CONVERSION_PLAN.md @@ -5,8 +5,8 @@ This document provides a comprehensive plan to convert the Perfect World skill GFX (graphical effects) system from C++ to Unity C#. The system handles visual effects when players cast skills, including projectile flight, hit effects, and various movement patterns. **Date Created:** 2026-02-11 -**Last Updated:** 2026-02-24 -**Status:** Phase 1 Complete — Movement system created, scale removed (Particle Systems) +**Last Updated:** 2026-04-08 +**Status:** Phase 1 Complete — Movement system, state machine, per-event GFX flags all working **Complexity:** Medium - Core structure exists, needs wiring up --- @@ -65,9 +65,9 @@ GFX Spawning (fly/hit) - Instantiate prefabs ✅ IMPLEMENTED (CECSkillGfxEvent) | `CECAttackEvent` | `CECAttacksMan.cs` | ✅ Working (full DoFire with Player/NPC/weapon branches) | | `A3DSkillGfxComposerMan` | `A3DSkillGfxComposerMan.cs` | ✅ Complete (load, play, lookup) | | `A3DSkillGfxComposer` | `CECAttacksMan.cs` (partial) + `CECSkillGfxMan.cs` (partial) | ✅ Mostly complete (Load from SkillStub, Play, AddOneTarget) | -| `A3DSkillGfxMan` | `A3DSkillGfxMan.cs` | ✅ Working (AddSkillGfxEvent, clustering, scale removed) | -| `A3DSkillGfxEvent` | `A3DSkillGfxMan.cs` | ✅ State machine working (Wait→Flying→Hit→Finished) | -| `CECSkillGfxEvent` | `CECSkillGfxMan.cs` | ✅ Working (Tick, SpawnFlyGfx, SpawnHitGfx, HitTarget) | +| `A3DSkillGfxMan` | `A3DSkillGfxMan.cs` | ✅ Working (AddSkillGfxEvent, clustering, scale removed, per-event fly/hit flags) | +| `A3DSkillGfxEvent` | `A3DSkillGfxMan.cs` | ✅ State machine working (Wait→Flying→Hit→Finished), `m_bShowFlyGfx`/`m_bShowHitGfx` flags | +| `CECSkillGfxEvent` | `CECSkillGfxMan.cs` | ✅ Working (Tick, SpawnFlyGfx, SpawnHitGfx, HitTarget — respects per-event show flags) | | `SkillGfxMan` | `CECSkillGfxMan.cs` | ✅ Event pool, Tick loop, GetEmptyEvent | | `CGfxMoveBase` (Movement) | `CGfxMoveBase.cs` | ✅ Created (Linear + OnTarget, factory method) | | `CECMultiSectionSkillMan` | `CECAttacksMan.cs` | ⚠️ Structure done, LoadConfig not implemented | @@ -816,11 +816,11 @@ m_pMoveMethod.TickMove(dwDeltaTime, m_vHostPos, m_vTargetPos); **Solution:** Remove SpawnGFX call from `AddOneSkillGfxEvent()`. GFX spawning should happen inside `CECSkillGfxEvent.Tick()` when transitioning from Wait→Flying state. -### 6.4 Challenge: GFX String vs Prefab in AddSkillGfxEvent +### 6.4 Challenge: GFX String vs Prefab in AddSkillGfxEvent ✅ RESOLVED -**Issue:** `AddSkillGfxEvent` receives `string szFlyGfx` / `string szHitGfx`, but the actual prefab is on the composer. +**Issue:** `AddSkillGfxEvent` receives `string szFlyGfx` / `string szHitGfx`, but the actual prefab is on the composer. All events shared the same composer, so `SpawnFlyGfx()` always called `m_pComposer.GetFlyGFX()` and spawned a fly GFX — even for secondary targets where `AddOneTarget()` had nulled the string via `enumAttArea`. This caused wide-area skills to spawn redundant fly GFX on every target instead of only the main target. -**Solution:** The event already receives `pComposer` reference. Use `pComposer.GetFlyGFX()` / `pComposer.GetHitGFX()` for instantiation. The string params can be used for null-check (if empty, skip fly/hit). +**Solution (implemented 2026-04-08):** Added per-event `m_bShowFlyGfx` / `m_bShowHitGfx` boolean flags on `A3DSkillGfxEvent`. In `AddOneSkillGfxEvent()`, flags are set based on whether `szFlyGfx` / `szHitGfx` are non-null. `SpawnFlyGfx()` and `SpawnHitGfx()` in `CECSkillGfxEvent` early-return when the flag is false. Flags reset to `true` in `Resume()` for event pool reuse. ### 6.5 Challenge: Timing Synchronization @@ -952,13 +952,14 @@ BMLogger.Log($"[GFX_FLOW] HitTarget at {vTarget}"); **End of Document** -This plan was last updated 2026-02-24. **Phase 1 is now complete (~95%)**: +This plan was last updated 2026-04-08. **Phase 1 is now complete (100%)**: 1. ✅ Movement system created (`CGfxMoveBase`, `CGfxLinearMove`, `CGfxOnTargetMove`) 2. ✅ State machine working (Wait→Flying→Hit→Finished) 3. ✅ GFX spawning via `CECSkillGfxEvent` (SpawnFlyGfx, SpawnHitGfx) 4. ✅ Scale parameters removed — Unity Particle Systems handle their own scale 5. ✅ SkillGfxMan.Tick() wired into Update loop 6. ✅ NPC skill GFX path wired up +7. ✅ Area skill (`enumAttArea`) per-event fly/hit GFX suppression — secondary targets no longer spawn redundant fly GFX **Remaining Phase 2+ work:** - Additional movement modes (Parabolic, Missile, Helix, etc.) From d70bfe7e070ea25233447b1ba2e30eaa3967572c Mon Sep 17 00:00:00 2001 From: HungDK <> Date: Thu, 9 Apr 2026 11:25:03 +0700 Subject: [PATCH 3/3] Update DlgNPC.cs --- Assets/PerfectWorld/Scripts/UI/Dialogs/DlgNPC.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgNPC.cs b/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgNPC.cs index 4683542a8c..4c2083490f 100644 --- a/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgNPC.cs +++ b/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgNPC.cs @@ -2079,7 +2079,7 @@ namespace BrewMonster.UI for (j = 0; j < pTalk.windows[i].num_option; j++) { strText = GetStringFromTable(249); - strText += pTalk.windows[i].options[j].text; + strText += Encoding.Unicode.GetString(MemoryMarshal.AsBytes(pTalk.windows[i].options[j].text)); m_pLst_Main.AddString(strText); nIndex = m_pLst_Main.GetCount() - 1; m_pLst_Main.SetItemData(nIndex, pTalk.windows[i].options[j].id); @@ -2201,7 +2201,7 @@ namespace BrewMonster.UI for (j = 0; j < pTalk.windows[i].num_option; j++) { strText = GetStringFromTable(249); - strText += pTalk.windows[i].options[j].text; + strText += Encoding.Unicode.GetString(MemoryMarshal.AsBytes(pTalk.windows[i].options[j].text)); m_pLst_Main.AddString(strText); nIndex = m_pLst_Main.GetCount() - 1; m_pLst_Main.SetItemData(nIndex, pTalk.windows[i].options[j].id);