1 | using System; |
---|
2 | using System.Collections.Generic; |
---|
3 | using System.Linq; |
---|
4 | using System.Text; |
---|
5 | using System.Xml; |
---|
6 | using System.IO; |
---|
7 | using System.Threading; |
---|
8 | using System.Diagnostics; |
---|
9 | using Jypeli; |
---|
10 | using Jypeli.Assets; |
---|
11 | using Jypeli.Controls; |
---|
12 | using Jypeli.Effects; |
---|
13 | using Jypeli.Widgets; |
---|
14 | |
---|
15 | /* Teemun TODO |
---|
16 | * - Arcade Mode: high score |
---|
17 | * - Enemy AI |
---|
18 | * - Common enemy framework |
---|
19 | * - Actual level design: -THR |
---|
20 | */ |
---|
21 | public class RREnemySpawner |
---|
22 | { |
---|
23 | private string gameMode = ""; |
---|
24 | private Thread spawnerThread; |
---|
25 | public 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.01, (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. // DOESN'T WORK!! |
---|
73 | while (true) |
---|
74 | { |
---|
75 | if (isPaused) { stopwatch.Stop(); Console.WriteLine("Stopped"); } |
---|
76 | while (isPaused) { Thread.Sleep(1); } |
---|
77 | if (!isPaused) { stopwatch.Start(); Console.WriteLine("Resumed"); } |
---|
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 | while (levelList.Count > 0) |
---|
164 | { |
---|
165 | while (levelList[0].wavesLeft() > 0) |
---|
166 | { |
---|
167 | levelList[0].spawnThisWave(); |
---|
168 | |
---|
169 | // Wait until there are no more enemies, and then spawn the next wave. |
---|
170 | while (levelList[0].enemiesLeftInCurrentWave() > 0) { Thread.Sleep(1); } |
---|
171 | levelList[0].removeThisWave(); |
---|
172 | |
---|
173 | // Wait for two seconds before launching the next wave. |
---|
174 | Thread.Sleep(2000); |
---|
175 | |
---|
176 | // Play wave end music |
---|
177 | SoundEffect waveIncoming = Jypeli.Game.LoadSoundEffect("Bomb2-Warp2"); |
---|
178 | waveIncoming.Play(); |
---|
179 | |
---|
180 | Thread.Sleep(2890); |
---|
181 | |
---|
182 | while (isPaused) { Thread.Sleep(1); } |
---|
183 | } |
---|
184 | |
---|
185 | // Remove the finished level |
---|
186 | levelList.RemoveAt(0); |
---|
187 | |
---|
188 | RampageRebellion.getGame().UpgradeMenu(); |
---|
189 | } |
---|
190 | |
---|
191 | // We're done! |
---|
192 | RampageRebellion.getGame().GameEnd(); |
---|
193 | } |
---|
194 | |
---|
195 | // The first correction term gets the enemy's center to the top left screen |
---|
196 | // and the second term moves the enemy so that it isn't immediately destroyed. |
---|
197 | private double inRelativeXCoordinates(double originalX, string enemyType) |
---|
198 | { |
---|
199 | return originalX - 517 + (getEnemySizeByType(enemyType) / 2); |
---|
200 | } |
---|
201 | |
---|
202 | private double inRelativeYCoordinates(double originalY, string enemyType) |
---|
203 | { |
---|
204 | return (-originalY) + 485 - (getEnemySizeByType(enemyType) / 2); |
---|
205 | } |
---|
206 | |
---|
207 | private double inCenteredXCoordinates(double originalX) |
---|
208 | { |
---|
209 | return originalX - 190; |
---|
210 | } |
---|
211 | private double getEnemySizeByType(string enemyType) |
---|
212 | { |
---|
213 | if (enemyType == "Small") return RampageRebellion.SMALLENEMY_SIZE; |
---|
214 | else if (enemyType == "Medium") return RampageRebellion.MEDENEMY_SIZE; |
---|
215 | else if (enemyType == "Big") return RampageRebellion.BIGENEMY_SIZE; |
---|
216 | else if (enemyType == "Boss") return RampageRebellion.BOSS_SIZE; |
---|
217 | else return 0; // Shouldn't ever happen! |
---|
218 | } |
---|
219 | |
---|
220 | private class RRLevel |
---|
221 | { |
---|
222 | private List<RRWave> waveList = new List<RRWave>(); |
---|
223 | private RRWave currentWave = new RRWave(); |
---|
224 | |
---|
225 | public void addEnemy(RREnemy enemy) |
---|
226 | { |
---|
227 | currentWave.addEnemy(enemy); |
---|
228 | } |
---|
229 | |
---|
230 | // Called when the parser is moving to the next wave, so the current wave should be added to the list |
---|
231 | public void initNewWave() |
---|
232 | { |
---|
233 | waveList.Add(currentWave); |
---|
234 | |
---|
235 | // Resets the wave |
---|
236 | currentWave = null; |
---|
237 | currentWave = new RRWave(); |
---|
238 | } |
---|
239 | |
---|
240 | public void spawnThisWave() |
---|
241 | { |
---|
242 | if (waveList.Count > 0) |
---|
243 | { |
---|
244 | waveList[0].spawn(); |
---|
245 | } |
---|
246 | else |
---|
247 | { |
---|
248 | // Throw an exception! |
---|
249 | } |
---|
250 | } |
---|
251 | |
---|
252 | // Mostly for debugging; should use spawnThisWave() instead |
---|
253 | public void spawnAllWaves() |
---|
254 | { |
---|
255 | foreach (RRWave wave in waveList) |
---|
256 | { |
---|
257 | wave.spawn(); |
---|
258 | } |
---|
259 | } |
---|
260 | |
---|
261 | public int enemiesLeftInCurrentWave() |
---|
262 | { |
---|
263 | return waveList[0].enemiesLeft(); |
---|
264 | } |
---|
265 | |
---|
266 | // Mostly for debugging purposes |
---|
267 | public void listAll() |
---|
268 | { |
---|
269 | foreach (RRWave wave in waveList) |
---|
270 | { |
---|
271 | Console.WriteLine("\tWave"); |
---|
272 | wave.listAll(); |
---|
273 | } |
---|
274 | } |
---|
275 | |
---|
276 | public int wavesLeft() |
---|
277 | { |
---|
278 | return waveList.Count; |
---|
279 | } |
---|
280 | |
---|
281 | public void removeThisWave() |
---|
282 | { |
---|
283 | waveList.RemoveAt(0); |
---|
284 | } |
---|
285 | } |
---|
286 | |
---|
287 | private class RRWave |
---|
288 | { |
---|
289 | private List<RREnemy> enemyList = new List<RREnemy>(); |
---|
290 | |
---|
291 | public void addEnemy(RREnemy enemy) |
---|
292 | { |
---|
293 | enemyList.Add(enemy); |
---|
294 | } |
---|
295 | |
---|
296 | public void spawn() |
---|
297 | { |
---|
298 | RampageRebellion game = RampageRebellion.getGame(); |
---|
299 | |
---|
300 | foreach (RREnemy enemy in enemyList) |
---|
301 | { |
---|
302 | game.Add(enemy); |
---|
303 | } |
---|
304 | } |
---|
305 | |
---|
306 | public int enemiesLeft() |
---|
307 | { |
---|
308 | // We must manually remove destroyed enemies |
---|
309 | enemyList.RemoveAll(delegate(RREnemy e) |
---|
310 | { |
---|
311 | if (e.IsDestroyed) return true; |
---|
312 | else return false; |
---|
313 | }); |
---|
314 | return enemyList.Count; |
---|
315 | } |
---|
316 | |
---|
317 | public void listAll() |
---|
318 | { |
---|
319 | foreach (RREnemy enemy in enemyList) |
---|
320 | { |
---|
321 | Console.WriteLine("\t\tEnemy"); |
---|
322 | } |
---|
323 | } |
---|
324 | } |
---|
325 | } |
---|