11
2- // The purpose of the AnimationTracker is to store the state of all ongoing animations in a module separate from the rest of the UI. It doesn't do
3- // anything with the animations, it simply keeps record of them while they're playing then calls a callback function when they're done. So it's
4- // basically just a stopwatch. Its update function must be called regularly so it can follow the passage of time, right now this is done in the Game
5- // class's _Process method. There is one instance of AnimationTracker and it is located in Game. TODO: Consider moving it to MapView.
6-
7- // The callbacks are hopefully temporary. I don't like using them since they obscure control flow as they get called at some later time potentially by
8- // a different thread. The threading issue doesn't matter at the moment since everything important runs on one thread but this could change if we want
9- // to have separate UI and engine threads (as I believe we should).
10-
112using System ;
123using System . Collections . Generic ;
4+ using System . Threading ;
135using System . Linq ;
146using C7GameData ;
15- using C7Engine ; // for IAnimationControl, OnAnimationCompleted
7+ using C7Engine ;
168
17- public class AnimationTracker : IAnimationControl {
18- public static readonly OnAnimationCompleted doNothing = ( unitGUID , action ) => { return true ; } ;
9+ public class AnimationTracker {
10+ private Civ3AnimData civ3AnimData ;
1911
20- private Civ3UnitAnim civ3UnitAnim ;
21-
22- public AnimationTracker ( Civ3UnitAnim civ3UnitAnim )
12+ public AnimationTracker ( Civ3AnimData civ3AnimData )
2313 {
24- this . civ3UnitAnim = civ3UnitAnim ;
14+ this . civ3AnimData = civ3AnimData ;
2515 }
2616
2717 public struct ActiveAnimation {
2818 public long startTimeMS , endTimeMS ;
29- public MapUnit . AnimatedAction action ;
30- public OnAnimationCompleted callback ;
19+ public AutoResetEvent completionEvent ;
20+ public Civ3Anim anim ;
3121 }
3222
33- private Dictionary < string , ActiveAnimation > activeAnims = new Dictionary < string , ActiveAnimation > ( ) ;
34- private Dictionary < string , ActiveAnimation > completedAnims = new Dictionary < string , ActiveAnimation > ( ) ;
23+ private Dictionary < string , ActiveAnimation > activeAnims = new Dictionary < string , ActiveAnimation > ( ) ;
3524
3625 public long getCurrentTimeMS ( )
3726 {
3827 return DateTime . Now . Ticks / TimeSpan . TicksPerMillisecond ;
3928 }
4029
41- public void startAnimation ( MapUnit unit , MapUnit . AnimatedAction action , OnAnimationCompleted callback )
30+ private string getTileID ( Tile tile )
31+ {
32+ // Generate a string to ID this tile that won't conflict with the unit GUIDs. TODO: Eventually we'll implement a common way of ID'ing
33+ // all game objects. Use that here instead.
34+ return String . Format ( "Tile.{0}.{1}" , tile . xCoordinate , tile . yCoordinate ) ;
35+ }
36+
37+ private void startAnimation ( string id , Civ3Anim anim , AutoResetEvent completionEvent )
4238 {
4339 long currentTimeMS = getCurrentTimeMS ( ) ;
44- long animDurationMS = ( long ) ( 1000.0 * civ3UnitAnim . getDuration ( unit . unitType . name , action ) ) ;
40+ long animDurationMS = ( long ) ( 1000.0 * anim . getDuration ( ) ) ;
4541
4642 ActiveAnimation aa ;
47- if ( activeAnims . TryGetValue ( unit . guid , out aa ) ) {
43+ if ( activeAnims . TryGetValue ( id , out aa ) ) {
4844 // If there's already an animation playing for this unit, end it first before replacing it
49- aa . callback ( unit . guid , aa . action ) ;
45+ // TODO: Consider instead queueing up the new animation until after the first one is completed
46+ if ( aa . completionEvent != null )
47+ aa . completionEvent . Set ( ) ;
5048 }
51- aa = new ActiveAnimation { startTimeMS = currentTimeMS , endTimeMS = currentTimeMS + animDurationMS , action = action , callback = callback ?? doNothing } ;
49+ aa = new ActiveAnimation { startTimeMS = currentTimeMS , endTimeMS = currentTimeMS + animDurationMS , completionEvent = completionEvent , anim = anim } ;
5250
53- civ3UnitAnim . playSound ( unit . unitType . name , action ) ;
51+ anim . playSound ( ) ;
5452
55- activeAnims [ unit . guid ] = aa ;
56- completedAnims . Remove ( unit . guid ) ;
53+ activeAnims [ id ] = aa ;
5754 }
5855
59- public void endAnimation ( MapUnit unit , bool triggerCallback = true )
56+ public void startAnimation ( MapUnit unit , MapUnit . AnimatedAction action , AutoResetEvent completionEvent )
57+ {
58+ startAnimation ( unit . guid , civ3AnimData . forUnit ( unit . unitType . name , action ) , completionEvent ) ;
59+ }
60+
61+ public void startAnimation ( Tile tile , AnimatedEffect effect , AutoResetEvent completionEvent )
62+ {
63+ startAnimation ( getTileID ( tile ) , civ3AnimData . forEffect ( effect ) , completionEvent ) ;
64+ }
65+
66+ public void endAnimation ( MapUnit unit )
6067 {
6168 ActiveAnimation aa ;
62- if ( triggerCallback && activeAnims . TryGetValue ( unit . guid , out aa ) ) {
63- var forget = aa . callback ( unit . guid , aa . action ) ;
64- if ( ! forget )
65- completedAnims [ unit . guid ] = aa ;
69+ if ( activeAnims . TryGetValue ( unit . guid , out aa ) ) {
70+ if ( aa . completionEvent != null )
71+ aa . completionEvent . Set ( ) ;
6672 activeAnims . Remove ( unit . guid ) ;
67- } else {
68- activeAnims . Remove ( unit . guid ) ;
69- completedAnims . Remove ( unit . guid ) ;
7073 }
7174 }
7275
7376 public bool hasCurrentAction ( MapUnit unit )
7477 {
75- return activeAnims . ContainsKey ( unit . guid ) || completedAnims . ContainsKey ( unit . guid ) ;
78+ return activeAnims . ContainsKey ( unit . guid ) ;
7679 }
7780
78- public ( MapUnit . AnimatedAction , double ) getCurrentActionAndRepetitionCount ( MapUnit unit )
81+ public ( MapUnit . AnimatedAction , double ) getCurrentActionAndRepetitionCount ( string id )
7982 {
80- ActiveAnimation aa ;
81- if ( ! activeAnims . TryGetValue ( unit . guid , out aa ) )
82- aa = completedAnims [ unit . guid ] ;
83-
83+ ActiveAnimation aa = activeAnims [ id ] ;
8484 var durationMS = ( double ) ( aa . endTimeMS - aa . startTimeMS ) ;
8585 if ( durationMS <= 0.0 )
8686 durationMS = 1.0 ;
8787 var repCount = ( double ) ( getCurrentTimeMS ( ) - aa . startTimeMS ) / durationMS ;
88- return ( aa . action , repCount ) ;
88+ return ( aa . anim . action , repCount ) ;
89+ }
90+
91+ public ( MapUnit . AnimatedAction , double ) getCurrentActionAndRepetitionCount ( MapUnit unit )
92+ {
93+ return getCurrentActionAndRepetitionCount ( unit . guid ) ;
94+ }
95+
96+ public ( MapUnit . AnimatedAction , double ) getCurrentActionAndRepetitionCount ( Tile tile )
97+ {
98+ return getCurrentActionAndRepetitionCount ( getTileID ( tile ) ) ;
8999 }
90100
91101 public void update ( )
92102 {
93103 long currentTimeMS = getCurrentTimeMS ( ) ;
94104 var keysToRemove = new List < string > ( ) ;
95105 foreach ( var guidAAPair in activeAnims . Where ( guidAAPair => guidAAPair . Value . endTimeMS <= currentTimeMS ) ) {
96- var ( unitGUID , aa ) = ( guidAAPair . Key , guidAAPair . Value ) ;
97- var forget = aa . callback ( unitGUID , aa . action ) ;
98- if ( ! forget )
99- completedAnims [ unitGUID ] = aa ;
100- keysToRemove . Add ( unitGUID ) ;
106+ var ( id , aa ) = ( guidAAPair . Key , guidAAPair . Value ) ;
107+ if ( aa . completionEvent != null )
108+ aa . completionEvent . Set ( ) ;
109+ keysToRemove . Add ( id ) ;
101110 }
102111 foreach ( var key in keysToRemove )
103112 activeAnims . Remove ( key ) ;
104113 }
105114
106- public MapUnit . ActiveAnimation getActiveAnimation ( MapUnit unit )
115+ public MapUnit . Appearance getUnitAppearance ( MapUnit unit )
107116 {
108117 if ( hasCurrentAction ( unit ) ) {
109118 var ( action , repCount ) = getCurrentActionAndRepetitionCount ( unit ) ;
@@ -128,20 +137,29 @@ public MapUnit.ActiveAnimation getActiveAnimation(MapUnit unit)
128137 offsetY = - 1 * dY * ( 1f - progress ) ;
129138 }
130139
131- return new MapUnit . ActiveAnimation {
140+ return new MapUnit . Appearance {
132141 action = action ,
133- direction = unit . facingDirection ,
134- progress = progress ,
135- offsetX = offsetX ,
136- offsetY = offsetY
137- } ;
142+ direction = unit . facingDirection ,
143+ progress = progress ,
144+ offsetX = offsetX ,
145+ offsetY = offsetY
146+ } ;
138147 } else
139- return new MapUnit . ActiveAnimation {
148+ return new MapUnit . Appearance {
140149 action = unit . isFortified ? MapUnit . AnimatedAction . FORTIFY : MapUnit . AnimatedAction . DEFAULT ,
141- direction = unit . facingDirection ,
142- progress = 1f ,
143- offsetX = 0f ,
144- offsetY = 0f
145- } ;
150+ direction = unit . facingDirection ,
151+ progress = 1f ,
152+ offsetX = 0f ,
153+ offsetY = 0f
154+ } ;
155+ }
156+
157+ public Civ3Anim getTileEffect ( Tile tile )
158+ {
159+ ActiveAnimation aa ;
160+ if ( activeAnims . TryGetValue ( getTileID ( tile ) , out aa ) )
161+ return aa . anim ;
162+ else
163+ return null ;
146164 }
147165}
0 commit comments