source: advance-wars/src/com/medievaltech/advancewars/GameView.java@ 331d180

Last change on this file since 331d180 was 41c11dd, checked in by dportnoy <devnull@…>, 13 years ago

Added cities to the game, moved the map to a new static class, and added incomplete support for capturing cities with soldiers.

  • Property mode set to 100644
File size: 14.9 KB
Line 
1package com.medievaltech.advancewars;
2
3import java.io.*;
4import java.util.*;
5
6import com.medievaltech.advancewars.Enum.*;
7import com.medievaltech.unit.*;
8import com.medievaltech.gui.*;
9
10import android.content.Context;
11import android.graphics.*;
12import android.os.*;
13import android.view.*;
14import android.util.AttributeSet;
15import android.util.Log;
16import android.widget.TextView;
17
18class GameView extends SurfaceView implements SurfaceHolder.Callback {
19
20 class DrawingThread extends Thread {
21 public GameState mGameState;
22
23 //maybe make this private and make an accessor for it
24 //public Map mMap;
25
26 public Tile grassTile, oceanTile;
27
28 public Turn mTurn;
29
30 public Player enemy;
31 private Unit selectedUnit;
32
33 private int mCanvasHeight = 1;
34 private int mCanvasWidth = 1;
35
36 private Paint mLinePaint, mTextPaint, mButtonPaint, mTilePaint1,
37 mTilePaint2, mSelectionPaint, mUnitPaint1, mUnitPaint2;
38
39 /** Indicate whether the surface has been created & is ready to draw */
40 private boolean mRun = false;
41
42 /** Handle to the surface manager object we interact with */
43 private SurfaceHolder mSurfaceHolder;
44
45 private com.medievaltech.gui.Window wndMainMenu;
46
47 public DrawingThread(SurfaceHolder surfaceHolder, Context context, Handler handler) {
48 mSurfaceHolder = surfaceHolder;
49
50 mLinePaint = new Paint();
51 mLinePaint.setAntiAlias(true);
52 mLinePaint.setARGB(255, 0, 255, 0);
53
54 mTextPaint = new Paint();
55 mTextPaint.setAntiAlias(true);
56 mTextPaint.setARGB(255, 255, 255, 255);
57 mTextPaint.setTextSize(12);
58 mTextPaint.setTextAlign(Paint.Align.CENTER);
59
60 mButtonPaint = new Paint();
61 mButtonPaint.setAntiAlias(true);
62 mButtonPaint.setARGB(255, 0, 0, 0);
63 mButtonPaint.setTextSize(20);
64 mButtonPaint.setTextAlign(Paint.Align.CENTER);
65
66 mTilePaint1 = new Paint();
67 mTilePaint1.setAntiAlias(true);
68 mTilePaint1.setARGB(255, 0, 255, 0);
69
70 mTilePaint2 = new Paint();
71 mTilePaint2.setAntiAlias(true);
72 mTilePaint2.setARGB(255, 0, 0, 255);
73
74 mUnitPaint1 = new Paint();
75 mUnitPaint1.setAntiAlias(true);
76 mUnitPaint1.setARGB(255, 255, 0, 0);
77
78 mUnitPaint2 = new Paint();
79 mUnitPaint2.setAntiAlias(true);
80 mUnitPaint2.setARGB(255, 160, 160, 255);
81
82 mSelectionPaint = new Paint();
83 mSelectionPaint.setAntiAlias(true);
84 mSelectionPaint.setARGB(255, 255, 127, 0);
85
86 Player.neutralColor = new Paint();
87 Player.neutralColor.setAntiAlias(true);
88 Player.neutralColor.setARGB(255, 127, 127, 127);
89
90 wndMainMenu = new com.medievaltech.gui.Window(0, 0, 320, 450);;
91 wndMainMenu.addGUIObject("txtTitle", new Text("Main Menu", 100, 30, 120, 20, mTextPaint));
92 wndMainMenu.addGUIObject("btnNewGame", new Button("New Game", 100, 90, 120, 20, mLinePaint, mButtonPaint));
93 wndMainMenu.addGUIObject("btnLoadGame", new Button("Load Game", 100, 125, 120, 20, mLinePaint, mButtonPaint));
94 wndMainMenu.addGUIObject("btnMapEditor", new Button("Map Editor", 100, 160, 120, 20, mLinePaint, mButtonPaint));
95 wndMainMenu.addGUIObject("btnQuit", new Button("Quit", 100, 195, 120, 20, mLinePaint, mButtonPaint));
96
97 grassTile = new Tile(mTilePaint1, TerrainType.LAND);
98 oceanTile = new Tile(mTilePaint2, TerrainType.SEA);
99
100 Static.map = new Map(grassTile, 6, 8, new Point(10, 25));
101
102 boolean land = true;
103
104 for(int x=0; x<Static.map.getWidth(); x++) {
105 for(int y=0; y<Static.map.getHeight(); y++) {
106 if(land)
107 Static.map.setTile(x, y, new Tile(grassTile, new Point(x, y)));
108 else
109 Static.map.setTile(x, y, new Tile(oceanTile, new Point(x, y)));
110 land = !land;
111 }
112 land = !land;
113 }
114
115 Player humanPlayer = new Player("Human", mUnitPaint1);
116 enemy = new Player("Comp", mUnitPaint2);
117
118 Static.map.getTile(0, 0).addUnit(new Soldier(enemy));
119 Static.map.getTile(2, 3).addUnit(new Soldier(humanPlayer));
120 Static.map.getTile(5, 6).addUnit(new Soldier(humanPlayer));
121
122 Static.map.getTile(4, 4).addBuilding(new City());
123
124 mTurn = Turn.YOUR_TURN;
125
126 mGameState = GameState.MAIN_MENU;
127 }
128
129 /**
130 * Starts the game, setting parameters for the current difficulty.
131 */
132 // I don't think this gets called now. maybe we should call it in the thread constructor
133 public void doStart() {
134 synchronized (mSurfaceHolder) {
135 Log.i("AdvanceWars", "Player's turn starting now");
136 mGameState = GameState.MAIN_MENU;
137 }
138 }
139
140 @Override
141 public void run() {
142 while (mRun) {
143 Canvas c = null;
144 try {
145 c = mSurfaceHolder.lockCanvas(null);
146 synchronized(mSurfaceHolder) {
147 doLogic();
148 doDraw(c);
149 }
150 } finally {
151 // do this in a finally so that if an exception is thrown
152 // during the above, we don't leave the Surface in an
153 // inconsistent state
154 if (c != null) {
155 mSurfaceHolder.unlockCanvasAndPost(c);
156 }
157 }
158 }
159 }
160
161 /**
162 * Used to signal the thread whether it should be running or not.
163 * Passing true allows the thread to run; passing false will shut it
164 * down if it's already running. Calling start() after this was most
165 * recently called with false will result in an immediate shutdown.
166 *
167 * @param b true to run, false to shut down
168 */
169 public void setRunning(boolean b) {
170 mRun = b;
171 }
172
173 public void setGameState(GameState state) {
174 synchronized (mSurfaceHolder) {
175 mGameState = state;
176 }
177 }
178
179 /* Callback invoked when the surface dimensions change. */
180 public void setSurfaceSize(int width, int height) {
181 // synchronized to make sure these all change atomically
182 synchronized (mSurfaceHolder) {
183 mCanvasWidth = width;
184 mCanvasHeight = height;
185
186 Log.i("AdvanceWars", "width: "+mCanvasWidth+", height: "+mCanvasHeight);
187 }
188 }
189
190 private void doLogic() {
191 if(mTurn == Turn.YOUR_TURN)
192 return;
193
194 switch(mGameState) {
195 case BATTLE_MAP:
196 Iterator<Unit> iter = enemy.getControlledUnits().iterator();
197 Unit cur;
198 int x, y;
199
200 Log.i("AdvanceWars", "starting to move enemy units");
201 while(iter.hasNext()) {
202 cur = iter.next();
203 x = cur.location.x;
204 y = cur.location.y;
205
206 Log.i("AdvanceWars", "moving enemy unit");
207
208 //any unit that's in the way is removed (needs to be changed eventuallyy)
209 Static.map.getTile(x, y).removeUnit();
210 Static.map.getTile(x, y+1).addUnit(cur);
211 }
212 Log.i("AdvanceWars", "finished moving enemy units");
213
214
215 mTurn = Turn.YOUR_TURN;
216 break;
217 }
218 }
219
220 /**
221 * Draws the ship, fuel/speed bars, and background to the provided
222 * Canvas.
223 */
224 private void doDraw(Canvas canvas) {
225 canvas.drawColor(Color.BLACK);
226
227 switch(mGameState) {
228 case MAIN_MENU:
229 wndMainMenu.draw(canvas);
230 break;
231 case BATTLE_MAP:
232 mTextPaint.setTextSize(12);
233
234 Static.map.draw(canvas);
235
236 if(selectedUnit != null) {
237 for(Point p : selectedUnit.getMovementRange()) {
238 canvas.drawRect(p.x*50+10, p.y*50+25, p.x*50+50+10, p.y*50+50+25, mSelectionPaint);
239 }
240 }
241
242 Static.map.drawBuildings(canvas);
243 Static.map.drawUnits(canvas);
244
245 break;
246 }
247 }
248 }
249
250 /** Pointer to the text view to display "Paused.." etc. */
251 private TextView mStatusText;
252
253 /** The thread that actually draws the animation */
254 private DrawingThread thread;
255
256 public Game mGame;
257
258 public GameView(Context context, AttributeSet attrs) {
259 super(context, attrs);
260
261 // register our interest in hearing about changes to our surface
262 SurfaceHolder holder = getHolder();
263 holder.addCallback(this);
264
265 // create thread only; it's started in surfaceCreated()
266 thread = new DrawingThread(holder, context, new Handler() {
267 @Override
268 public void handleMessage(Message m) {
269 mStatusText.setVisibility(m.getData().getInt("viz"));
270 mStatusText.setText(m.getData().getString("text"));
271 }
272 });
273
274 setFocusable(true); // make sure we get key events
275 }
276
277 @Override public boolean onTouchEvent(MotionEvent event) {
278 Log.i("AdvanceWars", "Detected touch event");
279
280 if(event.getAction() == MotionEvent.ACTION_UP) {
281 Log.i("AdvanceWars", "Detected UP touch action");
282 switch(thread.mGameState) {
283 case MAIN_MENU:
284 Log.i("AdvanceWars", "Switching to battle map");
285 if(thread.wndMainMenu.getGUIObject("btnNewGame").isClicked(event.getX(), event.getY())) {
286 thread.mGameState = GameState.BATTLE_MAP;
287 }else if(thread.wndMainMenu.getGUIObject("btnLoadGame").isClicked(event.getX(), event.getY())) {
288 BufferedReader b;
289 try {
290 b = new BufferedReader(new FileReader(android.os.Environment.getExternalStorageDirectory()+"/save.txt"));
291
292 int width = Integer.parseInt(b.readLine());
293 int height = Integer.parseInt(b.readLine());
294
295 String offset = b.readLine();
296 Log.i("GameSave", offset);
297 int offsetX = Integer.parseInt(offset.substring(0, offset.indexOf("x")));
298 int offsetY = Integer.parseInt(offset.substring(offset.indexOf("x")+1));
299
300 Static.map = new Map(thread.grassTile, width, height, new Point(offsetX, offsetY));
301
302 Log.i("GameSave", "Created the map");
303
304 for(int x=0; x<width; x++) {
305 String line = b.readLine();
306 Log.i("GameSave", line);
307 String[] arr = line.split(",");
308 for(int y=0; y<arr.length; y++) {
309 TerrainType type = TerrainType.values()[Integer.parseInt(arr[y])];
310 if(type.equals(TerrainType.LAND))
311 Static.map.setTile(x, y, new Tile(thread.grassTile, new Point(10, 25)));
312 else
313 Static.map.setTile(x, y, new Tile(thread.oceanTile, new Point(10, 25)));
314 }
315 }
316
317 while(b.ready()) {
318 String unit = b.readLine();
319 Log.i("GameSave", unit);
320 int x = Integer.parseInt(unit.substring(0, unit.indexOf(",")));
321 int y = Integer.parseInt(unit.substring(unit.indexOf(",")+1));
322
323 Player humanPlayer = new Player("Human", mGame.mThread.mUnitPaint1);
324
325 Static.map.getTile(x, y).addUnit(new Soldier(humanPlayer));
326 }
327
328 b.close();
329 }catch(IOException ioe) {
330 ioe.printStackTrace();
331 }
332 thread.mGameState = GameState.BATTLE_MAP;
333 }else if(thread.wndMainMenu.getGUIObject("btnQuit").isClicked(event.getX(), event.getY())) {
334 mGame.finish();
335 }
336 break;
337 case BATTLE_MAP:
338 Log.i("AdvanceWars", "Touch event detected on battle map");
339
340 if(event.getX() >= Static.map.offset.x && event.getY() >= Static.map.offset.y) {
341 int x = ((int)event.getX() - Static.map.offset.x) / 50;
342 int y = ((int)event.getY() - Static.map.offset.y) / 50;
343
344 Unit target = Static.map.getTile(x, y).currentUnit;
345
346 if(thread.selectedUnit != null && thread.selectedUnit.getMovementRange().contains(new Point(x, y))) {
347 if(target == null || target == thread.selectedUnit) {
348 Static.map.getTile(thread.selectedUnit.location.x, thread.selectedUnit.location.y).removeUnit();
349 Static.map.getTile(x, y).addUnit(thread.selectedUnit);
350 }else {
351 // the target contains another unit. If the unit is enemy-controlled, attack it
352 }
353 thread.selectedUnit = null;
354 }else
355 thread.selectedUnit = target;
356 }
357
358 Log.i("AdvanceWars", "Touch event handling finished");
359
360 break;
361 }
362 }else if(event.getAction() == MotionEvent.ACTION_DOWN) {
363
364 }
365
366 return true;
367 }
368
369 /**
370 * Fetches the animation thread corresponding to this LunarView.
371 *
372 * @return the animation thread
373 */
374 public DrawingThread getThread() {
375 return thread;
376 }
377
378 /**
379 * Installs a pointer to the text view used for messages.
380 */
381 public void setTextView(TextView textView) {
382 mStatusText = textView;
383 }
384
385 /* Callback invoked when the surface dimensions change. */
386 public void surfaceChanged(SurfaceHolder holder, int format, int width,
387 int height) {
388 thread.setSurfaceSize(width, height);
389 }
390
391 /*
392 * Callback invoked when the Surface has been created and is ready to be
393 * used.
394 */
395 public void surfaceCreated(SurfaceHolder holder) {
396 thread.setRunning(true);
397 thread.start();
398 }
399
400 /*
401 * Callback invoked when the Surface has been destroyed and must no longer
402 * be touched. WARNING: after this method returns, the Surface/Canvas must
403 * never be touched again!
404 */
405 public void surfaceDestroyed(SurfaceHolder holder) {
406 // we have to tell thread to shut down & wait for it to finish, or else
407 // it might touch the Surface after we return and explode
408 boolean retry = true;
409 thread.setRunning(false);
410 while (retry) {
411 try {
412 thread.join();
413 retry = false;
414 } catch (InterruptedException e) {
415 }
416 }
417 }
418}
Note: See TracBrowser for help on using the repository browser.