source: 2013/30/DenisZ/CastleMaster/CastleMaster/CastleMaster/World/Level.cs @ 4754

Revision 4754, 18.5 KB checked in by dezhidki, 8 years ago (diff)

Housekeeping

Line 
1using CastleMaster.Entities;
2using CastleMaster.Entities.TileEntities;
3using CastleMaster.Graphics;
4using CastleMaster.Guis;
5using CastleMaster.Physics;
6using CastleMaster.Players;
7using CastleMaster.Units;
8using CastleMaster.Units.Mobs;
9using CastleMaster.World.Tiles;
10using Microsoft.Xna.Framework;
11using Microsoft.Xna.Framework.Graphics;
12using System.Collections.Generic;
13using Viewport = CastleMaster.Graphics.Viewport;
14
15namespace CastleMaster.World
16{
17
18    public class EntityComprarer : Comparer<Entity>
19    {
20        /// <summary>
21        /// Compares entities between them.
22        /// </summary>
23        /// <param name="e1">Entity 1.</param>
24        /// <param name="e2">Entity 2.</param>
25        /// <returns>-1 = e1 render before e2 (e1 -> e2). +1 = e1 render after e2 (e2 -> e1).</returns>
26        public override int Compare(Entity e1, Entity e2)
27        {
28            BoundingRectangle br1 = e1.BoundingRectangle;
29            BoundingRectangle br2 = e2.BoundingRectangle;
30
31            if (br1.ZFar >= br2.ZNear)
32            {
33                //if ((e1.Z + e1.X - e1.RenderOffset.Y) - e1.RenderOffset.Y < (e2.Z + e2.X - e2.RenderOffset.Y) - e2.RenderOffset.Y) return -1;
34                return +1;
35            }
36            if (br1.ZNear <= br2.ZFar)
37                return -1;
38            if (br1.XRight <= br2.XLeft)
39                return -1;
40            if (br1.XLeft >= br2.XRight)
41                return +1;
42
43            return 0;
44        }
45    }
46
47    public class Level
48    {
49        public const int TILE_VOID = 0;
50        public const int UPDATES_IN_TICK = 500;
51        protected List<Tile> registeredTiles;
52        protected int[] tiles;
53        protected byte[] data;
54
55        private List<Entity> entities;
56        private List<TileEntity> tileEntities;
57        private List<Entity>[] entitiesInTiles;
58        private List<Entity> entitesToRender;
59        private List<Unit>[] units;
60        private int width, height;
61        protected Texture2D tileMap;
62        private EntityComprarer comparer = new EntityComprarer();
63        private TimerHelper waterAnimation = new TimerHelper(10, 2).Start();
64        private Player[] players;
65
66        public Level(Texture2D tileMap)
67        {
68            this.tileMap = tileMap;
69            width = tileMap.Width;
70            height = tileMap.Height;
71
72            players = new Player[2];
73            tiles = new int[width * height];
74            data = new byte[width * height];
75            registeredTiles = new List<Tile>();
76
77            units = new List<Unit>[2];
78            units[0] = new List<Unit>();
79            units[1] = new List<Unit>();
80
81            entities = new List<Entity>();
82            tileEntities = new List<TileEntity>();
83            entitiesInTiles = new List<Entity>[width * height];
84            for (int i = 0; i < width * height; i++)
85                entitiesInTiles[i] = new List<Entity>();
86            entitesToRender = new List<Entity>();
87        }
88
89        public List<Unit>[] Units { get { return units; } }
90
91        public Player[] Players { get { return players; } }
92
93        public int[] Tiles { get { return tiles; } }
94
95        public int Width { get { return width; } }
96
97        public int Height { get { return height; } }
98
99        public List<Tile> RegisteredTiles { get { return registeredTiles; } }
100
101        public int WaterTimer { get { return waterAnimation.CurrentFrame; } }
102
103        protected virtual void InitTiles() { }
104
105        public virtual void InitLevel()
106        {
107            new Tile(this);
108            InitTiles();
109        }
110
111        public void RenderBackground(Camera camera, RenderHelper renderer)
112        {
113            float w = (Game.WIDTH / Viewport.FLOOR_TILE_WIDTH) / Viewport.ZOOM;
114            float h = ((Game.HEIGHT - GuiPlayer.GUI_BAR_HEIGHT) / Viewport.Y_STEP) / Viewport.ZOOM;
115
116            int x0 = (int)((camera.XLeft / Viewport.FLOOR_TILE_WIDTH) / Viewport.ZOOM) - 3;
117            int y0 = (int)((camera.YTop / Viewport.Y_STEP) / Viewport.ZOOM) - 5;
118            int x1 = (int)(x0 + w) + 5;
119            int y1 = (int)(y0 + h) + 7;
120
121            renderer.SetOffset(camera);
122            int tp;
123            for (int y = y0; y < y1; y++)
124            {
125                for (int x = x0; x < x1; x++)
126                {
127                    int xTile = x + (y >> 1) + (y & 1);
128                    int zTile = (y >> 1) - x;
129
130                    if (xTile >= 0 && zTile >= 0 && xTile < width && zTile < height)
131                    {
132                        tp = xTile + zTile * width;
133                        Tile t = registeredTiles[tiles[tp]];
134                        if (t.ID != TILE_VOID)
135                            t.Render(renderer, this, new Vector2((x * Viewport.FLOOR_TILE_WIDTH + (y & 1) * Viewport.X_STEP) * Viewport.ZOOM, (y * Viewport.Y_STEP + Viewport.Y_STEP) * Viewport.ZOOM), xTile, zTile, data[tp]);
136                        entitiesInTiles[tp].ForEach(AddEntityToRenderList);
137                    }
138                }
139            }
140
141            renderer.SetOffset();
142        }
143
144        public void AddEntityToRenderList(Entity ent)
145        {
146            if (!ent.IsRendering) entitesToRender.Add(ent);
147            ent.IsRendering = true;
148        }
149
150        public void RenderEntities(Camera camera, RenderHelper renderer)
151        {
152            if (entitesToRender.Count > 0)
153            {
154                entitesToRender.Sort(comparer);
155
156                renderer.SetOffset(camera);
157
158                foreach (Entity ent in entitesToRender)
159                {
160                    ent.Render(renderer);
161                    ent.IsRendering = false;
162                }
163
164                renderer.SetOffset();
165
166                entitesToRender.Clear();
167            }
168        }
169
170        public void Update()
171        {
172            waterAnimation.UpdateStep();
173
174            for (int i = 0; i < UPDATES_IN_TICK; i++)
175            {
176                int xTile = Game.Random.Next(width);
177                int zTile = Game.Random.Next(height);
178
179                registeredTiles[tiles[xTile + zTile * width]].Update(this, xTile, zTile);
180
181                if (tileEntities.Count > 0)
182                {
183                    TileEntity te = tileEntities[Game.Random.Next(tileEntities.Count)];
184                    te.Update();
185                    if (te.Removed)
186                    {
187                        RemoveEntity(te);
188                        TakeEntity(te, te.XTile, te.ZTile);
189                    }
190                }
191            }
192
193            for (int i = 0; i < entities.Count; i++)
194            {
195                Entity ent = entities[i];
196
197                int xTile_old = (int)(ent.X / Viewport.TILESIZE);
198                int zTile_old = (int)(ent.Z / Viewport.TILESIZE);
199
200                ent.Update();
201
202                if (ent.Removed)
203                {
204                    RemoveEntity(ent);
205                    TakeEntity(ent, xTile_old, zTile_old);
206                    i--;
207                    continue;
208                }
209
210                int xTile = (int)(ent.X / Viewport.TILESIZE);
211                int zTile = (int)(ent.Z / Viewport.TILESIZE);
212
213                if (xTile != xTile_old || zTile != zTile_old)
214                {
215                    TakeEntity(ent, xTile_old, zTile_old);
216                    InsertEntity(ent, xTile, zTile);
217                }
218            }
219        }
220
221        public void RemoveUnit(Unit u)
222        {
223            units[u.Owner.Team.ID].Remove(u);
224        }
225
226        public void SetPlayer(Player player, int id)
227        {
228            players[id] = player;
229        }
230
231        public void SetTile(int tileX, int tileZ, int tileID)
232        {
233            tiles[tileX + tileZ * width] = tileID;
234        }
235
236        public void SetData(int tileX, int tileZ, byte dataVal)
237        {
238            data[tileX + tileZ * width] = dataVal;
239        }
240
241        public Tile GetTile(int tileX, int tileZ)
242        {
243            return IsValidPos(tileX, tileZ) ? registeredTiles[tiles[tileX + tileZ * width]] : registeredTiles[TILE_VOID];
244        }
245
246        public byte GetData(int tileX, int tileZ)
247        {
248            return IsValidPos(tileX, tileZ) ? data[tileX + tileZ * width] : (byte)0;
249        }
250
251        public void AddEntity(Entity ent, float xPos, float zPos)
252        {
253            int xTile = (int)(xPos / Viewport.TILESIZE);
254            int zTile = (int)(zPos / Viewport.TILESIZE);
255
256            if (!IsValidPos(xTile, zTile)) return;
257
258            ent.X = xPos;
259            ent.Z = zPos;
260
261            ent.Init();
262
263            if (typeof(TileEntity).IsAssignableFrom(ent.GetType()))
264                tileEntities.Add((TileEntity)ent);
265            else
266                entities.Add(ent);
267
268            if (typeof(Unit).IsAssignableFrom(ent.GetType()))
269            {
270                Unit u = (Unit)ent;
271                units[u.Owner.Team.ID].Add(u);
272            }
273
274            InsertEntity(ent, xTile, zTile);
275        }
276
277        private void InsertEntity(Entity ent, int xTile, int zTile)
278        {
279            entitiesInTiles[xTile + zTile * width].Add(ent);
280        }
281
282        private void TakeEntity(Entity ent, int xTile, int zTile)
283        {
284            entitiesInTiles[xTile + zTile * width].Remove(ent);
285        }
286
287        private void RemoveEntity(Entity ent)
288        {
289            ent.OnRemoved();
290
291            entities.Remove(ent);
292
293            TakeEntity(ent, (int)(ent.X / Viewport.TILESIZE), (int)(ent.Z / Viewport.TILESIZE));
294        }
295
296        public TileEntity GetTileEntity(Entity ent, int xTile, int zTile)
297        {
298            TileEntity te = null;
299            List<Entity> ents = entitiesInTiles[xTile + zTile * width];
300            if (ents.Count > 0)
301                te = ents[0] as TileEntity;
302            if (te == null) return null;
303
304            for (int z = zTile - 1; z <= zTile + 1; z++)
305            {
306                if (z < 0 || z >= height) continue;
307                for (int x = xTile - 1; x <= xTile + 1; x++)
308                {
309                    if (x < 0 || x >= width) continue;
310
311                    ents = entitiesInTiles[x + z * width];
312
313                    if (ents.Count > 0)
314                    {
315                        Entity e = ents[0];
316                        if (e != te && !e.Blocks(te)) return te;
317                    }
318                    else return te;
319                }
320            }
321
322            return null;
323        }
324
325        public List<Unit> GetUnitsWithinScreenSpace(float x0, float y0, float x1, float y1, Team team)
326        {
327            List<Unit> result = new List<Unit>();
328
329            foreach (Unit u in units[team.ID])
330            {
331                if (u.IsSelectable && u.IntersectsWithScreenSpace(x0, y0, x1, y1))
332                    result.Add(u);
333            }
334
335            return result;
336        }
337
338        public List<T> GetUnitsWithinScreenSpace<T>(BoundingRectangle rect, Team team) where T : Unit
339        {
340            List<T> result = new List<T>();
341
342            foreach (Unit u in units[team.ID])
343            {
344                T unit = u as T;
345                if (unit != null && unit.IsSelectable && unit.IntersectsWithScreenSpace(rect.XLeft, rect.ZFar, rect.XRight, rect.ZNear))
346                    result.Add(unit);
347            }
348
349            return result;
350        }
351
352        public List<BoundingRectangle> GetCollidables(Entity ent, BoundingRectangle br = null)
353        {
354            List<BoundingRectangle> result = new List<BoundingRectangle>();
355
356            BoundingRectangle entBR = br == null ? ent.BoundingRectangle : br;
357
358            int x0 = (int)(entBR.XLeft / Viewport.TILESIZE) - 1;
359            int z0 = (int)(entBR.ZFar / Viewport.TILESIZE) - 1;
360            int x1 = (int)(entBR.XRight / Viewport.TILESIZE) + 1;
361            int z1 = (int)(entBR.ZNear / Viewport.TILESIZE) + 1;
362
363            for (int z = z0; z <= z1; z++)
364            {
365                if (z < 0 || z >= height) continue;
366                for (int x = x0; x <= x1; x++)
367                {
368                    if (x < 0 || x >= width) continue;
369
370                    List<Entity> entits = entitiesInTiles[x + z * width];
371
372                    foreach (Entity e in entits)
373                    {
374                        if (e != ent && entBR.Intersects(e.BoundingRectangle))
375                            e.AddBoundingRect(ref result, ent);
376                    }
377
378                    Tile t = registeredTiles[tiles[x + z * width]];
379                    if (t.IsSolidTo(ent) && t.GetBoundingRect(x, z).Intersects(entBR))
380                        t.AddBoundingRect(ref result, x, z);
381                }
382            }
383
384            return result;
385        }
386
387
388        public List<Unit> GetNearbyEnemyUnits(Team enemyTeam, int xTile, int zTile, int radius)
389        {
390            List<Unit> result = new List<Unit>();
391
392            for (int z = zTile - radius; z <= zTile + radius; z++)
393            {
394                if (z < 0 || z >= height) continue;
395                for (int x = xTile - radius; x <= xTile + radius; x++)
396                {
397                    if (x < 0 || x >= width) continue;
398
399                    List<Entity> ents = entitiesInTiles[x + z * width];
400
401                    foreach (Entity ent in ents)
402                    {
403                        Mob m = ent as Mob;
404                        if (m != null && m.Owner.Team.ID == enemyTeam.ID)
405                            result.Add(m);
406                    }
407                }
408            }
409
410            return result;
411        }
412
413        private bool IsValidPos(int tileX, int tileZ)
414        {
415            return (tileX >= 0 && tileZ >= 0 && tileX < width && tileZ < height);
416        }
417
418        public bool[] BuildSolidnessTable(Mob mob, bool excludeEndSolidness = false)
419        {
420            bool[] result = new bool[tiles.Length];
421
422            for (int i = 0; i < tiles.Length; i++)
423            {
424                Tile t = registeredTiles[tiles[i]];
425                if (t is TileFloor && excludeEndSolidness)
426                    result[i] = false;
427                else
428                    result[i] = tiles[i] == TILE_VOID || t.IsSolid;
429
430                List<Entity> entInTiles = entitiesInTiles[i];
431
432                if (entInTiles.Count > 0)
433                {
434                    TileEntity te = entInTiles[0] as TileEntity;
435                    result[i] = te != null && te.Blocks(mob);
436                }
437            }
438
439            return result;
440        }
441
442        public int GetClosestDiagonalOpenPos(Entity ent)
443        {
444            int xTile = (int)(ent.X / Viewport.TILESIZE);
445            int zTile = (int)(ent.Z / Viewport.TILESIZE);
446
447            bool blocks = false;
448            int tp;
449
450            for (int z = zTile - 1; z <= zTile + 1; z++)
451            {
452                if (z < 0 || z >= height) continue;
453                if (z == zTile) continue;
454
455                tp = xTile + z * width;
456                Tile t = registeredTiles[tiles[tp]];
457                if (t.ID == TILE_VOID || t.IsSolidTo(ent)) blocks |= true;
458
459                List<Entity> ents = entitiesInTiles[tp];
460
461                foreach (Entity e in ents)
462                {
463                    if (e != ent)
464                        blocks |= e.Blocks(ent);
465                }
466                if (!blocks) return tp;
467            }
468
469            blocks = false;
470            for (int x = xTile - 1; x <= xTile + 1; x++)
471            {
472                if (x < 0 || x >= width) continue;
473                if (x == xTile) continue;
474
475                tp = x + zTile * width;
476                Tile t = registeredTiles[tiles[tp]];
477                if (t.ID == TILE_VOID || t.IsSolidTo(ent)) blocks |= true;
478
479                List<Entity> ents = entitiesInTiles[tp];
480
481                foreach (Entity e in ents)
482                {
483                    if (e != ent)
484                        blocks |= e.Blocks(ent);
485                }
486                if (!blocks) return tp;
487            }
488
489            return -1;
490        }
491
492        public T GetNearestEntity<T>(Entity caller, int radius) where T : Entity
493        {
494            T nearest = null;
495            float nearestDist = 0.0F, currentDist = 0.0F;
496
497            int xTile = (int)(caller.X / Viewport.TILESIZE);
498            int zTile = (int)(caller.Z / Viewport.TILESIZE);
499
500            List<T> inRadius = new List<T>();
501            for (int z = zTile - radius; z <= zTile + radius; z++)
502            {
503                if (z < 0 || z >= height) continue;
504                for (int x = xTile - radius; x <= xTile + radius; x++)
505                {
506                    if (x < 0 || x >= width) continue;
507                    if (x == xTile && z == zTile) continue;
508
509                    entitiesInTiles[x + z * width].ForEach(delegate(Entity ent)
510                    {
511                        if (typeof(T).IsAssignableFrom(ent.GetType())) inRadius.Add((T)ent);
512                    });
513                }
514            }
515
516            foreach (T ent in inRadius)
517            {
518                currentDist = ent.DistanceToSqr(caller.X, caller.Z);
519                if (nearest == null || currentDist < nearestDist)
520                {
521                    nearest = ent;
522                    nearestDist = currentDist;
523                }
524            }
525
526            return nearest;
527        }
528
529        public bool SolidTo(Entity ent, int xTile, int zTile)
530        {
531            if (registeredTiles[tiles[xTile + zTile * width]].IsSolidTo(ent))
532                return true;
533
534            foreach (Entity e in entitiesInTiles[xTile + zTile * width])
535                if (e.Blocks(ent)) return true;
536
537            return false;
538        }
539
540        public List<int> GetEntitySolidnessList(Entity caller, int xTile, int zTile, int radius)
541        {
542            List<int> result = new List<int>();
543
544            for (int z = zTile - radius; z <= zTile + radius; z++)
545            {
546                if (z < 0 || z >= height) continue;
547                for (int x = xTile - radius; x <= xTile + radius; x++)
548                {
549                    if (x < 0 || x >= width) continue;
550                    if (x == xTile && z == zTile) continue;
551
552                    foreach (Entity ent in entitiesInTiles[x + z * width])
553                    {
554                        if (ent.Blocks(caller))
555                        {
556                            result.Add(x + z * width);
557                            continue;
558                        }
559                    }
560                }
561            }
562
563            return result;
564        }
565    }
566}
Note: See TracBrowser for help on using the repository browser.