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

Revision 4646, 17.1 KB checked in by dezhidki, 6 years ago (diff)

Muokattu sotilaita viimeiseen muotoon.

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(Entity ent, int xTile, int zTile)
294        {
295            TileEntity te = null;
296            List<Entity> ents = entitiesInTiles[xTile + zTile * width];
297            if (ents.Count > 0)
298                te = ents[0] as TileEntity;
299            if (te == null) return null;
300
301            for (int z = zTile - 1; z <= zTile + 1; z++)
302            {
303                if (z < 0 || z >= height) continue;
304                for (int x = xTile - 1; x <= xTile + 1; x++)
305                {
306                    if (x < 0 || x >= width) continue;
307
308                    ents = entitiesInTiles[x + z * width];
309
310                    if (ents.Count > 0)
311                    {
312                        Entity e = ents[0];
313                        if (e != te && !e.Blocks(te)) return te;
314                    }
315                    else return te;
316                }
317            }
318
319            return null;
320        }
321
322        public List<Unit> GetUnitsWithinScreenSpace(float x0, float y0, float x1, float y1, Team team)
323        {
324            List<Unit> result = new List<Unit>();
325
326            foreach (Unit u in units[team.ID])
327            {
328                if (u.IsSelectable && u.IntersectsWithScreenSpace(x0, y0, x1, y1))
329                    result.Add(u);
330            }
331
332            return result;
333        }
334
335        public List<BoundingRectangle> GetCollidables(Entity ent, BoundingRectangle br = null)
336        {
337            List<BoundingRectangle> result = new List<BoundingRectangle>();
338
339            BoundingRectangle entBR = br == null ? ent.BoundingRectangle : br;
340
341            int x0 = (int)(entBR.XLeft / Viewport.TILESIZE) - 1;
342            int z0 = (int)(entBR.ZFar / Viewport.TILESIZE) - 1;
343            int x1 = (int)(entBR.XRight / Viewport.TILESIZE) + 1;
344            int z1 = (int)(entBR.ZNear / Viewport.TILESIZE) + 1;
345
346            for (int z = z0; z <= z1; z++)
347            {
348                if (z < 0 || z >= height) continue;
349                for (int x = x0; x <= x1; x++)
350                {
351                    if (x < 0 || x >= width) continue;
352
353                    List<Entity> entits = entitiesInTiles[x + z * width];
354
355                    foreach (Entity e in entits)
356                    {
357                        if (e != ent && entBR.Intersects(e.BoundingRectangle))
358                            e.AddBoundingRect(ref result, ent);
359                    }
360
361                    Tile t = registeredTiles[tiles[x + z * width]];
362                    if (t.IsSolidTo(ent) && t.GetBoundingRect(x, z).Intersects(entBR))
363                        t.AddBoundingRect(ref result, x, z);
364                }
365            }
366
367            return result;
368        }
369
370
371        public List<Unit> GetNearbyEnemyUnits(Team enemyTeam, int xTile, int zTile, int radius)
372        {
373            List<Unit> result = new List<Unit>();
374
375            for (int z = zTile - radius; z <= zTile + radius; z++)
376            {
377                if (z < 0 || z >= height) continue;
378                for (int x = xTile - radius; x <= xTile + radius; x++)
379                {
380                    if (x < 0 || x >= width) continue;
381
382                    List<Entity> ents = entitiesInTiles[x + z * width];
383
384                    foreach (Entity ent in ents)
385                    {
386                        Mob m = ent as Mob;
387                        if (m != null && m.Owner.Team.ID == enemyTeam.ID)
388                            result.Add(m);
389                    }
390                }
391            }
392
393            return result;
394        }
395
396        private bool IsValidPos(int tileX, int tileZ)
397        {
398            return (tileX >= 0 && tileZ >= 0 && tileX < width && tileZ < height);
399        }
400
401        public bool[] BuildSolidnessTable(Mob mob, bool excludeEndSolidness = false)
402        {
403            bool[] result = new bool[tiles.Length];
404
405            for (int i = 0; i < tiles.Length; i++)
406            {
407                Tile t = registeredTiles[tiles[i]];
408                if (t is TileFloor && excludeEndSolidness)
409                    result[i] = false;
410                else
411                    result[i] = tiles[i] == TILE_VOID || t.IsSolid;
412
413                List<Entity> entInTiles = entitiesInTiles[i];
414
415                if (entInTiles.Count > 0)
416                {
417                    TileEntity te = entInTiles[0] as TileEntity;
418                    result[i] = te != null && te.Blocks(mob);
419                }
420            }
421
422            return result;
423        }
424
425        public int GetClosestDiagonalOpenPos(Entity ent)
426        {
427            int xTile = (int)(ent.X / Viewport.TILESIZE);
428            int zTile = (int)(ent.Z / Viewport.TILESIZE);
429
430            bool blocks = false;
431            int tp;
432
433            for (int z = zTile - 1; z <= zTile + 1; z++)
434            {
435                if (z < 0 || z >= height) continue;
436                if (z == zTile) continue;
437
438                tp = xTile + z * width;
439                Tile t = registeredTiles[tiles[tp]];
440                if (t.ID == TILE_VOID || t.IsSolidTo(ent)) blocks |= true;
441
442                List<Entity> ents = entitiesInTiles[tp];
443
444                foreach (Entity e in ents)
445                {
446                    if (e != ent)
447                        blocks |= e.Blocks(ent);
448                }
449                if (!blocks) return tp;
450            }
451
452            blocks = false;
453            for (int x = xTile - 1; x <= xTile + 1; x++)
454            {
455                if (x < 0 || x >= width) continue;
456                if (x == xTile) continue;
457
458                tp = x + zTile * width;
459                Tile t = registeredTiles[tiles[tp]];
460                if (t.ID == TILE_VOID || t.IsSolidTo(ent)) blocks |= true;
461
462                List<Entity> ents = entitiesInTiles[tp];
463
464                foreach (Entity e in ents)
465                {
466                    if (e != ent)
467                        blocks |= e.Blocks(ent);
468                }
469                if (!blocks) return tp;
470            }
471
472
473            //for (int z = zTile - 1; z <= zTile + 1; z++)
474            //{
475            //    if (z < 0 || z >= height) continue;
476            //    for (int x = xTile - 1; x <= xTile + 1; x++)
477            //    {
478            //        if (x < 0 || x >= width) continue;
479            //        if (x == xTile && z == zTile) continue;
480
481            //        tp = x + z * width;
482            //        Tile t = registeredTiles[tiles[tp]];
483            //        if (t.ID == TILE_VOID || t.IsSolidTo(ent)) blocks |= true;
484
485            //        List<Entity> ents = entitiesInTiles[tp];
486
487            //        foreach (Entity e in ents)
488            //        {
489            //            if (e != ent)
490            //                blocks |= e.Blocks(ent);
491            //        }
492            //        if (!blocks) return tp;
493            //    }
494            //}
495
496            return -1;
497        }
498
499        public List<int> GetEntitySolidnessList(Entity caller, int xTile, int zTile, int radius)
500        {
501            List<int> result = new List<int>();
502
503            for (int z = zTile - radius; z <= zTile + radius; z++)
504            {
505                if (z < 0 || z >= height) continue;
506                for (int x = xTile - radius; x <= xTile + radius; x++)
507                {
508                    if (x < 0 || x >= width) continue;
509                    if (x == xTile && z == zTile) continue;
510
511                    foreach (Entity ent in entitiesInTiles[x + z * width])
512                    {
513                        if (ent.Blocks(caller))
514                        {
515                            result.Add(x + z * width);
516                            continue;
517                        }
518                    }
519                }
520            }
521
522            return result;
523        }
524    }
525}
Note: See TracBrowser for help on using the repository browser.