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

Revision 4592, 12.9 KB checked in by dezhidki, 7 years ago (diff)

Lisätty toimiva sotilas. Korjattu OrderMove:n epätarkkuuksia. Lisätty AStariin muuttuja, jolla voi jättää loppupisteen läpipääsemättömyyden huomioimatta.

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;
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 = 50;
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 AnimationHelper waterAnimation = new AnimationHelper(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            new Tile(this);
78            InitTiles();
79
80            units = new List<Unit>[2];
81            units[0] = new List<Unit>();
82            units[1] = new List<Unit>();
83
84            entities = new List<Entity>();
85            tileEntities = new List<TileEntity>();
86            entitiesInTiles = new List<Entity>[width * height];
87            for (int i = 0; i < width * height; i++)
88                entitiesInTiles[i] = new List<Entity>();
89            entitesToRender = new List<Entity>();
90        }
91
92        public Player[] Players { get { return players; } }
93
94        public int Width { get { return width; } }
95
96        public int Height { get { return height; } }
97
98        public List<Tile> RegisteredTiles { get { return registeredTiles; } }
99
100        public int WaterTimer { get { return waterAnimation.CurrentFrame; } }
101
102        protected virtual void InitTiles() { }
103
104        public virtual void InitLevel() { }
105
106        public void RenderBackground(Camera camera, RenderHelper renderer)
107        {
108            float w = (Game.WIDTH / Viewport.FLOOR_TILE_WIDTH) / Viewport.ZOOM;
109            float h = (Game.HEIGHT / Viewport.Y_STEP) / Viewport.ZOOM;
110
111            int x0 = (int)((camera.XLeft / Viewport.FLOOR_TILE_WIDTH) / Viewport.ZOOM) - 3;
112            int y0 = (int)((camera.YTop / Viewport.Y_STEP) / Viewport.ZOOM) - 5;
113            int x1 = (int)(x0 + w) + 5;
114            int y1 = (int)(y0 + h) + 7;
115
116            renderer.SetOffset(camera);
117            int tp;
118            for (int y = y0; y < y1; y++)
119            {
120                for (int x = x0; x < x1; x++)
121                {
122                    int xTile = x + (y >> 1) + (y & 1);
123                    int zTile = (y >> 1) - x;
124
125                    if (xTile >= 0 && zTile >= 0 && xTile < width && zTile < height)
126                    {
127                        tp = xTile + zTile * width;
128                        Tile t = registeredTiles[tiles[tp]];
129                        if (t.ID != TILE_VOID)
130                            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]);
131                        entitiesInTiles[tp].ForEach(ent => entitesToRender.Add(ent));
132                    }
133                }
134            }
135
136            renderer.SetOffset();
137        }
138
139        public void RenderEntities(Camera camera, RenderHelper renderer)
140        {
141            if (entitesToRender.Count > 0)
142            {
143                entitesToRender.Sort(comparer);
144
145                renderer.SetOffset(camera);
146
147                foreach (Entity ent in entitesToRender)
148                    ent.Render(renderer);
149
150                renderer.SetOffset();
151
152                entitesToRender.Clear();
153            }
154        }
155
156        public void Update()
157        {
158            waterAnimation.UpdateStep();
159
160            for (int i = 0; i < UPDATES_IN_TICK; i++)
161            {
162                int xTile = Game.Random.Next(width);
163                int zTile = Game.Random.Next(height);
164
165                registeredTiles[tiles[xTile + zTile * width]].Update(this, xTile, zTile);
166
167                if (tileEntities.Count > 0)
168                {
169                    TileEntity te = tileEntities[Game.Random.Next(tileEntities.Count)];
170                    te.Update();
171                    if (te.Removed)
172                    {
173                        RemoveEntity(te);
174                        TakeEntity(te, te.XTile, te.ZTile);
175                    }
176                }
177            }
178
179            for (int i = 0; i < entities.Count; i++)
180            {
181                Entity ent = entities[i];
182
183                int xTile_old = (int)(ent.X / Viewport.TILESIZE);
184                int zTile_old = (int)(ent.Z / Viewport.TILESIZE);
185
186                ent.Update();
187
188                if (ent.Removed)
189                {
190                    RemoveEntity(ent);
191                    TakeEntity(ent, xTile_old, zTile_old);
192                    i--;
193                    continue;
194                }
195
196                int xTile = (int)(ent.X / Viewport.TILESIZE);
197                int zTile = (int)(ent.Z / Viewport.TILESIZE);
198
199                if (xTile != xTile_old || zTile != zTile_old)
200                {
201                    TakeEntity(ent, xTile_old, zTile_old);
202                    InsertEntity(ent, xTile, zTile);
203                }
204            }
205        }
206
207        public void SetPlayer(Player player, int id)
208        {
209            players[id] = player;
210        }
211
212        public void SetTile(int tileX, int tileZ, int tileID)
213        {
214            if (IsValidPos(tileX, tileZ))
215                tiles[tileX + tileZ * width] = tileID;
216        }
217
218        public void SetData(int tileX, int tileZ, byte dataVal)
219        {
220            if (IsValidPos(tileX, tileZ))
221                data[tileX + tileZ * width] = dataVal;
222        }
223
224        public Tile GetTile(int tileX, int tileZ)
225        {
226            return IsValidPos(tileX, tileZ) ? registeredTiles[tiles[tileX + tileZ * width]] : registeredTiles[TILE_VOID];
227        }
228
229        public byte GetData(int tileX, int tileZ)
230        {
231            return IsValidPos(tileX, tileZ) ? data[tileX + tileZ * width] : (byte)0;
232        }
233
234        public void AddEntity(Entity ent, float xPos, float zPos)
235        {
236            int xTile = (int)(xPos / Viewport.TILESIZE);
237            int zTile = (int)(zPos / Viewport.TILESIZE);
238
239            if (!IsValidPos(xTile, zTile)) return;
240
241            ent.X = xPos;
242            ent.Z = zPos;
243
244            ent.Init();
245
246            if (typeof(TileEntity).IsAssignableFrom(ent.GetType()))
247                tileEntities.Add((TileEntity)ent);
248            else
249                entities.Add(ent);
250
251            if (typeof(Unit).IsAssignableFrom(ent.GetType()))
252            {
253                Unit u = (Unit)ent;
254                units[u.Owner.Team.ID].Add(u);
255            }
256
257            InsertEntity(ent, xTile, zTile);
258        }
259
260        private void InsertEntity(Entity ent, int xTile, int zTile)
261        {
262            entitiesInTiles[xTile + zTile * width].Add(ent);
263        }
264
265        private void TakeEntity(Entity ent, int xTile, int zTile)
266        {
267            entitiesInTiles[xTile + zTile * width].Remove(ent);
268        }
269
270        private void RemoveEntity(Entity ent)
271        {
272            ent.OnRemoved();
273
274            entities.Remove(ent);
275
276            TakeEntity(ent, (int)(ent.X / Viewport.TILESIZE), (int)(ent.Z / Viewport.TILESIZE));
277        }
278
279        public TileEntity GetTileEntity(int xTile, int zTile)
280        {
281            List<Entity> ents = entitiesInTiles[xTile + zTile * width];
282            if (ents.Count > 0)
283                return ents[0] as TileEntity;
284
285            return null;
286        }
287
288        public List<Unit> GetUnitsWithinScreenSpace(float x0, float y0, float x1, float y1, Team team)
289        {
290            List<Unit> result = new List<Unit>();
291
292            foreach (Unit u in units[team.ID])
293            {
294                if (u.IsSelectable && u.IntersectsWithScreenSpace(x0, y0, x1, y1))
295                    result.Add(u);
296            }
297
298            return result;
299        }
300
301        public List<BoundingRectangle> GetCollidables(Entity ent, BoundingRectangle br = null)
302        {
303            List<BoundingRectangle> result = new List<BoundingRectangle>();
304
305            BoundingRectangle entBR = br == null ? ent.BoundingRectangle : br;
306
307            int x0 = (int)(entBR.XLeft / Viewport.TILESIZE) - 1;
308            int z0 = (int)(entBR.ZFar / Viewport.TILESIZE) - 1;
309            int x1 = (int)(entBR.XRight / Viewport.TILESIZE) + 1;
310            int z1 = (int)(entBR.ZNear / Viewport.TILESIZE) + 1;
311
312            for (int z = z0; z <= z1; z++)
313            {
314                if (z < 0 || z >= height) continue;
315                for (int x = x0; x <= x1; x++)
316                {
317                    if (x < 0 || x >= width) continue;
318
319                    List<Entity> entits = entitiesInTiles[x + z * width];
320
321                    foreach (Entity e in entits)
322                    {
323                        if (e != ent && entBR.Intersects(e.BoundingRectangle))
324                            e.AddBoundingRect(ref result, ent);
325                    }
326
327                    Tile t = registeredTiles[tiles[x + z * width]];
328                    if (t.IsSolid && t.GetBoundingRect(x, z).Intersects(entBR))
329                        t.AddBoundingRect(ref result, x, z);
330                }
331            }
332
333            return result;
334        }
335
336
337        public List<Unit> GetNearbyEnemyUnits(Team enemyTeam, int xTile, int zTile, int radius)
338        {
339            List<Unit> result = new List<Unit>();
340
341            for (int z = zTile - radius; z <= zTile + radius; z++)
342            {
343                if (z < 0 || z >= height) continue;
344                for (int x = xTile - radius; x <= xTile + radius; x++)
345                {
346                    if (x < 0 || x >= width) continue;
347
348                    List<Entity> ents = entitiesInTiles[x + z * width];
349
350                    foreach (Entity ent in ents)
351                    {
352                        Mob m = ent as Mob;
353                        if (m != null && m.Owner.Team.ID == enemyTeam.ID)
354                            result.Add(m);
355                    }
356                }
357            }
358
359            return result;
360        }
361
362        private bool IsValidPos(int tileX, int tileZ)
363        {
364            return (tileX >= 0 && tileZ >= 0 && tileX < width && tileZ < height);
365        }
366
367        public bool[] BuildSolidnessTable(Mob mob, bool excludeEndSolidness = false, int xEnd = 0, int zEnd = 0)
368        {
369            bool[] result = new bool[tiles.Length];
370
371            for (int i = 0; i < tiles.Length; i++)
372            {
373                if (excludeEndSolidness && xEnd == i % width && zEnd == i / width)
374                {
375                    result[i] = false;
376                    continue;
377                }
378
379                result[i] = tiles[i] == TILE_VOID || registeredTiles[tiles[i]].IsSolid;
380
381                List<Entity> entInTiles = entitiesInTiles[i];
382
383                if (entInTiles.Count > 0)
384                {
385                    TileEntity te = entInTiles[0] as TileEntity;
386                    result[i] = te != null && te.Blocks(mob);
387                }
388            }
389
390            return result;
391        }
392    }
393}
Note: See TracBrowser for help on using the repository browser.