2013-09-01 64 views
0

今天我打算將我的遊戲打包成一個Jar,以便提供給編碼的朋友,並希望看到我設法創建的一個很好的故障。當我將它變成一個Runnable jar時,它會加載到命令提示符中,但會拋出Resource Not Found錯誤(.ogg's),這很好,因爲它們不會在它設置的調試模式下使用。然後,它在initTileMap()第137行的TileHanlder.class中拋出了一個NullPointerException。Java遊戲應用程序在Eclipse中工作,但不是.jar(Slick2D + LWJGL)

我不知所措,所以我來到StackOverflow,因爲我幾乎花了整整一天的時間纔得到工作的Jar。我也嘗試過JarSplice。

我的主要問題是,如果您發現任何異常或者我沒有做的事情導致資源在.jar中找不到。

所有代碼和資源在同一個JAR,生成一個JAR的一切無不是多個罐子

我所有的代碼(它是開放源代碼畢竟:Game Source Code

Level.java(類主叫AssetHandler和TileHandler)

public class Level extends BasicGameState { 

public MapHandler map = new MapHandler(); 
public AssetHandler asset = new AssetHandler(); 
static OutputHandler out = new OutputHandler(); 

public GameContainer container; 
public StateBasedGame game; 

public static float MouseX = 0; 
public static float MouseY = 0; 
public float RectX = 0; 
public float RectY = 0; 
public int tileAmount = 0; 
public static int mapID = 1; 
public static int delta; 
public static int score = 0; 
private static int EntityAmount = 0; 
private static int ActiveEntityAmount = 0; 

private int FPS = 0; 

public static Image mapImage; 
public static TileHandler Tile = new TileHandler(); 
public Point mousePoint; 
public Circle mouseCirc; 

public static Player p; 
public static Enemy Blinky, Pinky, Inky, Clyde; 
public static EntityAI AGGRESSIVE, AMBUSH, HIT_RUN, SORTOFRANDOM; 

public Level(int id) { 

} 

@Override 
public void init(GameContainer container, StateBasedGame game) throws SlickException { 

    MapHandler.mapRect(); 
    mapID = MapHandler.getMapID(); 
    MapHandler.deployMap(mapID); 

    try { 
     asset.initAssets(); 
     OutputHandler.initFont(); 
    } catch (AssetException e) { 
     e.printStackTrace(); 
    } 

    TileHandler.initTileMap(); 
    container.setUpdateOnlyWhenVisible(true); 
    container.setShowFPS(false); 
    container.setSmoothDeltas(false); 
    container.setVerbose(true); 

    this.container = container; 
    this.game = game; 

    AGGRESSIVE = new RedAI(); 
    AMBUSH = new PinkAI(); 
    HIT_RUN = new BlueAI(); 
    SORTOFRANDOM = new OrangeAI(); 

    p = new Player("Player1"); 
    Blinky = new Enemy("Shadow", AGGRESSIVE); 
    Pinky = new Enemy("Speedy", AMBUSH); 
    Inky = new Enemy("Bashful", HIT_RUN); 
    Clyde = new Enemy("Pokey", SORTOFRANDOM); 
} 

@Override 
public void render(GameContainer container, StateBasedGame game, Graphics g) throws SlickException { 

    Tile.drawTileMap(TileHandler.tileLayer, TileHandler.tMapTiles, g); 
    if (Reference.debug) { 
     displayTileBounds(TileHandler.tileLayer, g); 
    } 
    drawEntities(); 
    drawStrings(g); 
} 

@Override 
public void update(GameContainer container, StateBasedGame game, int delta) throws SlickException { 
    Input in = container.getInput(); 

    MouseX = in.getMouseX(); 
    MouseY = in.getMouseY(); 
    RectX = MapHandler.Map32.getX(); 
    RectY = MapHandler.Map32.getY(); 
    EntityAmount = Entity.entityList.size(); 
    ActiveEntityAmount = Enemy.enemyList.size() + Projectile.activeProjectiles.size() + 1; 
    Level.delta = delta; 
    Reference.defProjectileVelocity = .13f * Level.delta; 

    p.update(in); 
    updateNonPlayerEntities(); 

    FPS = container.getFPS(); 
} 

@Override 
public int getID() { 

    return 2; 
} 

/** @deprecated **/ 
@Deprecated 
protected void drawMap(Graphics g) { 

    g.drawImage(mapImage, Reference.MAP_X, Reference.MAP_Y); 

} 

protected void drawStrings(Graphics g) { 

    if (Reference.debug) { 
     OutputHandler.write("FPS: " + Integer.toString(FPS), 11, 10); 
     OutputHandler.write(String.format("Mouse X: %s, Mouse Y: %s", MouseX, MouseY), 11, 30); 
     OutputHandler.write(String.format("Rect X: %s, Y: %s", RectX, RectY), 11, 50); 
     OutputHandler.write("Amount of Tiles: " + (TileHandler.tileLayer.length * TileHandler.tileLayer[0].length), 11, 70); 
     OutputHandler.write(String.format("Amount of Entities = %s", Integer.toString(EntityAmount)), 11, 90); 
     OutputHandler.write(String.format("Active Entities = %s", Integer.toString(ActiveEntityAmount)), 11, 110); 
     out.write("Currently Loaded: " + p.isReloaded(), 11, 130); 

     OutputHandler.write("Amount of Entities is Accumulative", 11, 666); 
    } else { 
     String curTime = Reference.getTime(); 
     String scoreStr = Reference.convertScore(score); 
     OutputHandler.write("Time: " + curTime, 11, 10); 
     OutputHandler.write("Score: " + scoreStr, 550, 10); 
    } 
} 

protected void displayTileBounds(Rectangle[][] tileLayer, Graphics g) { 
    g.setColor(Color.white); 
    for (int x = 0; x < tileLayer.length; x++) { 
     for (int y = 0; y < tileLayer[0].length; y++) { 
      g.fill(tileLayer[x][y]); 
     } 
    } 
    g.setColor(Color.magenta); 

    for (int s = 0; s < TileHandler.collisionTiles.size(); s++) { 
     Rectangle r = TileHandler.collisionTiles.get(s); 
     g.fill(r); 
    } 
    g.setColor(Color.orange); 
    g.fill(p.boundingBox); 

    for (int z = 0; z < Entity.teleportingTiles.length; z++) { 
     Rectangle r = Entity.teleportingTiles[z]; 
     g.fill(r); 
    } 
} 

protected void drawEntities() { 
    ArrayList<Entity> list = Entity.entityList; 

    for (int i = 0; i < list.size(); i++) { 

     list.get(i).drawEntity(list.get(i)); 

    } 
} 

protected void updateNonPlayerEntities() { 
    ArrayList<Enemy> list = Enemy.enemyList; 

    for (int i = 0; i < list.size(); i++) { 
     list.get(i).update(); 
    } 

    ArrayList<Projectile> pList = Projectile.activeProjectiles; 

    for (int p = 0; p < pList.size(); p++) { 
     pList.get(p).update(); 
    } 
} 

} 

的AssetHandler(Game-Handlers-AssetHandler.java)聲音是第三至最後一種方法

public class AssetHandler { 

public static boolean isComplete = false; 

private static String musPath = "res/Sounds/"; 
static TileHandler tile; 

private static int tsize = 32; 

private static String spritesPath = "res/GameSprites/Maze Game/sprites.png"; 
private static String terrainPath = "res/GameSprites/Maze Game/terrain.png"; 
private static String twPath = "res/GameSprites/Maze Game/animation/tankToWest.png"; 
private static String tePath = "res/GameSprites/Maze Game/animation/tankToEast.png"; 
private static String tnPath = "res/GameSprites/Maze Game/animation/tankToNorth.png"; 
private static String tsPath = "res/GameSprites/Maze Game/animation/tankToSouth.png"; 
private static String bwPath = "res/GameSprites/Maze Game/animation/blueToWest.png"; 
private static String bePath = "res/GameSprites/Maze Game/animation/blueToEast.png"; 
private static String bnPath = "res/GameSprites/Maze Game/animation/blueToNorth.png"; 
private static String bsPath = "res/GameSprites/Maze Game/animation/blueToSouth.png"; 

private static String rePath, rwPath, rsPath, rnPath; 
private static String pePath, pwPath, psPath, pnPath; 
private static String oePath, owPath, osPath, onPath; 



public static Music titleMus1, titleMus2, titleMus3, loadingScreenMus1, loadingScreenMus2, loadingScreenMus3; 

public static Sound tankMove, tankFire, tankExplode, tankSurrender, tankRetreat; 




public static void initSounds() { 

    System.out.println("Initializing Main Menu Music..."); 
    try { 
     titleMus1 = new Music(musPath + "title/titlefirst.ogg"); 
     titleMus2 = new Music(musPath + "title/titlesecond.ogg"); 
     titleMus3 = new Music(musPath + "title/titlethird.ogg"); 

     System.out.println("Initialized Main Menu Music!..."); 
    } catch (SlickException e) { 
     e.printStackTrace(); 
     System.out.println("ERROR: Initializing Main Menu Sounds at " + "com.treehouseelite.tank.game.handlers.AssetHandler" + " : initSounds() Method, First Try/Catch"); 
    } 
    System.out.println("Initializing Loading Screen Music..."); 
    try { 
     loadingScreenMus1 = new Music(musPath + "levels or loading screens/ActionBuilder.ogg"); 
     loadingScreenMus2 = new Music(musPath + "levels or loading screens/StruggleforSurvival.ogg"); 
     loadingScreenMus3 = new Music(musPath + "levels or loading screens/SurrealSomber.ogg"); 
    } catch (SlickException e) { 
     e.printStackTrace(); 
     System.out.println("ERROR: Initializing Loading Screen Sounds at " + "com.treehouseelite.tank.game.handlers.AssetHandler" + " : initSounds() Method, Second Try/Catch"); 
    } 
    initSFX(); 
    initsComplete(); 
} 

private static void initsComplete() { 
    System.out.println("========================ALL ASSETS INITIALIZED========================"); 
} 

public static void initSFX() { 

    try { 
     tankMove = new Sound("res/Sounds/SFX/tankMove.wav"); 
    } catch (SlickException e) { 
     e.printStackTrace(); 
    } finally { 
     System.out.println("All Sound Effects Initialized..."); 
    } 
} 

} 

TileHandler.java(Game-Handlers-TileHandler.java)

public class TileHandler { 

public static String mapPath = "res/World/level_"; 

public static int bg, paths, collision; 

public static Image[][] tMapTiles = new Image[25][20]; 

public static boolean[][] collidableTile = new boolean[25][20]; 

static Graphics g = new Graphics(); 
static AssetHandler asset = new AssetHandler(); 

// The Amount of Image is too damn high! 

static TiledMap tMap; 

public static int wFrame = 0; 

private static int id; 

public static Rectangle[][] tileLayer = new Rectangle[25][20]; 
public static ArrayList<Rectangle> collisionTiles = new ArrayList<Rectangle>(500); 

public TileHandler() { 

} 

public TileHandler(int id, Rectangle rect) { 

    TileHandler.id = id; 

    try { 
     createTiles(id, rect); 
    } catch (SlickException e) { 
     e.printStackTrace(); 
    } 
} 

protected void createTiles(int id, Rectangle layer) throws SlickException { 
    // Scans 0,0 to 0,20 of the tiles and then moves down the x line 
    // gettings tiles 
    // 0,0 = tileLayer[0][0] 
    mapPath = String.format("res/World/level_%s.tmx", id); 

    tMap = new TiledMap(mapPath); 

    bg = tMap.getLayerIndex("background"); 
    paths = tMap.getLayerIndex("paths"); 
    collision = tMap.getLayerIndex("collision"); 
    // Constructs a Grid of Rectangles based on the Map's Top Left point 

    for (int i = 0; i < tileLayer.length; i++) { 
     for (int y = 0; y < tileLayer[0].length; y++) { 
      Rectangle tile = new Rectangle((i + Reference.MAP_X) + (i * Reference.TILE_SIZE), (y + Reference.MAP_Y) + (y * Reference.TILE_SIZE), 32, 32); 
      tileLayer[i][y] = tile; 
     } 
    } 
    /* 
    * for(int x = 0; x<collisionTiles.length; x++){ for(int y = 0; 
    * y<collisionTiles[0].length; y++){ Rectangle tile = new 
    * Rectangle((x+Reference.MAP_X) + (x*31), 
    * (y+Reference.MAP_Y+14)+(y*31),32,32); collisionTiles[x][y] = tile; } 
    * } 
    */ 

} 

/** @deprecated */ 
@Deprecated 
public static void initSprites(Rectangle[][] layer) { 

    bg = tMap.getLayerIndex("background"); 
    paths = tMap.getLayerIndex("paths"); 
    collision = tMap.getLayerIndex("collision"); 

    System.out.println("Initialized Sprites!"); 

} 

// Initializes all tiles and put them into Image and Boolean Arrays 
// Boolean Array for later use with determining whether the player or entity 
// can be there. (collidableTile) 
// Image array holds the tiles (tMapTiles) 
public static void initTileMap() { 
    new Graphics(); 


    // Getting Tiles based off Tile ID's 
    /** DIRT PATH MAPS (Dev Map, Level 1) **/ 
    if ((id == 0) || (id == 1)) { 
     for (int x = 0; x < tileLayer.length; x++) { 
      for (int y = 0; y < tileLayer[0].length; y++) { 
       Rectangle r = new Rectangle(tileLayer[x][y].getX(), tileLayer[x][y].getY(), 32, 32); 

       if (tMap.getTileId(x, y, bg) == 1) { 
        tMapTiles[x][y] = AssetHandler.sparseGrass; 

       } 

       if (tMap.getTileId(x, y, collision) == 2) { 
        tMapTiles[x][y] = AssetHandler.water11; 

        collisionTiles.add(r); 

       } 
       if (tMap.getTileId(x, y, collision) == 57) { 
        tMapTiles[x][y] = AssetHandler.concrete1; 

        collisionTiles.add(r); 

       } 
       if (tMap.getTileId(x, y, collision) == 71) { 
        tMapTiles[x][y] = AssetHandler.concrete2; 

        // collisionTiles.add(new 
        // Rectangle(tileLayer[x][y].getX(), 
        // tileLayer[x][y].getY()+14, 32, 32)) ; 
        collisionTiles.add(r); 
       } 
       if (tMap.getTileId(x, y, collision) == 85) { 
        tMapTiles[x][y] = AssetHandler.concrete3; 

        collisionTiles.add(r); 

       } 
       if (tMap.getTileId(x, y, collision) == 72) { 
        tMapTiles[x][y] = AssetHandler.metal1; 

        collisionTiles.add(r); 

       } 
       if (tMap.getTileId(x, y, collision) == 58) { 
        tMapTiles[x][y] = AssetHandler.metal2; 

        collisionTiles.add(r); 

       } 
       if (tMap.getTileId(x, y, paths) == 50) { 
        tMapTiles[x][y] = AssetHandler.hDirtPath; 

       } 
       if (tMap.getTileId(x, y, paths) == 60) { 
        tMapTiles[x][y] = AssetHandler.dirtPath; 

       } 
       if (tMap.getTileId(x, y, paths) == 59) { 
        tMapTiles[x][y] = AssetHandler.dirtPathTurn4; 

       } 
       if (tMap.getTileId(x, y, paths) == 73) { 
        tMapTiles[x][y] = AssetHandler.dirtPathTurn3; 

       } 
       if (tMap.getTileId(x, y, paths) == 79) { 
        tMapTiles[x][y] = AssetHandler.dirtThreewayRight; 

       } 
       if (tMap.getTileId(x, y, paths) == 46) { 
        tMapTiles[x][y] = AssetHandler.dirtPathTurn1; 

       } 
       if (tMap.getTileId(x, y, paths) == 37) { 
        tMapTiles[x][y] = AssetHandler.hDirtCrossing1; 

       } 
       if ((tMap.getTileId(x, y, paths) == 80) || (tMap.getTileId(x, y, paths) == 88)) { 
        tMapTiles[x][y] = AssetHandler.dirtThreewayLeft; 

       } 
       if (tMap.getTileId(x, y, paths) == 102) { 
        tMapTiles[x][y] = AssetHandler.dirtThreewayDown; 

       } 
       if (tMap.getTileId(x, y, paths) == 74) { 
        tMapTiles[x][y] = AssetHandler.dirtPathTurn2; 

       } 
       if (tMap.getTileId(x, y, paths) == 107) { 
        tMapTiles[x][y] = AssetHandler.dirtThreewayUp; 

       } 
       if (tMap.getTileId(x, y, paths) == 88) { 
        tMapTiles[x][y] = AssetHandler.dirtCrossroads; 

       } 

      } 
     } 
    } 

} 

public void drawTileMap(Rectangle[][] layer, Image[][] tiles, Graphics g) { 

    // Loops through the Image array and places tile based on the Top Left 
    // corner of the Rectangle in the rectangle array 
    // Rectangle Array = layer (tileLayer was passed) 
    // Image Array = tiles (tMapTiles was passed) 
    // Asset Refers to Asset Handler 
    for (int x = 0; x < layer.length; x++) { 
     for (int y = 0; y < layer[0].length; y++) { 
      g.drawImage(tiles[x][y], layer[x][y].getX(), layer[x][y].getY()); 

      // Below here is image detection for the placement of Animations 
      if (tiles[x][y] == AssetHandler.water11) { 
       AssetHandler.vRiver1.draw(layer[x][y].getX(), layer[x][y].getY()); 
       AssetHandler.vRiver1.start(); 
       AssetHandler.vRiver1.update(Level.delta); 
      } else if (tiles[x][y] == AssetHandler.hDirtCrossing1) { 
       AssetHandler.hDirtCrossing.draw(layer[x][y].getX(), layer[x][y].getY()); 
       AssetHandler.hDirtCrossing.start(); 
       AssetHandler.hDirtCrossing.update(Level.delta); 
      } 
     } 
    } 
} 

} 

最後,MapHandler.java - 疏使用的,主要的目標是並初始化一個TileHandler對象構造tile網格用於構造TiledMap類。

public class MapHandler { 

public static AssetHandler asset = new AssetHandler(); 

static Image devMap; 

Image map_1; 

Image map_2; 

Image map_3; 

public static Rectangle Map32; 

public MapHandler() { 
} 

// Sends a Rectangle set Around the Map Image to TileHandler 
// to construct a grid of 32x32 Rectangles inside the Map's Rectangle 
public static void deployMap(int id) { 
    if (id == 0) { 
     new TileHandler(id, Map32); 
    } 
} 

// Randomly Generates a Map ID corresponding to a Level_X.tmx 
// Currently set to 0 for development purposes 
public static int getMapID() { 
    new Random(); 
    return 0; 
    // return id; 
} 

/* Create the Rectangle and Grid */ 
public static void mapRect() throws SlickException { 

    System.out.println("Initializing Rectangular Plane..."); 
    Map32 = new Rectangle(Reference.GUI_WIDTH/24, Reference.GUI_HEIGHT/24, 800, 640); 
    System.out.println("Map32 Initialized!..."); 
} 

} 

如果您需要任何其他資源或信息,請讓我知道,我會很樂意提供,所以我可以克服這一點。我也會考慮其他方式,謝謝你的迴應!

由於問題文本框中的30k字符限制,會出現問題。主要是在瘋狂擁擠的AssetHandler.java中,它仍然存在於git倉庫中。

回答

0

我有同樣的問題。經過一段時間的搜索後,我遇到了這個簡潔的解決方案。見this LWJGL forum post

public static void main(String[] args) throws SlickException { 
     /* Set lwjgl library path so that LWJGL finds the natives depending on the OS. */ 
     String osName = System.getProperty("os.name"); 
     // Get .jar dir. new File(".") and property "user.dir" will not work if .jar is called from 
     // a different directory, e.g. java -jar /someOtherDirectory/myApp.jar 
     String nativeDir = ""; 
     try { 
      nativeDir = new File(GameMain.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParent(); 
     } catch (URISyntaxException uriEx) { 
      try { 
       // Try to resort to current dir. May still fail later due to bad start dir. 
       uriEx.printStackTrace(); 
       nativeDir = new File(".").getCanonicalPath(); 
      } catch (IOException ioEx) { 
       // Completely failed 
       ioEx.printStackTrace(); 
       JOptionPane.showMessageDialog(new JFrame(), "Failed to locate native library directory. " + 
         "Error:\n" + ioEx.toString(), "Error", JOptionPane.ERROR_MESSAGE); 
       System.exit(-1); 
      } 
     } 
     // Append library subdir 
     nativeDir += File.separator + "lib" + File.separator + "native" + File.separator; 
     if (osName.startsWith("Windows")) { 
      nativeDir += "windows"; 
     } else if (osName.startsWith("Linux") || osName.startsWith("FreeBSD")) { 
      nativeDir += "linux"; 
     } else if (osName.startsWith("Mac OS X")) { 
      nativeDir += "macosx"; 
     } else if (osName.startsWith("Solaris") || osName.startsWith("SunOS")) { 
      nativeDir += "solaris"; 
     } else { 
      JOptionPane.showMessageDialog(new JFrame(), "Unsupported OS: " + osName + ". Exiting.", 
        "Error", JOptionPane.ERROR_MESSAGE); 
      System.exit(-1); 
     } 
     System.setProperty("org.lwjgl.librarypath", nativeDir); 
    } 

請記住,您需要一個lib文件夾在同一目錄中。我將它存儲在.jar之外,但也可以將其放在裏面。另外請注意,它需要在你做任何LWJGL的東西之前發生,所以主要的方法是一個好地方。

相關問題