Возникли проблемы при перемещении объекта без мерцания в Java - PullRequest
0 голосов
/ 18 декабря 2018

Я изучил Двойную буферизацию и планирую реализовать ее в конечном итоге, но на данный момент я не могу понять, как ее использовать или что-то в этом роде.Я пытаюсь сделать понг, поэтому я планирую добавить всего три объекта, но сейчас я просто хочу, чтобы один объект работал гладко.Я довольно новичок в графике, поэтому я не знаю полностью, что я делаю, и я просто пытаюсь учиться на ходу.

Вот мой код:

Понг:

public static void main(String[]args) {
    JFrame window= new JFrame();
    window.setTitle("Pong Game");
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    window.setPreferredSize(new Dimension(800,500));
    window.pack();
    window.setVisible(true);
    Ball ball= new Ball();
    Paddle player= new Paddle();
    window.getContentPane().add(ball);
    for(;;) {
        ball.move();
        //window.setContentPane(ball);
        window.setContentPane(player);
        player.move();
    }
}

Весла:

double x, y, ymove;
boolean cpu;

public Paddle() {
    x=5;
    y=180;
    ymove=.1;
}

//passing an integer through to make the computer paddle
public Paddle(int a) {
    cpu= true;
    x=761;
    y=180;
    ymove=.1;
}

public void paint(Graphics g) {
    g.setColor(Color.blue);
    g.fillRect((int)x, (int)y, 18, 120);
}

public void move() {
    y+=ymove;
    if(y>=500-160||y<=0) {
        ymove*=-1;
    }
}

Шар:

double x, y, xspeed, yspeed;

public Ball() {
    x=200;
    y=200;
    xspeed=0;
    yspeed=.1;
}

public void move() {
    x+=xspeed;
    y+=yspeed;
    if(y>=440||y<=0) {
        yspeed*=-1;
    }
}

public void paint(Graphics g) {
    g.setColor(Color.black);
    g.fillOval((int)x, (int)y, 20, 20);
}

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

Этот ответ является очень очень упрощенным объяснением!Я рекомендую проверить этот журнал linux , который исследует что-то похожее.

Основная проблема, которая вызывает «мерцание», заключается в том, что розыгрыш выполняется «быстро».

Возьмите свой основной цикл:

for(;;) {
    ball.move();
    window.setContentPane(ball);
    window.setContentPane(player);
    player.move();
}

Этот цикл обновляет позиции шара, а затем "добавляет его на панель содержимого".Пока он рисуется, следующее изображение уже добавлено и нарисовано.Это вызывает мерцание (опять же, обратите внимание: это очень упрощено).

Самое простое решение, чтобы устранить «мерцание» - это позволить потоку спать после того, как он нарисован, и «ждать», пока ничья не станетготово.

boolean running = true;
int delay = 15; // adjust the delay
while(running) {
    ball.move();
    player.move();
    window.setContentPane(ball);
    window.setContentPane(player);
    try {
        Thread.sleep(delay);
    } catch(InterruptedException e) {
        // We were interrupted while waiting
        // Something "woke us up". Stop the loop.
        e.printStackTrace();
        running = false;
    }
}

Этот метод Thread.sleep позволяет текущему Thread"подождать" указанное время.

Задержка может быть скорректирована до чего-то более практичного.Вы можете, например, рассчитать, сколько кадров вы хотите и спать на эту сумму.

Другим способом было бы «время» обновления.Это можно сделать с помощью таймера.Так как это более или менее устарело, я реализую его с помощью ScheduledExecutorService

int delay = 15; // adjust the delay

ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool();
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
    public void run() {
        ball.move();
        player.move();
    }
}, delay, TimeUnit.MILLISECONDS)

Начиная с Java8, вы можете написать это, используя лямбду, например:

scheduledExecutorService.scheduleAtFixedRate(() -> {
    ball.move();
    player.move();
}, delay, TimeUnit.MILLISECONDS)

Чтобы остановить это,Теперь вы можете позвонить:

scheduledExecutorService.shutdown();

Однако: существуют более сложные решения.Одним из них, как вы уже отметили, является двойная буферизация .Но есть также несколько различных техник , которые компенсируют более сложные проблемы.Они используют то, что называется перелистыванием страниц.

0 голосов
/ 18 декабря 2018

Проблема, с которой вы столкнулись, состоит в том, что вы разбили свои методы рисования, если вы делаете один класс, посвященный рисованию, и вы помещаете все свои краски в один метод рисования, он должен работать без мерцания.

Я бы также порекомендовал посмотреть, чтобы ваши вызовы рисования выполнялись по таймеру, который позволяет вам выбирать частоту обновления, которая обычно приводит к более плавному восприятию в целом.

Вот пример моего класса графики в моей последней игре

class GameGraphics extends JPanel implements ActionListener {

private Timer refreshHZTimer;

private int refreshHZ = 10;
private int frameID = 0;

public GameGraphics(int width, int height) {

    setBounds(0,0, width, height);
    setVisible(true);

    refreshHZTimer = new Timer(refreshHZ, this);
    refreshHZTimer.start();

}

@Override
public void actionPerformed(ActionEvent e) {

    frameID++;
    if (frameID % 100 == 1)
    System.out.println("Painting FrameID: " + frameID);
    repaint();

}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);

    //Init graphics
    Graphics2D g2 = (Graphics2D) g;
    //Paint stuff here:
}
}

И добавьте этот код в конструктор JFrame:

    GameGraphics gpu = new GameGraphics(width, height);
    frame.add(gpu);
...