diff --git a/MerchantRPGCSE2102/src/controller/RPGame.java b/MerchantRPGCSE2102/src/controller/RPGame.java index f52ac41..dda4f40 100644 --- a/MerchantRPGCSE2102/src/controller/RPGame.java +++ b/MerchantRPGCSE2102/src/controller/RPGame.java @@ -1,11 +1,17 @@ package controller; +import java.awt.image.BufferedImage; import java.io.File; + +import model.Object; + import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; +import java.util.Random; import java.util.Scanner; +import javax.imageio.ImageIO; import javax.swing.JFrame; import model.Map; @@ -13,96 +19,83 @@ import model.Merchant; import model.Player; import view.MapUI; import view.StartScreen; +import model.Character; public class RPGame { - + // Window properties public static final int WIDTH = 1206; public static final int HEIGHT = 929; - + // Inventory lists from file private ArrayList merchantInventoryList1 = new ArrayList(); // merchant 1's inventory list private ArrayList merchantInventoryList2 = new ArrayList(); // merchant 2's inventory list private ArrayList merchantInventoryList3 = new ArrayList(); // merchant 3's inventory list private ArrayList playerInventoryList = new ArrayList(); // the player's inventory list - private ArrayList miscList = new ArrayList(); - + // Character instances private Player _player; private Merchant _merchant1; private Merchant _merchant2; private Merchant _merchant3; private Merchant _misc1; - + // Map instance private Map map; - + // MapUI instance and properties private MapUI mapui; - + // Current game properties public boolean _movement = true; private int _currentDay; private int _transactionLimit; - public boolean _initialGameVariable; - public RPGame(int transactionLimit, int tileSize) { - + // Initializing member variables _currentDay = 1; _transactionLimit = transactionLimit; - + // Calculating number of rows and columns for map int rows = (HEIGHT - 29)/tileSize; int cols = (WIDTH - 6)/tileSize; - + // Read inventory lists from file inventoryFromFile(); - + // Build merchant and player instances buildMerchants(); buildPlayer("test", 500); - - // Initialize the start screen - _initialGameVariable = false; - - try { - createStartScreen(this); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - while(_initialGameVariable == false) - { - System.out.println("In Loop"); - } - - // Initialiing Map instance and adding the player and merchants to the map + + // Initialiing Map instance and adding the player, objects, and merchants to the map map = new Map(rows, cols); + Object object = new Object(rows/2, cols/2 - 1, "house"); map.initializePlayer(_player, rows/2, cols/2); map.initializeMerchant(_merchant1, rows/2, 1); map.initializeMerchant(_merchant2, rows-2, cols/2); map.initializeMerchant(_merchant3, rows/2, cols-2); - map.initializeMerchant(_misc1, rows/3, cols/3); + map.initializeObject(object, rows/2, cols/2 - 1); // Creating the MapUI instance and Sprites cooresponding to characters mapui = new MapUI(map, this, tileSize); mapui.createPlayerSprite(rows/2, cols/2); mapui.addMerchantSprite(rows/2, 1); - mapui.addCollison(rows/2,1); mapui.addMerchantSprite(rows-2, cols/2); - mapui.addCollison(rows-2, cols/2); mapui.addMerchantSprite(rows/2, cols-2); - mapui.addCollison(rows/2, cols-2); - //just the object collison - mapui.addCollison(rows/3, cols/3); - + mapui.addObject(object); + buildRandomEnvironment(250); + // Creating JFrame window - JFrame frame = new JFrame("Merchant RPG"); - + JFrame frame = new JFrame("The Merchant RPG"); + try { + frame.setIconImage(loadIcon()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // Adding MapUI instance to window frame.add(mapui); @@ -114,6 +107,17 @@ public class RPGame { frame.setLocationRelativeTo(null); } + + public BufferedImage loadIcon() throws IOException { + BufferedImage img = null; + try { + img = ImageIO.read(new File("src/images/icon.png")); + return img; + } catch (IOException e) { + System.out.println("File not found"); + return null; + } + } /** * This method scans the inventory.txt file located in src\config. It will read lines of the format and store them in the inventory list member variables @@ -161,7 +165,6 @@ public class RPGame { _merchant1 = new Merchant("Cheap Merchant", 300, merchantInventoryList1, 0); _merchant2 = new Merchant("Medium Merchant", 600, merchantInventoryList2, merchantInventoryList1.size()); _merchant3 = new Merchant("Expensive Merchant", 1000, merchantInventoryList3, merchantInventoryList1.size()+ merchantInventoryList2.size()); - _misc1 = new Merchant(null, 0, miscList, 0); } /** @@ -174,6 +177,48 @@ public class RPGame { _player = new Player(name, startingCash, playerInventoryList); } + public void buildRandomEnvironment(int size) { + int clusterCount = 0; + boolean newCluster = true; + + for (int i = 0; i < size; i++) { + if (clusterCount == 6) { + clusterCount = 0; + newCluster = true; + } + Random randomGenerator = new Random(); + int row = randomGenerator.nextInt(map.getRows()-1); + int col = randomGenerator.nextInt(map.getCols()-1); + + while (map.isOccupied(col, row) || closeToCharacter(row, col) || (!newCluster && !(map.isOccupiedByObject(col + 1, row) || map.isOccupiedByObject(col - 1, row) || map.isOccupiedByObject(col, row + 1) || map.isOccupiedByObject(col, row - 1) || map.isOccupiedByObject(col - 1, row - 1) || map.isOccupiedByObject(col + 1, row + 1) || map.isOccupiedByObject(col - 1, row + 1) || map.isOccupiedByObject(col + 1, row - 1)))) { + row = randomGenerator.nextInt(map.getRows()-1); + col = randomGenerator.nextInt(map.getCols()-1); + } + Object object = new Object(row, col, "tree"); + map.initializeObject(object, row, col); + mapui.addObject(object); + clusterCount++; + newCluster = false; + } + } + + public boolean closeToCharacter(int row, int col) { + Object o = new Object(row, col, ""); + if (distanceBetween(o, _merchant1) < 90) + return true; + if (distanceBetween(o, _merchant2) < 90) + return true; + if (distanceBetween(o, _merchant3) < 90) + return true; + if (distanceBetween(o, _player) < 90) + return true; + return false; + } + + public int distanceBetween(Character a, Character b) { + return (int) Math.sqrt(Math.pow((a.getCol()-b.getCol())*30, 2) + Math.pow((a.getRow()-b.getRow())*30, 2)); + } + /** * This method returns the specified merchant inventory list * @@ -224,11 +269,6 @@ public class RPGame { } } - public void createStartScreen(RPGame game) throws IOException - { - StartScreen newStartScreen = new StartScreen(game); - } - /** * Will refresh number of transactions the Player has available * @@ -295,7 +335,7 @@ public class RPGame { targetMerchant.addCash(increaseAmount); targetMerchant.refreshCash(); } - + /** * Updates the MapUI to move characters and detect events * @@ -369,6 +409,18 @@ public class RPGame { */ public static void main(String[] args) throws InterruptedException, IOException { + + // Initialize the start screen + StartScreen startScreen = new StartScreen(); + boolean ready = false; + + while(ready == false) + { + System.out.println(""); + ready = startScreen.getStatus(); + } + + int fps = 300; // Frames per second RPGame rpgGame = new RPGame(3, 30); diff --git a/MerchantRPGCSE2102/src/images/RPG_samplemap.png b/MerchantRPGCSE2102/src/images/RPG_samplemap.png index 03fbf72..1df83d9 100644 Binary files a/MerchantRPGCSE2102/src/images/RPG_samplemap.png and b/MerchantRPGCSE2102/src/images/RPG_samplemap.png differ diff --git a/MerchantRPGCSE2102/src/images/dialogbubble.png b/MerchantRPGCSE2102/src/images/dialogbubble.png index d9500ad..0d1fc47 100644 Binary files a/MerchantRPGCSE2102/src/images/dialogbubble.png and b/MerchantRPGCSE2102/src/images/dialogbubble.png differ diff --git a/MerchantRPGCSE2102/src/images/house.png b/MerchantRPGCSE2102/src/images/house.png new file mode 100644 index 0000000..b127b21 Binary files /dev/null and b/MerchantRPGCSE2102/src/images/house.png differ diff --git a/MerchantRPGCSE2102/src/images/tree.png b/MerchantRPGCSE2102/src/images/tree.png new file mode 100644 index 0000000..436eb7f Binary files /dev/null and b/MerchantRPGCSE2102/src/images/tree.png differ diff --git a/MerchantRPGCSE2102/src/images/water.png b/MerchantRPGCSE2102/src/images/water.png new file mode 100644 index 0000000..59292c4 Binary files /dev/null and b/MerchantRPGCSE2102/src/images/water.png differ diff --git a/MerchantRPGCSE2102/src/model/Map.java b/MerchantRPGCSE2102/src/model/Map.java index b42c479..4e3f2e0 100644 --- a/MerchantRPGCSE2102/src/model/Map.java +++ b/MerchantRPGCSE2102/src/model/Map.java @@ -9,6 +9,7 @@ public class Map { private int[] initialPlayerLocation = new int[2]; private Player _player; private Merchant currentNearbyMerchant; + private Character currentNearbyHouse; public Map(int rows, int cols) { _rows = rows; @@ -46,6 +47,19 @@ public class Map { _mapGraph.getVertex(vertexNum).setOccupant(merchant); } + /** + * This method stores the sepcified instance of Object at the specified position on the map + * @param player The object to be initialized + * @param row The row of the object's location + * @param col The column of the object's location + */ + public void initializeObject(Object object, int row, int col) { + int vertexNum = row*_cols + col; + object.setCol(col); + object.setRow(row); + _mapGraph.getVertex(vertexNum).setOccupant(object); + } + /** * Moves the specified instance of Player in the specified direction on the map * @param String The direction to be moved (north, west, east, or south) @@ -63,7 +77,7 @@ public class Map { } } } - + if (direction.equals("east")) { if (currentCol != _cols - 1) { if (!isOccupied(currentCol + 1, currentRow)) { @@ -73,7 +87,7 @@ public class Map { } } } - + if (direction.equals("south")) { if (currentRow != _rows - 1) { if (!isOccupied(currentCol, currentRow + 1)) { @@ -83,7 +97,7 @@ public class Map { } } } - + if (direction.equals("west")) { if (currentCol != 0) { if (!isOccupied(currentCol - 1, currentRow)) { @@ -93,7 +107,7 @@ public class Map { } } } - + } /** @@ -115,19 +129,46 @@ public class Map { return false; else { if (_mapGraph.getVertex(row*_cols + col).getOccupant() != null) { - System.out.println(_mapGraph.getVertex(row*_cols + col).getOccupant().getClass().getName()); if (_mapGraph.getVertex(row*_cols + col).getOccupant().getClass().getName().equals("model.Merchant")) setCurrentNearbyMerchant((Merchant) _mapGraph.getVertex(row*_cols + col).getOccupant()); return true; } } - + setCurrentNearbyMerchant(null); return false; } + + public boolean isOccupiedByObject(int col, int row) { + if (row < 0 || col < 0 || row >= _rows || col >= _cols) + return false; + else { + if (_mapGraph.getVertex(row*_cols + col).getOccupant() != null) { + if (_mapGraph.getVertex(row*_cols + col).getOccupant().getClass().getName().equals("model.Object")) + if (_mapGraph.getVertex(row*_cols + col).getOccupant().getName().equals("tree")) + return true; + } + } + return false; + } + public boolean isOccupiedByHouse(int col, int row) { + if (row < 0 || col < 0 || row >= _rows || col >= _cols) + return false; + else { + if (_mapGraph.getVertex(row*_cols + col).getOccupant() != null) { + if (_mapGraph.getVertex(row*_cols + col).getOccupant().getClass().getName().equals("model.Object")) + if (_mapGraph.getVertex(row*_cols + col).getOccupant().getName().equals("house")) { + setCurrentNearbyHouse(_mapGraph.getVertex(row*_cols + col).getOccupant()); + return true; + } + } + } + return false; + } + public boolean collisionTo(String direction) { - + if (direction.equals("north")) return isOccupied(_player.getCol(), _player.getRow() - 1); if (direction.equals("south")) @@ -146,15 +187,26 @@ public class Map { return isOccupied(_player.getCol() + 1, _player.getRow() + 1); return false; } - - + + public void resetPlayerLocation() { _mapGraph.getVertex(_player.getRow()*_cols + _player.getCol()).setOccupant(null); _mapGraph.getVertex(initialPlayerLocation[0]*_cols + initialPlayerLocation[1]).setOccupant(_player); _player.setCol(initialPlayerLocation[1]); _player.setRow(initialPlayerLocation[0]); } - + + public boolean isHouseNearPlayer() { + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <=1; j++) { + if (!(i == 0 && j == 0)) + if (isOccupiedByHouse(_player.getCol() + j, _player.getRow() + i)) + return true; + } + } + return false; + } + public Player getPlayer() { return _player; } @@ -166,13 +218,21 @@ public class Map { public void setCurrentNearbyMerchant(Merchant currentNearbyMerchant) { this.currentNearbyMerchant = currentNearbyMerchant; } - + public int getRows() { return _rows; } - + public int getCols() { return _cols; } + public Character getCurrentNearbyHouse() { + return currentNearbyHouse; + } + + public void setCurrentNearbyHouse(Character currentNearbyHouse) { + this.currentNearbyHouse = currentNearbyHouse; + } + } diff --git a/MerchantRPGCSE2102/src/model/Object.java b/MerchantRPGCSE2102/src/model/Object.java index a53239b..5fef033 100644 --- a/MerchantRPGCSE2102/src/model/Object.java +++ b/MerchantRPGCSE2102/src/model/Object.java @@ -1,6 +1,6 @@ package model; -public class Object { +public class Object extends Character { private int col, row; private String name; diff --git a/MerchantRPGCSE2102/src/sprites/ObjectSprite.java b/MerchantRPGCSE2102/src/sprites/ObjectSprite.java new file mode 100644 index 0000000..7bf32ed --- /dev/null +++ b/MerchantRPGCSE2102/src/sprites/ObjectSprite.java @@ -0,0 +1,57 @@ +package sprites; + +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import model.Object; + +import javax.imageio.ImageIO; + +public class ObjectSprite { + + private static final int WIDTH = 30; + private int x, y; + private BufferedImage objectImage = null; + private String name; + + public ObjectSprite(Object object) { + this.name = object.getName(); + this.x = object.getCol()*WIDTH; + this.y = object.getRow()*WIDTH; + loadSprite(); + } + public void loadSprite() { + + try { + if (name.equals("tree")) + objectImage = ImageIO.read(new File("src/images/tree.png")); + else if (name.equals("house")) { + objectImage = ImageIO.read(new File("src/images/house.png")); + } + + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Paints the sprite at its current location + * @param g Graphics2D for painting + */ + public void paint(Graphics2D g) { + g.drawImage(objectImage, x, y, null); + } + + /** + * Gets the bounds of the sprite in the form of a Rectangle + * @return the Rectangle formed by the sprite + */ + public Rectangle getBounds() { + return new Rectangle(x, y, WIDTH, WIDTH); + } +} + + diff --git a/MerchantRPGCSE2102/src/sprites/PlayerSprite.java b/MerchantRPGCSE2102/src/sprites/PlayerSprite.java index d2e78bd..00e976a 100644 --- a/MerchantRPGCSE2102/src/sprites/PlayerSprite.java +++ b/MerchantRPGCSE2102/src/sprites/PlayerSprite.java @@ -89,8 +89,10 @@ public class PlayerSprite { public void keyReleased(KeyEvent e) { if(e.getKeyChar()=='n') { - mapui.nextDay(); - resetLocation(); + if (isHouseNearby()) { + mapui.nextDay(); + resetLocation(); + } } if (e.getKeyCode() == KeyEvent.VK_LEFT) { @@ -153,27 +155,28 @@ public class PlayerSprite { if (collision()) { // If there is a collision, we check from which direction the collision occurs. During each collision the sprite is stopped and their position is reset so they are no longer collided. - if (mapui.getMap().collisionTo("east")) { + // Also check the changeInX and changeInY to make sure the occupant in each direction is actually what the player is colliding into + if (mapui.getMap().collisionTo("east") && changeInX > 15) { dx = 0; setChangeInX(getChangeInX() - 1); setX(getX() - 1); } - if (mapui.getMap().collisionTo("west")) { + if (mapui.getMap().collisionTo("west") && changeInX < 15) { dx = 0; setChangeInX(getChangeInX() + 1); setX(getX() + 1); } - if (mapui.getMap().collisionTo("north")) { + if (mapui.getMap().collisionTo("north") && changeInY < 15) { dy = 0; setChangeInY(getChangeInY() + 1); setY(getY() + 1); } - if (mapui.getMap().collisionTo("south")) { + if (mapui.getMap().collisionTo("south") && changeInY > 15) { dy = 0; setChangeInY(getChangeInY() - 1); setY(getY() - 1); } - if (mapui.getMap().collisionTo("northwest")) { + if (mapui.getMap().collisionTo("northwest") && changeInY < 15 && changeInX < 15) { dy = 0; dx = 0; setChangeInY(getChangeInY() + 1); @@ -181,7 +184,7 @@ public class PlayerSprite { setY(getY() + 1); setX(getX() + 1); } - if (mapui.getMap().collisionTo("southwest")) { + if (mapui.getMap().collisionTo("southwest") && changeInY > 15 && changeInX < 15) { dy = 0; dx = 0; setChangeInY(getChangeInY() - 1); @@ -189,7 +192,7 @@ public class PlayerSprite { setY(getY() - 1); setX(getX() + 1); } - if (mapui.getMap().collisionTo("northeast")) { + if (mapui.getMap().collisionTo("northeast") && changeInY < 15 && changeInX > 15) { dy = 0; dx = 0; setChangeInY(getChangeInY() + 1); @@ -197,7 +200,7 @@ public class PlayerSprite { setY(getY() + 1); setX(getX() - 1); } - if (mapui.getMap().collisionTo("southeast")) { + if (mapui.getMap().collisionTo("southeast") && changeInY > 15 && changeInX > 15) { dy = 0; dx = 0; setChangeInY(getChangeInY() - 1); @@ -252,6 +255,9 @@ public class PlayerSprite { for (MerchantSprite merchant : mapui.getMerchants()) if (merchant.getBounds().intersects(getBounds())) return true; + for (ObjectSprite object : mapui.getCollisions()) + if (object.getBounds().intersects(getBounds())) + return true; return false; } @@ -294,4 +300,8 @@ public class PlayerSprite { return false; } + public boolean isHouseNearby() { + return mapui.getMap().isHouseNearPlayer(); + } + } diff --git a/MerchantRPGCSE2102/src/view/MapUI.java b/MerchantRPGCSE2102/src/view/MapUI.java index 2c8378d..ad4f488 100644 --- a/MerchantRPGCSE2102/src/view/MapUI.java +++ b/MerchantRPGCSE2102/src/view/MapUI.java @@ -1,6 +1,9 @@ package view; import java.awt.Color; + +import model.Object; + import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; @@ -18,6 +21,7 @@ import javax.swing.JPanel; import controller.RPGame; import model.Map; import sprites.MerchantSprite; +import sprites.ObjectSprite; import sprites.PlayerSprite; @@ -29,7 +33,7 @@ public class MapUI extends JPanel { public int tileSize; private PlayerSprite player; private ArrayList merchants = new ArrayList(); - private ArrayList collisons = new ArrayList(); + private ArrayList collisions = new ArrayList(); public MapUI(Map map, RPGame Game, int tileSize) { @@ -74,6 +78,9 @@ public class MapUI extends JPanel { // Paints each merchant onto the canvas for (MerchantSprite merchant : merchants) merchant.paint(g2d); + + for (ObjectSprite object : collisions) + object.paint(g2d); if (player.isMerchantNearby()) { if (map.getCurrentNearbyMerchant().getName() != null) { @@ -83,6 +90,10 @@ public class MapUI extends JPanel { g2d.drawImage(loadImage("dialogbubble.png"), (map.getCurrentNearbyMerchant().getCol() + 1)*tileSize, map.getCurrentNearbyMerchant().getRow()*tileSize - 60, null); } } + + if (player.isHouseNearby()) + g2d.drawImage(loadImage("dialogbubble-newday.png"), (map.getCurrentNearbyHouse().getCol() + 1)*tileSize, map.getCurrentNearbyHouse().getRow()*tileSize - 60, null); + g2d.setColor(Color.BLUE); g2d.setFont(new Font("Verdana", Font.BOLD, 18)); @@ -101,9 +112,9 @@ public class MapUI extends JPanel { MerchantSprite merchant = new MerchantSprite(row, col); merchants.add(merchant); } - public void addCollison(int row, int col) { - MerchantSprite merchant = new MerchantSprite(row, col); - collisons.add(merchant); + public void addObject(Object object) { + ObjectSprite objectSprite = new ObjectSprite(object); + collisions.add(objectSprite); } /** * Creates a player sprite to be painted on the canvas @@ -180,9 +191,13 @@ public class MapUI extends JPanel { public Map getMap() { return map; } - + public ArrayList getMerchants() { - return collisons; + return merchants; + } + + public ArrayList getCollisions() { + return collisions; } diff --git a/MerchantRPGCSE2102/src/view/StartScreen.java b/MerchantRPGCSE2102/src/view/StartScreen.java index 8f933ca..39547bd 100644 --- a/MerchantRPGCSE2102/src/view/StartScreen.java +++ b/MerchantRPGCSE2102/src/view/StartScreen.java @@ -1,30 +1,23 @@ package view; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; - import javax.imageio.ImageIO; import javax.swing.*; -import javax.swing.border.EmptyBorder; - -import controller.RPGame; -import model.Player; @SuppressWarnings("serial") public class StartScreen extends JFrame { JPanel startMenu = new JPanel(); - RPGame _master; + boolean gameReady; - public StartScreen(RPGame master) throws IOException { + public StartScreen() throws IOException { - _master = master; + gameReady = false; JLabel MainMenuBG = new JLabel(new ImageIcon("src/images/background.jpg")); MainMenuBG.setVisible(true); Image icon, background; @@ -46,7 +39,7 @@ public class StartScreen extends JFrame { @Override public void mouseReleased(MouseEvent arg0) { System.out.println("Game started"); - _master._initialGameVariable = true; + gameReady = true; exitWindow(); } @@ -102,6 +95,10 @@ public class StartScreen extends JFrame { } } + public boolean getStatus() { + return gameReady; + } + public void exitWindow() { this.dispose();