/*
* Implementation of "Ms Pac-Man" for the "Ms Pac-Man versus Ghost Team Competition", brought
* to you by Philipp Rohlfshagen, David Robles and Simon Lucas of the University of Essex.
*
* www.pacman-vs-ghosts.net
*
* Code written by Philipp Rohlfshagen, based on earlier implementations of the game by
* Simon Lucas and David Robles.
*
* You may use and distribute this code freely for non-commercial purposes. This notice
* needs to be included in all distributions. Deviations from the original should be
* clearly documented. We welcome any comments and suggestions regarding the code.
*/
package game.core;
import game.core.G;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
//import java.io.BufferedReader;
//import java.io.File;
import java.io.File;
import java.io.IOException;
//import java.io.InputStreamReader;
//import java.net.URL;
import java.util.ArrayList;
@SuppressWarnings("serial")
public final class GameView extends JComponent
{
private static String pathImages="images";
private static String[] mazes={"maze-a.png","maze-b.png","maze-c.png","maze-d.png"};
private int MAG=2;
private int pacManDir=G.INITIAL_PAC_DIR;
private static boolean isVisible=false;
private final _G_ game;
private final BufferedImage[][] pacmanImgs=new BufferedImage[4][3];
private final BufferedImage[][][] ghostsImgs=new BufferedImage[6][4][2];
private final BufferedImage[] images;
//for debugging/illustration purposes only: draw colors in the maze to check whether controller is working
//correctly or not; can draw squares and lines (see NearestPillPacManVS for demonstration).
public static ArrayList<DebugPointer> debugPointers=new ArrayList<DebugPointer>();
public static ArrayList<DebugLine> debugLines=new ArrayList<DebugLine>();
private GameFrame frame;
private Graphics bufferGraphics;
private Image offscreen;
public GameView(_G_ game)
{
this.game=game;
images=loadImages();
isVisible=true;
pacmanImgs[G.UP][0]=getImage("mspacman-up-normal.png");
pacmanImgs[G.UP][1]=getImage("mspacman-up-open.png");
pacmanImgs[G.UP][2]=getImage("mspacman-up-closed.png");
pacmanImgs[G.RIGHT][0]=getImage("mspacman-right-normal.png");
pacmanImgs[G.RIGHT][1]=getImage("mspacman-right-open.png");
pacmanImgs[G.RIGHT][2]=getImage("mspacman-right-closed.png");
pacmanImgs[G.DOWN][0]=getImage("mspacman-down-normal.png");
pacmanImgs[G.DOWN][1]=getImage("mspacman-down-open.png");
pacmanImgs[G.DOWN][2]=getImage("mspacman-down-closed.png");
pacmanImgs[G.LEFT][0]=getImage("mspacman-left-normal.png");
pacmanImgs[G.LEFT][1]=getImage("mspacman-left-open.png");
pacmanImgs[G.LEFT][2]=getImage("mspacman-left-closed.png");
ghostsImgs[0][G.UP][0]=getImage("blinky-up-1.png");
ghostsImgs[0][G.UP][1]=getImage("blinky-up-2.png");
ghostsImgs[0][G.RIGHT][0]=getImage("blinky-right-1.png");
ghostsImgs[0][G.RIGHT][1]=getImage("blinky-right-2.png");
ghostsImgs[0][G.DOWN][0]=getImage("blinky-down-1.png");
ghostsImgs[0][G.DOWN][1]=getImage("blinky-down-2.png");
ghostsImgs[0][G.LEFT][0]=getImage("blinky-left-1.png");
ghostsImgs[0][G.LEFT][1]=getImage("blinky-left-2.png");
ghostsImgs[1][G.UP][0]=getImage("pinky-up-1.png");
ghostsImgs[1][G.UP][1]=getImage("pinky-up-2.png");
ghostsImgs[1][G.RIGHT][0]=getImage("pinky-right-1.png");
ghostsImgs[1][G.RIGHT][1]=getImage("pinky-right-2.png");
ghostsImgs[1][G.DOWN][0]=getImage("pinky-down-1.png");
ghostsImgs[1][G.DOWN][1]=getImage("pinky-down-2.png");
ghostsImgs[1][G.LEFT][0]=getImage("pinky-left-1.png");
ghostsImgs[1][G.LEFT][1]=getImage("pinky-left-2.png");
ghostsImgs[2][G.UP][0]=getImage("inky-up-1.png");
ghostsImgs[2][G.UP][1]=getImage("inky-up-2.png");
ghostsImgs[2][G.RIGHT][0]=getImage("inky-right-1.png");
ghostsImgs[2][G.RIGHT][1]=getImage("inky-right-2.png");
ghostsImgs[2][G.DOWN][0]=getImage("inky-down-1.png");
ghostsImgs[2][G.DOWN][1]=getImage("inky-down-2.png");
ghostsImgs[2][G.LEFT][0]=getImage("inky-left-1.png");
ghostsImgs[2][G.LEFT][1]=getImage("inky-left-2.png");
ghostsImgs[3][G.UP][0]=getImage("sue-up-1.png");
ghostsImgs[3][G.UP][1]=getImage("sue-up-2.png");
ghostsImgs[3][G.RIGHT][0]=getImage("sue-right-1.png");
ghostsImgs[3][G.RIGHT][1]=getImage("sue-right-2.png");
ghostsImgs[3][G.DOWN][0]=getImage("sue-down-1.png");
ghostsImgs[3][G.DOWN][1]=getImage("sue-down-2.png");
ghostsImgs[3][G.LEFT][0]=getImage("sue-left-1.png");
ghostsImgs[3][G.LEFT][1]=getImage("sue-left-2.png");
ghostsImgs[4][0][0]=getImage("edible-ghost-1.png");
ghostsImgs[4][0][1]=getImage("edible-ghost-2.png");
ghostsImgs[5][0][0]=getImage("edible-ghost-blink-1.png");
ghostsImgs[5][0][1]=getImage("edible-ghost-blink-2.png");
}
////////////////////////////////////////
////// Visual aids for debugging ///////
////////////////////////////////////////
//Adds a node to be highlighted using the color specified
//NOTE: This won't do anything in the competition but your code will still work
public synchronized static void addPoints(Game game,Color color,int... nodeIndices)
{
if(isVisible)
for(int i=0;i<nodeIndices.length;i++)
debugPointers.add(new DebugPointer(game.getX(nodeIndices[i]),game.getY(nodeIndices[i]),color));
}
//Adds a set of lines to be drawn using the color specified (fromNnodeIndices.length must be equals toNodeIndices.length)
//NOTE: This won't do anything in the competition but your code will still work
public synchronized static void addLines(Game game,Color color,int[] fromNnodeIndices,int[] toNodeIndices)
{
if(isVisible)
for(int i=0;i<fromNnodeIndices.length;i++)
debugLines.add(new DebugLine(game.getX(fromNnodeIndices[i]),game.getY(fromNnodeIndices[i]),game.getX(toNodeIndices[i]),game.getY(toNodeIndices[i]),color));
}
//Adds a line to be drawn using the color specified
//NOTE: This won't do anything in the competition but your code will still work
public synchronized static void addLines(Game game,Color color,int fromNnodeIndex,int toNodeIndex)
{
if(isVisible)
debugLines.add(new DebugLine(game.getX(fromNnodeIndex),game.getY(fromNnodeIndex),game.getX(toNodeIndex),game.getY(toNodeIndex),color));
}
public synchronized static void addLines(Game game,Color color, Point from, Point to)
{
if(isVisible)
debugLines.add(new DebugLine(from.x, from.y, to.x, to.y, color));
}
private void drawDebugInfo()
{
for(int i=0;i<debugPointers.size();i++)
{
DebugPointer dp=debugPointers.get(i);
bufferGraphics.setColor(dp.color);
bufferGraphics.fillRect(dp.x*MAG+1,dp.y*MAG+5,10,10);
}
for(int i=0;i<debugLines.size();i++)
{
DebugLine dl=debugLines.get(i);
bufferGraphics.setColor(dl.color);
bufferGraphics.drawLine(dl.x1*MAG+5,dl.y1*MAG+10,dl.x2*MAG+5,dl.y2*MAG+10);
}
debugPointers.clear();
debugLines.clear();
}
////////////////////////////////////////
////// Visual aids for debugging ///////
////////////////////////////////////////
public void paintComponent(Graphics g)
{
if(offscreen==null)
{
offscreen=createImage(this.getPreferredSize().width,this.getPreferredSize().height);
bufferGraphics=offscreen.getGraphics();
}
drawMaze();
drawDebugInfo(); //this will be used during testing only and will be disabled in the competition itself
drawPills();
drawPowerPills();
drawPacMan();
drawGhosts();
drawLives();
drawGameInfo();
if(game.gameOver())
drawGameOver();
g.drawImage(offscreen,0,0,this);
}
private void drawMaze()
{
bufferGraphics.setColor(Color.BLACK);
bufferGraphics.fillRect(0,0,game.getWidth()*MAG,game.getHeight()*MAG+20);
if(images[game.getCurMaze()]!=null)
bufferGraphics.drawImage(images[game.getCurMaze()],2,6,null);
}
private void drawPills()
{
int[] pillIndices=game.getPillIndices();
bufferGraphics.setColor(Color.white);
for(int i=0;i<pillIndices.length;i++)
if(game.checkPill(i))
bufferGraphics.fillOval(game.getX(pillIndices[i])*MAG+4,game.getY(pillIndices[i])*MAG+8,3,3);
}
private void drawPowerPills()
{
int[] powerPillIndices=game.getPowerPillIndices();
bufferGraphics.setColor(Color.white);
for(int i=0;i<powerPillIndices.length;i++)
if(game.checkPowerPill(i))
bufferGraphics.fillOval(game.getX(powerPillIndices[i])*MAG+1,game.getY(powerPillIndices[i])*MAG+5,8,8);
}
private void drawPacMan()
{
int pacLoc=game.getCurPacManLoc();
int pacDir=game.getCurPacManDir();
if(pacDir>=0 && pacDir<4)
pacManDir=pacDir;
bufferGraphics.drawImage(pacmanImgs[pacManDir][(game.getTotalTime()%6)/2],game.getX(pacLoc)*MAG-1,game.getY(pacLoc)*MAG+3,null);
}
private void drawGhosts()
{
for(int index=0;index<G.NUM_GHOSTS;index++)
{
int loc=game.getCurGhostLoc(index);
int x=game.getX(loc);
int y=game.getY(loc);
if(game.getEdibleTime(index)>0)
{
if(game.getEdibleTime(index)<_G_.EDIBLE_ALERT && ((game.getTotalTime()%6)/3)==0)
bufferGraphics.drawImage(ghostsImgs[5][0][(game.getTotalTime()%6)/3],x*MAG-1,y*MAG+3,null);
else
bufferGraphics.drawImage(ghostsImgs[4][0][(game.getTotalTime()%6)/3],x*MAG-1,y*MAG+3,null);
}
else
{
if(game.getLairTime(index)>0)
bufferGraphics.drawImage(ghostsImgs[index][G.UP][(game.getTotalTime()%6)/3],x*MAG-1+(index*5),y*MAG+3,null);
else
bufferGraphics.drawImage(ghostsImgs[index][game.getCurGhostDir(index)][(game.getTotalTime()%6)/3],x*MAG-1,y*MAG+3,null);
}
}
}
private void drawLives()
{
for(int i=0;i<game.getLivesRemaining()-1;i++) //-1 as lives remaining includes the current life
bufferGraphics.drawImage(pacmanImgs[G.RIGHT][0],210-(30*i)/2,260,null);
}
private void drawGameInfo()
{
bufferGraphics.setColor(Color.WHITE);
bufferGraphics.drawString("S: ",4,271);
bufferGraphics.drawString(""+game.getScore(),16,271);
bufferGraphics.drawString("L: ",78,271);
bufferGraphics.drawString(""+(game.getCurLevel()+1),90,271);
bufferGraphics.drawString("T: ",116,271);
bufferGraphics.drawString(""+game.getLevelTime(),129,271);
}
private void drawGameOver()
{
bufferGraphics.setColor(Color.WHITE);
bufferGraphics.drawString("Game Over",80,150);
}
public Dimension getPreferredSize()
{
return new Dimension(game.getWidth()*MAG,game.getHeight()*MAG+20);
}
private BufferedImage[] loadImages()
{
BufferedImage[] images=new BufferedImage[4];
for(int i=0;i<images.length;i++)
images[i]=getImage(mazes[i]);
return images;
}
private BufferedImage getImage(String fileName)
{
BufferedImage image=null;
try
{
//APPLET
// image=ImageIO.read(this.getClass().getResourceAsStream("/images/"+fileName));
//APPLICATION
image=ImageIO.read(new File(pathImages+System.getProperty("file.separator")+fileName));
}
catch(IOException e)
{
e.printStackTrace();
}
return image;
}
public GameView showGame()
{
this.frame=new GameFrame(this);
//just wait for a bit for player to be ready
try{Thread.sleep(2000);}catch(Exception e){}
return this;
}
public GameFrame getFrame()
{
return frame;
}
public class GameFrame extends JFrame
{
public GameFrame(JComponent comp)
{
getContentPane().add(BorderLayout.CENTER,comp);
pack();
Dimension screen=Toolkit.getDefaultToolkit().getScreenSize();
this.setLocation((int)(screen.getWidth()*3/8),(int)(screen.getHeight()*3/8));
this.setVisible(true);
this.setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
repaint();
}
}
private static class DebugPointer
{
public int x,y;
public Color color;
public DebugPointer(int x,int y,Color color)
{
this.x=x;
this.y=y;
this.color=color;
}
}
private static class DebugLine
{
public int x1,y1,x2,y2;
public Color color;
public DebugLine(int x1,int y1,int x2,int y2,Color color)
{
this.x1=x1;
this.y1=y1;
this.x2=x2;
this.y2=y2;
this.color=color;
}
}
}