Guest User

Untitled

a guest
Jan 22nd, 2018
62
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.07 KB | None | 0 0
  1. package BOut;
  2.  
  3. import com.golden.gamedev.*;
  4. import com.golden.gamedev.object.*;
  5. import com.golden.gamedev.object.background.*;
  6. import java.awt.*;
  7. import java.awt.event.KeyEvent;
  8. import java.awt.event.MouseEvent;
  9. import java.io.*;
  10. import java.util.Arrays;
  11. import java.util.Comparator;
  12. import java.util.Iterator;
  13.  
  14. import static BOut.BreakOutEngine.*;
  15.  
  16. /**
  17. * The menu screen. Currently just lets you select the level, but you could add high score tables, options, etc.
  18. * @author Paul Barba
  19. */
  20. public class GameMenu extends GameObject {
  21.  
  22. /**
  23. * PlayField for the game choice menu screen;
  24. */
  25. private PlayField field;
  26.  
  27. /**
  28. * Font used for the title of the game
  29. */
  30. private GameFont titleFont;
  31.  
  32. /**
  33. * Font used for the name of the currently chosen level of the game
  34. */
  35. private GameFont choiceFont;
  36.  
  37.  
  38. /**
  39. * Sprite (roughly, "image") for moving forward in the menu list
  40. */
  41. private Sprite forward;
  42.  
  43. /**
  44. * Sprite (roughly, "image") for moving backward in the menu list
  45. */
  46. private Sprite backward;
  47.  
  48. /**
  49. * Sprite for playing the chosen level
  50. */
  51. private Sprite play;
  52.  
  53. /**
  54. * Sprite for quitting entirely
  55. */
  56. private Sprite quit;
  57.  
  58. /**
  59. * horiz position on which to center the level name
  60. */
  61. private int nameCenter;
  62.  
  63. /**
  64. * vert position for the name
  65. */
  66. private int nameYpos;
  67.  
  68. /**
  69. * vert position for the title
  70. */
  71. private int titleYpos;
  72.  
  73. /*
  74. * New FileSet object to keep track of level files
  75. */
  76. FileSet level = new FileSet("levels", "Level\\d+\\.xml");
  77.  
  78. /*
  79. * New FileSet object to keep track of archive files
  80. */
  81. FileSet archive = new FileSet(".", ".+\\.sav");
  82. /**
  83. * Default constructor -- nothing special
  84. * @param engine
  85. */
  86. public GameMenu (GameEngine engine)
  87. {
  88. super(engine);
  89. }
  90.  
  91. /**
  92. * Prepares the "playing field" for rendering and receiving input actions
  93. */
  94. public void initResources ()
  95. {
  96. // Found in a search for 800x600 public domain images.
  97. Background bground = new ImageBackground(super.getImage(GraphicsDirectory + "MenuBackground.jpg"));
  98. field = new PlayField();
  99. field.setBackground(bground);
  100.  
  101. // Fonts are used to write to the screen
  102. GameFontManager fontMgr = new GameFontManager();
  103. // This color is "half-strength" pure red
  104. titleFont = fontMgr.getFont(new Font("sansserif", Font.BOLD, 48), new Color(128, 0, 0));
  105. choiceFont = fontMgr.getFont(new Font("serif", Font.BOLD, 24), Color.BLACK);
  106.  
  107.  
  108.  
  109.  
  110. // find maximum width of names, to determine screen layout
  111. //Comment: call to scanArchiveFiles() method
  112. int maxWidth = scanArchiveFiles();
  113.  
  114.  
  115. int halfMaxWidth = (maxWidth + 1) / 2; // round up
  116.  
  117. // approximate layout:
  118. // < level-name >
  119. // PLAY QUIT
  120.  
  121. titleYpos = bground.getHeight() / 3;
  122.  
  123. nameCenter = bground.getWidth() / 2;
  124. int gap = 10; // to separate forward/backward from name
  125.  
  126. play = new Sprite(getImage(GraphicsDirectory + "PlayButton.png"));
  127. field.add(play);
  128. int startYpos = bground.getHeight() - 2*gap - play.getHeight();
  129. play.setLocation(nameCenter - play.getWidth() - gap, startYpos);
  130.  
  131. quit = new Sprite(getImage(GraphicsDirectory + "QuitButton.png"));
  132. field.add(quit);
  133. quit.setLocation(nameCenter + gap, startYpos);
  134.  
  135. forward = new Sprite(getImage(GraphicsDirectory + "RightButton.png"));
  136. field.add(forward);
  137. nameYpos = startYpos - gap - forward.getHeight();
  138. forward.setLocation(nameCenter+halfMaxWidth+gap, nameYpos);
  139.  
  140. backward = new Sprite(getImage(GraphicsDirectory + "LeftButton.png"));
  141. field.add(backward);
  142. backward.setLocation(nameCenter-halfMaxWidth-gap-backward.getWidth(), nameYpos);
  143. }
  144.  
  145. /**
  146. * are we displaying levels, or archives?
  147. */
  148. private enum Mode {
  149. Levels {
  150. State getChoosingState () { return State.ChoosingLevel; }
  151. State getQuittingState () { return State.QuittingLevel; }
  152. State getOppositeState () { return State.ChoosingArchive; }
  153. String getChoiceString (GameMenu menu) {
  154. if (menu.level.size() <= 0) { return ""; }
  155. return menu.level.currentDisplay();
  156. }
  157. String getMenuString (GameMenu menu) { return "(Level)"; }
  158. State getDeletingState (){ return State.ChoosingLevel;}
  159. },
  160. Archives {
  161. State getChoosingState () { return State.ChoosingArchive; }
  162. State getQuittingState () { return State.QuittingArchive; }
  163. State getOppositeState () { return State.ChoosingLevel; }
  164. String getChoiceString (GameMenu menu) {
  165. if (menu.archive.size() <= 0) { return ""; }
  166. return menu.archive.currentDisplay();
  167. }
  168. String getMenuString (GameMenu menu) { return "(Archive)"; }
  169. //comment: obtain the state for deleting archives
  170. State getDeletingState () { return State.DeletingArchive; }
  171.  
  172. };
  173.  
  174. // obtain the proper state for ordinary choosing in this mode
  175. abstract State getChoosingState ();
  176.  
  177. // obtain the proper state for quitting in this mode
  178. abstract State getQuittingState ();
  179.  
  180. // obtain the state for choosing in the opposite mode
  181. abstract State getOppositeState ();
  182.  
  183. // obtain the appropriate String that might be displayed
  184. abstract String getChoiceString (GameMenu menu);
  185.  
  186. // obtain the appropriate String that might be displayed above a menu item
  187. abstract String getMenuString (GameMenu menu);
  188.  
  189. //comment: obtain the appropriate state for deleting in this mode
  190. abstract State getDeletingState ();
  191. }
  192.  
  193. /**
  194. * the different possible input processing states
  195. */
  196. private enum State
  197. {
  198. // presenting choices of levels to play
  199. ChoosingLevel(Mode.Levels) {
  200. State gotForward (GameMenu menu) {
  201. menu.level.advance(1);
  202. menu.level.refresh();
  203. return this;
  204. }
  205. State gotBackward (GameMenu menu) {
  206. menu.level.advance(-1);
  207. menu.level.refresh();
  208. return this;
  209. }
  210. State gotPlay (GameMenu menu) {
  211. if (menu.level.size() <= 0)
  212. {
  213. return this; // no game to play
  214. }
  215. menu.parent.nextGameID = BreakOutEngine.BreakOutPlayGame;
  216. ((BreakOutEngine)menu.parent).nextLevel = menu.level.current().getAbsolutePath();
  217. return Finish;
  218. }
  219. },
  220.  
  221. // presenting choices of archives to restore
  222. ChoosingArchive(Mode.Archives) {
  223. State gotForward (GameMenu menu) {
  224. menu.archive.advance(1);
  225. menu.archive.refresh();
  226. return this;
  227. }
  228. State gotBackward (GameMenu menu) {
  229. menu.archive.advance(-1);
  230. menu.archive.refresh();
  231. return this;
  232. }
  233. State gotPlay (GameMenu menu) {
  234. if (menu.archive.size()<= 0)
  235. {
  236. return this; // no archive to restore: ignore key
  237. }
  238. menu.parent.nextGameID = BreakOutEngine.BreakOutRestore;
  239. ((BreakOutEngine)menu.parent).restoreFilename = menu.archive.current().getAbsolutePath();
  240. return Finish;
  241. }
  242. State gotDelete (GameMenu menu) {
  243. if (menu.archive.size() <= 0)
  244. {
  245. return this; // no archive to restore: ignore key
  246. }
  247. return DeletingArchive.gotDelete(menu); }
  248. },
  249.  
  250. // quit requested; awaiting confirmation
  251. QuittingLevel(Mode.Levels) {
  252. State gotYes (GameMenu menu) {
  253. menu.parent.nextGame = null;
  254. return Finish;
  255. }
  256. String getMenuString (GameMenu menu) { return "Quit entirely? Y or N"; }
  257. },
  258.  
  259. // quit requested; awaiting confirmation
  260. QuittingArchive(Mode.Archives) {
  261. State gotYes (GameMenu menu) {
  262. menu.parent.nextGame = null;
  263. return Finish;
  264. }
  265. String getMenuString (GameMenu menu) { return "Quit entirely? Y or N"; }
  266. },
  267. //Comment: Deletes the current archive
  268. DeletingArchive(Mode.Archives){
  269. // respond to a Yes confirmation
  270. State gotYes (GameMenu menu) { return this; }
  271.  
  272. State gotDelete (GameMenu menu)
  273. {
  274. menu.archive.current().getAbsoluteFile().delete();
  275. menu.scanArchiveFiles();
  276. return ChoosingArchive;
  277. }
  278.  
  279. String getMenuString (GameMenu menu) { return "Delete this archive? Y or N"; }
  280. },
  281. // quit has been confirmed; level vs archive does not matter
  282. Finish(Mode.Levels) {
  283. boolean shouldFinish (GameMenu menu) { return true; }
  284. };
  285.  
  286. // is this a state that is handling levels, or archives?
  287. private final Mode mode;
  288.  
  289. // constructor, which distinguishes level states versus archive states
  290. State (Mode mode) { this.mode = mode; }
  291.  
  292. // are we in a state that should exit this "game"?
  293. boolean shouldFinish (GameMenu menu) { return false; }
  294.  
  295. // respond to a Yes confirmation
  296. State gotYes (GameMenu menu) { return this; }
  297.  
  298. // respond to a No confirmation
  299. State gotNo (GameMenu menu) { return mode.getChoosingState(); }
  300.  
  301. // respond to a move-forward-in-the-list request
  302. State gotForward (GameMenu menu) { return this; }
  303.  
  304. // respond to a move-backward-in-the-list request
  305. State gotBackward (GameMenu menu) { return this; }
  306.  
  307. // respond to a request to play the current choice
  308. State gotPlay (GameMenu menu) { return this; }
  309.  
  310. // respond to a request to quit
  311. State gotQuit (GameMenu menu) { return mode.getQuittingState(); }
  312.  
  313. // respond to a request to toggle between choosing a level or an archive
  314. State gotRestore (GameMenu menu) {
  315. State newState = mode.getOppositeState();
  316. return newState;
  317. }
  318.  
  319. // get the current choice string to display
  320. String getChoiceString (GameMenu menu) { return mode.getChoiceString(menu); }
  321.  
  322. // get the current string to display above the menu choice
  323. String getMenuString (GameMenu menu) { return mode.getMenuString(menu); }
  324.  
  325. // get suitable starting state
  326. static State initial (Mode mode) { return mode.getChoosingState(); }
  327.  
  328. // Comment: Default action is do nothing if D or Delete is pressed.
  329. State gotDelete (GameMenu menu) { return this; }
  330. }
  331.  
  332. /**
  333. * the current input processing state
  334. */
  335. private State state = State.initial(Mode.Levels);
  336.  
  337. private enum MyEvent {
  338. None,
  339. MoveForward,
  340. MoveBackward,
  341. No,
  342. Play,
  343. Quit,
  344. Restore,
  345. Yes,
  346. Delete;
  347. }
  348.  
  349. /**
  350. * Checks mouse position and determines appropriate event, if any
  351. * @return the MyEvent for the current mouse position
  352. */
  353. private MyEvent getMouseEvent ()
  354. {
  355. if (mouseOver(forward))
  356. return MyEvent.MoveForward;
  357. else if (mouseOver(backward))
  358. return MyEvent.MoveBackward;
  359. else if (mouseOver(play))
  360. return MyEvent.Play;
  361. else if (mouseOver(quit))
  362. return MyEvent.Quit;
  363. else
  364. return MyEvent.None;
  365. }
  366.  
  367. /**
  368. * Return the MyEvent for the current key pressed, if any
  369. * @return the MyEvent for the current key pressed (None if none)
  370. */
  371. private MyEvent getKeyEvent ()
  372. {
  373. if (bsInput.isKeyPressed(KeyEvent.VK_RIGHT))
  374. return MyEvent.MoveForward;
  375. else if (bsInput.isKeyPressed(KeyEvent.VK_LEFT))
  376. return MyEvent.MoveBackward;
  377. else if (bsInput.isKeyPressed(KeyEvent.VK_ENTER))
  378. return MyEvent.Play;
  379. else if (bsInput.isKeyPressed(KeyEvent.VK_N))
  380. return MyEvent.No;
  381. else if (bsInput.isKeyPressed(KeyEvent.VK_Q))
  382. return MyEvent.Quit;
  383. else if (bsInput.isKeyPressed(KeyEvent.VK_R))
  384. return MyEvent.Restore;
  385. else if (bsInput.isKeyPressed(KeyEvent.VK_Y))
  386. return MyEvent.Yes;
  387. else if (bsInput.isKeyPressed(KeyEvent.VK_D)||bsInput.isKeyPressed(KeyEvent.VK_DELETE))
  388. return MyEvent.Delete;
  389. else
  390. return MyEvent.None;
  391. }
  392.  
  393. /**
  394. * Looks for keyboard or mouse input, converting to the
  395. * common type MyEvent
  396. * @return a MyEvent (None if nothing happened)
  397. */
  398. private MyEvent getEvent () {
  399. MyEvent event = MyEvent.None;
  400. if (bsInput.isMousePressed(MouseEvent.BUTTON1))
  401. event = getMouseEvent();
  402. else
  403. event = getKeyEvent();
  404. return event;
  405. }
  406.  
  407. /**
  408. * Check for and process any input event
  409. */
  410. private void processInput () {
  411. switch (getEvent()) {
  412. case MoveForward: state = state.gotForward (this); break;
  413. case MoveBackward: state = state.gotBackward(this); break;
  414. case No: state = state.gotNo (this); break;
  415. case Play: state = state.gotPlay (this); break;
  416. case Quit: state = state.gotQuit (this); break;
  417. case Restore: state = state.gotRestore (this); break;
  418. case Yes: state = state.gotYes (this); break;
  419. case Delete: state = state.gotDelete (this); break;
  420. case None: break;
  421. }
  422. }
  423.  
  424. /**
  425. * Called to update the screen.
  426. * Here just checks for input events and updates information for
  427. * rendering (or starts the chosen game)
  428. * @param elaspedTime time since last update (not very relevant here)
  429. */
  430. @Override
  431. public void update (long elapsedTime)
  432. {
  433. field.update(elapsedTime);
  434. processInput();
  435. if (state.shouldFinish(this))
  436. {
  437. finish();
  438. }
  439. }
  440.  
  441. /**
  442. * paint the menu screen
  443. */
  444. public void render (Graphics2D g)
  445. {
  446. field.render(g);
  447.  
  448. String title = "UMASS BREAKOUT";
  449. int titleWidth = titleFont.getWidth(title);
  450. titleFont.drawString(g, title, nameCenter-(titleWidth/2), titleYpos);
  451.  
  452. String choice = state.getChoiceString(this);
  453. int choiceWidth = choiceFont.getWidth(choice);
  454. choiceFont.drawString(g, choice, nameCenter-(choiceWidth/2), nameYpos);
  455.  
  456. String kind = state.getMenuString(this);
  457. int kindWidth = choiceFont.getWidth(kind);
  458. choiceFont.drawString(g, kind, nameCenter-(kindWidth/2), nameYpos - 10 - choiceFont.getHeight());
  459. }
  460.  
  461. /**
  462. * Tests whether the mouse is currently over a given sprite.
  463. * Used for telling what to do on mouse presses.
  464. * @param s the sprite
  465. * @return true if the mouse is over the sprite
  466. */
  467. private boolean mouseOver(Sprite s)
  468. {
  469. return (getMouseX() >= s.getX() && getMouseX() < (s.getX() + s.getWidth ()) &&
  470. getMouseY() >= s.getY() && getMouseY() < (s.getY() + s.getHeight()));
  471. }
  472.  
  473.  
  474. private int scanArchiveFiles()
  475. {
  476. archive.refresh();
  477. // find maximum width of names, to determine screen layout
  478. int maxWidth = 0;
  479. Iterator<File> it = level.iterator();
  480. while(it.hasNext())
  481. {
  482. int width = choiceFont.getWidth(level.currentDisplay());
  483. if (maxWidth < width)
  484. {
  485. maxWidth = width;
  486. }
  487. it.next();
  488. }
  489.  
  490. Iterator<File> it2 = archive.iterator();
  491. while(it2.hasNext())
  492. {
  493. int width = choiceFont.getWidth(archive.currentDisplay());
  494. if (maxWidth < width)
  495. {
  496. maxWidth = width;
  497. }
  498. it2.next();
  499. }
  500. return maxWidth;
  501. }
  502.  
  503. }
Add Comment
Please, Sign In to add comment