source: 2013/27/JaakkoL/RampageRebellion/RampageRebellion/RampageRebellion/RREnemySpawner.cs @ 4463

Revision 4463, 10.0 KB checked in by jaollipa, 8 years ago (diff)

RREnemySpawner slightly redesigned.

Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using System.Xml;
6using System.IO;
7using System.Threading;
8using System.Diagnostics;
9using Jypeli;
10using Jypeli.Assets;
11using Jypeli.Controls;
12using Jypeli.Effects;
13using Jypeli.Widgets;
14
15/* Teemun TODO
16 * - Arcade Mode: high score
17 * - Enemy AI
18 * - Common enemy framework
19 * - Actual level design: -THR
20 */
21public class RREnemySpawner
22{
23    private string gameMode = "";
24    private Thread spawnerThread;
25    private bool isPaused = false;
26
27    public RREnemySpawner(string requestedGameMode)
28    {
29        gameMode = requestedGameMode;
30
31        if (gameMode == "arcade")
32        {
33            spawnerThread = new Thread(arcade);
34        }
35        else if (gameMode == "levels")
36        {
37            List<RRLevel> levelList = new List<RRLevel>();
38            levelList = loadLevelsFromXML();
39            spawnerThread = new Thread(delegate() { executeLevelList(levelList); });
40        }
41        else
42        {
43            // Throw an exception!
44        }
45
46        spawnerThread.Start();
47        spawnerThread.IsBackground = true;
48    }
49
50    public void arcade()
51    {
52        Stopwatch stopwatch = new Stopwatch();
53        stopwatch.Start();
54
55        double multiplier = 1.0;
56
57        RampageRebellion game = RampageRebellion.getGame();
58        Jypeli.Timer t = new Jypeli.Timer();
59        t.Interval = 1.0;
60
61        t.Timeout += delegate {
62            // The multiplier function
63            multiplier = (Math.Pow(1.1, (double)stopwatch.ElapsedMilliseconds / 10000));
64            Console.WriteLine(multiplier);
65            game.Add(new SmallEnemy(inCenteredXCoordinates(RandomGen.NextInt(-300, 300)), 
66                                    inRelativeYCoordinates(RandomGen.NextInt(0, 200), "Small"),
67                                    multiplier));
68            t.Interval = RandomGen.NextDouble(1.0, 2.0);
69        };
70        t.Start();
71
72        // Stops the stopwatch when paused, and resumes it when unpaused.
73        while (true)
74        {
75            if (isPaused) stopwatch.Stop();
76            while (isPaused) Thread.Sleep(1);
77            stopwatch.Start();
78        }
79    }
80
81    private List<RRLevel> loadLevelsFromXML()
82    {
83        // The string to contain the XML data
84        String XMLFile;
85
86        // The type of the enemy to be created
87        String enemyType = "";
88
89        // The coordinates for the enemy
90        double x = 0.0;
91        double y = 0.0;
92
93        List<RRLevel> levelList = new List<RRLevel>();
94
95        // Read the XML data from the file
96        using (StreamReader sr = new StreamReader("Content/levels.xml"))
97        {
98            XMLFile = sr.ReadToEnd();
99        }
100
101        using (XmlReader reader = XmlReader.Create(new StringReader(XMLFile)))
102        {
103            while (reader.ReadToFollowing("level"))
104            {
105                // Creates a new level object to which the waves are added
106                RRLevel currentLevel = new RRLevel();
107
108                // The XMLReader first reads to the first element and then to that element's siblings
109                // This way it doesn't "leak" and read every element in the file
110                reader.ReadToFollowing("wave");
111                do
112                {
113                    reader.ReadToFollowing("enemy");
114                    do
115                    {
116                        reader.MoveToFirstAttribute();      // The type of the enemy (small, medium etc.)
117                        enemyType = reader.Value;
118                        reader.MoveToNextAttribute();       // The x-coordinate
119                        x = Convert.ToDouble(reader.Value);
120                        reader.MoveToNextAttribute();       // The y-coordinate
121                        y = Convert.ToDouble(reader.Value);
122
123                        // In the relative coordinates, the top left corner of the enemy
124                        // is in the top left corner of the screen when (x, y) = (0, 0)
125                        x = inCenteredXCoordinates(x);
126                        y = inRelativeYCoordinates(y, enemyType);
127
128                        // Adds an enemy to the current RRLevel object
129                        if (enemyType == "Small") currentLevel.addEnemy(new SmallEnemy(x, y));
130                        else if (enemyType == "Medium") currentLevel.addEnemy(new MediumEnemy(x, y));
131                        else if (enemyType == "Big") currentLevel.addEnemy(new BigEnemy(x, y));
132                        else if (enemyType == "Boss") currentLevel.addEnemy(new BossEnemy(x, y));
133                        else
134                        {
135                            // Throw an exception, since the type of the enemy is unknown.
136                        }
137
138                    } while (reader.ReadToNextSibling("enemy"));
139
140                    // Notifies the Level object that we're moving to a new wave
141                    currentLevel.initNewWave();
142
143                } while (reader.ReadToNextSibling("wave"));
144
145                // Adds the current Level object to the list of level objects
146                levelList.Add(currentLevel);
147                currentLevel = null;
148            }
149        }
150
151        // Debugging: Reads back the structure
152        /*foreach (RRLevel level in levelList)
153        {
154            Console.WriteLine("Level");
155            level.listAll();
156        }*/
157
158        return levelList;
159    }
160
161    private void executeLevelList(List<RRLevel> levelList)
162    {
163        RampageRebellion.getGame().Gravity = new Vector(0, 0);
164        while (levelList.Count > 0)
165        {
166            while (levelList[0].wavesLeft() > 0)
167            {
168                levelList[0].spawnThisWave();
169
170                // Wait until there are no more enemies, and then spawn the next wave.
171                while (levelList[0].enemiesLeftInCurrentWave() > 0) { Thread.Sleep(1); }
172                levelList[0].removeThisWave();
173
174                // Wait for two seconds before launching the next wave.
175                Thread.Sleep(2000);
176
177                // Play wave end music
178                SoundEffect waveIncoming = Jypeli.Game.LoadSoundEffect("Bomb2-Warp2");
179                waveIncoming.Play();
180
181                Thread.Sleep(2890);
182            }
183
184            // Remove the finished level
185            levelList.RemoveAt(0);
186
187            RampageRebellion.getGame().UpgradeMenu();
188        }
189
190        // We're done!
191        RampageRebellion.getGame().GameEnd();
192    }
193
194    // The first correction term gets the enemy's center to the top left screen
195    // and the second term moves the enemy so that it isn't immediately destroyed.
196    private double inRelativeXCoordinates(double originalX, string enemyType)
197    {
198        return originalX - 517 + (getEnemySizeByType(enemyType) / 2);
199    }
200
201    private double inRelativeYCoordinates(double originalY, string enemyType)
202    {
203        return (-originalY) + 485 - (getEnemySizeByType(enemyType) / 2);
204    }
205
206    private double inCenteredXCoordinates(double originalX)
207    {
208        return originalX - 190;
209    }
210    private double getEnemySizeByType(string enemyType)
211    {
212        if (enemyType == "Small") return RampageRebellion.SMALLENEMY_SIZE;
213        else if (enemyType == "Medium") return RampageRebellion.MEDENEMY_SIZE;
214        else if (enemyType == "Big") return RampageRebellion.BIGENEMY_SIZE;
215        else if (enemyType == "Boss") return RampageRebellion.BOSS_SIZE;
216        else return 0; // Shouldn't ever happen!
217    }
218
219    private class RRLevel
220    {
221        private List<RRWave> waveList = new List<RRWave>();
222        private RRWave currentWave = new RRWave();
223
224        public void addEnemy(RREnemy enemy)
225        {
226            currentWave.addEnemy(enemy);
227        }
228
229        // Called when the parser is moving to the next wave, so the current wave should be added to the list
230        public void initNewWave()
231        {
232            waveList.Add(currentWave);
233
234            // Resets the wave
235            currentWave = null;
236            currentWave = new RRWave();
237        }
238
239        public void spawnThisWave()
240        {
241            if (waveList.Count > 0)
242            {
243                waveList[0].spawn();
244            }
245            else
246            {
247                // Throw an exception!
248            }
249        }
250
251        // Mostly for debugging; should use spawnThisWave() instead
252        public void spawnAllWaves()
253        {
254            foreach (RRWave wave in waveList)
255            {
256                wave.spawn();
257            }
258        }
259
260        public int enemiesLeftInCurrentWave()
261        {
262            return waveList[0].enemiesLeft();
263        }
264
265        // Mostly for debugging purposes
266        public void listAll()
267        {
268            foreach (RRWave wave in waveList)
269            {
270                Console.WriteLine("\tWave");
271                wave.listAll();
272            }
273        }
274
275        public int wavesLeft()
276        {
277            return waveList.Count;
278        }
279
280        public void removeThisWave()
281        {
282            waveList.RemoveAt(0);
283        }
284    }
285
286    private class RRWave
287    {
288        private List<RREnemy> enemyList = new List<RREnemy>();
289
290        public void addEnemy(RREnemy enemy)
291        {
292            enemyList.Add(enemy);
293        }
294
295        public void spawn()
296        {
297            RampageRebellion game = RampageRebellion.getGame();
298
299            foreach (RREnemy enemy in enemyList)
300            {
301                game.Add(enemy);
302            }
303        }
304
305        public int enemiesLeft()
306        {
307            // We must manually remove destroyed enemies
308            enemyList.RemoveAll(delegate(RREnemy e)
309            {
310                if (e.IsDestroyed) return true;
311                else return false;
312            });
313            return enemyList.Count;
314        }
315
316        public void listAll()
317        {
318            foreach (RREnemy enemy in enemyList)
319            {
320                Console.WriteLine("\t\tEnemy");
321            }
322        }
323    }
324}
Note: See TracBrowser for help on using the repository browser.