2013-04-20 2 views
2

Моя игра (каркас) не может идти быстрее 30 кадров в секунду (около 33 мс между вызовами обновления) в полноэкранном режиме. Я использую таймер для цикла. На самом деле это становится немного сложнее, поскольку, когда я уменьшаю задержку постепенно, время между вызовами i измеряется гайками. Он перескакивает с установленной задержкой на два или более ожидаемое значение. Похоже, что порог составляет 30 мс. Нет проблем в оконном режиме, когда расхождения начинают появляться с порогом 4 мс. Оба режима действуют нормально при более высоких задержках. Вот часть кода, который я считаю уместным.Полноэкранный режим ограничения частоты кадров

fps = 30;  
timer = new Timer(1000/fps, new ActionListener() {   
@Override 
public void actionPerformed(ActionEvent arg0) { 
    tick();    
} 

Вышеуказанная установка таймера. Ниже - все остальное.

private void tick(){ 
    update(gameTime); 
    draw(gameTime);  
} 

Вот моя графика (2D) и BufferedImage.

public DrawBatch(DeviceManager deviceManager) { 
    this.deviceManager = deviceManager; 
    color = Color.MAGENTA; 
    bufferedImage = deviceManager.getBufferedImage();  
    bufferedGraphics = (Graphics2D)bufferedImage.getGraphics();bufferedGraphics = (Graphics2D)bufferedImage.getGraphics(); 
    bufferedGraphics.setBackground(color); 
    bufferedGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
    bufferedGraphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
    bufferedGraphics.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); 
} 

метод Розыгрыш (GameTime Gametime) начинается с этого метода:

public void begin(){ 
    bufferedGraphics.clearRect(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight()); 
} 

Теперь мы можем сделать с помощью bufferedGraphics. рисовать (GT дт) заканчивается этим. (вдохновленный XNA)

public void end(){ 
    if(deviceManager.isFullScreen())deviceManager.getGraphics().drawImage(bufferedImage, 0,0, null); 
    else deviceManager.getGraphics().drawImage(bufferedImage, 3,25, null);  
    deviceManager.getGraphics().dispose();  
    bufferedImage.flush(); 
} 

Я перерабатывают же BufferedImage с момента создания нового (наряду с объектом Graphics) сделал один ад утечки памяти. Не знаю, использовать ли один и тот же графический объект вместо выполнения .dispose()/new Graphics каждый кадр.

В оконном режиме BufferedImage нарисован на jFrame.getGraphics() и в fulls-creen на graphicDevice.getFullScreenWindow(). GetGraphics().

Вот полноэкранная настройка.

public void setFS(){ 
    jFrame.setVisible(false); 
    jFrame.dispose(); 
    jFrame.setIgnoreRepaint(true); 
    jFrame.setResizable(false); 
    jFrame.setUndecorated(true); 
    graphicDevice.setFullScreenWindow(jFrame); 
    graphicDevice.getFullScreenWindow().setIgnoreRepaint(true); 
    graphicDevice.setDisplayMode(new DisplayMode(width, height, 32, 60)); 
    jFrame.setVisible(true);   
    fullScreen = true;  
} 

И оконная установка.

public void setW(){ 
    jFrame.setVisible(false); 
    jFrame.dispose(); 
    jFrame.setIgnoreRepaint(true); 
    jFrame.setResizable(false); 
    jFrame.setUndecorated(false); 
    graphicDevice.setFullScreenWindow(null); 
    jFrame.setSize(width, height);  
    jFrame.setVisible(true); 
    jFrame.getContentPane().setPreferredSize(new Dimension(800, 600));   
    jFrame.pack();  
    fullScreen = false; 
} 

Любая идея, почему различное поведение режимов? (За исключением частоты кадров и некоторых потенциальных утечек памяти, программа работает плавно.)

+0

Я считаю, что ваши тики получают вызов быстрее/медленнее, потому что Swing Event Dispatch Thread - это поток, который ваш таймер не контролирует. Вы должны ограничить количество вызовов в заданный таймфрейм другим способом. – arynaq

+1

На весу приходит немало вещей, которые, кажется, имеют смысл, так это то, что EDT становится перегруженным, а таймер просто укладывает на него события. Таймер имеет метод под названием [setCoalesce] (http://docs.oracle.com/javase/7/docs/api/javax/swing/Timer.html#setCoalesce (boolean)), который сжимает несколько коротких запросов в один запрос на EDT – MadProgrammer

+0

Да. EDT подавлен на 'graphicDevice.getFullScreenWindow(). GetGraphics()' уходит каждый цикл. Был ли EDT хорошей идеей для игрового цикла? Одним из недостатков является то, что я не могу использовать некоторые из SwingUtilities. Знать кого-нибудь другого? –

ответ

1

Теоретически период таймера может быть не короче времени, затраченного на визуализацию одного кадра. Практически, он должен быть длиннее, или вы сразу же насытите общий поток таймера. Для этого вам понадобится profile. Звонки на drawImage() обычно доминируют, даже без масштабирования. Этот AnimationTest отображает скользящее среднее времени рендеринга за последние несколько FRAMES. Вы можете использовать этот подход для настройки своей реализации в соответствии с вашей самой медленной приемлемой целевой платформой.

+0

Booyah!Благодаря предложению профиля я заметил, что для получения нового графического объекта из полноэкранного окна потребовалось много времени. Теперь я создаю объект Graphics в режиме (полноэкранный/оконный). Частота кадров фиксирована. Там возникает новая проблема с переключением между режимами и потерями объекта Graphics, но я уверен, что это легко исправить. Спасибо, trashgod. –

+0

@ Саша-сан: Рад, что это помогло. Графический контекст из 'getGraphics()' является эфемерным. Все в порядке от 'BufferedImage', но будьте осторожны, как вы его получите в своем« DeviceManager ». – trashgod

+0

Последующий вопрос. Jframe.getGraphics() получает объект Grpahics этого фрейма (ссылка) или создает новый? Не слишком ясно на этом. –

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