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

Revision 4694, 18.0 KB checked in by dezhidki, 6 years ago (diff)

Guit lisätty, AIn viimestely.

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