package ch.idsia.mario.engine;
import ch.idsia.ai.agents.Agent;
import ch.idsia.ai.agents.human.CheaterKeyboardAgent;
import ch.idsia.mario.engine.sprites.Mario;
import ch.idsia.mario.environments.Environment;
import ch.idsia.tools.EvaluationInfo;
import ch.idsia.tools.GameViewer;
import ch.idsia.tools.tcp.ServerAgent;
import javax.swing.*;
import java.awt.*;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.image.VolatileImage;
import java.util.ArrayList;
import java.util.List;
public class MarioComponent extends JComponent implements Runnable, /*KeyListener,*/ FocusListener, Environment {
private static final long serialVersionUID = 790878775993203817L;
public static final int TICKS_PER_SECOND = 24;
private boolean running = false;
private int width, height;
private GraphicsConfiguration graphicsConfiguration;
private Scene scene;
private boolean focused = false;
int frame;
int delay;
Thread animator;
private int ZLevelEnemies = 1;
private int ZLevelMap = 1;
public void setGameViewer(GameViewer gameViewer) {
this.gameViewer = gameViewer;
}
private GameViewer gameViewer = null;
private Agent agent = null;
private CheaterKeyboardAgent cheatAgent = null;
private KeyAdapter prevHumanKeyBoardAgent;
private Mario mario = null;
private LevelScene levelScene = null;
public MarioComponent(int width, int height) {
adjustFPS();
this.setFocusable(true);
this.setEnabled(true);
this.width = width;
this.height = height;
Dimension size = new Dimension(width, height);
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setFocusable(true);
if (this.cheatAgent == null)
{
this.cheatAgent = new CheaterKeyboardAgent();
this.addKeyListener(cheatAgent);
}
GlobalOptions.registerMarioComponent(this);
}
public void adjustFPS() {
int fps = GlobalOptions.FPS;
delay = (fps > 0) ? (fps >= GlobalOptions.InfiniteFPS) ? 0 : (1000 / fps) : 100;
// System.out.println("Delay: " + delay);
}
public void paint(Graphics g) {
}
public void update(Graphics g) {
}
public void init() {
graphicsConfiguration = getGraphicsConfiguration();
// if (graphicsConfiguration != null) {
Art.init(graphicsConfiguration);
// }
}
public void start() {
if (!running) {
running = true;
animator = new Thread(this, "Game Thread");
animator.start();
}
}
public void stop() {
running = false;
}
public void run() {
}
// write frames to disk
public VolatileImage image = null;
public EvaluationInfo run1(int currentAttempt, int totalNumberOfAttempts) {
running = true;
adjustFPS();
EvaluationInfo evaluationInfo = new EvaluationInfo();
image = null;
Graphics g = null;
Graphics og = null;
image = createVolatileImage(320, 240);
g = getGraphics();
og = image.getGraphics();
if (!GlobalOptions.VisualizationOn) {
String msgClick = "Vizualization is not available";
drawString(og, msgClick, 160 - msgClick.length() * 4, 110, 1);
drawString(og, msgClick, 160 - msgClick.length() * 4, 110, 7);
}
addFocusListener(this);
// Remember the starting time
long tm = System.currentTimeMillis();
long tick = tm;
int marioStatus = Mario.STATUS_RUNNING;
mario = ((LevelScene) scene).mario;
int totalActionsPerfomed = 0;
// TODO: Manage better place for this:
Mario.resetCoins();
while (/*Thread.currentThread() == animator*/ running) {
// Display the next frame of animation.
// repaint();
tm = System.currentTimeMillis();
scene.tick();
if (gameViewer != null && gameViewer.getContinuousUpdatesState())
gameViewer.tick();
float alpha = 0;
// og.setColor(Color.RED);
if (GlobalOptions.VisualizationOn) {
og.fillRect(0, 0, 320, 240);
scene.render(og, alpha);
}
if (agent instanceof ServerAgent && !((ServerAgent) agent).isAvailable()) {
System.err.println("Agent became unavailable. Simulation Stopped");
running = false;
break;
}
boolean[] action = agent.getAction(this/*DummyEnvironment*/);
if (action != null)
{
for (int i = 0; i < Environment.numberOfButtons; ++i)
if (action[i])
{
++totalActionsPerfomed;
break;
}
}
else
{
System.err.println("Null Action received. Skipping simulation...");
stop();
}
//Apply action;
// scene.keys = action;
((LevelScene) scene).mario.keys = action;
((LevelScene) scene).mario.cheatKeys = cheatAgent.getAction(null);
if (GlobalOptions.VisualizationOn) {
if (GlobalOptions.drawText){
String msg = "Attempt: " + currentAttempt + " of " + ((totalNumberOfAttempts == -1) ? "\\infty" : totalNumberOfAttempts);
drawString(og, msg, 7, 31, 0);
drawString(og, msg, 6, 30, 1);
msg = agent.getName();
drawString(og, msg, 7, 41, 0);
drawString(og, msg, 6, 40, 5);
msg = "Selected Actions: ";
drawString(og, msg, 7, 51, 0);
drawString(og, msg, 6, 50, 6);
msg = "";
if (action != null)
{
for (int i = 0; i < Environment.numberOfButtons; ++i)
msg += (action[i]) ? scene.keysStr[i] : " ";
}
else
msg = "NULL";
drawString(og, msg, 6, 70, 1);
if (!this.hasFocus() && tick / 4 % 2 == 0) {
String msgClick = "CLICK TO PLAY";
// og.setColor(Color.YELLOW);
// og.drawString(msgClick, 320 + 1, 20 + 1);
drawString(og, msgClick, 160 - msgClick.length() * 4, 110, 1);
drawString(og, msgClick, 160 - msgClick.length() * 4, 110, 7);
}
og.setColor(Color.DARK_GRAY);
drawString(og, "FPS: " + ((GlobalOptions.FPS > 99) ? "\\infty" : GlobalOptions.FPS.toString()), 5, 22, 0);
drawString(og, "FPS: " + ((GlobalOptions.FPS > 99) ? "\\infty" : GlobalOptions.FPS.toString()), 4, 21, 7);
}
if (width != 320 || height != 240) {
g.drawImage(image, 0, 0, 640 * 2, 480 * 2, null);
} else {
g.drawImage(image, 0, 0, null);
}
} else {
// Win or Die without renderer!! independently.
marioStatus = ((LevelScene) scene).mario.getStatus();
if (marioStatus != Mario.STATUS_RUNNING)
stop();
}
// Delay depending on how far we are behind.
if (delay > 0)
try {
tm += delay;
Thread.sleep(Math.max(0, tm - System.currentTimeMillis()));
} catch (InterruptedException e) {
break;
}
// Advance the frame
frame++;
}
//=========
evaluationInfo.agentType = agent.getClass().getSimpleName();
evaluationInfo.agentName = agent.getName();
evaluationInfo.marioStatus = mario.getStatus();
evaluationInfo.livesLeft = mario.lives;
evaluationInfo.lengthOfLevelPassedPhys = mario.x;
evaluationInfo.lengthOfLevelPassedCells = mario.mapX;
evaluationInfo.totalLengthOfLevelCells = levelScene.level.getWidthCells();
evaluationInfo.totalLengthOfLevelPhys = levelScene.level.getWidthPhys();
evaluationInfo.timeSpentOnLevel = levelScene.getStartTime();
evaluationInfo.timeLeft = levelScene.getTimeLeft();
evaluationInfo.totalTimeGiven = levelScene.getTotalTime();
evaluationInfo.numberOfGainedCoins = Mario.coins;
// evaluationInfo.totalNumberOfCoins = -1 ; // TODO: total Number of coins.
evaluationInfo.totalActionsPerfomed = totalActionsPerfomed; // Counted during the play/simulation process
evaluationInfo.totalFramesPerfomed = frame;
evaluationInfo.marioMode = mario.getMode();
// evaluationInfo.Memo = "Number of attempt: " + Mario.numberOfAttempts;
if (agent instanceof ServerAgent && mario.keys != null /*this will happen if client quits unexpectedly in case of Server mode*/)
((ServerAgent)agent).integrateEvaluationInfo(evaluationInfo);
return evaluationInfo;
}
private void drawString(Graphics g, String text, int x, int y, int c) {
char[] ch = text.toCharArray();
for (int i = 0; i < ch.length; i++) {
g.drawImage(Art.font[ch[i] - 32][c], x + i * 8, y, null);
}
}
public void startLevel(long seed, int difficulty, int type, int levelLength, int timeLimit) {
scene = new LevelScene(graphicsConfiguration, this, seed, difficulty, type, levelLength, timeLimit);
levelScene = ((LevelScene) scene);
scene.init();
}
public void levelFailed() {
// scene = mapScene;
Mario.lives--;
stop();
}
public void focusGained(FocusEvent arg0) {
focused = true;
}
public void focusLost(FocusEvent arg0) {
focused = false;
}
public void levelWon() {
stop();
// scene = mapScene;
// mapScene.levelWon();
}
public void toTitle() {
// Mario.resetStatic();
// scene = new TitleScene(this, graphicsConfiguration);
// scene.init();
}
public List<String> getTextObservation(boolean Enemies, boolean LevelMap, boolean Complete, int ZLevelMap, int ZLevelEnemies) {
if (scene instanceof LevelScene)
return ((LevelScene) scene).LevelSceneAroundMarioASCII(Enemies, LevelMap, Complete, ZLevelMap, ZLevelEnemies);
else {
return new ArrayList<String>();
}
}
public String getBitmapEnemiesObservation()
{
if (scene instanceof LevelScene)
return ((LevelScene) scene).bitmapEnemiesObservation(1);
else {
//
return new String();
}
}
public String getBitmapLevelObservation()
{
if (scene instanceof LevelScene)
return ((LevelScene) scene).bitmapLevelObservation(1);
else {
//
return null;
}
}
// upcoming feature for Milano conf, unkomment this, if you would like to try it!
// Chaning ZLevel during the game on-the-fly;
public byte[][] getCompleteObservation(/*int ZLevelMap, int ZLevelEnemies*/) {
// this.ZLevelMap = ZLevelMap;
// this.ZLevelEnemies = ZLevelEnemies;
if (scene instanceof LevelScene)
return ((LevelScene) scene).mergedObservation(this.ZLevelMap, this.ZLevelEnemies);
return null;
}
public byte[][] getEnemiesObservation(/*int ZLevelEnemies*/) {
// this.ZLevelEnemies = ZLevelEnemies;
if (scene instanceof LevelScene)
return ((LevelScene) scene).enemiesObservation(this.ZLevelEnemies);
return null;
}
public byte[][] getLevelSceneObservation(/*int ZLevelMap*/) {
// this.ZLevelMap = ZLevelMap;
if (scene instanceof LevelScene)
return ((LevelScene) scene).levelSceneObservation(this.ZLevelMap);
return null;
}
public boolean isMarioOnGround() {
return mario.isOnGround();
}
public boolean mayMarioJump() {
return mario.mayJump();
}
public void setAgent(Agent agent) {
this.agent = agent;
if (agent instanceof KeyAdapter) {
if (prevHumanKeyBoardAgent != null)
this.removeKeyListener(prevHumanKeyBoardAgent);
this.prevHumanKeyBoardAgent = (KeyAdapter) agent;
this.addKeyListener(prevHumanKeyBoardAgent);
}
}
public void setPaused(boolean paused) {
levelScene.paused = paused;
}
public void setZLevelEnemies(int ZLevelEnemies) {
this.ZLevelEnemies = ZLevelEnemies;
}
public void setZLevelMap(int ZLevelMap) {
this.ZLevelMap = ZLevelMap;
}
public float[] getMarioFloatPos()
{
return new float[]{this.mario.x, this.mario.y};
}
public float[] getEnemiesFloatPos()
{
if (scene instanceof LevelScene)
return ((LevelScene) scene).enemiesFloatPos();
return null;
}
public int getMarioMode()
{
return mario.getMode();
}
public boolean isMarioCarrying()
{
return mario.carried != null;
}
}