11using System . Collections . Generic ;
2+ using System . Linq ;
23using Code . Logic . Zuma . Balls ;
34using Code . Services . Levels ;
45using Code . Services . LocalProgress ;
@@ -21,10 +22,10 @@ public class AttachingBallChainHandler
2122 public AttachingBallChainHandler (
2223 PathCreator pathCreator ,
2324 BallChainDTO ballChainDto ,
24- ChainTracker chainTracker ,
25- WidgetBallChainProvider widgetBallChainProvider ,
26- WinBallChainHandler winBallChainHandler ,
27- ILevelService levelService ,
25+ ChainTracker chainTracker ,
26+ WidgetBallChainProvider widgetBallChainProvider ,
27+ WinBallChainHandler winBallChainHandler ,
28+ ILevelService levelService ,
2829 ILevelLocalProgressService levelLocalProgressService )
2930 {
3031 _pathCreator = pathCreator ;
@@ -44,10 +45,9 @@ public void TryAttachBall(Ball newBall)
4445
4546 InsertBallToChainByDistance ( newBall , collision ) ;
4647 }
47-
48+
4849 private CollisionData GetClosestCollision ( Ball newBall )
4950 {
50- var path = _pathCreator . path ;
5151 float minDistance = float . MaxValue ;
5252 CollisionData closest = null ;
5353
@@ -58,12 +58,7 @@ private CollisionData GetClosestCollision(Ball newBall)
5858
5959 if ( distance <= _ballChainDto . CollisionThreshold && distance < minDistance )
6060 {
61- closest = new CollisionData
62- {
63- Ball = existingBall ,
64- Distance = distance ,
65- Index = i
66- } ;
61+ closest = new CollisionData { Ball = existingBall , Distance = distance , Index = i } ;
6762 minDistance = distance ;
6863 }
6964 }
@@ -79,106 +74,136 @@ private void InsertBallToChainByDistance(Ball newBall, CollisionData collision)
7974 float closestBallDist = path . GetClosestDistanceAlongPath ( collision . Ball . transform . position ) ;
8075
8176 if ( collision . Index == _chainTracker . Balls . Count - 1 && newBallDist < closestBallDist )
82- {
8377 AttachBallToChain ( newBall , _chainTracker . Balls . Count ) ;
84- }
8578 else if ( collision . Index == 0 && newBallDist > closestBallDist )
86- {
8779 AttachBallToChain ( newBall , 0 ) ;
88- }
8980 else
9081 {
9182 int insertIndex = ( newBallDist > closestBallDist ) ? collision . Index : collision . Index + 1 ;
9283 AttachBallToChain ( newBall , insertIndex ) ;
9384 }
9485 }
95-
86+
9687 private void AttachBallToChain ( Ball newBall , int index )
9788 {
9889 newBall . Dispose ( ) ;
99-
90+
10091 _chainTracker . InsertBall ( index , newBall ) ;
10192 _chainTracker . AddDistanceTravelled ( _ballChainDto . SpacingBalls ) ;
102-
93+
10394 ReIndexBalls ( ) ;
104-
95+
10596 WaitToCheckAndDestroyMatches ( newBall ) . Forget ( ) ;
10697 }
10798
10899 private async UniTask WaitToCheckAndDestroyMatches ( Ball insertedBall )
109100 {
110101 await UniTask . Delay ( ( int ) ( _ballChainDto . DurationMovingOffset * 1000 ) ) ;
111- CheckAndDestroyMatches ( insertedBall , _chainTracker . Balls ) ;
102+ await CheckAndDestroyMatches ( insertedBall , _chainTracker . Balls ) ;
112103 }
113-
114- private void CheckAndDestroyMatches ( Ball insertedBall , List < Ball > balls )
104+
105+ private async UniTask CheckAndDestroyMatches ( Ball pivotBall , List < Ball > balls )
115106 {
116- List < Ball > matchingBalls = new List < Ball > { insertedBall } ;
117- Color matchColor = insertedBall . Color ;
107+ var matchingBalls = FindMatchesAroundBall ( pivotBall , balls ) ;
118108
119- for ( int i = insertedBall . Index - 1 ; i >= 0 ; i -- )
109+ if ( matchingBalls . Count >= _ballChainDto . MatchingCount )
120110 {
121- if ( balls [ i ] . Color == matchColor )
122- matchingBalls . Add ( balls [ i ] ) ;
123- else
124- break ;
125- }
111+ int score = matchingBalls . Count * _levelService . GetCurrentLevelStaticData ( ) . LevelConfig . ScoreConfig . ScorePerItem ;
112+ _levelLocalProgressService . AddScore ( score ) ;
113+ _widgetBallChainProvider . SetUpWidget ( matchingBalls , pivotBall , score ) ;
114+ _winBallChainHandler . TryWin ( balls . Count - matchingBalls . Count ) ;
115+
116+ int junctionIndex = matchingBalls . Min ( b => b . Index ) - 1 ;
126117
127- for ( int i = insertedBall . Index + 1 ; i < balls . Count ; i ++ )
118+ await DestroyBalls ( matchingBalls , balls ) ;
119+ await CheckChainReaction ( junctionIndex , balls ) ;
120+ }
121+ else
128122 {
129- if ( balls [ i ] . Color == matchColor )
130- matchingBalls . Add ( balls [ i ] ) ;
131- else
132- break ;
123+ pivotBall . SetInteractive ( false ) ;
133124 }
125+ }
126+
127+ // Recursively checks for new matches after a group is destroyed.
128+ // junctionIndex points to the ball just before the destroyed group.
129+ private async UniTask CheckChainReaction ( int junctionIndex , List < Ball > balls )
130+ {
131+ if ( balls . Count == 0 || _winBallChainHandler . IsWin )
132+ return ;
133+
134+ await UniTask . Delay ( ( int ) ( _ballChainDto . DurationMovingOffset * 1000 ) ) ;
135+
136+ junctionIndex = Mathf . Clamp ( junctionIndex , 0 , balls . Count - 1 ) ;
137+ Ball anchor = balls [ junctionIndex ] ;
138+ var matchingBalls = FindMatchesAroundBall ( anchor , balls ) ;
134139
135140 if ( matchingBalls . Count >= _ballChainDto . MatchingCount )
136141 {
137- int count = matchingBalls . Count * _levelService . GetCurrentLevelStaticData ( ) . LevelConfig . ScoreConfig . ScorePerItem ;
138- _levelLocalProgressService . AddScore ( count ) ;
139-
140- _widgetBallChainProvider . SetUpWidget ( matchingBalls , insertedBall , count ) ;
142+ int score = matchingBalls . Count * _levelService . GetCurrentLevelStaticData ( ) . LevelConfig . ScoreConfig . ScorePerItem ;
143+ _levelLocalProgressService . AddScore ( score ) ;
144+ _widgetBallChainProvider . SetUpWidget ( matchingBalls , anchor , score ) ;
141145 _winBallChainHandler . TryWin ( balls . Count - matchingBalls . Count ) ;
142-
143- PlayDestroyMatchingBalls ( insertedBall , balls , matchingBalls ) ;
144-
145- ReIndexBalls ( ) ;
146+
147+ int nextJunctionIndex = matchingBalls . Min ( b => b . Index ) - 1 ;
148+
149+ await DestroyBalls ( matchingBalls , balls ) ;
150+ await CheckChainReaction ( nextJunctionIndex , balls ) ;
146151 }
147- else
152+ }
153+
154+ // Waits for ALL destroy animations to finish, then removes balls and contracts the chain at once.
155+ private async UniTask DestroyBalls ( List < Ball > matchingBalls , List < Ball > allBalls )
156+ {
157+ await UniTask . WhenAll ( matchingBalls . Select ( WaitForDestroyAnimation ) ) ;
158+
159+ foreach ( var ball in matchingBalls )
148160 {
149- insertedBall . SetInteractive ( false ) ;
161+ allBalls . Remove ( ball ) ;
162+ ball . Deactivate ( ) ;
150163 }
164+
165+ _chainTracker . SubtractDistanceTravelled ( matchingBalls . Count * _ballChainDto . SpacingBalls ) ;
166+ ReIndexBalls ( ) ;
151167 }
152168
153- private void PlayDestroyMatchingBalls ( Ball insertedBall , List < Ball > balls , List < Ball > matchingBalls )
169+ private UniTask WaitForDestroyAnimation ( Ball ball )
154170 {
155- foreach ( var ball in matchingBalls )
171+ var tcs = new UniTaskCompletionSource ( ) ;
172+ ball . PlayDestroyAnimation ( ( ) => tcs . TrySetResult ( ) ) ;
173+ return tcs . Task ;
174+ }
175+
176+ private List < Ball > FindMatchesAroundBall ( Ball pivotBall , List < Ball > balls )
177+ {
178+ var matching = new List < Ball > { pivotBall } ;
179+ Color color = pivotBall . Color ;
180+
181+ for ( int i = pivotBall . Index - 1 ; i >= 0 ; i -- )
156182 {
157- ball . PlayDestroyAnimation ( ( ) =>
158- {
159- balls . Remove ( ball ) ;
160- ball . Deactivate ( ) ;
161-
162- insertedBall . SetInteractive ( false ) ;
163-
164- _chainTracker . SubtractDistanceTravelled ( _ballChainDto . SpacingBalls ) ;
165- } ) ;
183+ if ( balls [ i ] . Color == color ) matching . Add ( balls [ i ] ) ;
184+ else break ;
166185 }
186+
187+ for ( int i = pivotBall . Index + 1 ; i < balls . Count ; i ++ )
188+ {
189+ if ( balls [ i ] . Color == color ) matching . Add ( balls [ i ] ) ;
190+ else break ;
191+ }
192+
193+ return matching ;
167194 }
168195
169196 private void ReIndexBalls ( )
170197 {
171198 for ( int i = 0 ; i < _chainTracker . Balls . Count ; i ++ )
172- {
173199 _chainTracker . Balls [ i ] . SetIndex ( i ) ;
174- }
175200 }
176-
201+
177202 private class CollisionData
178203 {
179204 public Ball Ball ;
180205 public float Distance ;
181206 public int Index ;
182207 }
183208 }
184- }
209+ }
0 commit comments