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

Revision 4590, 12.9 KB checked in by dezhidki, 10 years ago (diff)

Puut lisätty, woodcutter toimii.

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            foreach (Entity ent in entities)
180            {
181                int xTile_old = (int)(ent.X / Viewport.TILESIZE);
182                int zTile_old = (int)(ent.Z / Viewport.TILESIZE);
183
184                ent.Update();
185
186                if (ent.Removed)
187                {
188                    RemoveEntity(ent);
189                    TakeEntity(ent, xTile_old, zTile_old);
190                    continue;
191                }
192
193                int xTile = (int)(ent.X / Viewport.TILESIZE);
194                int zTile = (int)(ent.Z / Viewport.TILESIZE);
195
196                if (xTile != xTile_old || zTile != zTile_old)
197                {
198                    TakeEntity(ent, xTile_old, zTile_old);
199                    InsertEntity(ent, xTile, zTile);
200                }
201            }
202        }
203
204        public void SetPlayer(Player player, int id)
205        {
206            players[id] = player;
207        }
208
209        public void SetTile(int tileX, int tileZ, int tileID)
210        {
211            if (IsValidPos(tileX, tileZ))
212                tiles[tileX + tileZ * width] = tileID;
213        }
214
215        public void SetData(int tileX, int tileZ, byte dataVal)
216        {
217            if (IsValidPos(tileX, tileZ))
218                data[tileX + tileZ * width] = dataVal;
219        }
220
221        public Tile GetTile(int tileX, int tileZ)
222        {
223            return IsValidPos(tileX, tileZ) ? registeredTiles[tiles[tileX + tileZ * width]] : registeredTiles[TILE_VOID];
224        }
225
226        public byte GetData(int tileX, int tileZ)
227        {
228            return IsValidPos(tileX, tileZ) ? data[tileX + tileZ * width] : (byte)0;
229        }
230
231        public void AddEntity(Entity ent, float xPos, float zPos)
232        {
233            int xTile = (int)(xPos / Viewport.TILESIZE);
234            int zTile = (int)(zPos / Viewport.TILESIZE);
235
236            if (!IsValidPos(xTile, zTile)) return;
237
238            ent.X = xPos;
239            ent.Z = zPos;
240
241            ent.Init();
242
243            if (typeof(TileEntity).IsAssignableFrom(ent.GetType()))
244                tileEntities.Add((TileEntity)ent);
245            else
246                entities.Add(ent);
247
248            if (typeof(Unit).IsAssignableFrom(ent.GetType()))
249            {
250                Unit u = (Unit)ent;
251                units[u.Owner.Team.ID].Add(u);
252            }
253
254            InsertEntity(ent, xTile, zTile);
255        }
256
257        private void InsertEntity(Entity ent, int xTile, int zTile)
258        {
259            entitiesInTiles[xTile + zTile * width].Add(ent);
260        }
261
262        private void TakeEntity(Entity ent, int xTile, int zTile)
263        {
264            entitiesInTiles[xTile + zTile * width].Remove(ent);
265        }
266
267        private void RemoveEntity(Entity ent)
268        {
269            ent.OnRemoved();
270
271            entities.Remove(ent);
272
273            TakeEntity(ent, (int)(ent.X / Viewport.TILESIZE), (int)(ent.Z / Viewport.TILESIZE));
274        }
275
276        //public Vector2 GetNearestEmptyTileWorldPos(int xTile, int zTile, Entity ent)
277        //{
278        //    int xt = 0, zt = 0;
279        //    for (int z = zTile - 1; z <= zTile + 1; z++)
280        //    {
281        //        for (int x = xTile - 1; x <= xTile + 1; x++)
282        //        {
283        //            if (x == xTile && z == zTile) continue;
284        //            int tp = xTile + zTile * width;
285
286        //            if (registeredTiles[tiles[tp]].IsSolid) continue;
287
288        //            TileEntity te = GetTileEntity(xTile, zTile);
289        //            if (te != null && te.IsSolidTo(ent)) continue;
290        //            xt = x;
291        //            zt = z;
292        //        }
293        //    }
294
295        //    if (xt != 0 || zt != 0)
296        //        return new Vector2(xt * Viewport.TILESIZE + 8.0F, zt * Viewport.TILESIZE + 8.0F);
297
298        //    return new Vector2(-1, -1);
299        //}
300
301        public TileEntity GetTileEntity(int xTile, int zTile)
302        {
303            List<Entity> ents = entitiesInTiles[xTile + zTile * width];
304            if (ents.Count > 0)
305                return ents[0] as TileEntity;
306
307            return null;
308        }
309
310        public List<Unit> GetUnitsWithinScreenSpace(float x0, float y0, float x1, float y1, Player player)
311        {
312            List<Unit> result = new List<Unit>();
313
314            foreach (Unit u in units[player.Team.ID])
315            {
316                if (u.IsSelectable && u.IntersectsWithScreenSpace(x0, y0, x1, y1))
317                    result.Add(u);
318            }
319
320            return result;
321        }
322
323        public List<BoundingRectangle> GetCollidables(Entity ent, BoundingRectangle br = null)
324        {
325            List<BoundingRectangle> result = new List<BoundingRectangle>();
326
327            BoundingRectangle entBR = br == null ? ent.BoundingRectangle : br;
328
329            int x0 = (int)(entBR.XLeft / Viewport.TILESIZE) - 1;
330            int z0 = (int)(entBR.ZFar / Viewport.TILESIZE) - 1;
331            int x1 = (int)(entBR.XRight / Viewport.TILESIZE) + 1;
332            int z1 = (int)(entBR.ZNear / Viewport.TILESIZE) + 1;
333
334            for (int z = z0; z <= z1; z++)
335            {
336                if (z < 0 || z >= height) continue;
337                for (int x = x0; x <= x1; x++)
338                {
339                    if (x < 0 || x >= width) continue;
340
341                    List<Entity> entits = entitiesInTiles[x + z * width];
342
343                    foreach (Entity e in entits)
344                    {
345                        if (e != ent && entBR.Intersects(e.BoundingRectangle))
346                            e.AddBoundingRect(ref result, ent);
347                    }
348
349                    Tile t = registeredTiles[tiles[x + z * width]];
350                    if (t.IsSolid && t.GetBoundingRect(x, z).Intersects(entBR))
351                        t.AddBoundingRect(ref result, x, z);
352                }
353            }
354
355            return result;
356        }
357
358        private bool IsValidPos(int tileX, int tileZ)
359        {
360            return (tileX >= 0 && tileZ >= 0 && tileX < width && tileZ < height);
361        }
362
363        public bool[] BuildSolidnessTable(Mob mob, bool excludeEndSolidness = false, int xEnd = 0, int zEnd = 0)
364        {
365            bool[] result = new bool[tiles.Length];
366
367            for (int i = 0; i < tiles.Length; i++)
368            {
369                if (excludeEndSolidness && xEnd == i % width && zEnd == i / width)
370                {
371                    result[i] = false;
372                    continue;
373                }
374
375                result[i] = tiles[i] == TILE_VOID || registeredTiles[tiles[i]].IsSolid;
376
377                List<Entity> entInTiles = entitiesInTiles[i];
378
379                if (entInTiles.Count > 0)
380                {
381                    TileEntity te = entInTiles[0] as TileEntity;
382                    result[i] = te != null && te.Blocks(mob);
383                }
384            }
385
386            return result;
387        }
388    }
389}
Note: See TracBrowser for help on using the repository browser.