Work through the AI book

Signed-off-by: Chris Cromer <chris@cromer.cl>
This commit is contained in:
Chris Cromer 2019-09-21 20:41:21 -03:00
parent 86d6dcb4ab
commit ca46991813
46 changed files with 4588 additions and 175 deletions

5
.gitignore vendored
View File

@ -1,2 +1,3 @@
out
doc
/out/
/doc/
/log/

View File

@ -0,0 +1,12 @@
<component name="ArtifactManager">
<artifact type="jar" name="Game:jar">
<output-path>$PROJECT_DIR$/out/artifacts/Game_jar</output-path>
<root id="archive" name="Game.jar">
<element id="module-output" name="Game" />
<element id="extracted-dir" path="$PROJECT_DIR$/lib/json-simple-3.1.0.jar" path-in-jar="/" />
<element id="directory" name="javadoc">
<element id="dir-copy" path="$PROJECT_DIR$/doc" />
</element>
</root>
</artifact>
</component>

View File

@ -0,0 +1,7 @@
<component name="ProjectDictionaryState">
<dictionary name="cromer">
<words>
<w>cromer</w>
</words>
</dictionary>
</component>

10
.idea/libraries/lib.xml Normal file
View File

@ -0,0 +1,10 @@
<component name="libraryTable">
<library name="lib">
<CLASSES>
<root url="file://$PROJECT_DIR$/lib" />
</CLASSES>
<JAVADOC />
<SOURCES />
<jarDirectory url="file://$PROJECT_DIR$/lib" recursive="false" />
</library>
</component>

View File

@ -2,8 +2,9 @@
<project version="4">
<component name="JavadocGenerationManager">
<option name="OUTPUT_DIRECTORY" value="$PROJECT_DIR$/doc" />
<option name="OPTION_SCOPE" value="private" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_12" default="true" project-jdk-name="12" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11 OpenJDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

124
.idea/uiDesigner.xml Normal file
View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

View File

@ -2,11 +2,16 @@
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<javadoc-paths>
<root url="file://$MODULE_DIR$/doc" />
</javadoc-paths>
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/doc" />
<excludeFolder url="file://$MODULE_DIR$/log" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="lib" level="project" />
</component>
</module>

BIN
lib/json-simple-3.1.0.jar Normal file

Binary file not shown.

3
src/META-INF/MANIFEST.MF Normal file
View File

@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: cl.cromer.game.Main

View File

@ -15,9 +15,18 @@
package cl.cromer.game;
import java.awt.*;
import javax.swing.JComponent;
import cl.cromer.game.sprite.Animation;
import cl.cromer.game.sprite.AnimationException;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.logging.Logger;
/**
* This class is a cell that will contain a game element such as a player, enemy, prize, etc
*/
public class Celda extends JComponent implements Constantes {
/**
* The x coordinate of the cell
@ -31,18 +40,22 @@ public class Celda extends JComponent implements Constantes {
* The type of cell
*/
private Type type = Type.SPACE;
/**
* The possible types of cell that this could be
* If the cell is selected
*/
protected enum Type {
SPACE,
PLAYER,
END,
ENEMY,
OBSTACLE,
PRIZE
}
private boolean selected = false;
/**
* The sprites that can be used in the cell
*/
private Animation animation = null;
/**
* The tiles to show in this cell
*/
private ArrayList<BufferedImage> tiles = new ArrayList<>();
/**
* The logger
*/
private Logger logger;
/**
* Initialize the cell with its coordinates
@ -52,6 +65,85 @@ public class Celda extends JComponent implements Constantes {
public Celda(int x, int y) {
this.x = x;
this.y = y;
logger = getLogger(this.getClass(), CELDA_LOG_LEVEL);
}
/**
* Set the x and y coordinates of the cell
*
* @param x The x coordinate
* @param y The y coordinate
*/
public void setCoords(int x, int y) {
this.x = x;
this.y = y;
}
/**
* Get the x coordinate of the cell
*
* @return Returns the x coordinate
*/
public int getX() {
return x;
}
/**
* Set the x coordinate for the cell
*
* @param x The new x coordinate
*/
public void setX(int x) {
this.x = x;
}
/**
* Get the y coordinate for the cell
*
* @return Returns the y coordinate
*/
public int getY() {
return y;
}
/**
* Set the y coordinate for the cell
*
* @param y The new y coordinate
*/
public void setY(int y) {
this.y = y;
}
/**
* Get the sprite for the cell
*
* @return Return the sprite in use
*/
public Animation getAnimation() {
return animation;
}
/**
* Set which sprite to use for this cell
*
* @param animation The sprite to show
*/
public void setAnimation(Animation animation) {
this.animation = animation;
}
public void addTile(BufferedImage tile) {
tiles.add(tile);
}
/**
* Get the current type of this cell
*
* @return Returns the type of cell
*/
public Type getType() {
return this.type;
}
/**
@ -63,61 +155,102 @@ public class Celda extends JComponent implements Constantes {
}
/**
* Get the current type of this cell
* @return Returns the type of cell
*/
private Type getType() {
return this.type;
}
/**
* Override the paintComponent method of JComponent to pain the cell based on type
* Override the paintComponent method of JComponent to paint the cell based on type
* @param g The graphics object to paint
*/
@Override
public void paintComponent(Graphics g) {
// Draw the borders
g.setColor(Color.black);
g.drawRect(x, y, CELL_PIXELS, CELL_PIXELS);
update(g);
}
/**
* Override the update method of JComponent to do double buffering
* @param g The graphics object to paint
*/
@Override
public void update(Graphics g) {
// Set the text font
g.setFont(new Font("monospaced", Font.BOLD, 10));
// Fill in the cell
for (BufferedImage tile : tiles) {
if (tile != null) {
g.drawImage(tile, x, y, null);
}
}
// Draw a sprite in the cell if needed
switch (getType()) {
case SPACE:
g.setColor(Color.orange);
g.fillRect(x + 1, y + 1, CELL_PIXELS - 1, CELL_PIXELS - 1);
break;
case PLAYER:
g.setColor(Color.green);
g.fillRect(x + 1, y + 1, CELL_PIXELS - 1, CELL_PIXELS - 1);
g.setColor(Color.black);
g.drawString(String.valueOf(PLAYER), x + (CELL_PIXELS / 2), y + (CELL_PIXELS / 2));
case ENEMY:
case CHEST:
try {
if (animation != null && animation.getFrame() != null) {
g.drawImage(animation.getFrame(), x + animation.getXOffset(), y + animation.getYOffset(), null);
}
}
catch (AnimationException e) {
logger.warning(e.getMessage());
}
break;
case END:
case PORTAL:
g.setColor(Color.pink);
g.fillRect(x + 1, y + 1, CELL_PIXELS - 1, CELL_PIXELS - 1);
g.setColor(Color.black);
g.drawString(String.valueOf(END), x + (CELL_PIXELS / 2), y + (CELL_PIXELS / 2));
break;
case PRIZE:
g.setColor(Color.red);
g.fillRect(x + 1, y + 1, CELL_PIXELS - 1, CELL_PIXELS - 1);
g.setColor(Color.black);
g.drawString(String.valueOf(PRIZE), x + (CELL_PIXELS / 2), y + (CELL_PIXELS / 2));
break;
case ENEMY:
g.setColor(Color.blue);
g.fillRect(x + 1, y + 1, CELL_PIXELS - 1, CELL_PIXELS - 1);
g.setColor(Color.black);
g.drawString(String.valueOf(ENEMY), x + (CELL_PIXELS / 2), y + (CELL_PIXELS / 2));
break;
case OBSTACLE:
g.setColor(Color.black);
g.fillRect(x + 1, y + 1, CELL_PIXELS - 1, CELL_PIXELS - 1);
g.setColor(Color.white);
g.drawString(String.valueOf(OBSTACLE), x + (CELL_PIXELS / 2), y + (CELL_PIXELS / 2));
break;
}
// The cell is selected
if (isSelected()) {
g.setColor(Color.black);
g.drawRect(x, y, CELL_PIXELS - 1, CELL_PIXELS - 1);
}
}
/**
* Check if the cell is selected
*
* @return Returns true if the cell is selected
*/
public boolean isSelected() {
return selected;
}
/**
* Set the call as selected or unselected
*
* @param selected True if the cell is selected
*/
public void setSelected(boolean selected) {
this.selected = selected;
}
/**
* Called when the player uses mouse to select cell
*
* @param clickX The x coordinate
* @param clickY They y coordinate
* @return Returns true if the cell is selected
*/
public boolean selected(int clickX, int clickY) {
Rectangle rectangle = new Rectangle(x, y, CELL_PIXELS, CELL_PIXELS);
if (rectangle.contains(new Point(clickX, clickY))) {
selected = !selected;
return true;
}
return false;
}
/**
* The possible types of cell that this could be
*/
public enum Type {
PLAYER,
ENEMY,
SPACE,
PORTAL,
OBSTACLE,
CHEST,
KEY
}
}

View File

@ -15,67 +15,179 @@
package cl.cromer.game;
import cl.cromer.game.logging.HtmlFormatter;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Constants used in the game
*/
public interface Constantes {
/**
* The name of the game
*/
String TITLE = "La Aventura de Azaraka";
/**
* The level of logs to record
*/
Level GLOBAL_LOG_LEVEL = Level.WARNING;
Level MAIN_LOG_LEVEL = Level.WARNING;
Level VENTANA_PRINCIPAL_LOG_LEVEL = Level.WARNING;
Level LIENZO_LOG_LEVEL = Level.WARNING;
Level ESCENARIO_LOG_LEVEL = Level.WARNING;
Level ENEMY_LOG_LEVEL = Level.WARNING;
Level CONFIG_LOG_LEVEL = Level.WARNING;
Level SOUND_LOG_LEVEL = Level.WARNING;
Level IMAGE_LOG_LEVEL = Level.WARNING;
Level CELDA_LOG_LEVEL = Level.WARNING;
/**
* Use a global log if true or individual logs if false
*/
boolean GLOBAL_LOG = true;
/**
* Append to the logs if true or make a new log if false
*/
boolean APPEND_LOGS = false;
/**
* The size in pixels of the cells
*/
int CELL_PIXELS = 32;
int CELL_PIXELS = 64;
/**
* The number of cells to draw horizontally
*/
int HORIZONTAL_CELLS = 40;
int HORIZONTAL_CELLS = 18;
/**
* The number of cells to draw vertically
*/
int VERTICAL_CELLS = 20;
/**
* The window border width
*/
int WINDOW_BORDER_WIDTH = 30;
/**
* The window border height
*/
int WINDOW_BORDER_HEIGHT = 50;
int VERTICAL_CELLS = 10;
/**
* The scene width
*/
int SCENE_WIDTH = (CELL_PIXELS * HORIZONTAL_CELLS) + WINDOW_BORDER_WIDTH;
/**
* The scene height
*/
int SCENE_HEIGHT = (CELL_PIXELS * VERTICAL_CELLS) + WINDOW_BORDER_HEIGHT;
int TOP_MARGIN = 40;
int LEFT_MARGIN = 40;
Dimension SCREEN_SIZE = Toolkit.getDefaultToolkit().getScreenSize();
/**
* The letter that represents the player
*/
char PLAYER = 'P';
/**
* The letter that represents the end
*/
char END = 'F';
/**
* The letter that represents the prize
* The amount of chests to draw
*/
char PRIZE = 'G';
/**
* The letter that represents the enemy
*/
char ENEMY = 'E';
/**
* The letter that represents the obstacle
*/
char OBSTACLE = 'O';
/**
* The amount of prizes to draw
*/
int PRIZES = 5;
int CHESTS = 3;
/**
* The amount of enemies to draw
*/
int ENEMIES = 3;
int ENEMIES = 2;
int PLAYER_START_X = 2;
int PLAYER_START_Y = 1;
int FONT_SIZE = 12;
Font BOLD_FONT = new Font("monospaced", Font.BOLD, FONT_SIZE);
Font FONT = new Font("monospaced", Font.PLAIN, FONT_SIZE);
int MINIMUM_SPEED = 100;
int MAXIMUM_SPEED = 500;
int DEFAULT_SPEED = 100;
int MINIMUM_VOLUME = 0;
int MAXIMUM_VOLUME = 100;
int DEFAULT_VOLUME = 100;
boolean GENERATE_SCENE = false;
boolean EXPORT_SCENE = false;
/**
* Generate a random number between given min and max
*
* @param min Minimum number in range
* @param max Maximum number in range
* @return Returns a random number
*/
default int random(int min, int max) {
Random random = new Random();
return random.nextInt((max - min) + 1) + min;
}
/**
* Initialize the logger and assign a html handler
*
* @param logClass The class to be initialized
*/
default void initializeLogger(Class logClass) {
String className = logClass.getName();
Logger logger;
if (GLOBAL_LOG) {
logger = Logger.getGlobal();
}
else {
logger = Logger.getLogger(className);
}
FileHandler fileHandler = null;
File directory = new File("log");
if (!directory.exists()) {
if (!directory.mkdir()) {
System.out.println("Could not make directory \"log\"");
}
}
try {
if (GLOBAL_LOG) {
fileHandler = new FileHandler("log/log.html", APPEND_LOGS);
}
else {
fileHandler = new FileHandler("log/" + className + ".html", APPEND_LOGS);
}
}
catch (IOException e) {
e.printStackTrace();
}
if (fileHandler != null) {
logger.addHandler(fileHandler);
}
Formatter formatter = new HtmlFormatter();
if (fileHandler != null) {
fileHandler.setFormatter(formatter);
}
}
/**
* Get a logger object to use for debugging
*
* @param logClass The class that is in need of a logger
* @param level What log level to use
* @return Returns the logger
*/
default Logger getLogger(Class logClass, Level level) {
String className = logClass.getName();
Logger logger;
if (GLOBAL_LOG) {
logger = Logger.getGlobal();
}
else {
logger = Logger.getLogger(className);
}
if (logger.getHandlers().length == 0) {
initializeLogger(logClass);
}
if (GLOBAL_LOG) {
logger.setLevel(GLOBAL_LOG_LEVEL);
}
else {
logger.setLevel(level);
}
return logger;
}
/**
* The sprite type
*/
enum SpriteType {
PLAYER,
ENEMY,
CHEST
}
}

View File

@ -15,87 +15,908 @@
package cl.cromer.game;
import java.awt.Graphics;
import cl.cromer.game.sound.Sound;
import cl.cromer.game.sound.SoundException;
import cl.cromer.game.sprite.*;
import com.github.cliftonlabs.json_simple.JsonArray;
import com.github.cliftonlabs.json_simple.JsonObject;
import com.github.cliftonlabs.json_simple.Jsoner;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.io.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JComponent;
import java.util.Map;
import java.util.logging.Logger;
/**
* The scene used for the game
*/
public class Escenario extends JComponent implements Constantes {
/**
* The width of the scene
*/
protected int width = CELL_PIXELS * HORIZONTAL_CELLS;
/**
* The height of the scene
*/
protected int height = CELL_PIXELS * VERTICAL_CELLS;
/**
* The canvas
*/
private Lienzo canvas;
/**
* The cells of the game
*/
private Celda[][] celdas;
/**
* The cell that contains the player
*/
private Celda player;
/**
* A hashmap that contains all the sprites for the game
*/
private Map<SpriteType, Animation> sprites = new AnimationMap();
/**
* A collection of tiles that can be used in the scene
*/
private Sheet textureSheet;
/**
* Whether or not the door is closed yet
*/
private boolean doorClosed = false;
/**
* The logger
*/
private Logger logger;
/**
* Initialize the scene
*/
public Escenario() {
Random random = new Random();
final int cells = (HORIZONTAL_CELLS * VERTICAL_CELLS);
final int obstacles = (int) Math.floor((double) cells * 0.1);
int random_value;
ArrayList<RandomPositionList> arrayList = new ArrayList<>();
for (int i = 0; i < ENEMIES; i++) {
random_value = random.nextInt(cells - 1) + 1;
while (arrayList.contains(new RandomPositionList(random_value, Celda.Type.ENEMY))) {
random_value = random.nextInt(cells - 1) + 1;
}
arrayList.add(new RandomPositionList(random_value, Celda.Type.ENEMY));
}
for (int i = 0; i < PRIZES; i++) {
random_value = random.nextInt(cells - 1) + 1;
while (arrayList.contains(new RandomPositionList(random_value, Celda.Type.PRIZE))) {
random_value = random.nextInt(cells - 1) + 1;
}
arrayList.add(new RandomPositionList(random_value, Celda.Type.PRIZE));
}
for (int i = 0; i < obstacles; i++) {
random_value = random.nextInt(cells - 1) + 1;
while (arrayList.contains(new RandomPositionList(random_value, Celda.Type.OBSTACLE))) {
random_value = random.nextInt(cells - 1) + 1;
}
arrayList.add(new RandomPositionList(random_value, Celda.Type.OBSTACLE));
}
random_value = random.nextInt(cells - 1) + 1;
while (arrayList.contains(new RandomPositionList(random_value, Celda.Type.END))) {
random_value = random.nextInt(cells - 1) + 1;
}
arrayList.add(new RandomPositionList(random_value, Celda.Type.END));
public Escenario(Lienzo canvas) {
logger = getLogger(this.getClass(), ESCENARIO_LOG_LEVEL);
this.canvas = canvas;
loadResources();
player = new Celda(PLAYER_START_X, PLAYER_START_Y);
celdas = new Celda[HORIZONTAL_CELLS][VERTICAL_CELLS];
int cell_count = 0;
StringBuilder stringBuilder;
if (!GENERATE_SCENE) {
stringBuilder = new StringBuilder();
InputStream inputStream = getClass().getResourceAsStream("/res/scene.json");
try {
String line;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line);
}
}
catch (IOException e) {
logger.warning(e.getMessage());
}
}
int cellCount = 0;
for (int i = 0; i < HORIZONTAL_CELLS; i++) {
for (int j = 0; j < VERTICAL_CELLS; j++) {
celdas[i][j] = new Celda(i * CELL_PIXELS + 10, j * CELL_PIXELS + 10);
if (i == 0 && j == 0) {
celdas[i][j].setType(Celda.Type.PLAYER);
celdas[i][j] = new Celda((i * CELL_PIXELS) + LEFT_MARGIN, (j * CELL_PIXELS) + TOP_MARGIN);
if (GENERATE_SCENE) {
generateScene(i, j);
}
else {
for (RandomPositionList randomList : arrayList) {
if (cell_count == randomList.getPosition()) {
celdas[i][j].setType(randomList.getType());
break;
}
}
loadScene(i, j, stringBuilder, cellCount);
cellCount++;
}
cell_count++;
}
}
if (EXPORT_SCENE) {
exportScene();
}
generateRandomObjects();
}
private void generateRandomObjects() {
final int cells = (HORIZONTAL_CELLS * VERTICAL_CELLS);
final int obstacles = (int) Math.floor((double) cells * 0.05);
int random_x;
int random_y;
ArrayList<RandomPositionList> arrayList = new ArrayList<>();
for (int i = 0; i < ENEMIES; i++) {
random_x = random(0, HORIZONTAL_CELLS - 1);
random_y = random(0, VERTICAL_CELLS - 1);
while (arrayList.contains(new RandomPositionList(random_x, random_y, Celda.Type.ENEMY)) || celdas[random_x][random_y].getType() != Celda.Type.SPACE) {
random_x = random(0, HORIZONTAL_CELLS - 1);
random_y = random(0, VERTICAL_CELLS - 1);
}
arrayList.add(new RandomPositionList(random_x, random_y, Celda.Type.ENEMY));
}
for (int i = 0; i < obstacles; i++) {
random_x = random(0, HORIZONTAL_CELLS - 1);
random_y = random(0, VERTICAL_CELLS - 1);
while (arrayList.contains(new RandomPositionList(random_x, random_y, Celda.Type.OBSTACLE)) || celdas[random_x][random_y].getType() != Celda.Type.SPACE) {
random_x = random(0, HORIZONTAL_CELLS - 1);
random_y = random(0, VERTICAL_CELLS - 1);
}
arrayList.add(new RandomPositionList(random_x, random_y, Celda.Type.OBSTACLE));
}
for (int i = 0; i < CHESTS; i++) {
random_x = random(0, HORIZONTAL_CELLS - 1);
random_y = random(0, VERTICAL_CELLS - 1);
// Don't put a chest if it can't be opened
while (arrayList.contains(new RandomPositionList(random_x, random_y, Celda.Type.CHEST)) || arrayList.contains(new RandomPositionList(random_x, random_y + 1, Celda.Type.CHEST)) || celdas[random_x][random_y].getType() != Celda.Type.SPACE || celdas[random_x][random_y + 1].getType() != Celda.Type.SPACE) {
random_x = random(0, HORIZONTAL_CELLS - 1);
random_y = random(0, VERTICAL_CELLS - 1);
}
arrayList.add(new RandomPositionList(random_x, random_y, Celda.Type.CHEST));
}
/*random_value = random(1, cells);
while (arrayList.contains(new RandomPositionList(random_value, Celda.Type.PORTAL))) {
random_value = random(1, cells);
}
arrayList.add(new RandomPositionList(random_value, Celda.Type.PORTAL));*/
for (RandomPositionList randomList : arrayList) {
int x = randomList.getX();
int y = randomList.getY();
celdas[x][y].setType(randomList.getType());
switch (randomList.getType()) {
case ENEMY:
celdas[x][y].setAnimation(sprites.get(SpriteType.ENEMY));
break;
case CHEST:
celdas[x][y].setAnimation(sprites.get(SpriteType.CHEST));
break;
case OBSTACLE:
try {
celdas[x][y].addTile(textureSheet.getTile(30));
}
catch (SheetException e) {
e.printStackTrace();
}
break;
}
}
}
/**
* Override the painComponent method of JComponent to paint the scene
* Generate the scene manually without the JSON file
*
* @param x The cell x position
* @param y The cell y position
*/
private void generateScene(int x, int y) {
logger.info("Generate cell x: " + x + " y: " + y + " manually");
try {
celdas[x][y].addTile(textureSheet.getTile(0));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
if (x == 0 && y == 0) {
// Top left corner
celdas[x][y].setType(Celda.Type.OBSTACLE);
try {
celdas[x][y].addTile(textureSheet.getTile(33));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
else if (x == 4 && y == 3) {
// Obstacle on floor
try {
celdas[x][y].setType(Celda.Type.OBSTACLE);
celdas[x][y].addTile(textureSheet.getTile(30));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
else if (x == 6 && y == 6) {
// Blood on floor
try {
celdas[x][y].addTile(textureSheet.getTile(12));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
else if (x == HORIZONTAL_CELLS - 1 && y == 0) {
// Top right corner
celdas[x][y].setType(Celda.Type.OBSTACLE);
try {
celdas[x][y].addTile(textureSheet.getTile(37));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
else if (x == 0 && y == VERTICAL_CELLS - 1) {
// Bottom left corner
celdas[x][y].setType(Celda.Type.OBSTACLE);
try {
celdas[x][y].addTile(textureSheet.getTile(97));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
else if (x == HORIZONTAL_CELLS - 1 && y == VERTICAL_CELLS - 1) {
// Bottom right corner
celdas[x][y].setType(Celda.Type.OBSTACLE);
try {
celdas[x][y].addTile(textureSheet.getTile(101));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
else if (y == 0) {
// Top wall
celdas[x][y].setType(Celda.Type.OBSTACLE);
if (x == 1) {
// Left door frame
try {
celdas[x][y].addTile(textureSheet.getTile(144));
celdas[x][y].addTile(textureSheet.getTile(192));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
else if (x == 2) {
// Door
try {
celdas[x][y].addTile(textureSheet.getTile(145));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
else if (x == 3) {
// Right door frame
try {
celdas[x][y].addTile(textureSheet.getTile(146));
celdas[x][y].addTile(textureSheet.getTile(194));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
else if (x == 8) {
// Broken wall piece
try {
celdas[x][y].addTile(textureSheet.getTile(105));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
else if (x % 2 == 0) {
try {
celdas[x][y].addTile(textureSheet.getTile(34));
celdas[x][y].addTile(textureSheet.getTile(222));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
else {
try {
celdas[x][y].addTile(textureSheet.getTile(35));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
}
else if (x == 0) {
// Left wall
celdas[x][y].setType(Celda.Type.OBSTACLE);
if (y % 2 == 0) {
try {
celdas[x][y].addTile(textureSheet.getTile(49));
celdas[x][y].addTile(textureSheet.getTile(255));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
else {
try {
celdas[x][y].addTile(textureSheet.getTile(65));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
}
else if (x == HORIZONTAL_CELLS - 1) {
// Right wall
celdas[x][y].setType(Celda.Type.OBSTACLE);
if (y % 2 == 0) {
try {
celdas[x][y].addTile(textureSheet.getTile(53));
celdas[x][y].addTile(textureSheet.getTile(238));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
else {
try {
celdas[x][y].addTile(textureSheet.getTile(69));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
}
else if (y == VERTICAL_CELLS - 1) {
// Bottom wall
celdas[x][y].setType(Celda.Type.OBSTACLE);
if (x % 2 == 0) {
try {
celdas[x][y].addTile(textureSheet.getTile(98));
celdas[x][y].addTile(textureSheet.getTile(207));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
else {
try {
celdas[x][y].addTile(textureSheet.getTile(99));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
}
if (x == PLAYER_START_X && y == PLAYER_START_Y) {
celdas[x][y].setType(Celda.Type.PLAYER);
celdas[x][y].setAnimation(sprites.get(SpriteType.PLAYER));
}
else if (x == 10 && y == 3) {
celdas[x][y].setType(Celda.Type.ENEMY);
celdas[x][y].setAnimation(sprites.get(SpriteType.ENEMY));
}
else if (x == 10 && y == 7) {
celdas[x][y].setType(Celda.Type.ENEMY);
celdas[x][y].setAnimation(sprites.get(SpriteType.ENEMY));
}
/*else if (x == 16 && y == 1) {
celdas[x][y].setType(Celda.Type.CHEST);
celdas[x][y].setAnimation(sprites.get(SpriteType.CHEST));
}
else if (x == 12 && y == 7) {
celdas[x][y].setType(Celda.Type.CHEST);
celdas[x][y].setAnimation(sprites.get(SpriteType.CHEST));
}*/
/*else {
for (RandomPositionList randomList : arrayList) {
if (cellCount == randomList.getPosition()) {
celdas[i][j].setType(randomList.getType());
switch (randomList.getType()) {
case ENEMY:
celdas[i][j].setAnimation(sprites.get(SpriteType.ENEMY));
break;
case CHEST:
Animation chestSprite = sprites.get(SpriteType.CHEST);
celdas[i][j].setAnimation(chestSprite);
break;
}
break;
}
}
}*/
}
/**
* Load the cell for the scene
*
* @param x The cell x position
* @param y The cell y position
* @param stringBuilder The string builder which contains the JSON
* @param cellCount Which cell to get out of the JSON
*/
private void loadScene(int x, int y, StringBuilder stringBuilder, int cellCount) {
logger.info("Load cell x: " + x + " y: " + y + " from JSON file");
JsonArray jsonArray = Jsoner.deserialize(stringBuilder.toString(), new JsonArray());
// Get the cell
JsonObject cell = (JsonObject) jsonArray.get(cellCount);
// Get the textures
JsonObject textures = (JsonObject) cell.get("textures");
// Get the type
BigDecimal bigDecimal = (BigDecimal) cell.get("type");
int type = bigDecimal.intValue();
// Create the textures needed
for (int k = 0; k < textures.size(); k++) {
int tile = Integer.parseInt(textures.get(String.valueOf(k)).toString());
try {
celdas[x][y].addTile(textureSheet.getTile(tile));
}
catch (SheetException e) {
logger.warning(e.getMessage());
}
}
// Set the type and animation
if (type == Celda.Type.PLAYER.ordinal()) {
celdas[x][y].setType(Celda.Type.PLAYER);
celdas[x][y].setAnimation(sprites.get(SpriteType.PLAYER));
}
else if (type == Celda.Type.ENEMY.ordinal()) {
celdas[x][y].setType(Celda.Type.ENEMY);
celdas[x][y].setAnimation(sprites.get(SpriteType.ENEMY));
}
else if (type == Celda.Type.CHEST.ordinal()) {
celdas[x][y].setType(Celda.Type.CHEST);
celdas[x][y].setAnimation(sprites.get(SpriteType.CHEST));
}
else if (type == Celda.Type.OBSTACLE.ordinal()) {
celdas[x][y].setType(Celda.Type.OBSTACLE);
}
}
/**
* Export the scene to a JSON file
*/
private void exportScene() {
logger.info("Export scene to JSON");
JsonObject textures;
JsonObject cell;
JsonArray cells = new JsonArray();
for (int i = 0; i < HORIZONTAL_CELLS; i++) {
for (int j = 0; j < VERTICAL_CELLS; j++) {
cell = new JsonObject();
textures = new JsonObject();
textures.put("0", 0);
if (i == 0 && j == 0) {
// Top left corner
textures.put("1", 33);
cell.put("type", Celda.Type.OBSTACLE.ordinal());
}
else if (i == 4 && j == 3) {
// Obstacle on floor
textures.put("1", 30);
cell.put("type", Celda.Type.OBSTACLE.ordinal());
}
else if (i == 6 && j == 6) {
// Blood on floor
textures.put("1", 12);
cell.put("type", Celda.Type.SPACE.ordinal());
}
else if (i == HORIZONTAL_CELLS - 1 && j == 0) {
// Top right corner
textures.put("1", 37);
cell.put("type", Celda.Type.OBSTACLE.ordinal());
}
else if (i == 0 && j == VERTICAL_CELLS - 1) {
// Bottom left corner
textures.put("1", 97);
cell.put("type", Celda.Type.OBSTACLE.ordinal());
}
else if (i == HORIZONTAL_CELLS - 1 && j == VERTICAL_CELLS - 1) {
// Bottom right corner
textures.put("1", 101);
cell.put("type", Celda.Type.OBSTACLE.ordinal());
}
else if (j == 0) {
// Top wall
if (i == 1) {
// Left door frame
textures.put("1", 144);
textures.put("2", 192);
}
else if (i == 2) {
// Door
textures.put("1", 145);
}
else if (i == 3) {
// Right door frame
textures.put("1", 146);
textures.put("2", 194);
}
else if (i == 8) {
// Broken wall piece
textures.put("1", 105);
}
else if (i % 2 == 0) {
textures.put("1", 34);
textures.put("2", 222);
}
else {
textures.put("1", 35);
}
cell.put("type", Celda.Type.OBSTACLE.ordinal());
}
else if (i == 0) {
// Left wall
if (j % 2 == 0) {
textures.put("1", 49);
textures.put("2", 255);
}
else {
textures.put("1", 65);
}
cell.put("type", Celda.Type.OBSTACLE.ordinal());
}
else if (i == HORIZONTAL_CELLS - 1) {
// Right wall
if (j % 2 == 0) {
textures.put("1", 53);
textures.put("2", 238)