diff --git a/src/BufferedImageWrapper.java b/src/BufferedImageWrapper.java index 3473ba3..9bac3f1 100644 --- a/src/BufferedImageWrapper.java +++ b/src/BufferedImageWrapper.java @@ -61,8 +61,14 @@ public class BufferedImageWrapper implements Serializable { flipImage = (Boolean)in.readObject(); o = in.readObject(); if (o instanceof String) { - image = GamePanel.getImage((String)o); + BufferedImage temporaryImage; this.imageString = (String)o; + temporaryImage = GamePanel.getImage(imageString); + if (flipImage) { + image = GamePanel.flipImageHorizontally(temporaryImage); + } else { + image = temporaryImage; + } } else { image = ImageIO.read(in); } diff --git a/src/DialogueMenu.java b/src/DialogueMenu.java index 5e778b6..70201d6 100644 --- a/src/DialogueMenu.java +++ b/src/DialogueMenu.java @@ -9,7 +9,10 @@ public class DialogueMenu extends TextBox implements Serializable { public static final int PADDING = 20; public static final int TOP_PADDING = 10; public static final double LINE_SPACING = 1.5; + public static final int FREQUENCY = 2; public BufferedImageWrapper PORTRAIT; + public int currentFrame = 0; + public int frameCounter = 0; public DialogueMenu(int y, int yHeight, Font font, BufferedImageWrapper portrait) { super(y, GamePanel.GAME_WIDTH - PORTRAIT_WIDTH - PADDING*3, yHeight, 0, font, null, null); @@ -18,6 +21,7 @@ public class DialogueMenu extends TextBox implements Serializable { } public void drawCenteredTextBox(Graphics g, String text, Color backgroundColor, Color textColor) { + text = text.substring(0, currentFrame); if (backgroundColor != null) { g.setColor(textColor); // TODO: make drawn line widths consistent @@ -59,8 +63,19 @@ public class DialogueMenu extends TextBox implements Serializable { } } - public void draw(Graphics g, String text, Color backgroundColor, Color textColor) { + public boolean draw(Graphics g, String text, Color backgroundColor, Color textColor) { + if (frameCounter >= FREQUENCY) { + frameCounter -= FREQUENCY; + currentFrame += 1; + } g.setFont(font); drawCenteredTextBox(g, text, backgroundColor, textColor); + frameCounter++; + if (currentFrame >= text.length()) { + currentFrame = 0; + return true; + } else { + return false; + } } } diff --git a/src/FileManager.java b/src/FileManager.java index d9bd032..bf2eb86 100644 --- a/src/FileManager.java +++ b/src/FileManager.java @@ -34,6 +34,8 @@ public class FileManager { } else { objectStream = new ObjectInputStream(fileStream); } + objectStream.close(); + fileStream.close(); return objectStream.readObject(); } @@ -41,6 +43,7 @@ public class FileManager { FileOutputStream fileStream = new FileOutputStream(fileLocation); ObjectOutputStream objectStream = new ObjectOutputStream(fileStream); objectStream.writeObject(o); - //System.out.println(o + " " + fileLocation); + objectStream.close(); + fileStream.close(); } } diff --git a/src/GameFrame.java b/src/GameFrame.java index afd250f..79849e8 100644 --- a/src/GameFrame.java +++ b/src/GameFrame.java @@ -26,7 +26,7 @@ public class GameFrame extends JFrame{ main.setLayout(new CardLayout()); menu = new MenuPanel(main); try { - game = (GamePanel)FileManager.readObjectFromFile("local/game_state", Arrays.asList("Any")); + game = (GamePanel)FileManager.readObjectFromFile("local/game_state.dat", Arrays.asList("Any")); game.gameFrame = main; game.addUserInterface(); game.startThread(); diff --git a/src/GamePanel.java b/src/GamePanel.java index 261e913..5bd288c 100644 --- a/src/GamePanel.java +++ b/src/GamePanel.java @@ -14,16 +14,21 @@ import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import java.io.Serializable; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.UnsupportedAudioFileException; import javax.swing.*; +import static java.nio.file.StandardCopyOption.ATOMIC_MOVE; + public class GamePanel extends JPanel implements Runnable, KeyListener, Serializable { //dimensions of window public static final int GAME_WIDTH = 1225; public static final int GAME_HEIGHT = 630; + public int bombCount; public transient JPanel gameFrame; @@ -37,9 +42,10 @@ public class GamePanel extends JPanel implements Runnable, KeyListener, Serializ // keeps track of how many ticks has elapsed since last frame change public int playerFrameCounter = 0; public int enemyFrameCounter = 0; - public boolean isPaused, isDialogue; + public boolean isPaused, isDialogue, waitForDialogue; public PauseMenu pauseMenu; public DialogueMenu dialogueMenu; + public ArrayList dialogueArray = new ArrayList(); public BufferedImageWrapper[][][] playerSpriteArray = new BufferedImageWrapper[2][2][11]; @@ -67,6 +73,7 @@ public class GamePanel extends JPanel implements Runnable, KeyListener, Serializ public BufferedImageWrapper cloud3 = new BufferedImageWrapper(("img/backgrounds/cloud3.png")); public BufferedImageWrapper bomb; public BufferedImageWrapper onePortrait = new BufferedImageWrapper(("img/dialogue/Gunther.png")); + public String lastText; public GamePanel(JPanel gameFrame) throws IOException, SpriteException, UnsupportedAudioFileException, LineUnavailableException { @@ -78,6 +85,8 @@ public class GamePanel extends JPanel implements Runnable, KeyListener, Serializ cloudThreeBackground = new BackgroundImage(1000, 200, cloud3, cloud2.image.getWidth(), cloud3.image.getHeight(), 5, camera); pauseMenu = new PauseMenu(GAME_HEIGHT/2, 100, 400, 400, GAME_WIDTH, new Font(Font.MONOSPACED, Font.BOLD, 60), "Paused"); dialogueMenu = new DialogueMenu(GAME_HEIGHT-100, 200, new Font(Font.MONOSPACED, Font.BOLD, 20), onePortrait); + dialogueArray.add("Lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum"); + dialogueArray.add("I told you so"); try { // load player sprites from disk here for (int i = 0; i < 11; i++) { @@ -254,7 +263,19 @@ public class GamePanel extends JPanel implements Runnable, KeyListener, Serializ } else if (isDialogue) { g.setColor(new Color(255, 255, 255, 100)); g.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT); - dialogueMenu.draw(g, "Lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum", Color.white, Color.black); + try { + if (waitForDialogue) { + System.out.println(dialogueArray); + dialogueMenu.currentFrame = dialogueArray.get(0).length(); + dialogueMenu.frameCounter = 0; + dialogueMenu.draw(g, dialogueArray.get(0), Color.white, Color.black); + } else if (dialogueMenu.draw(g, dialogueArray.get(0), Color.white, Color.black)) { + waitForDialogue = true; + } + } catch (IndexOutOfBoundsException e) { + isDialogue = false; + throw new RuntimeException(e); + } } } @@ -321,6 +342,8 @@ public class GamePanel extends JPanel implements Runnable, KeyListener, Serializ if (isNewStart) { LevelManager.setLevel(1); isDialogue = true; + } else { + LevelManager.bombs = bombCount; } //the CPU runs our game code too quickly - we need to slow it down! The following lines of code "force" the computer to get stuck in a loop for short intervals between calling other methods to update the screen. long lastTime = System.nanoTime(); @@ -354,14 +377,17 @@ public class GamePanel extends JPanel implements Runnable, KeyListener, Serializ // increment sprite image to be used and keeps it below 12 playerFrame = (playerFrame + 1) % 11; playerFrameCounter -= 5; - // if the player has moved enough to justify a frame change, a new save will also be made - try { - FileManager.writeObjectToFile("local/game_state", this); // this is placeholder, replace with this - } catch (IOException e) { - e.printStackTrace(); - } } } + // a new save is made every tick + bombCount = LevelManager.bombs; + try { + // atomic save to prevent EOF errors + FileManager.writeObjectToFile("local\\temp_state.dat", this); + Files.move(Path.of("local", "temp_state.dat"), Path.of("local", "game_state.dat"), ATOMIC_MOVE); + } catch (IOException e) { + e.printStackTrace(); + } repaint(); delta--; } @@ -395,7 +421,10 @@ public class GamePanel extends JPanel implements Runnable, KeyListener, Serializ if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { isPaused = !isPaused; } else if (e.getKeyCode() == KeyEvent.VK_ENTER) { - isDialogue = false; + dialogueMenu.currentFrame = 0; + dialogueMenu.frameCounter = 0; + dialogueArray.remove(0); + waitForDialogue = false; } else { player.keyPressed(e); }