Hallo Forum
Ich habe ein Jump and Run in Java programmiert, das ich jetzt für Android umschreibe.
Ich bin fast fertig, allerdings gibt es noch ein Problem beim Laden der Levels: Es dauert viel zu lange. Auf der PC-Version dauert es nur wenige Sekunden, auf Android hingegen mehrere Minuten.
Die Levels sind folgendermassen aufgebaut:
Der Spieler läuft über Balken, bei denen ich die oberste und die unterste Pixelreihe speichere. Ausserdem gibt es noch Monster, Münzen und Power-Ups, die ich als Objekte bezeichnen werde (wie die Pixel der Pixelreihen auch). Jedes dieser Objekte hat eine ID, eine XY-Koordinate und eventuell zusätzliche Parameter.
Der Code zum speichern (im Leveleditor verwende ich BufferedImages um das Level zu repräsentieren):
Der Code zum laden:
Wie könnte man das effizienter machen?
Ich freue mich auf die Antworten
Mit freundlichen Grüssen, Faberix
Ich habe ein Jump and Run in Java programmiert, das ich jetzt für Android umschreibe.
Ich bin fast fertig, allerdings gibt es noch ein Problem beim Laden der Levels: Es dauert viel zu lange. Auf der PC-Version dauert es nur wenige Sekunden, auf Android hingegen mehrere Minuten.
Die Levels sind folgendermassen aufgebaut:
Der Spieler läuft über Balken, bei denen ich die oberste und die unterste Pixelreihe speichere. Ausserdem gibt es noch Monster, Münzen und Power-Ups, die ich als Objekte bezeichnen werde (wie die Pixel der Pixelreihen auch). Jedes dieser Objekte hat eine ID, eine XY-Koordinate und eventuell zusätzliche Parameter.
Der Code zum speichern (im Leveleditor verwende ich BufferedImages um das Level zu repräsentieren):
Java:
public void saveForMobile(String path) throws IOException {
File file = new File(path);
File file2 = new File(path.substring(0, path.lastIndexOf(".")) + "_2" + ".lvl");
System.out.println(file2.getAbsolutePath());
File file3 = new File(path.substring(0, path.lastIndexOf(".")) + "_3" + ".lvl");
if(file.exists()) {
int option = JOptionPane.showConfirmDialog(levelEditor.frame, new JLabel("Die Datei " + path + "existiert bereits. Soll sie überschrieben werden?"), "Überschreiben?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if(option == JOptionPane.NO_OPTION)
return;
file.delete();
}
if(file2.exists()) {
int option = JOptionPane.showConfirmDialog(levelEditor.frame, new JLabel("Die Datei " + file2.getAbsolutePath() + "existiert bereits. Soll sie überschrieben werden?"), "Überschreiben?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if(option == JOptionPane.NO_OPTION)
return;
file2.delete();
}
if(file3.exists()) {
int option = JOptionPane.showConfirmDialog(levelEditor.frame, new JLabel("Die Datei " + file3.getAbsolutePath() + "existiert bereits. Soll sie überschrieben werden?"), "Überschreiben?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if(option == JOptionPane.NO_OPTION)
return;
file3.delete();
}
file.createNewFile();
file2.createNewFile();
file3.createNewFile();
levelImageGraphics.dispose();
FileOutputStream outputStream = new FileOutputStream(file);
FileOutputStream outputStream2 = new FileOutputStream(file2);
FileOutputStream outputStream3 = new FileOutputStream(file3);
// Länge und Breite
outputStream.write(0);
outputStream.write(toBytes(levelWidth));
outputStream.write(toBytes(levelHeight));
outputStream2.write(0);
outputStream2.write(toBytes(levelWidth/2));
outputStream2.write(toBytes(levelHeight/2));
outputStream3.write(0);
outputStream3.write(toBytes(levelWidth/4));
outputStream3.write(toBytes(levelHeight/4));
for(int x = 0; x < levelImage.getWidth(); x++) {
boolean isBalk = false;
for(int y = 0; y < levelImage.getHeight(); y++) {
int rgb = levelImage.getRGB(x, y);
int id = 0;
int[] customs = new int[0];
// Solid
if(rgb == -16777216) {
if(!isBalk) {
id = 1;
isBalk = true;
}
}
else {
if(isBalk) {
id = 2;
isBalk = false;
}
// Sitzender Hund
if(rgb == -10485747) {
id = 3;
// continue;
}
// Grünes Monster
else if(rgb == -16724166) {
id = 4;
}
// Münze
else if(rgb == -256) {
id = 5;
}
// Gras
else if(rgb == -16724167) {
id = 6;
}
// Steinblock 0
else if(rgb == -16724168) {
id = 7;
}
// Steinblock 1
else if(rgb == -16724169) {
id = 8;
}
// Steinblock 2
else if(rgb == -16724170) {
id = 9;
}
// Steinblock 3
else if(rgb == -16724171) {
id = 10;
}
// Flugplattform
else if(rgb == FLY_PLATFORM_COLOR.getRGB()) {
int rangeUp = 0, rangeDown = 0, rangeLeft = 0, rangeRight = 0;
Rectangle entityRect = new Rectangle(x, y, flyPlatformImage.getWidth(), flyPlatformImage.getHeight());
for(List<Object> list : entities) {
if(entityRect.equals(list.get(INDEX_RECTANGLE))) {
RangeButtonListener[] rangeButtonListeners = (RangeButtonListener[]) list.get(INDEX_CUSTOMS);
for(RangeButtonListener rangeButtonListener : rangeButtonListeners) {
if(rangeButtonListener.direction == RangeButtonListener.UP) {
rangeUp = Integer.parseInt(rangeButtonListener.getButton().getText());
}
else if(rangeButtonListener.direction == RangeButtonListener.DOWN) {
rangeDown = Integer.parseInt(rangeButtonListener.getButton().getText());
}
else if(rangeButtonListener.direction == RangeButtonListener.LEFT) {
rangeLeft = Integer.parseInt(rangeButtonListener.getButton().getToolTipText());
}
else if(rangeButtonListener.direction == RangeButtonListener.RIGHT) {
rangeRight = Integer.parseInt(rangeButtonListener.getButton().getToolTipText());
}
}
break;
}
}
id = 11;
customs = new int[4];
customs[0] = rangeUp;
customs[1] = rangeDown;
customs[2] = rangeLeft;
customs[3] = rangeRight;
// continue;
}
// Schleimmonster
else if(rgb == -16724172) {
id = 12;
}
// Schild
else if(rgb == -16724173) {
id = 13;
}
// Jetpack
else if(rgb == -16724174) {
id = 14;
}
// Magnet
else if(rgb == -16724175) {
id = 15;
}
// Flugroboter
else if(rgb == -16724176) {
int rangeUp = 0, rangeDown = 0, rangeLeft = 0, rangeRight = 0;
Rectangle entityRect = new Rectangle(x, y, flyRobotImage.getWidth(), flyRobotImage.getHeight());
for(List<Object> list : entities) {
if(entityRect.equals(list.get(INDEX_RECTANGLE))) {
RangeButtonListener[] rangeButtonListeners = (RangeButtonListener[]) list.get(INDEX_CUSTOMS);
for(RangeButtonListener rangeButtonListener : rangeButtonListeners) {
if(rangeButtonListener.direction == RangeButtonListener.UP) {
rangeUp = Integer.parseInt(rangeButtonListener.getButton().getText());
}
else if(rangeButtonListener.direction == RangeButtonListener.DOWN) {
rangeDown = Integer.parseInt(rangeButtonListener.getButton().getText());
}
else if(rangeButtonListener.direction == RangeButtonListener.LEFT) {
rangeLeft = Integer.parseInt(rangeButtonListener.getButton().getToolTipText());
}
else if(rangeButtonListener.direction == RangeButtonListener.RIGHT) {
rangeRight = Integer.parseInt(rangeButtonListener.getButton().getToolTipText());
}
}
break;
}
}
id = 16;
customs = new int[4];
customs[0] = rangeUp;
customs[1] = rangeDown;
customs[2] = rangeLeft;
customs[3] = rangeRight;
}
}
if(id != 0) {
outputStream.write(id);
outputStream.write(toBytes(x));
outputStream.write(toBytes(y));
if(customs.length > 0) {
for(int i : customs) {
outputStream.write(toBytes(i));
}
}
if(id == 1 || id == 2) {
if(x%2 == 0) {
ByteBuffer.allocate(4);
System.out.println("x:" + x/2 + ":" + ByteBuffer.wrap(toBytes(x/2)).getInt());
System.out.println("y:" + y/2 + ":" + ByteBuffer.wrap(toBytes(y/2)).getInt());
outputStream2.write(id);
outputStream2.write(toBytes(x/2));
outputStream2.write(toBytes(y/2));
}
if(x%4 == 0) {
outputStream3.write(id);
outputStream3.write(toBytes(x/4));
outputStream3.write(toBytes(y/4));
}
}
else {
outputStream2.write(id);
outputStream2.write(toBytes(x/2));
outputStream2.write(toBytes(y/2));
if(customs.length > 0) {
for(int i : customs) {
outputStream2.write(toBytes(i/2));
}
}
outputStream3.write(id);
outputStream3.write(toBytes(x/4));
outputStream3.write(toBytes(y/4));
if(customs.length > 0) {
for(int i : customs) {
outputStream.write(toBytes(i/4));
}
}
}
}
}
}
outputStream.close();
outputStream2.close();
outputStream3.close();
}
Der Code zum laden:
Java:
/**Lädt ein Level aus einer .lvl-Datei
* @throws IOException */
public Level(GameView game, /*URL*/InputStream sourceFile, boolean fromScaledFile) throws IOException {
int lastX = 0;
int texturePosX = 0;
List<Integer> solids = new ArrayList<Integer>();
List<Rect> preDefinedSolids = new ArrayList<Rect>();
List<Integer> underSolids = new ArrayList<Integer>();
sourceFile.read();
byte[] widthBytes = new byte[4], heightBytes = new byte[4];
sourceFile.read(widthBytes);
sourceFile.read(heightBytes);
ByteBuffer.allocate(4);
levelWidth = ByteBuffer.wrap(widthBytes).getInt();
levelHeight = ByteBuffer.wrap(heightBytes).getInt();
System.out.println("width: " + levelWidth + ", height: " + levelHeight);
while(sourceFile.available() > 0) {
int id = sourceFile.read();
byte[] xBytes = new byte[4];
byte[] yBytes = new byte[4];
sourceFile.read(xBytes);
sourceFile.read(yBytes);
ByteBuffer.allocate(4);
int x,y;
if(!fromScaledFile) {
x = (int)(ByteBuffer.wrap(xBytes).getInt() * GameActivity.scaleFactorX);
y = (int)(ByteBuffer.wrap(yBytes).getInt() * GameActivity.scaleFactorY);
}
else {
x = ByteBuffer.wrap(xBytes).getInt();
y = ByteBuffer.wrap(yBytes).getInt();
}
if(x > lastX) {
this.solids.put(lastX, solids);
List<Integer> preSolids = new ArrayList<Integer>();
for(int i1 = 0; i1 < preDefinedSolids.size(); i1++) {
Rect rect = preDefinedSolids.get(i1);
preSolids.add(rect.top);
if(rect.left + rect.width() < x) {
preDefinedSolids.remove(i1);
i1--;
}
}
if(!preSolids.isEmpty())
this.preDefinedSolids.put(lastX, preSolids);
this.underSolids.put(lastX, underSolids);
lastX = x;
solids = new ArrayList<Integer>();
texturePosX++;
if(texturePosX >= grassTexture.getWidth()) {
texturePosX = 0;
}
}
switch(id) {
case 0:
break;
case 1:
solids.add(y);
System.out.println("solid: " + x + ", " + y);
break;
case 2:
underSolids.add(y);
break;
case 3:
monsters.add(new EntitySittingDog(x, y, game));
break;
case 4:
monsters.add(new EntityGreenMonster(x, y, game));
break;
case 5:
coins.add(new EntityCoin(x, y));
break;
case 6:
drawObjects.add(new DrawObject(x, y, DrawObjectType.GRASS));
break;
case 7:
drawObjects.add(new DrawObject(x, y, DrawObjectType.STONE_BLOCK_0));
obstacles.add(RectangleFactory.createRect(x, y, (int)(10 * GameActivity.scaleFactorX), (int)(130 * GameActivity.scaleFactorY)));
preDefinedSolids.add(RectangleFactory.createRect(x, y, (int)(79 * GameActivity.scaleFactorX), (int)(140 * GameActivity.scaleFactorY)));
break;
case 8:
drawObjects.add(new DrawObject(x, y, DrawObjectType.STONE_BLOCK_1));
obstacles.add(RectangleFactory.createRect(x, y, (int)(79 * GameActivity.scaleFactorX), (int)(130*GameActivity.scaleFactorY)));
preDefinedSolids.add(RectangleFactory.createRect(x, y, (int)(79*GameActivity.scaleFactorX), (int)(140*GameActivity.scaleFactorY)));
break;
case 9:
drawObjects.add(new DrawObject(x, y, DrawObjectType.STONE_BLOCK_2));
obstacles.add(RectangleFactory.createRect(x, y, (int)(100*GameActivity.scaleFactorX), (int)(70*GameActivity.scaleFactorY)));
preDefinedSolids.add(RectangleFactory.createRect(x, y, (int)(100*GameActivity.scaleFactorX), (int)(80*GameActivity.scaleFactorY)));
break;
case 10:
drawObjects.add(new DrawObject(x, y, DrawObjectType.STONE_BLOCK_3));
obstacles.add(RectangleFactory.createRect(x, y, (int)(100*GameActivity.scaleFactorX), (int)(70*GameActivity.scaleFactorY)));
preDefinedSolids.add(RectangleFactory.createRect(x, y, (int)(100*GameActivity.scaleFactorX), (int)(80*GameActivity.scaleFactorY)));
break;
case 11:
byte[] upBytes = new byte[4], downBytes = new byte[4], leftBytes = new byte[4], rightBytes = new byte[4];
sourceFile.read(upBytes);
sourceFile.read(downBytes);
sourceFile.read(leftBytes);
sourceFile.read(rightBytes);
int upRange = ByteBuffer.wrap(upBytes).getInt();
int downRange = ByteBuffer.wrap(downBytes).getInt();
int leftRange = ByteBuffer.wrap(leftBytes).getInt();
int rightRange = ByteBuffer.wrap(rightBytes).getInt();
movingSolids.add(new EntityFlyPlatform(x, y, x + rightRange, x - leftRange, y + downRange, y - upRange));
System.out.println("FlyPlatform: x: " + x + ", y: " + y);
break;
case 12:
monsters.add(new EntitySlimeMonster(x, y, game));
break;
case 13:
powerUps.add(new EntityShield(x, y));
break;
case 14:
powerUps.add(new EntityJetpack(x, y));
break;
case 15:
powerUps.add(new EntityMagnet(x, y));
break;
case 16:
byte[] bytesUp = new byte[4], bytesDown = new byte[4], bytesLeft = new byte[4], bytesRight = new byte[4];
sourceFile.read(bytesUp);
sourceFile.read(bytesDown);
sourceFile.read(bytesLeft);
sourceFile.read(bytesRight);
upRange = ByteBuffer.wrap(bytesUp).getInt();
downRange = ByteBuffer.wrap(bytesDown).getInt();
leftRange = ByteBuffer.wrap(bytesLeft).getInt();
rightRange = ByteBuffer.wrap(bytesRight).getInt();
monsters.add(new EntityFlyRobot(x, y, x - leftRange, x + rightRange, y - upRange, y + downRange, game));
break;
default:
break;
}
}
sourceFile.close();
finishedLoading = true;
}
Wie könnte man das effizienter machen?
Ich freue mich auf die Antworten
Mit freundlichen Grüssen, Faberix