如何阻止我的气泡动画闪烁?几乎尝试了所有事情

时间:2016-03-20 12:47:47

标签: java swing animation flicker

我绝望,因为我的动画并不像我预期的那样顺畅。所以我知道,围绕这个问题有很多东西,但我的不同之处在于,我知道常见的问题,我认为,我做得对。首先,这是我的代码:

Game.java

import de.lwerner.collisions.CircleCollision;
import de.lwerner.collisions.math.Vector2D;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

public class Game extends JPanel implements ActionListener {

    private static final Color BACKGROUND_COLOR = new Color(0, 0, 25);
    private static final Color TEXT_COLOR = Color.WHITE;
    private static final int TARGET_FPS = 60;

    private javax.swing.Timer swingTimer;

    private JFrame window;

    private Timer timer;
    private Timer fpsTimer;

    private int counter;
    private long[] diffs;
    private int fps;

    private LinkedList<Circle> circles;
    private LinkedList<Sprite> sprites;

    public Game() {
        timer = new Timer();
        fpsTimer = new Timer(System.currentTimeMillis());

        diffs = new long[TARGET_FPS];

        circles = new LinkedList<>();
        circles.add(new Circle(100, 100, 50, 300, 300, Color.WHITE));
//        circles.add(new Circle(250, 250, 50, 300, 300, Color.WHITE));
//        circles.add(new Circle(400, 400, 50, 300, 300, Color.WHITE));
//        circles.add(new Circle(550, 550, 50, 300, 300, Color.WHITE));
//        circles.add(new Circle(700, 700, 50, 300, 300, Color.WHITE));
//        circles.add(new Circle(100, 700, 50, -300, 300, Color.WHITE));
//        circles.add(new Circle(250, 550, 50, 300, -300, Color.WHITE));
//        circles.add(new Circle(550, 250, 50, 300, -300, Color.WHITE));
//        circles.add(new Circle(700, 100, 50, -300, 300, Color.WHITE));

        sprites = new LinkedList<>();
        sprites.addAll(circles);

        window = new JFrame("Game");
        window.setContentPane(this);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setLocationRelativeTo(null);
        window.setUndecorated(true);
        window.setResizable(false);
        window.validate();
        window.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e) {
                stop();
            }
        });
        window.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                stop();
            }
        });
        GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(window);
    }

    @Override
    protected void paintComponent(Graphics g) {
        g.setColor(BACKGROUND_COLOR);
        g.fillRect(0, 0, getWidth(), getHeight());

        Graphics2D g2d = (Graphics2D)g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        for (Sprite s: sprites) {
            s.render(g);
        }

        g.setColor(TEXT_COLOR);
        g.drawString(fps + " FPS", 10, 20);

        diffs[counter % TARGET_FPS] = fpsTimer.tick();
        if (++counter % TARGET_FPS == 0) {
            int sum = 0;
            for (long diff: diffs) {
                sum += diff;
            }
            fps = 1000 / (sum / TARGET_FPS);
        }
    }

    private void step() {
        long tick = timer.tick();
        for (Sprite s: sprites) {
            s.update(tick);
        }
        repaint();
        checkCollisions();
    }

    private void checkCollisions() {
        for (Sprite s1: sprites) {
            BoundingBox bb = s1.getBoundingBox();
            int offset = 0;
            if (s1 instanceof Circle) {
                offset = ((Circle) s1).getRadius();
            }
            if (bb.getLeft() < 0 || bb.getRight() >= getWidth()) {
                s1.setVelX(-s1.getVelX());

                if (bb.getLeft() < 0) {
                    s1.setX(0 + offset);
                } else {
                    s1.setX(getWidth() - 1 - offset);
                }
            }
            if (bb.getTop() < 0 || bb.getBottom() >= getHeight()) {
                s1.setVelY(-s1.getVelY());

                if (bb.getTop() < 0) {
                    s1.setY(0 + offset);
                } else {
                    s1.setY(getHeight() - 1 - offset);
                }
            }
        }

//        Set<Set<Circle>> collidingPairs = new HashSet<>();
//        for (Circle c1: circles) {
//            for (Circle c2: circles) {
//                if (c1 == c2) {
//                    continue;
//                } else {
//                    if (c1.intersects(c2)) {
//                        Set<Circle> pair = new HashSet<>(Arrays.asList(c1, c2));
//                        if (!collidingPairs.contains(pair)) {
//                            collidingPairs.add(pair);
//                            de.lwerner.collisions.Circle cc1 = new de.lwerner.collisions.Circle(c1.getX(), c1.getY(), c1.getRadius(), new Vector2D(c1.getVelX(), c1.getVelY()));
//                            de.lwerner.collisions.Circle cc2 = new de.lwerner.collisions.Circle(c2.getX(), c2.getY(), c2.getRadius(), new Vector2D(c2.getVelX(), c2.getVelY()));
//                            CircleCollision collision = new CircleCollision(cc1, cc2);
//                            collision.resolveCollision();
//                            Vector2D v1New = cc1.getV();
//                            Vector2D v2New = cc2.getV();
//                            c1.setVelX((int) v1New.getX());
//                            c1.setVelY((int) v1New.getY());
//                            c2.setVelX((int) v2New.getX());
//                            c2.setVelY((int) v2New.getY());
//                        }
//                    }
//                }
//            }
//        }
    }

    private void stop() {
        if (swingTimer.isRunning()) {
            swingTimer.stop();
            window.dispose();
        }
    }

    public void start() {
        swingTimer = new javax.swing.Timer(1000 / TARGET_FPS, this);
        swingTimer.start();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        step();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Game().start());
    }
}

Sprite.java

import java.awt.*;

public abstract class Sprite {

    protected double x;
    protected double y;
    protected int width;
    protected int height;
    protected int velX;
    protected int velY;

    public Sprite(int x, int y, int width, int height) {
        this(x, y, width, height, 0, 0);
    }

    public Sprite(int x, int y, int width, int height, int velX, int velY) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.velX = velX;
        this.velY = velY;
    }

    public int getX() {
        return (int)Math.round(x);
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return (int)Math.round(y);
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getVelX() {
        return velX;
    }

    public void setVelX(int velX) {
        this.velX = velX;
    }

    public int getVelY() {
        return velY;
    }

    public void setVelY(int velY) {
        this.velY = velY;
    }

    public void update(long tick) {
        x += tick * velX / 1000.0;
        y += tick * velY / 1000.0;
    }

    public BoundingBox getBoundingBox() {
        return new BoundingBox(getY(), getX() + width, getY() + height, getX());
    }

    public boolean intersects(Sprite other) {
        return getBoundingBox().intersects(other.getBoundingBox());
    }

    public abstract void render(Graphics g);

}

Circle.java

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;

public class Circle extends Sprite {

    private Color color;

    private BufferedImage image;

    public Circle(int x, int y, int r, Color c) {
        super(x, y, r * 2, r * 2);
        color = c;
//        try {
//            loadImage();
//        } catch (Exception e) {
//
//        }
    }

    public Circle(int x, int y, int r, int velX, int velY, Color c) {
        super(x, y, r * 2, r * 2, velX, velY);
        color = c;
//        try {
//            loadImage();
//        } catch (Exception e) {
//
//        }
    }

    private void loadImage() throws IOException {
        image = ImageIO.read(getClass().getResource("/bubble.png"));
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public int getRadius() {
        return width / 2;
    }

    public boolean intersects(Circle other) {
        int dx = Math.abs(getX() - other.getX());
        int dy = Math.abs(getY() - other.getY());
        int r1 = getRadius();
        int r2 = other.getRadius();
        return dx * dx + dy * dy < (r1 + r2) * (r1 + r2);
    }

    @Override
    public BoundingBox getBoundingBox() {
        return new BoundingBox(getY() - getRadius(), getX() + getRadius(), getY() + getRadius(), getX() - getRadius());
    }

    @Override
    public void render(Graphics g) {
        if (image == null) {
            g.setColor(color);
            g.fillOval(getX() - getRadius(), getY() - getRadius(), width, height);
        } else {
            g.drawImage(image, getX() - getRadius(), getY() - getRadius(), null);
        }
    }

}

Timer.java

public class Timer {

    private long lastTime;

    public Timer() {
        this(0L);
    }

    public Timer(long initialTime) {
        lastTime = initialTime;
    }

    public long tick() {
        if (lastTime == 0) {
            lastTime = System.currentTimeMillis();
            return 0;
        }
        long current = System.currentTimeMillis();
        long diff = current - lastTime;
        lastTime = current;
        return diff;
    }

}

BoundingBox.java

import java.awt.*;

public class BoundingBox {

    private int top;
    private int right;
    private int bottom;
    private int left;

    public BoundingBox(int top, int right, int bottom, int left) {
        this.top = top;
        this.right = right;
        this.bottom = bottom;
        this.left = left;
    }

    public int getTop() {
        return top;
    }

    public int getRight() {
        return right;
    }

    public int getBottom() {
        return bottom;
    }

    public int getLeft() {
        return left;
    }

    public Rectangle getRectangle() {
        return new Rectangle(left, top, right - left, bottom - top);
    }

    public boolean intersects(BoundingBox other) {
        return getRectangle().intersects(other.getRectangle());
    }

    @Override
    public String toString() {
        return "BoundingBox{" +
                "top=" + top +
                ", right=" + right +
                ", bottom=" + bottom +
                ", left=" + left +
                '}';
    }

}

所以我不知道,我做错了什么。常见的问题,如调用paint(),使用非双缓冲组件,使用错误的方法定期运行代码等等都不存在,但它是闪烁的。 FPS是不变的。

所以,请帮助我!我很乐意过来这个......

谢谢!

0 个答案:

没有答案