33using System ;
44using Serilog ;
55using System . Linq ;
6+ using System . Collections . Generic ;
7+ using C7Engine ;
68
79namespace C7 . Map {
810
@@ -34,17 +36,96 @@ public void toggleGrid() {
3436 private GameData data ;
3537 private GameMap gameMap ;
3638
37- public override void _Draw ( ) {
38- GD . Print ( "draw..." ) ;
39- game . animTracker . update ( ) ;
40- foreach ( ( string id , AnimationTracker . ActiveAnimation anim ) in game . animTracker . activeAnims ) {
41- GD . Print ( $ "{ id } : { anim . ToString ( ) } ") ;
39+ private Dictionary < MapUnit , UnitSprite > unitSprites = new Dictionary < MapUnit , UnitSprite > ( ) ;
40+ private CursorSprite cursor ;
41+
42+ private UnitSprite spriteFor ( MapUnit unit ) {
43+ UnitSprite sprite = unitSprites . GetValueOrDefault ( unit , null ) ;
44+ if ( sprite is null ) {
45+ sprite = new UnitSprite ( game . civ3AnimData ) ;
46+ unitSprites . Add ( unit , sprite ) ;
47+ AddChild ( sprite ) ;
4248 }
43- base . _Draw ( ) ;
49+ return sprite ;
50+ }
51+
52+ private Vector2 getSpriteLocalPosition ( Tile tile , MapUnit . Appearance appearance ) {
53+ Vector2 position = tilemap . MapToLocal ( stackedCoords ( tile ) ) ;
54+ Vector2 offset = tileSize * new Vector2 ( appearance . offsetX , appearance . offsetY ) / 2 ;
55+ return position + offset ;
4456 }
4557
46- public override void _Process ( double delta ) {
47- base . _Process ( delta ) ;
58+ private void animateUnit ( Tile tile , MapUnit unit ) {
59+ // TODO: simplify AnimationManager and drawing animations it is unnecessarily complex
60+ // - also investigate if the custom offset tracking and SetFrame can be replaced by
61+ // engine functionality
62+ MapUnit . Appearance appearance = game . animTracker . getUnitAppearance ( unit ) ;
63+ string name = AnimationManager . AnimationKey ( unit . unitType , appearance . action , appearance . direction ) ;
64+ C7Animation animation = game . civ3AnimData . forUnit ( unit . unitType , appearance . action ) ;
65+ animation . loadSpriteAnimation ( ) ;
66+ UnitSprite sprite = spriteFor ( unit ) ;
67+ int frame = sprite . GetNextFrameByProgress ( name , appearance . progress ) ;
68+ float yOffset = sprite . FrameSize ( name ) . Y / 4f ; // TODO: verify actual value
69+ Vector2 position = getSpriteLocalPosition ( tile , appearance ) ;
70+ sprite . Position = position - new Vector2 ( 0 , yOffset ) ;
71+ Color civColor = new Color ( unit . owner . color ) ;
72+ sprite . SetColor ( civColor ) ;
73+ sprite . SetAnimation ( name ) ;
74+ sprite . SetFrame ( frame ) ;
75+ sprite . Show ( ) ;
76+
77+ if ( unit == game . CurrentlySelectedUnit ) {
78+ cursor . Position = position ;
79+ cursor . Show ( ) ;
80+ }
81+ }
82+
83+ private MapUnit selectUnitToDisplay ( List < MapUnit > units ) {
84+ if ( units . Count == 0 ) {
85+ return MapUnit . NONE ;
86+ }
87+ MapUnit bestDefender = units [ 0 ] , selected = null , interesting = null ;
88+ MapUnit currentlySelected = game . CurrentlySelectedUnit ;
89+ foreach ( MapUnit unit in units ) {
90+ if ( unit == currentlySelected ) {
91+ selected = unit ;
92+ }
93+ if ( unit . HasPriorityAsDefender ( bestDefender , currentlySelected ) ) {
94+ bestDefender = unit ;
95+ }
96+ if ( game . animTracker . getUnitAppearance ( unit ) . DeservesPlayerAttention ( ) ) {
97+ interesting = unit ;
98+ }
99+ }
100+ // Prefer showing the selected unit, secondly show one doing a relevant animation, otherwise show the top defender
101+ return selected ?? interesting ?? bestDefender ;
102+ }
103+
104+ public List < Tile > getVisibleTiles ( ) {
105+ List < Tile > tiles = new List < Tile > ( ) ;
106+ Rect2 bounds = game . camera . getVisibleWorld ( ) ;
107+ Vector2I topLeft = tilemap . LocalToMap ( ToLocal ( bounds . Position ) ) ;
108+ Vector2I bottomRight = tilemap . LocalToMap ( ToLocal ( bounds . End ) ) ;
109+ for ( int x = topLeft . X - 1 ; x < bottomRight . X + 1 ; x ++ ) {
110+ for ( int y = topLeft . Y - 1 ; y < bottomRight . Y + 1 ; y ++ ) {
111+ ( int usX , int usY ) = unstackedCoords ( new Vector2I ( x , y ) ) ;
112+ tiles . Add ( data . map . tileAt ( usX , usY ) ) ;
113+ }
114+ }
115+ return tiles ;
116+ }
117+
118+ public void updateAnimations ( ) {
119+ foreach ( UnitSprite s in unitSprites . Values ) {
120+ s . Hide ( ) ;
121+ }
122+ cursor . Hide ( ) ;
123+ foreach ( Tile tile in getVisibleTiles ( ) ) {
124+ MapUnit unit = selectUnitToDisplay ( tile . unitsOnTile ) ;
125+ if ( unit != MapUnit . NONE ) {
126+ animateUnit ( tile , unit ) ;
127+ }
128+ }
48129 }
49130
50131 private void initializeTileMap ( ) {
@@ -127,7 +208,10 @@ private Vector2I stackedCoords(Tile tile) {
127208 public MapView ( Game game , GameData data ) {
128209 this . data = data ;
129210 this . game = game ;
211+ this . data = data ;
130212 this . gameMap = data . map ;
213+ cursor = new CursorSprite ( ) ;
214+ AddChild ( cursor ) ;
131215 width = gameMap . numTilesWide / 2 ;
132216 height = gameMap . numTilesTall ;
133217 initializeTileMap ( ) ;
@@ -151,24 +235,6 @@ public MapView(Game game, GameData data) {
151235 foreach ( Tile tile in gameMap . tiles ) {
152236 updateTile ( tile ) ;
153237 }
154-
155- // temp but place units in current position
156- foreach ( Tile tile in gameMap . tiles ) {
157- if ( tile . unitsOnTile . Count > 0 ) {
158- MapUnit unit = tile . unitsOnTile [ 0 ] ;
159- UnitSprite sprite = new UnitSprite ( game . civ3AnimData ) ;
160- MapUnit . Appearance appearance = game . animTracker . getUnitAppearance ( unit ) ;
161-
162- var coords = stackedCoords ( tile ) ;
163- sprite . Position = tilemap . MapToLocal ( coords ) ;
164-
165- game . civ3AnimData . forUnit ( unit . unitType , appearance . action ) . loadSpriteAnimation ( ) ;
166- string animName = AnimationManager . AnimationKey ( unit . unitType , appearance . action , appearance . direction ) ;
167- sprite . SetAnimation ( animName ) ;
168- sprite . SetFrame ( 0 ) ;
169- AddChild ( sprite ) ;
170- }
171- }
172238 }
173239
174240 public Tile tileAt ( GameMap gameMap , Vector2 globalMousePosition ) {
0 commit comments