我之前已经问过这个问题,但这还不够好,所以我删除了它并制作了一个新问题。
我正在构建游戏,我想将游戏导出为.jar文件,以便我可以在其他人的计算机上运行它。唯一的问题是,当我运行jar时,会出现一个空的JFrame。至少应该出现什么是黑屏,即使我已经将我的Canvas添加到JFrame中。
我可以在我的IDE(Eclipse)中运行所有内容,但是当我将它放在桌面上时,似乎没有任何事情发生。我考虑的解决方案之一是下载.jars并将它们放在所述计算机的AppData文件夹中,然后使用URLClassLoader获取登录应用程序(工作正常)以运行.jar中的主类。
唯一的问题是我不太了解如何使用URLClassLoader,也不熟悉使用JavaDoc。 :/
以下是我的主要课程(我也有我的所有进口):
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 6601282971656374659L;
/* The version of the game, will be updates with annotation later! It also has the location to the game path! */
public static final String version = "Version: 0.1 Alpha";
private static final String GAME_PATH = System.getProperty("user.home") + "\\AppData\\Roaming\\[Game]";
/* Basic integers and Dimensions for the JFrame and Canvas */
public static final int WIDTH = 460;
public static final int HEIGHT = 280;
private static final int SCALE = 2;
private final Dimension size = new Dimension((WIDTH * SCALE), (HEIGHT * SCALE));
/* BufferedImage below is the one thing that is drawn to the screen. The pixels[] array holds the pixel data of said image. */
private BufferedImage screen = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
public int[] pixels = ((DataBufferInt) screen.getRaster().getDataBuffer()).getData();
/* A Thread for running the game and two Booleans for being either in-game or in-menu. */
private Thread thread;
public static volatile boolean isRunning = false;
public static volatile boolean inGame = false;
/* Characters for determining what state the player is in, and what level is selected. (MAY CHANGE TO INT LATER!) */
public static char state = 'N';
public static int player_select = 0;
public static int level_select = 0;
/* The only non-local reference in this class. Used for creating the window. */
JFrame frame;
/* Imports having to do with the logic behind the game and then rendering. */
Display display;
UIListener listen;
Keyboard key;
Mouser mouse;
Music music;
/* The three main classes. */
/**
* The main constructor. It's responsible for creating the JFrame and adding this canvas to it. It also sets the level to a default selection.
*/
public Game() {
frame = new JFrame("Game");
display = new Display(screen);
key = new Keyboard(200);
mouse = new Mouser();
listen = new UIListener(mouse);
setPlayer(PlayerClass.KNIGHT);
setLevel(ClassicLevel.FLOOR_1);
if (getLevel() == ClassicLevel.floor_1) {
getPlayer().setDirection(PlayerClass.NORTH);
}
setPreferredSize(size);
setMaximumSize(size);
setMinimumSize(size);
addKeyListener(key);
addMouseListener(mouse);
frame.setLayout(new BorderLayout());
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setIconImage(new ImageIcon("res/Game_logo.png").getImage());
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
/**
* Responsible for starting the game, the most important part. It also requests the focus of the Canvas and creates a buffer strategy.
*/
public synchronized void begin() {
thread = new Thread(this, "Game");
createBufferStrategy(3);
requestFocus();
thread.start();
isRunning = true;
}
/**
* Method responsible for stopping the thread that runs the game.
*
* @throws InterruptedException
*/
public synchronized void finish() throws InterruptedException {
isRunning = false;
thread.join();
}
/* Integers that reflect the Keyboard's movements. Should not be removed. */
int xMove = 0, yMove = 0;
/**
* This method is responsible for updating the logic behind the game, i.e. Mobs, time, AI, etc.
*/
private synchronized void tick() {
key.checkForKeys();
int speed = getPlayer().getSpeed();
if (key.up) {
yMove -= speed;
getPlayer().setDirection(PlayerClass.NORTH);
}
if (key.down) {
yMove += speed;
getPlayer().setDirection(PlayerClass.SOUTH);
}
if (key.left) {
xMove -= speed;
getPlayer().setDirection(PlayerClass.WEST);
}
if (key.right) {
xMove += speed;
getPlayer().setDirection(PlayerClass.EAST);
}
}
/* Integers responsible for the FPS and UPS. */
public int frames = 0, updates = 0;
/**
* Method responsible for rendering the logic in the "update()" method to the screen.
*/
private synchronized void render() {
BufferStrategy buffer = this.getBufferStrategy();
Graphics gfx = buffer.getDrawGraphics();
final int centerY = (HEIGHT / 2) - (48 / 2);
final int centerX = (WIDTH / 2) - (48 / 2);
display.clear();
getLevel().render(xMove, yMove, display);
display.renderPlayer(getPlayer(), centerX, centerY);
display.alignPixels(pixels);
gfx.drawImage(screen, 0, 0, getWidth(), getHeight(), null);
gfx.drawImage(UIRender.playerBar(getPlayer().getIcon()), 0, getHeight() - 100, 200, 100, null);
gfx.setFont(GameGUI.gameFont());
gfx.setColor(new Color(220, 220, 220));
gfx.drawString(Game.version, 3, 15);
if (key.show) {
key.showInfo(gfx, frames, updates);
} else if (key.escape) {
UIRender.renderEscapeMenu(this);
}
gfx.dispose();
buffer.show();
}
public final void screenShot(String filename) throws Exception {
Robot robot = new Robot();
Rectangle window = new Rectangle(frame.getX(), frame.getY(), WIDTH * SCALE, HEIGHT * SCALE);
BufferedImage image = robot.createScreenCapture(window);
ImageIO.write(image, "png", new File(GAME_PATH + filename));
}
/**
* Method responsible for setting the state of the game. (i.e. in options, in credits, etc.)
*
* @param setState
*/
public static void setState(char setState) {
state = setState;
}
/**
* Sets the desired player for the game.
*
* @param selection
*/
public static void setPlayer(int selection) {
player_select = selection;
}
/**
* Method for returning the player that the user has selected while in the class select.
*
* @return
*/
public static PlayerClass getPlayer() {
if (player_select == 1) return KnightClass.knight;
if (player_select == 2) return WizardClass.wizard;
if (player_select == 3) return ArcherClass.archer;
return KnightClass.knight;
}
/**
* Method responsible for setting the desired level of the user.
*
* @param selection
*/
public static void setLevel(int selection) {
level_select = selection;
}
/**
* Method used for getting the level that the user picked.
*
* @return
*/
private final Level getLevel() {
if (level_select == ClassicLevel.FLOOR_1) return ClassicLevel.floor_1;
return SurvivalLevel.level;
}
/**
* The main "run()" method; needed for any class that implements the Runnable.java interface.
*/
public void run() {
long pastTime = System.nanoTime(), lastSecond = System.currentTimeMillis();
final float desig = 1_000_000_000F / 50F;
float single = 0;
// Remove to play actual game.
state = 50;
if (state != 50) {
//Music.playTitleMusic();
}
while (isRunning == true) {
if (state == 'N') {
UIRender.renderNaprav(this);
if ((System.currentTimeMillis() - lastSecond) > 2000) {
// Wait 2 seconds and then go to the menu.
lastSecond += 1000;
state = 'M';
}
} else if (state == 'M') {
UIRender.renderMenu(this);
listen.listenInMenu();
} else if (state == 'O') {
UIRender.renderOptions(this);
listen.listenInOptions();
} else if (state == 'C') {
UIRender.renderCredits(this);
listen.listenInCredits();
} else if (state == 'S') {
UIRender.renderClassSelect(this);
listen.listenInClassSelection();
} else if (state == 'L') {
UIRender.renderLevelSelect(this);
listen.listenInLevelSelection();
} else if (state == 'Q') {
System.exit(0);
} else {
inGame = true;
// Remember to comment out the code below when state is auto-equal to 50.
//Music.stopTitleMusic();
break;
}
}
while (inGame == true) {
long currentTime = System.nanoTime();
single += (currentTime - pastTime) / desig;
pastTime = currentTime;
while (single >= 1) {
tick();
updates++;
single--;
}
frames++;
render();
if ((System.currentTimeMillis() - lastSecond) > 1000) {
lastSecond += 1000;
frame.setTitle("Game | FPS: " + frames + ", UPS: " + updates);
frames = 0;
updates = 0;
}
}
}
/**
* The "main()" method; needed for every Java program.
*
* @param args
*/
public static void main(String[] args) {
//new Login();
Game dungeon = new Game();
dungeon.begin();
}
}
提前致谢。