source: advance-wars/src/com/medievaltech/advancewars/GameView.java@ 99433bb

Last change on this file since 99433bb was fea4b77, checked in by dportnoy <devnull@…>, 13 years ago

Implemented turn and support for computer-controller movement of units. Right now, the computer moves a specific unit down one square when its his turn.

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