2014-02-06 4 views
1

Я пытаюсь сделать игру на основе 2D-плитки, но не очень далеко, прежде чем что-то пойдет не так. Игра прекрасна, за исключением того, что она очень медленная, и между плитами появляются пробелы. Я попытался поместить все изображения плитки в одно изображение для загрузки, чтобы сделать его более плавным, но это не сработало. Мне нужна помощь в оптимизации моей игры для улучшения fps.Оптимизация рендеринга 2D-плееров 2D 2D

Большинство дисплея класса

Player p = new Player(); 
static Map m = new Map(); 
Hotbar h = new Hotbar(); 
static Zombie z = new Zombie(); 

public static void main(String args[]) { 
    Thread t1 = new Thread(new Display()); 
    t1.start(); 
    Thread t2 = new Thread(z); 
    t2.start(); 
    Thread t3 = new Thread(m); 
    t3.start(); 
} 

@SuppressWarnings("static-access") 
public void run() { 
    while (true) { 
     try { 
      oldTime = currentTime; 
      currentTime = System.currentTimeMillis(); 
      elapsedTime = currentTime - oldTime; 
      fps = (int) ((1000/40) - elapsedTime); 
      Thread.sleep(fps); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     if (started) { 
      p.playerMovement(); 
      p.width = getWidth(); 
      p.height = getHeight(); 
      h.width = getWidth(); 
      h.height = getHeight(); 
      if (p.maptiles != null) { 
       z.maptiles = new Rectangle[p.maptiles.length]; 
       z.maptiles = p.maptiles; 
      } 
     } else { 

     } 
     repaint(); 
    } 
} 

Большинство Карта класса

BufferedImage backLayer; 
BufferedImage backLayer2; 

@SuppressWarnings("static-access") 
public void createBack() { 
    backLayer = new BufferedImage(mapwidth * 32, mapheight * 32, BufferedImage.TYPE_INT_ARGB); 
    Graphics g = backLayer.getGraphics(); 
    Graphics2D gd = (Graphics2D) g; 
    Color daycolor = new Color(0, 150, 255, 255); 
    Color nightcolor = new Color(0, 50, 100, Math.abs(time/daylength - 510/2)); 
    Color backtilecolor = new Color(10, 10, 20, Math.abs(time/daylength - 510/4)); 
    g.setColor(daycolor); 
    g.fillRect(0, 0, p.width, p.height); 
    g.setColor(nightcolor); 
    g.fillRect(0, 0, p.width, p.height); 
    time++; 
    if (time > 510 * daylength) 
     time = 0; 
    if (time < 100 * daylength || time > 410 * daylength) { 
     z.SpawnZombie(); 

    } else { 

    } 
    g.setColor(backtilecolor); 
    int i = 0; 
    for (int x = 0; x < mapwidth; x++) { 
     for (int y = 0; y < mapheight; y++) { 
      if (mapdatasky[i] == 0) { 
       p.mapsky[i] = new Rectangle(x * 32 - p.playerX, y * 32 - p.playerY, 32, 32); 
      } 
      if (mapdatasky[i] >= 1) { 
       g.drawImage(tiles[mapdatasky[i]], x * 32 - p.playerX, y * 32 - p.playerY, 32, 32, null); 
       mapsky[i] = new Rectangle(x * 32 - p.playerX, y * 32 - p.playerY, 32, 32); 
       p.mapsky[i] = new Rectangle(x * 32 - p.playerX, y * 32 - p.playerY, 32, 32); 
       gd.fill(mapsky[i]); 
      } 
      i++; 
     } 
    } 
    backLayer2 = backLayer; 
} 

BufferedImage middleLayer; 
BufferedImage middleLayer2; 

@SuppressWarnings("static-access") 
public void createMiddle() { 
    middleLayer = new BufferedImage(mapwidth * 32, mapheight * 32, BufferedImage.TYPE_INT_ARGB); 
    Graphics g = middleLayer.getGraphics(); 
    Color fronttilecolor = new Color(20, 20, 40, Math.abs(time/daylength - 510/4)); 
    int i = 0; 
    for (int x = 0; x < mapwidth; x++) { 
     for (int y = 0; y < mapheight; y++) { 
      if (mapdata[i] == -1) { 
       spawnX = x * 32 - p.width; 
       spawnY = y * 32 - p.height; 
       p.spawnX = spawnX; 
       p.spawnY = spawnY; 
      } 
      if (mapdata[i] == 0) { 
       p.mapsky[i] = new Rectangle(x * 32 - p.playerX, y * 32 - p.playerY, 32, 32); 
      } 
      if (mapdata[i] > 0) { 
       g.drawImage(tiles[mapdata[i]], x * 32 - p.playerX, y * 32 - p.playerY, 32, 32, null); 
       maptiles[i] = new Rectangle(x * 32 - p.playerX, y * 32 - p.playerY, 32, 32); 
       p.maptiles[i] = new Rectangle(x * 32 - p.playerX, y * 32 - p.playerY, 32, 32); 
      } 
      if (!p.breaking) { 
       tileid = -1; 
      } 
      if (tileid == i) { 
       g.setColor(new Color(100, 0, 0, 100)); 
       g.fillRect(x * 32 - p.playerX + 16 - timer/(breaktime/16), y * 32 - p.playerY + 16 - timer/(breaktime/16), (timer/(breaktime/16)) * 2, (timer/(breaktime/16)) * 2); 
      } 
      i++; 
     } 
    } 
    g.setColor(fronttilecolor); 
    g.fillRect(0, 0, p.width, p.height); 
    middleLayer2 = middleLayer; 
} 


BufferedImage both; 
BufferedImage both2; 

public void mergeLayers() { 
    both = new BufferedImage(mapwidth * 32, mapheight * 32, BufferedImage.TYPE_INT_ARGB); 
    Graphics g = both.getGraphics(); 
    g.drawImage(backLayer2, 0, 0, mapwidth * 32, mapheight * 32, null); 
    g.drawImage(middleLayer2, 0, 0, mapwidth * 32, mapheight * 32, null); 
    both2 = both; 
} 

public void renderMap(Graphics g) { 
    g.drawImage(both2, 0, 0, mapwidth * 32, mapheight * 32, null); 
    if (placetimer > 0) 
     placetimer--; 
} 
@Override 
public void run() { 
    while (true) { 
     try { 
      oldTime = currentTime; 
      currentTime = System.currentTimeMillis(); 
      elapsedTime = currentTime - oldTime; 
      fps = (int) ((1000/100) - elapsedTime); 
      Thread.sleep(fps); 
      if (!mapset) { 
       setMap(); 
       mapset = true; 
      } 
      createBack(); 
      createMiddle(); 
      mergeLayers(); 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Вот картина ошибок рендеринга между плитками

игры Скриншот: Screenshot

+0

Это лучше подходит для сайта Code Review. –

ответ

2

I согласитесь, что обзор может быть здесь.

Но общие советы: Если вы добавили это «слияние» (createBack/createMiddle/mergeLayers) по соображениям производительности: не делайте этого! Там вы рисуете ВСЕ плитки (и, возможно, также некоторые, которые не будут видны во всяком случае, которые могут быть обрезаны, когда они нарисованы непосредственно с g.drawImage). Рисуя много маленьких изображений на большом изображении, а затем рисуя большое изображение на экране, вряд ли может быть быстрее, чем непосредственно рисовать маленькие изображения на экране в первую очередь ....

Если вы добавили это «слияние» «разрешить появляющиеся« полосы »: не делайте этого! Полосы исходят из координат, которые меняются из другой нити, кроме той, которая рисует изображения. Вы можете избежать этого, изменив способ вычисления плиток и их координат. Код немного слишком ... «комплекс», чтобы указать на это, так что я буду использовать некоторые псевдокод здесь:

void paintTiles(Graphics g) 
{ 
    for (Tile tile : allTiles) 
    { 
     g.drawImage(tile, player.x, player.y, null); 
    } 
} 

Проблема здесь состоит в том, что в то время как картина нить перебирает все плитки, в другой поток может изменять координаты игрока. Например, некоторые плитки могут быть окрашены player.x=10 и player.y=20, затем другая нить меняет координаты игрока, и, таким образом, оставшиеся плитки окрашиваются player.x=15 и player.y=25 - и вы заметите это как «полосу», возникающую между плитами.

В лучшем случае, это может быть решено довольно легко:

void paintTiles(Graphics g) 
{ 
    int currentPlayerX = player.x; 
    int currentPlayerY = player.y; 

    for (Tile tile : allTiles) 
    { 
     g.drawImage(tile, currentPlayerX, currentPlayerY, null); 
    } 
} 

Таким образом, «текущая» координата игрока останется прежней, а итерация плитки.

+0

Спасибо, я никогда не понимал, что он будет использовать разные координаты игроков из других потоков. Не могли бы вы предложить мне сохранить текущие потоки или собрать все вместе? – NickM13

+0

Я не могу дать рекомендацию, не зная (предназначенную) архитектуру игры. «Обычно» есть рендеринг Thread (Event Dispatch Thread) и один игровой поток, и я думаю, что для «простой» игры с черепицей этого должно быть достаточно. Более потоки, как правило, усложняют ситуацию с точки зрения синхронизации, и пока не выполняется * очень много времени, требуемая для выполнения, вряд ли стоит использовать несколько потоков, которые стоили бы хлопот, но ... все это без каких-либо знаний об игре – Marco13

Смежные вопросы