diff --git a/Mario-AI-Interface/src/Play.java b/Mario-AI-Interface/src/Play.java index 5bf2c1d..a22cfac 100644 --- a/Mario-AI-Interface/src/Play.java +++ b/Mario-AI-Interface/src/Play.java @@ -23,31 +23,35 @@ public class Play { public static void main(String[] args) throws IOException { String groupID = args[0]; String levelName = args[1]; -// MarioGame game = new MarioGame(); -// -//// String levelPath = String.format("/app/levels/group%s/%s.txt", groupID, levelName); // For web -//// String repPath = String.format("/files/tmp.rep"); // For web -// -// String levelPath = String.format("./levels/group%s/%s.txt", groupID, levelName); // For local -// String repPath = String.format("./reps/%s_sav.rep", levelName); // For local + MarioGame game = new MarioGame(); + +// String levelPath = String.format("/app/levels/group%s/%s.txt", groupID, levelName); // For web +// String repPath = String.format("/files/tmp.rep"); // For web + game.setLives(10); + String levelPath = String.format("./levels/group%s/%s.txt", groupID, levelName); // For local + String repPath = String.format("./reps/%s_sav.rep", levelName); // For local + MarioResult r2 = game.playGame(getLevel(levelPath), repPath); // MarioResult tmpResult = game.playGame(Replay.getRepAgentFromFile(repPath),getLevel(levelPath), 200, repPath); // MarioGame game2 = new MarioGame(); -// MarioResult r2 = game2.playGame(getLevel(levelPath),200,repPath) } - public static byte[] playGameMain(String groupID, String levelName){ + public static byte[] playGameMain(String groupID, String levelName, int lives){ String levelPath = String.format("/app/levels/%s.lvl", levelName); // For web String repPath = String.format("/files/%s_sav.rep", levelName); // For web - MarioGame game = new MarioGame(); + game.setLives(lives); MarioResult tmpResult = game.playGame(new HumanAgent(),getLevel(levelPath), 200, repPath); return Replay.serializeAgentEvents(tmpResult.getAgentEvents()); } + public static byte[] playGameMain(String groupID, String levelName){ + return playGameMain(groupID, levelName, 0); + } + public static void replayGameMain(String groupID, String levelName){ String levelPath = String.format("/app/levels/%s.lvl", levelName); // For web String repPath = String.format("/files/%s_sav.rep", levelName); // For web diff --git a/Mario-AI-Interface/src/engine/core/MarioGame.java b/Mario-AI-Interface/src/engine/core/MarioGame.java index e8e8215..ab4ec96 100644 --- a/Mario-AI-Interface/src/engine/core/MarioGame.java +++ b/Mario-AI-Interface/src/engine/core/MarioGame.java @@ -56,6 +56,7 @@ public class MarioGame { private MarioRender render = null; private MarioAgent agent = null; private MarioWorld world = null; + private int initialLives; /** * Create a mario game to be played @@ -86,6 +87,9 @@ public class MarioGame { this.render.addKeyListener((KeyAdapter) this.agent); } } + public MarioResult playGame(String level, String resultPath) { + return this.runGame(new agents.HumanAgent(), level, 200, 0, true, 30, 2, resultPath); + } /** * Play a certain mario level @@ -144,6 +148,7 @@ public class MarioGame { if (visual) { this.world.initializeVisuals(this.render.getGraphicsConfiguration()); } + this.world.lives = this.initialLives; this.world.mario.isLarge = marioState > 0; this.world.mario.isFire = marioState > 1; this.world.update(new boolean[MarioActions.numberOfActions()]); @@ -206,16 +211,19 @@ public class MarioGame { return new MarioResult(this.world, gameEvents, agentEvents); } public static void showNewWindow(JFrame relativeWindow) { - // 创建一个新窗口 - JFrame newJFrame = new JFrame("新的窗口"); + // 鍒涘缓涓�涓柊绐楀彛 + JFrame newJFrame = new JFrame("鏂扮殑绐楀彛"); newJFrame.setSize(250, 250); - // 把新窗口的位置设置到 relativeWindow 窗口的中心 + // 鎶婃柊绐楀彛鐨勪綅缃缃埌 relativeWindow 绐楀彛鐨勪腑蹇� newJFrame.setLocationRelativeTo(relativeWindow); newJFrame.setVisible(true); } + public void setLives(int lives) { + this.initialLives = lives; + } } diff --git a/Mario-AI-Interface/src/engine/core/MarioLevel.java b/Mario-AI-Interface/src/engine/core/MarioLevel.java index bc31b00..f00eebe 100644 --- a/Mario-AI-Interface/src/engine/core/MarioLevel.java +++ b/Mario-AI-Interface/src/engine/core/MarioLevel.java @@ -21,6 +21,7 @@ public class MarioLevel { private int[][] levelTiles; private SpriteType[][] spriteTemplates; private int[][] lastSpawnTime; + private boolean[][] solidMap; private MarioTilemap graphics; private MarioImage flag; @@ -41,6 +42,7 @@ public class MarioLevel { this.levelTiles = new int[lines[0].length()][lines.length]; this.spriteTemplates = new SpriteType[lines[0].length()][lines.length]; this.lastSpawnTime = new int[lines[0].length()][lines.length]; + this.solidMap = new boolean[lines[0].length()][lines.length]; for (int y = 0; y < lines.length; y++) { for (int x = 0; x < lines[y].length(); x++) { this.levelTiles[x][y] = 0; @@ -54,6 +56,7 @@ public class MarioLevel { for (int y = 0; y < lines.length; y++) { for (int x = 0; x < lines[y].length(); x++) { Character c = lines[y].charAt(x); + this.solidMap[x][y] = this.isSolid(c); switch (c) { case 'M': this.marioTileX = x; @@ -283,10 +286,12 @@ public class MarioLevel { level.exitTileY = this.exitTileY; level.levelTiles = new int[this.levelTiles.length][this.levelTiles[0].length]; level.lastSpawnTime = new int[this.levelTiles.length][this.levelTiles[0].length]; + level.solidMap = new boolean[this.levelTiles.length][this.levelTiles[0].length]; for (int x = 0; x < level.levelTiles.length; x++) { for (int y = 0; y < level.levelTiles[x].length; y++) { level.levelTiles[x][y] = this.levelTiles[x][y]; level.lastSpawnTime[x][y] = this.lastSpawnTime[x][y]; + level.solidMap[x][y] = this.solidMap[x][y]; } } level.spriteTemplates = this.spriteTemplates; @@ -386,4 +391,11 @@ public class MarioLevel { this.flag.render(og, this.exitTileX * 16 - 8 - cameraX, Math.max(1, this.exitTileY - 11) * 16 + 16 - cameraY); } } + + public boolean standable(int xTile, int yTile) { + if (yTile >= this.tileHeight) + return false; + else + return !this.solidMap[xTile][yTile] && this.solidMap[xTile][yTile+1]; + } } diff --git a/Mario-AI-Interface/src/engine/core/MarioWorld.java b/Mario-AI-Interface/src/engine/core/MarioWorld.java index 2ddf12a..905f80a 100644 --- a/Mario-AI-Interface/src/engine/core/MarioWorld.java +++ b/Mario-AI-Interface/src/engine/core/MarioWorld.java @@ -3,7 +3,6 @@ package engine.core; import java.awt.Graphics; import java.awt.GraphicsConfiguration; import java.util.ArrayList; - import engine.effects.*; import engine.graphics.MarioBackground; import engine.helper.EventType; @@ -13,6 +12,9 @@ import engine.helper.TileFeature; import engine.sprites.*; public class MarioWorld { + public static final int onlineTimerMax = 100000; + + public GameStatus gameStatus; public int pauseTimer = 0; public int fireballsOnScreen = 0; @@ -24,9 +26,12 @@ public class MarioWorld { public boolean visuals; public int currentTick; //Status - public int coins, lives; + public int coins, lives, kills, deaths, jumps, items; + public int airStart, airTime; public ArrayList lastFrameEvents; +// private int segTime = -1; +// private int passedSegs = 0; private MarioEvent[] killEvents; private ArrayList sprites; private ArrayList shellsToCheck; @@ -37,6 +42,8 @@ public class MarioWorld { private ArrayList effects; private MarioBackground[] backgrounds = new MarioBackground[2]; +// private boolean revivable = false; + // private int totalEnemies; public MarioWorld(MarioEvent[] killEvents) { this.pauseTimer = 0; @@ -49,6 +56,9 @@ public class MarioWorld { this.effects = new ArrayList<>(); this.lastFrameEvents = new ArrayList<>(); this.killEvents = killEvents; + this.lives = 0; + this.kills = 0; + this.deaths = 0; } public void initializeVisuals(GraphicsConfiguration graphicsConfig) { @@ -93,8 +103,21 @@ public class MarioWorld { this.mario.alive = true; this.mario.world = this; this.sprites.add(this.mario); +// totalEnemies = getEnemies().size(); } +// public int getTotalEnemies() { +// return level.totalEnemies; +// } + +// public int getEnemiesRemain() { +// int n = 0; +// for (int x = (int)(mario.x / 16) + MarioGame.width / 2; x < level.tileWidth; x++) { +// n += level.enemyNumList.get(x); +// } +// return n; +// } + public ArrayList getEnemies() { ArrayList enemies = new ArrayList<>(); for (MarioSprite sprite : sprites) { @@ -141,6 +164,16 @@ public class MarioWorld { if (this.mario.isFire) { marioState = 2; } + if (eventType == EventType.STOMP_KILL || eventType == EventType.FIRE_KILL || eventType == EventType.SHELL_KILL) + this.kills++; + if (eventType == EventType.COLLECT && eventParam != MarioForwardModel.OBS_COIN) + this.items++; + if (eventType == EventType.JUMP) { + this.jumps++; + this.airStart = this.currentTick; + } + if (eventType == EventType.LAND) + this.airTime += (this.currentTick - this.airStart); this.lastFrameEvents.add(new MarioEvent(eventType, eventParam, mario.x, mario.y, marioState, this.currentTick)); } @@ -187,6 +220,27 @@ public class MarioWorld { this.mario.alive = false; } + public void revive() { + int newTileX = (int) this.mario.x / 16; + int newTileY = (int) this.mario.y / 16; + try { + l: while (true) { + for (int y = this.level.tileHeight - 2; y >= 8; y--) { + if (this.level.standable(newTileX, y)) { + newTileY = y; + break l; + } + } + newTileX--; + } + } catch (ArrayIndexOutOfBoundsException e) { + this.lose(); + return; + } + this.mario.x = (float)(newTileX * 16.0 + 8); + this.mario.y = (float)(newTileY * 16.0); + } + public int[][] getSceneObservation(float centerX, float centerY, int detail) { int[][] ret = new int[MarioGame.tileWidth][MarioGame.tileHeight]; int centerXInMap = (int) centerX / 16; @@ -304,6 +358,10 @@ public class MarioWorld { if (this.currentTimer > 0) { this.currentTimer -= 30; +// if (this.segTime > 0 && (int) (this.mario.x / 512) > this.passedSegs) { +// this.passedSegs = (int) (this.mario.x / 512); +// this.currentTimer = Math.min(this.currentTimer + this.segTime, 2 * this.segTime) ; +// } if (this.currentTimer <= 0) { this.currentTimer = 0; this.timeout(); @@ -332,11 +390,18 @@ public class MarioWorld { for (MarioSprite sprite : sprites) { if (sprite.x < cameraX - 64 || sprite.x > cameraX + MarioGame.width + 64 || sprite.y > this.level.height + 32) { if (sprite.type == SpriteType.MARIO) { - this.lose(); + if (this.lives > 0) { + this.mario.getDrop(); + this.revive(); + } + else + this.lose(); } - this.removeSprite(sprite); - if (this.isEnemy(sprite) && sprite.y > MarioGame.height + 32) { - this.addEvent(EventType.FALL_KILL, sprite.type.getValue()); + else{ + this.removeSprite(sprite); + if (this.isEnemy(sprite) && sprite.y > MarioGame.height + 32) { + this.addEvent(EventType.FALL_KILL, sprite.type.getValue()); + } } continue; } @@ -433,6 +498,9 @@ public class MarioWorld { if (this.killEvents != null) { for (MarioEvent k : this.killEvents) { if (this.lastFrameEvents.contains(k)) { +// if (this.revivable) +// this.revive(); +// else this.lose(); } } @@ -526,4 +594,13 @@ public class MarioWorld { this.effects.get(i).render(og, cameraX, cameraY); } } + +// public void setSegTime(int segTime) { +// this.segTime = segTime; +// this.currentTimer = 2 * segTime; +// } + + // public void setRevivable(boolean revivable) { +// this.revivable = revivable; +// } } diff --git a/Mario-AI-Interface/src/engine/helper/Assets.java b/Mario-AI-Interface/src/engine/helper/Assets.java index 8871912..eb63254 100644 --- a/Mario-AI-Interface/src/engine/helper/Assets.java +++ b/Mario-AI-Interface/src/engine/helper/Assets.java @@ -43,8 +43,8 @@ public class Assets { private static Image getImage(GraphicsConfiguration gc, String imageName) throws IOException { //FIXME web/local - //File file = new File(System.getProperty("user.dir") + "/img/" + imageName); // Local test - File file = new File("/app/img/" + imageName); // For web + File file = new File(System.getProperty("user.dir") + "/img/" + imageName); // Local test +// File file = new File("/app/img/" + imageName); // For web BufferedImage source = ImageIO.read(file); Image image = gc.createCompatibleImage(source.getWidth(), source.getHeight(), Transparency.BITMASK); Graphics2D g = (Graphics2D) image.getGraphics(); diff --git a/Mario-AI-Interface/src/engine/sprites/Mario.java b/Mario-AI-Interface/src/engine/sprites/Mario.java index 5a05c14..a5c22b6 100644 --- a/Mario-AI-Interface/src/engine/sprites/Mario.java +++ b/Mario-AI-Interface/src/engine/sprites/Mario.java @@ -404,13 +404,38 @@ public class Mario extends MarioSprite { this.isLarge = false; } invulnerableTime = 32; - } else { - if (this.world != null) { + } else if (this.world != null) { + if (this.world.lives <= 0) { this.world.lose(); + } else { + this.world.lives -= 1; + this.world.deaths += 1; + world.pauseTimer = 3 * POWERUP_TIME; + invulnerableTime = 32; } } } + public void getDrop() { + if (!this.alive) + return; + + this.oldLarge = this.isLarge; + this.oldFire = this.isFire; + this.isFire = false; + this.isLarge = false; + if (this.world != null) { + if (this.world.lives <= 0) { + this.world.lose(); + } else if (invulnerableTime <= 0) { + this.world.lives -= 1; + this.world.deaths += 1; + world.pauseTimer = 3 * POWERUP_TIME; + } + } + invulnerableTime = 72; + } + public void getFlower() { if (!this.alive) { return;