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

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