Add revive feature
This commit is contained in:
parent
3a0d15b8ea
commit
e14261619e
@ -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
|
||||
|
@ -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("新的窗口");
|
||||
// 鍒涘缓涓<EFBFBD>涓柊绐楀彛
|
||||
JFrame newJFrame = new JFrame("鏂扮殑绐楀彛");
|
||||
|
||||
newJFrame.setSize(250, 250);
|
||||
|
||||
// 把新窗口的位置设置到 relativeWindow 窗口的中心
|
||||
// 鎶婃柊绐楀彛鐨勪綅缃缃埌 relativeWindow 绐楀彛鐨勪腑蹇<EFBFBD>
|
||||
newJFrame.setLocationRelativeTo(relativeWindow);
|
||||
|
||||
newJFrame.setVisible(true);
|
||||
}
|
||||
public void setLives(int lives) {
|
||||
this.initialLives = lives;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
@ -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<MarioEvent> lastFrameEvents;
|
||||
|
||||
// private int segTime = -1;
|
||||
// private int passedSegs = 0;
|
||||
private MarioEvent[] killEvents;
|
||||
private ArrayList<MarioSprite> sprites;
|
||||
private ArrayList<Shell> shellsToCheck;
|
||||
@ -37,6 +42,8 @@ public class MarioWorld {
|
||||
private ArrayList<MarioEffect> 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<MarioSprite> getEnemies() {
|
||||
ArrayList<MarioSprite> 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;
|
||||
// }
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user