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

Revision 4635, 14.0 KB checked in by dezhidki, 6 years ago (diff)

Talletus.

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