Game.java 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. package me.hammerle.supersnuvi;
  2. import java.io.File;
  3. import java.util.ArrayList;
  4. import java.util.Arrays;
  5. import me.hammerle.snuviengine.api.ColorRenderer;
  6. import me.hammerle.snuviengine.api.Engine;
  7. import me.hammerle.snuviengine.api.FontRenderer;
  8. import me.hammerle.snuviengine.api.KeyBinding;
  9. import me.hammerle.snuviengine.api.Shader;
  10. import me.hammerle.supersnuvi.gamelogic.Level;
  11. import me.hammerle.supersnuvi.savegame.SimpleConfig;
  12. import me.hammerle.supersnuvi.tiles.*;
  13. import me.hammerle.supersnuvi.util.SoundUtils;
  14. public class Game extends Engine
  15. {
  16. public static final int MS_PER_TICK = 50;
  17. public static final float SECS_PER_TICK = MS_PER_TICK / 1000.0f;
  18. public static int getTicksForMillis(int millis)
  19. {
  20. return millis / MS_PER_TICK;
  21. }
  22. private static Game instance;
  23. public static Game get()
  24. {
  25. return instance;
  26. }
  27. // constants
  28. public static final NullTile FALLBACK_TILE = new NullTile();
  29. // tiles
  30. private final Tile[] registeredTiles = new Tile[70];
  31. // levels
  32. private Level currentLevel = null;
  33. private final Level[] levels;
  34. private int levelIndex = 0;
  35. // config and savegames
  36. private final SimpleConfig config = new SimpleConfig("options.txt", true);
  37. private final SimpleConfig[] saveSlots = new SimpleConfig[]
  38. {
  39. new SimpleConfig("slot1.txt", true),
  40. new SimpleConfig("slot2.txt", true),
  41. new SimpleConfig("slot3.txt", true)
  42. };
  43. private int screen = 0;
  44. private int startScreenIndex = 0;
  45. private int optionScreenIndex = 0;
  46. private int slotScreenIndex = 0;
  47. private boolean optionsDirty = false;
  48. // sound
  49. private boolean sound = config.getBoolean("sound", false);
  50. public Game()
  51. {
  52. instance = this;
  53. registerTiles();
  54. File[] files = new File("./levels").listFiles();
  55. Arrays.sort(files, (o1, o2) -> o1.compareTo(o2));
  56. ArrayList<Level> levelList = new ArrayList<>();
  57. for(File file : files)
  58. {
  59. if(file.isFile())
  60. {
  61. Level l = new Level(file);
  62. levelList.add(l);
  63. }
  64. }
  65. levels = levelList.toArray(new Level[levelList.size()]);
  66. }
  67. @Override
  68. public void init()
  69. {
  70. setMaxFps(120);
  71. setNanosPerTick(MS_PER_TICK * 1_000_000);
  72. }
  73. // -------------------------------------------------------------------------
  74. // tick, rendering
  75. // -------------------------------------------------------------------------
  76. @Override
  77. public void tick()
  78. {
  79. if(currentLevel != null)
  80. {
  81. SoundUtils.playSound(SoundUtils.Sound.SONG_1);
  82. SoundUtils.stopSound(SoundUtils.Sound.MENU_MUSIC);
  83. currentLevel.tick();
  84. // doing that here to prevent concurent modification
  85. if(currentLevel.shouldFinish())
  86. {
  87. String base = "level." + currentLevel.getFileName();
  88. SimpleConfig sp = saveSlots[slotScreenIndex];
  89. // save success
  90. sp.set(base, true);
  91. // update time, if a new highscore was scored
  92. double time = sp.getDouble(base + ".time", Integer.MAX_VALUE);
  93. if(currentLevel.getTime() < time)
  94. {
  95. sp.set(base + ".time", currentLevel.getTime());
  96. }
  97. // update bottles, if a new highscore was scored
  98. int bottles = sp.getInt(base + ".bottles", 0);
  99. if(currentLevel.getCurrentBottles() > bottles)
  100. {
  101. sp.set(base + ".bottles", currentLevel.getCurrentBottles());
  102. }
  103. // final save
  104. sp.save();
  105. currentLevel.resetLevel();
  106. currentLevel = null;
  107. return;
  108. }
  109. if(currentLevel.shouldReset())
  110. {
  111. if(currentLevel.resetLevel())
  112. {
  113. currentLevel = null;
  114. }
  115. }
  116. if(Keys.ESCAPE.isReleased())
  117. {
  118. currentLevel = null;
  119. }
  120. }
  121. else
  122. {
  123. SoundUtils.playSound(SoundUtils.Sound.MENU_MUSIC);
  124. SoundUtils.stopSound(SoundUtils.Sound.SONG_1);
  125. switch(screen)
  126. {
  127. case 0: // start screen
  128. {
  129. menuMove(() ->
  130. {
  131. // do nothing on escape in start screen
  132. }, () ->
  133. {
  134. switch(startScreenIndex)
  135. {
  136. case 0:
  137. screen = 1;
  138. break;
  139. case 1:
  140. screen = 2;
  141. break;
  142. case 2:
  143. stop();
  144. break;
  145. }
  146. }, () -> startScreenIndex++, () -> startScreenIndex--, () ->
  147. {
  148. if(startScreenIndex < 0)
  149. {
  150. startScreenIndex = 0;
  151. }
  152. else if(startScreenIndex >= 3)
  153. {
  154. startScreenIndex = 2;
  155. }
  156. });
  157. break;
  158. }
  159. case 1: // slot screen
  160. {
  161. menuMove(() ->
  162. {
  163. screen = 0;
  164. }, () ->
  165. {
  166. if(slotScreenIndex == 3)
  167. {
  168. screen = 0;
  169. return;
  170. }
  171. screen = 3;
  172. }, () -> slotScreenIndex++, () -> slotScreenIndex--, () ->
  173. {
  174. if(slotScreenIndex < 0)
  175. {
  176. slotScreenIndex = 0;
  177. }
  178. else if(slotScreenIndex >= 4)
  179. {
  180. slotScreenIndex = 3;
  181. }
  182. });
  183. break;
  184. }
  185. case 2: // option screen
  186. {
  187. menuMove(() ->
  188. {
  189. screen = 0;
  190. }, () ->
  191. {
  192. switch(optionScreenIndex)
  193. {
  194. case 0: // toggle sound
  195. sound = !sound;
  196. if(!sound)
  197. {
  198. SoundUtils.turnSoundOff();
  199. }
  200. optionsDirty = true;
  201. break;
  202. case 15: // save options
  203. Keys.write(config);
  204. config.set("sound", sound);
  205. config.save();
  206. optionsDirty = false;
  207. break;
  208. case 16: // go back
  209. screen = 0;
  210. break;
  211. default: // rebind keys
  212. Keys.rebind(Keys.get(optionScreenIndex - 1));
  213. optionsDirty = true;
  214. break;
  215. }
  216. }, () -> optionScreenIndex++, () -> optionScreenIndex--, () ->
  217. {
  218. if(optionScreenIndex < 0)
  219. {
  220. optionScreenIndex = 0;
  221. }
  222. int options = Keys.getAmount() + 3;
  223. if(optionScreenIndex >= options)
  224. {
  225. optionScreenIndex = options - 1;
  226. }
  227. });
  228. break;
  229. }
  230. case 3: // level choose screen
  231. {
  232. menuMove(() ->
  233. {
  234. screen = 1;
  235. }, () -> currentLevel = levels[levelIndex], () -> levelIndex++, () -> levelIndex--, () ->
  236. {
  237. if(levelIndex < 0)
  238. {
  239. levelIndex = 0;
  240. }
  241. else if(levelIndex >= levels.length)
  242. {
  243. levelIndex = levels.length - 1;
  244. }
  245. });
  246. break;
  247. }
  248. }
  249. }
  250. }
  251. private final static int COLOR_BROWN = 0xFF13458B;
  252. private final static int COLOR_OVERLAY = 0x77000000;
  253. private String getKeyName(KeyBinding key)
  254. {
  255. if(key.isRebinding())
  256. {
  257. return "[...]";
  258. }
  259. return key.getName();
  260. }
  261. @Override
  262. public void renderTick(float lag)
  263. {
  264. if(currentLevel != null)
  265. {
  266. currentLevel.renderTick(lag);
  267. return;
  268. }
  269. Shader.translateTo(0.0f, 0.0f);
  270. Shader.updateMatrix();
  271. switch(screen)
  272. {
  273. case 0:
  274. {
  275. ColorRenderer cr = Shader.getColorRenderer();
  276. FontRenderer fr = Shader.getFontRenderer();
  277. float width = Shader.getViewWidth();
  278. float height = Shader.getViewHeight();
  279. float line = fr.getHeight();
  280. float left = width * 0.25f;
  281. float right = width * 0.75f;
  282. float top = (height - line * 7.0f) * 0.5f;
  283. float bottom = top + line * 7.0f;
  284. Shader.setTextureEnabled(false);
  285. Shader.setColorEnabled(true);
  286. // brown background
  287. cr.drawRectangle(0, 0, width, height, COLOR_BROWN);
  288. Shader.setBlendingEnabled(true);
  289. cr.drawRectangle(left, top, right, bottom, COLOR_OVERLAY);
  290. float base = top + (3 + startScreenIndex) * line;
  291. cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY);
  292. Shader.setBlendingEnabled(false);
  293. Shader.setTextureEnabled(true);
  294. float y = top + line;
  295. y = fr.drawString(left + line, y, "Super Snuvi");
  296. y += line;
  297. y = fr.drawString(left + line, y, "Start Game");
  298. y = fr.drawString(left + line, y, "Options");
  299. fr.drawString(left + line, y, "Exit Game");
  300. break;
  301. }
  302. case 1:
  303. {
  304. ColorRenderer cr = Shader.getColorRenderer();
  305. FontRenderer fr = Shader.getFontRenderer();
  306. float width = Shader.getViewWidth();
  307. float height = Shader.getViewHeight();
  308. float line = fr.getHeight();
  309. float left = width * 0.25f;
  310. float right = width * 0.75f;
  311. float top = (height - line * 8.0f) * 0.5f;
  312. float bottom = top + line * 8.0f;
  313. Shader.setTextureEnabled(false);
  314. Shader.setColorEnabled(true);
  315. // brown background
  316. cr.drawRectangle(0, 0, width, height, COLOR_BROWN);
  317. Shader.setBlendingEnabled(true);
  318. cr.drawRectangle(left, top, right, bottom, COLOR_OVERLAY);
  319. float base = top + (3 + slotScreenIndex) * line;
  320. cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY);
  321. Shader.setBlendingEnabled(false);
  322. Shader.setTextureEnabled(true);
  323. float y = top + line;
  324. y = fr.drawString(left + line, y, "Choose a Savegame");
  325. y += line;
  326. y = fr.drawString(left + line, y, "Slot 1");
  327. y = fr.drawString(left + line, y, "Slot 2");
  328. y = fr.drawString(left + line, y, "Slot 3");
  329. fr.drawString(left + line, y, "Back");
  330. break;
  331. }
  332. case 2:
  333. {
  334. ColorRenderer cr = Shader.getColorRenderer();
  335. FontRenderer fr = Shader.getFontRenderer();
  336. float width = Shader.getViewWidth();
  337. float height = Shader.getViewHeight();
  338. float line = fr.getHeight();
  339. float left = width * 0.2f;
  340. float right = width * 0.8f;
  341. float top = (height - line * 21.0f) * 0.5f;
  342. float bottom = top + line * 21.0f;
  343. Shader.setTextureEnabled(false);
  344. Shader.setColorEnabled(true);
  345. // brown background
  346. cr.drawRectangle(0, 0, width, height, COLOR_BROWN);
  347. Shader.setBlendingEnabled(true);
  348. cr.drawRectangle(left, top, right, bottom, COLOR_OVERLAY);
  349. float base = top + (3 + optionScreenIndex) * line;
  350. cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY);
  351. Shader.setBlendingEnabled(false);
  352. Shader.setTextureEnabled(true);
  353. left += line;
  354. float secLeft = right - line * 11;
  355. float y = top + line;
  356. y = fr.drawString(left, y, "Options");
  357. y += line;
  358. fr.drawString(left, y, "Sound");
  359. y = fr.drawString(secLeft, y, sound ? "yes" : "no");
  360. fr.drawString(left, y, "K: Up");
  361. y = fr.drawString(secLeft, y, getKeyName(Keys.UP));
  362. fr.drawString(left, y, "K: Down");
  363. y = fr.drawString(secLeft, y, getKeyName(Keys.DOWN));
  364. fr.drawString(left, y, "K: Left");
  365. y = fr.drawString(secLeft, y, getKeyName(Keys.LEFT));
  366. fr.drawString(left, y, "K: Right");
  367. y = fr.drawString(secLeft, y, getKeyName(Keys.RIGHT));
  368. fr.drawString(left, y, "K: Jump");
  369. y = fr.drawString(secLeft, y, getKeyName(Keys.JUMP));
  370. fr.drawString(left, y, "K: Run");
  371. y = fr.drawString(secLeft, y, getKeyName(Keys.RUN));
  372. fr.drawString(left, y, "K: Back");
  373. y = fr.drawString(secLeft, y, getKeyName(Keys.ESCAPE));
  374. fr.drawString(left, y, "K: Enter");
  375. y = fr.drawString(secLeft, y, getKeyName(Keys.ENTER));
  376. fr.drawString(left, y, "K: Combat");
  377. y = fr.drawString(secLeft, y, getKeyName(Keys.COMBAT));
  378. fr.drawString(left, y, "K: Switch Face");
  379. y = fr.drawString(secLeft, y, getKeyName(Keys.COMBAT_SWITCH_FACE));
  380. fr.drawString(left, y, "K: Dash/Dodge");
  381. y = fr.drawString(secLeft, y, getKeyName(Keys.COMBAT_DASH));
  382. fr.drawString(left, y, "K: Dash/Dodge");
  383. y = fr.drawString(secLeft, y, getKeyName(Keys.COMBAT_DODGE));
  384. fr.drawString(left, y, "K: Block");
  385. y = fr.drawString(secLeft, y, getKeyName(Keys.COMBAT_BLOCK));
  386. fr.drawString(left, y, "K: Attack");
  387. y = fr.drawString(secLeft, y, getKeyName(Keys.COMBAT_ATTACK));
  388. if(optionsDirty)
  389. {
  390. y = fr.drawString(left, y, true, "&cSave");
  391. }
  392. else
  393. {
  394. y = fr.drawString(left, y, true, "Save");
  395. }
  396. fr.drawString(left, y, true, "Back");
  397. break;
  398. }
  399. case 3:
  400. {
  401. ColorRenderer cr = Shader.getColorRenderer();
  402. FontRenderer fr = Shader.getFontRenderer();
  403. float width = Shader.getViewWidth();
  404. float height = Shader.getViewHeight();
  405. float line = fr.getHeight();
  406. int maxView = 7; // only for odd numbers
  407. int half = maxView / 2;
  408. float left = width * 0.2f;
  409. float right = width * 0.8f;
  410. float top = (height - line * (maxView + 4)) * 0.5f;
  411. float bottom = top + line * (maxView + 4);
  412. Shader.setTextureEnabled(false);
  413. Shader.setColorEnabled(true);
  414. // brown background
  415. cr.drawRectangle(0, 0, width, height, COLOR_BROWN);
  416. Shader.setBlendingEnabled(true);
  417. cr.drawRectangle(left, top, right, bottom, COLOR_OVERLAY);
  418. int firstIndex;
  419. int lastIndex;
  420. int baseIndex;
  421. if(levelIndex <= half) // first half
  422. {
  423. firstIndex = 0;
  424. lastIndex = Math.min(levels.length, maxView);
  425. baseIndex = levelIndex;
  426. }
  427. else if(levelIndex >= levels.length - half) // last half
  428. {
  429. lastIndex = levels.length;
  430. firstIndex = Math.max(lastIndex - maxView, 0);
  431. if(levels.length <= maxView)
  432. {
  433. baseIndex = levelIndex;
  434. }
  435. else
  436. {
  437. baseIndex = levelIndex - (levels.length - half - 1) + half;
  438. }
  439. }
  440. else // middle
  441. {
  442. firstIndex = levelIndex - half;
  443. lastIndex = firstIndex + maxView;
  444. baseIndex = half;
  445. }
  446. float base = top + (3 + baseIndex) * line;
  447. cr.drawRectangle(left, base, right, base + line, COLOR_OVERLAY);
  448. Shader.setBlendingEnabled(false);
  449. Shader.setTextureEnabled(true);
  450. left += line;
  451. float secLeft = right - line * 12;
  452. float thirdLeft = right - line * 6;
  453. float y = top + line;
  454. y = fr.drawString(left, y, "Choose a Level ...");
  455. y += line;
  456. if(firstIndex >= 1)
  457. {
  458. y = fr.drawString(left, y, "...");
  459. firstIndex++;
  460. }
  461. SimpleConfig sc = saveSlots[slotScreenIndex];
  462. for(int i = firstIndex; i < lastIndex - 1; i++)
  463. {
  464. Level l = levels[i];
  465. fr.drawString(left, y, l.getName());
  466. fr.drawString(secLeft, y, l.formatBottles(sc.getInt("level." + l.getFileName() + ".bottles", 0)));
  467. y = fr.drawString(thirdLeft, y, l.formatTime(sc.getFloat("level." + l.getFileName() + ".time", 0)));
  468. }
  469. if(lastIndex == levels.length)
  470. {
  471. Level l = levels[lastIndex - 1];
  472. fr.drawString(left, y, l.getName());
  473. fr.drawString(secLeft, y, l.formatBottles(sc.getInt("level." + l.getFileName() + ".bottles", 0)));
  474. fr.drawString(thirdLeft, y, l.formatTime(sc.getFloat("level." + l.getFileName() + ".time", 0)));
  475. }
  476. else
  477. {
  478. fr.drawString(left, y, "...");
  479. }
  480. break;
  481. }
  482. }
  483. }
  484. // -------------------------------------------------------------------------
  485. // config
  486. // -------------------------------------------------------------------------
  487. public boolean isSoundEnabled()
  488. {
  489. return sound;
  490. }
  491. // -------------------------------------------------------------------------
  492. // tile stuff
  493. // -------------------------------------------------------------------------
  494. private void registerTiles()
  495. {
  496. // dirt
  497. registeredTiles[0] = new BaseBoxTile(0.125f, 0.0f, 0.1875f, 0.0625f);
  498. // grass
  499. registeredTiles[1] = new BaseBoxTile(0.0625f, 0.0f, 0.125f, 0.0625f);
  500. // bottled soul
  501. registeredTiles[2] = new BottledSoulTile(1);
  502. registeredTiles[3] = new BottledSoulTile(2);
  503. registeredTiles[4] = new BottledSoulTile(3);
  504. // bounce shroom
  505. registeredTiles[5] = new TrampolinTile();
  506. // crumbling stones
  507. registeredTiles[6] = new CrumblingStoneTile();
  508. // spike trap
  509. registeredTiles[7] = new SpikeTile();
  510. // water
  511. for(int i = 0; i < 16; i++)
  512. {
  513. registeredTiles[8 + i] = new WaterTile(15 - i);
  514. }
  515. // snuvi start block
  516. registeredTiles[24] = new StartTile();
  517. // sky
  518. registeredTiles[25] = new BaseTile(0.0f, 0.0f, 0.0625f, 0.0625f);
  519. // slippery slime
  520. registeredTiles[26] = new SlipperyTile();
  521. // end level
  522. registeredTiles[27] = new GoalTile(0.25f, 0.125f, 0.3125f, 0.1875f);
  523. registeredTiles[28] = new GoalTile(0.25f, 0.0625f, 0.3125f, 0.125f);
  524. // thorns
  525. registeredTiles[29] = new KillTile(0.0f, 0.125f, 0.0625f, 0.1875f);
  526. registeredTiles[30] = new KillTile(0.0625f, 0.125f, 0.125f, 0.1875f);
  527. registeredTiles[31] = new KillTile(0.125f, 0.125f, 0.1875f, 0.1875f);
  528. // decoration shrooms
  529. registeredTiles[32] = new DecoShroomTile(0.0f, 0.21875f, 0.0625f, 0.25f);
  530. registeredTiles[33] = new DecoShroomTile(0.0f, 0.1875f, 0.0625f, 0.21875f);
  531. registeredTiles[34] = new DecoShroomTile(0.0625f, 0.21875f, 0.125f, 0.25f);
  532. registeredTiles[35] = new DecoShroomTile(0.0625f, 0.1875f, 0.125f, 0.21875f);
  533. // ramp
  534. registeredTiles[36] = new Ramp(0.375f, 0.0f, 0.4375f, 0.0625f, 0.0f, Tile.SIZE, Tile.SIZE, 0.0f);
  535. registeredTiles[37] = new Ramp(0.4375f, 0.0f, 0.5f, 0.0625f, 0.0f, Tile.SIZE, Tile.SIZE, Tile.SIZE * 0.5f);
  536. registeredTiles[38] = new Ramp(0.5f, 0.0f, 0.5625f, 0.0625f, 0.0f, Tile.SIZE * 0.5f, Tile.SIZE, 0.0f);
  537. registeredTiles[39] = new Ramp(0.375f, 0.0625f, 0.4375f, 0.125f, Tile.SIZE, Tile.SIZE, 0.0f, 0.0f);
  538. registeredTiles[40] = new Ramp(0.4375f, 0.0625f, 0.5f, 0.125f, Tile.SIZE, Tile.SIZE, 0.0f, Tile.SIZE * 0.5f);
  539. registeredTiles[41] = new Ramp(0.5f, 0.0625f, 0.5625f, 0.125f, Tile.SIZE, Tile.SIZE * 0.5f, 0.0f, 0.0f);
  540. // london stuff
  541. // street
  542. registeredTiles[42] = new BaseBoxTile(0.3125f, 0.125f, 0.375f, 0.1875f);
  543. // dirt
  544. registeredTiles[43] = new BaseBoxTile(0.375f, 0.125f, 0.4375f, 0.1875f);
  545. // background
  546. registeredTiles[44] = new BaseTile(0.3125f, 0.0625f, 0.375f, 0.125f);
  547. // street lamp
  548. for(int x = 0; x < 5; x++)
  549. {
  550. for(int y = 0; y < 5; y++)
  551. {
  552. registeredTiles[45 + 5 * y + x] = new BaseTile(0.0625f * x, 0.25f + 0.0625f * y, 0.0625f * (x + 1), 0.25f + 0.0625f * (y + 1));
  553. }
  554. }
  555. }
  556. public Tile getTile(int id)
  557. {
  558. if(id < 0 || id >= registeredTiles.length || registeredTiles[id] == null)
  559. {
  560. return FALLBACK_TILE;
  561. }
  562. return registeredTiles[id];
  563. }
  564. public void resetTiles(Level l)
  565. {
  566. for(Tile t : registeredTiles)
  567. {
  568. t.reset(l);
  569. }
  570. }
  571. public void tickTiles()
  572. {
  573. for(Tile t : registeredTiles)
  574. {
  575. t.tick();
  576. }
  577. }
  578. private void menuMove(Runnable esc, Runnable enter, Runnable down, Runnable up, Runnable end)
  579. {
  580. if(Keys.ESCAPE.isReleased())
  581. {
  582. esc.run();
  583. return;
  584. }
  585. if(Keys.ENTER.isReleased())
  586. {
  587. enter.run();
  588. return;
  589. }
  590. if(Keys.DOWN.getTime() > 4)
  591. {
  592. Keys.DOWN.setTime(0);
  593. down.run();
  594. }
  595. else if(Keys.UP.getTime() > 4)
  596. {
  597. Keys.UP.setTime(0);
  598. up.run();
  599. }
  600. else if(Keys.DOWN.isReleased())
  601. {
  602. down.run();
  603. }
  604. else if(Keys.UP.isReleased())
  605. {
  606. up.run();
  607. }
  608. end.run();
  609. }
  610. @Override
  611. public void onStop()
  612. {
  613. SoundUtils.closeSounds();
  614. }
  615. }