11using System ;
2+ using System . Collections ;
23using System . Collections . Generic ;
34using UnityEngine ;
45using UnityEngine . UIElements ;
89using Unity . BossRoom . Gameplay . Messages ;
910using Unity . BossRoom . Infrastructure ;
1011using VContainer ;
11- using System . Linq ;
1212
1313public class MessageFeed : MonoBehaviour
1414{
1515 [ SerializeField ]
1616 UIDocument doc ;
1717
18- List < Message > m_messages ;
18+ List < Message > m_Messages ;
1919
20- VisualElement messageContainer ;
20+ VisualElement m_MessageContainer ;
2121
2222 DisposableGroup m_Subscriptions ;
2323
@@ -106,15 +106,15 @@ void Start()
106106 templateLabel . style . display = DisplayStyle . None ;
107107 templateBox . style . display = DisplayStyle . None ;
108108
109- m_messages = new List < Message > ( ) ;
109+ m_Messages = new List < Message > ( ) ;
110110
111111 // Create a container for all messages
112- messageContainer = new VisualElement ( ) ;
113- messageContainer . style . flexDirection = FlexDirection . Column ; // Arrange messages vertically
112+ m_MessageContainer = new VisualElement ( ) ;
113+ m_MessageContainer . style . flexDirection = FlexDirection . Column ; // Arrange messages vertically
114114
115115 // make sure other visual elements don't get pushed down by the message container
116- messageContainer . style . position = Position . Absolute ;
117- doc . rootVisualElement . Add ( messageContainer ) ;
116+ m_MessageContainer . style . position = Position . Absolute ;
117+ doc . rootVisualElement . Add ( m_MessageContainer ) ;
118118 }
119119
120120 void OnDestroy ( )
@@ -125,72 +125,140 @@ void OnDestroy()
125125 }
126126 }
127127
128- static void StartFadeout ( Message message , float opacity )
128+ void Update ( )
129129 {
130- message . messageBox . style . opacity = opacity ;
131- message . messageBox . schedule . Execute ( ( ) =>
130+ foreach ( var m in m_Messages )
132131 {
133- opacity -= 0.01f ;
134- message . messageBox . style . opacity = opacity ;
135- if ( opacity <= 0 )
132+ if ( m . isShown )
136133 {
137- message . messageBox . style . display = DisplayStyle . None ;
138- message . startTime = 0 ;
134+ // Check if a message should begin fading out
135+ if ( Time . realtimeSinceStartup - m . startTime > 5 && m . messageBox . style . opacity == 1 )
136+ {
137+ StartFadeout ( m , 1f ) ;
138+ m . isShown = false ;
139+ }
139140 }
140- } ) . Every ( ( long ) 0.1f ) . Until ( ( ) => opacity <= 0 ) ;
141+ }
141142 }
142143
143144 void ShowMessage ( string message )
144145 {
145- // Limit maximum number of active messages
146- int maxMessages = 10 ;
147- if ( m_messages . Count ( m => m . isShown ) >= maxMessages )
146+ const float messageHeight = 40f ; // Approximate height of a message (adjust based on UI)
147+ const float verticalSpacing = 10f ; // Spacing between stacked messages
148+
149+ // Reuse or create a new message
150+ Message newMessage = null ;
151+
152+ foreach ( var m in m_Messages )
148153 {
149- // Find the oldest active message and start fading it out
150- var oldestMessage = m_messages . FirstOrDefault ( m => m . isShown && m . startTime > 0 ) ;
151- if ( oldestMessage != null )
154+ if ( ! m . isShown )
152155 {
153- StartFadeout ( oldestMessage , 1f ) ;
154- oldestMessage . isShown = false ;
156+ // Reuse the hidden message
157+ newMessage = m ;
158+ break ;
155159 }
156160 }
157161
158- // Reuse or create a new message
159- foreach ( var m in m_messages )
162+ if ( newMessage == null )
160163 {
161- if ( ! m . isShown )
164+ // Create a new message if no reusable messages are available
165+ var newBox = new VisualElement ( ) ;
166+ newBox . AddToClassList ( "messageBox" ) ;
167+ newBox . style . position = Position . Absolute ; // Explicitly position it
168+ // Position the new message box below the last message
169+ //newBox.style.top = m_MessageContainer.childCount * (messageHeight + verticalSpacing);
170+
171+ var newLabel = new Label ( ) ;
172+ newLabel . AddToClassList ( "message" ) ;
173+ newBox . Add ( newLabel ) ;
174+
175+ newMessage = new Message ( )
162176 {
163- m . isShown = true ;
164- m . Label . text = message ;
165- m . messageBox . style . display = DisplayStyle . Flex ;
166- m . startTime = Time . realtimeSinceStartup ;
177+ isShown = true ,
178+ startTime = Time . realtimeSinceStartup ,
179+ messageBox = newBox ,
180+ Label = newLabel
181+ } ;
167182
168- return ;
169- }
183+ m_MessageContainer . Add ( newBox ) ; // Add the message box to the parent container
184+ m_Messages . Add ( newMessage ) ; // Add to the list of messages
170185 }
171186
172- // Create a new message container
173- var newBox = new VisualElement ( ) ;
174- newBox . AddToClassList ( "messageBox" ) ;
187+ // Set the properties of the reused or new message
188+ newMessage . isShown = true ;
189+ newMessage . Label . text = message ;
190+ newMessage . startTime = Time . realtimeSinceStartup ;
191+ newMessage . messageBox . style . opacity = 1 ;
192+ newMessage . messageBox . style . display = DisplayStyle . Flex ;
193+
194+ // Start a fly-in animation
195+ StartCoroutine ( FlyInWithBounce ( newMessage . messageBox , - 300 , 50 , 0.2f , 0.2f ) ) ;
196+ }
197+
198+ IEnumerator FlyInWithBounce ( VisualElement element , float startLeft , float targetLeft , float duration , float bounceDuration )
199+ {
200+ float elapsedTime = 0 ;
201+ element . style . opacity = 0 ;
202+
203+ // Main fly-in animation (linear movement from off-screen)
204+ while ( elapsedTime < duration )
205+ {
206+ elapsedTime += Time . deltaTime ;
207+ float t = elapsedTime / duration ; // Normalized time (0 to 1)
175208
176- var newLabel = new Label ( ) ;
177- newLabel . text = message ;
178- newLabel . AddToClassList ( "message" ) ;
209+ // Linearly interpolate left position
210+ float newLeft = Mathf . Lerp ( startLeft , targetLeft , t ) ;
211+ element . style . left = newLeft ;
179212
180- newBox . Add ( newLabel ) ;
213+ // Gradually fade in
214+ element . style . opacity = t ;
181215
182- var newMessage = new Message ( )
216+ yield return null ;
217+ }
218+
219+ // Ensure the message is at the target final position
220+ element . style . left = targetLeft ;
221+ element . style . opacity = 1 ;
222+
223+ // Bounce Animation: Overshoot to the right and come back
224+ float overshootAmount = 20 ;
225+ float bounceElapsedTime = 0 ;
226+
227+ while ( bounceElapsedTime < bounceDuration )
183228 {
184- isShown = true ,
185- startTime = Time . realtimeSinceStartup ,
186- messageBox = newBox ,
187- Label = newLabel
188- } ;
189-
190- messageContainer . Add ( newBox ) ;
191- m_messages . Add ( newMessage ) ;
229+ bounceElapsedTime += Time . deltaTime ;
230+ float t = bounceElapsedTime / bounceDuration ;
231+
232+ // Use a simple sine easing for the bounce effect
233+ float bounceT = Mathf . Sin ( t * Mathf . PI ) ;
234+
235+ // Interpolate between targetLeft and overshoot position
236+ float bounceLeft = Mathf . Lerp ( targetLeft , targetLeft + overshootAmount , bounceT ) ;
237+
238+ element . style . left = bounceLeft ;
239+ yield return null ;
240+ }
241+
242+ // Finally snap back to the exact target position
243+ element . style . left = targetLeft ;
244+ }
245+
246+ static void StartFadeout ( Message message , float opacity )
247+ {
248+ message . messageBox . schedule . Execute ( ( ) =>
249+ {
250+ opacity -= 0.01f ;
251+ message . messageBox . style . opacity = opacity ;
252+
253+ if ( opacity <= 0 )
254+ {
255+ // Once faded out fully, hide the message and reset state
256+ message . messageBox . style . display = DisplayStyle . None ;
257+ message . isShown = false ;
258+ message . startTime = 0 ;
259+ }
260+ } ) . Every ( ( long ) 0.1f ) . Until ( ( ) => opacity <= 0 ) ;
192261 }
193-
194262
195263 class Message
196264 {
0 commit comments