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

Revision 4581, 11.2 KB checked in by dezhidki, 10 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;
13
14namespace CastleMaster.World
15{
16
17    public class EntityComprarer : Comparer<Entity>
18    {
19        /// <summary>
20        /// Compares entities between them.
21        /// </summary>
22        /// <param name="e1">Entity 1.</param>
23        /// <param name="e2">Entity 2.</param>
24        /// <returns>-1 = e1 render before e2 (e1 -> e2). +1 = e1 render after e2 (e2 -> e1).</returns>
25        public override int Compare(Entity e1, Entity e2)
26        {
27            BoundingRectangle br1 = e1.BoundingRectangle;
28            BoundingRectangle br2 = e2.BoundingRectangle;
29
30            if (br1.ZFar >= br2.ZNear)
31            {
32                if ((e1.Z + e1.X - e1.RenderOffset.Y) - e1.RenderOffset.Y < (e2.Z + e2.X - e2.RenderOffset.Y) - e2.RenderOffset.Y) return -1;
33                return +1;
34            }
35            if (br1.ZNear <= br2.ZFar)
36                return -1;
37            if (br1.XRight <= br2.XLeft)
38                return -1;
39            if (br1.XLeft >= br2.XRight)
40                return +1;
41
42            return 0;
43        }
44    }
45
46    public class Level
47    {
48        public const int TILE_VOID = 0;
49        public const int UPDATES_IN_TICK = 50;
50        protected List<Tile> registeredTiles;
51        protected int[] tiles;
52        protected byte[] data;
53
54        private List<Entity> entities;
55        private List<TileEntity> tileEntities;
56        private List<Entity>[] entitiesInTiles;
57        private List<Entity> entitesToRender;
58        private List<Unit>[] units;
59        private int width, height;
60        protected Texture2D tileMap;
61        private EntityComprarer comparer = new EntityComprarer();
62        private AnimationHelper waterAnimation = new AnimationHelper(10, 2);
63        private Player[] players;
64
65        public Level(Texture2D tileMap)
66        {
67            this.tileMap = tileMap;
68            width = tileMap.Width;
69            height = tileMap.Height;
70
71            players = new Player[2];
72            tiles = new int[width * height];
73            data = new byte[width * height];
74            registeredTiles = new List<Tile>();
75
76            new Tile(this);
77            InitTiles();
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 Player[] Players { get { return players; } }
92
93        public int Width { get { return width; } }
94
95        public int Height { get { return height; } }
96
97        public List<Tile> RegisteredTiles { get { return registeredTiles; } }
98
99        public int WaterTimer { get { return waterAnimation.CurrentFrame; } }
100
101        protected virtual void InitTiles() { }
102
103        public virtual void InitLevel() { }
104
105        public void RenderBackground(Camera camera, RenderHelper renderer)
106        {
107            float w = (Game.WIDTH / Viewport.FLOOR_TILE_WIDTH) / Viewport.ZOOM;
108            float h = (Game.HEIGHT / Viewport.Y_STEP) / Viewport.ZOOM;
109
110            int x0 = (int)((camera.XLeft / Viewport.FLOOR_TILE_WIDTH) / Viewport.ZOOM) - 3;
111            int y0 = (int)((camera.YTop / Viewport.Y_STEP) / Viewport.ZOOM) - 5;
112            int x1 = (int)(x0 + w) + 5;
113            int y1 = (int)(y0 + h) + 7;
114
115            renderer.SetOffset(camera);
116            int tp;
117            for (int y = y0; y < y1; y++)
118            {
119                for (int x = x0; x < x1; x++)
120                {
121                    int xTile = x + (y >> 1) + (y & 1);
122                    int zTile = (y >> 1) - x;
123
124                    if (xTile >= 0 && zTile >= 0 && xTile < width && zTile < height)
125                    {
126                        tp = xTile + zTile * width;
127                        Tile t = registeredTiles[tiles[tp]];
128                        if (t.ID != TILE_VOID)
129                            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]);
130                        entitiesInTiles[tp].ForEach(ent => entitesToRender.Add(ent));
131                    }
132                }
133            }
134
135            renderer.SetOffset();
136        }
137
138        public void RenderEntities(Camera camera, RenderHelper renderer)
139        {
140            if (entitesToRender.Count > 0)
141            {
142                entitesToRender.Sort(comparer);
143
144                renderer.SetOffset(camera);
145
146                foreach (Entity ent in entitesToRender)
147                    ent.Render(renderer);
148
149                renderer.SetOffset();
150
151                entitesToRender.Clear();
152            }
153        }
154
155        public void Update()
156        {
157            waterAnimation.UpdateStep();
158
159            for (int i = 0; i < UPDATES_IN_TICK; i++)
160            {
161                int xTile = Game.Random.Next(width);
162                int zTile = Game.Random.Next(height);
163
164                registeredTiles[tiles[xTile + zTile * width]].Update(this, xTile, zTile);
165
166                if (tileEntities.Count > 0)
167                    tileEntities[Game.Random.Next(tileEntities.Count)].Update();
168            }
169
170            foreach (Entity ent in entities)
171            {
172                int xTile_old = (int)(ent.X / Viewport.TILESIZE);
173                int zTile_old = (int)(ent.Z / Viewport.TILESIZE);
174
175                ent.Update();
176
177                //if (ent.Removed)
178                //{
179                //    RemoveEntity(ent);
180                //    TakeEntity(ent, xTile_old, zTile_old);
181                //    continue;
182                //}
183
184                int xTile = (int)(ent.X / Viewport.TILESIZE);
185                int zTile = (int)(ent.Z / Viewport.TILESIZE);
186
187                if (xTile != xTile_old || zTile != zTile_old)
188                {
189                    TakeEntity(ent, xTile_old, zTile_old);
190                    InsertEntity(ent, xTile, zTile);
191                }
192            }
193        }
194
195        public void SetPlayer(Player player, int id)
196        {
197            players[id] = player;
198        }
199
200        public void SetTile(int tileX, int tileZ, int tileID)
201        {
202            if (IsValidPos(tileX, tileZ))
203                tiles[tileX + tileZ * width] = tileID;
204        }
205
206        public void SetData(int tileX, int tileZ, byte dataVal)
207        {
208            if (IsValidPos(tileX, tileZ))
209                data[tileX + tileZ * width] = dataVal;
210        }
211
212        public Tile GetTile(int tileX, int tileZ)
213        {
214            return IsValidPos(tileX, tileZ) ? registeredTiles[tiles[tileX + tileZ * width]] : registeredTiles[TILE_VOID];
215        }
216
217        public byte GetData(int tileX, int tileZ)
218        {
219            return IsValidPos(tileX, tileZ) ? data[tileX + tileZ * width] : (byte)0;
220        }
221
222        public void AddEntity(Entity ent, float xPos, float zPos)
223        {
224            int xTile = (int)(xPos / Viewport.TILESIZE);
225            int zTile = (int)(zPos / Viewport.TILESIZE);
226
227            if (!IsValidPos(xTile, zTile)) return;
228
229            ent.X = xPos;
230            ent.Z = zPos;
231
232            ent.Init();
233
234            if (typeof(TileEntity).IsAssignableFrom(ent.GetType()))
235                tileEntities.Add((TileEntity)ent);
236            else
237                entities.Add(ent);
238
239            if(typeof(Unit).IsAssignableFrom(ent.GetType()))
240            {
241                Unit u = (Unit)ent;
242                units[u.Owner.Team.ID].Add(u);
243            }
244
245            InsertEntity(ent, xTile, zTile);
246        }
247
248        private void InsertEntity(Entity ent, int xTile, int zTile)
249        {
250            entitiesInTiles[xTile + zTile * width].Add(ent);
251        }
252
253        private void TakeEntity(Entity ent, int xTile, int zTile)
254        {
255            entitiesInTiles[xTile + zTile * width].Remove(ent);
256        }
257
258        private void RemoveEntity(Entity ent)
259        {
260            ent.OnRemoved();
261
262            entities.Remove(ent);
263
264            TakeEntity(ent, (int)(ent.X / Viewport.TILESIZE), (int)(ent.Z / Viewport.TILESIZE));
265        }
266
267        public List<Unit> GetUnitsWithinScreenSpace(float x0, float y0, float x1, float y1, Player player)
268        {
269            List<Unit> result = new List<Unit>();
270
271            foreach (Unit u in units[player.Team.ID])
272            {
273                if (u.IsSelectable && u.IntersectsWithScreenSpace(x0, y0, x1, y1))
274                    result.Add(u);
275            }
276
277            return result;
278        }
279
280        public List<BoundingRectangle> GetCollidables(Entity ent, BoundingRectangle br = null)
281        {
282            List<BoundingRectangle> result = new List<BoundingRectangle>();
283
284            BoundingRectangle entBR = br == null ? ent.BoundingRectangle : br;
285
286            int x0 = (int)(entBR.XLeft / Viewport.TILESIZE) - 1;
287            int z0 = (int)(entBR.ZFar / Viewport.TILESIZE) - 1;
288            int x1 = (int)(entBR.XRight / Viewport.TILESIZE) + 1;
289            int z1 = (int)(entBR.ZNear / Viewport.TILESIZE) + 1;
290
291            for (int z = z0; z <= z1; z++)
292            {
293                if (z < 0 || z >= height) continue;
294                for (int x = x0; x <= x1; x++)
295                {
296                    if (x < 0 || x >= width) continue;
297
298                    List<Entity> entits = entitiesInTiles[x + z * width];
299
300                    foreach (Entity e in entits)
301                    {
302                        if (e != ent && entBR.Intersects(e.BoundingRectangle))
303                            e.AddBoundingRect(ref result, ent);
304                    }
305
306                    Tile t = registeredTiles[tiles[x + z * width]];
307                    if (t.IsSolid && t.GetBoundingRect(x, z).Intersects(entBR))
308                        t.AddBoundingRect(ref result, x, z);
309                }
310            }
311
312            return result;
313        }
314
315        private bool IsValidPos(int tileX, int tileZ)
316        {
317            return (tileX >= 0 && tileZ >= 0 && tileX < width && tileZ < height);
318        }
319
320        public bool[] BuildSolidnessTable(Mob mob)
321        {
322            bool[] result = new bool[tiles.Length];
323
324            for (int i = 0; i < tiles.Length; i++)
325            {
326                result[i] = tiles[i] == TILE_VOID || registeredTiles[tiles[i]].IsSolid;
327
328                List<Entity> entInTiles = entitiesInTiles[i];
329
330                if (entInTiles.Count > 0)
331                {
332                    TileEntity te = entInTiles[0] as TileEntity;
333                    result[i] = te != null && te.Blocks(mob);
334                }
335            }
336
337            return result;
338        }
339    }
340}
Note: See TracBrowser for help on using the repository browser.