如何在 Java 中独立旋转对象/图像? [英] How do I rotate objects/images independently in Java?

查看:27
本文介绍了如何在 Java 中独立旋转对象/图像?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图让一系列矩形围绕它们各自的中心旋转并向右移动,但由于平面包含所有矩形,所有矩形围绕最新添加的矩形的中心一致旋转,而不是独立围绕他们各自的中心.以下是代码:

I am trying to have a series of rectangles rotating about their respective centres and moving to the right, but since the plane contains all the rectangles, all the rectangles rotate in unison about the centre of the latest added rectangle instead of independently around their respective centres. Here are the codes:

主程序:

import java.awt.Graphics2D;
import java.util.ArrayList;

public class Rectangles {

    public static final int SCREEN_WIDTH = 400;
    public static final int SCREEN_HEIGHT = 400;

    public static void main(String[] args) throws Exception {
        Rectangles game = new Rectangles();
        game.play();
    }

    public void play() {
        board.setupAndDisplay();
    }

    public Rectangles() {
        board = new Board(SCREEN_WIDTH, SCREEN_HEIGHT, this);
        rectangle_2 = new Rectangle_2();
        rectangles = new ArrayList<Rectangle_2>();
    }

    public void drawRectangles(Graphics2D g, float elapsedTime) {
        ticks++;
        if (ticks % 4000 == 0) {
            Rectangle_2 rectangle = new Rectangle_2();
            rectangles.add(rectangle);
        }
        rotateRectangles(g);
        drawRectangles(g);
        moveRectangles(elapsedTime);

        for (int i = 0; i < rectangles.size(); i++) {
            Rectangle_2 rectangle = rectangles.get(i);
            if (rectangle.getX() < -75) {
                rectangles.remove(i);
                i--;
            }
        }
    }

    public void drawRectangles(Graphics2D g) {
        for (Rectangle_2 rectangle: rectangles) {
            rectangle.drawRectangle(g);
        }
    }

    public void rotateRectangles(Graphics2D g) {
        for (Rectangle_2 rectangle: rectangles) {
            rectangle.rotateRectangle(g);
        }
    }

    public void moveRectangles(float elapsedTime) {
        for (Rectangle_2 rectangle: rectangles) {
            rectangle.move(10 * elapsedTime);
        }
    }

    private Board board;
    private Rectangle_2 rectangle_2;
    private int ticks = 0;
    private ArrayList<Rectangle_2> rectangles;
}

矩形类:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;

public class Rectangle_2 {

    public Rectangle_2() {
        x = 0;
        y = 200;
        rectangle = new Rectangle((int) x, (int) y, 25, 25);
    }

    public void drawRectangle(Graphics2D g) {
        g.setColor(Color.red);
        g.draw(rectangle);
    }

    public void rotateRectangle(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        angle += 0.001;
        g2.rotate(angle, rectangle.getX() + rectangle.getWidth() / 2, rectangle.getY() + rectangle.getHeight() / 2);
        g2.setColor(Color.red);
    }

    public void move(float elapsedTime) {
        x = x + elapsedTime;
        rectangle.setLocation((int) x, (int) y);
    }

    public boolean collides(Rectangle r) {
        return r.intersects(rectangle);
    }

    @Override
    public String toString() {
        return "Pipe [x = " + x + ", y = " + y + ", rectangle = " + rectangle + "]";
    }

    public Rectangle getRectangle() {
        return rectangle;
    }

    public double getX() {
        return x;
    }

    private double x;
    private double y;
    private double angle = 0;
    private Rectangle rectangle;
}

动画发生的棋盘类:

import java.awt.*;
import javax.swing.*;

public class Board extends JPanel {

    private static final long serialVersionUID = 1L;

    public Board(int width_, int height_, Rectangles simulator_) {
        width = width_;
        height = height_;
        game = simulator_;
        lastTime = -1L;
    }

    public void setupAndDisplay() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new JScrollPane(this));
        f.setSize(width, height);
        f.setLocation(200, 200);
        f.setVisible(true);
        this.setFocusable(true);
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        boolean first = (lastTime == -1L);
        long elapsedTime = System.nanoTime() - lastTime;
        lastTime = System.nanoTime();
        g.setColor(Color.white);
        g.fillRect(0, 0, width, height);
        g.setColor(Color.white);
        game.drawRectangles((Graphics2D) g, (first ? 0.0f : (float) elapsedTime / 1e9f));
        repaint();
    }

    private int width;
    private int height;
    private long lastTime;
    private Rectangles game;
}

请注意,由于实施了延迟,矩形需要几秒钟才能出现.谢谢 :).

Please note the rectangle takes a couple of seconds to appear because of the delay implemented. Thank you :).

推荐答案

Graphics 上下文是共享资源,即在一个绘制周期内,所有组件都获得相同的图形上下文.您对 Graphics 上下文所做的任何更改也会被保留(或在相同转换的情况下复合).所以这意味着,每次你调用 Graphics#rotate 时,你实际上是在复合之前可能已经在其上执行的任何旋转.

The Graphics context is a shared resource, that is, during a single paint cycle, all the components get the same Graphics context. Any changes you make to the Graphics context are also maintained (or compound in the case of same transformations). So this means, each time you call Graphics#rotate, you are actually compounding any of the previous rotations which might have been executed on it.

您需要通过两种方式更改代码...

You need to change you code in two ways...

  1. 您需要一个独立的更新周期,独立于绘制周期
  2. 在应用任何转换之前,创建 Graphics 上下文的本地副本
  1. You need a independent update cycle, independent of the paint cycle
  2. Create a local copy of the Graphics context BEFORE you apply any transformations

例如...

Rectangles 成为主要的驱动程序/引擎.它负责管理实体并在每个周期更新它们.通常,我会使用某种 interface 来描述其他案例可能能够使用的功能,但你明白了

Rectangles becomes the main driver/engine. It's responsible for managing the entities and updating them each cycle. Normally, I'd use some kind of interface that described the functionality that other case might be able to use, but you get the idea

public class Rectangles {

    public static void main(String[] args) throws Exception {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }
                Rectangles game = new Rectangles();
                game.play();
            }
        });
    }

    public void play() {

        Board board = new Board(this);

        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(board);
        f.pack();
        f.setLocation(200, 200);
        f.setVisible(true);
        Timer timer = new Timer(40, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                updateRectangles();
                board.repaint();
                lastTime = System.nanoTime();
            }
        });
        timer.start();
    }

    public Rectangles() {
        rectangle_2 = new Rectangle_2();
        rectangles = new ArrayList<Rectangle_2>();
    }

    protected void updateRectangles() {
        boolean first = (lastTime == -1L);
        double elapsedTime = System.nanoTime() - lastTime;
        elapsedTime = (first ? 0.0f : (float) elapsedTime / 1e9f);

        ticks++;
        if (ticks <= 1 || ticks % 100 == 0) {
            Rectangle_2 rectangle = new Rectangle_2();
            rectangles.add(rectangle);
        }

        rotateRectangles();
        moveRectangles(elapsedTime);


        for (int i = 0; i < rectangles.size(); i++) {
            Rectangle_2 rectangle = rectangles.get(i);
            if (rectangle.getX() < -75) {
                rectangles.remove(i);
                i--;
            }
        }
    }

    public void drawRectangles(Graphics2D g) {
        for (Rectangle_2 rectangle : rectangles) {
            rectangle.drawRectangle(g);
        }
    }

    protected void rotateRectangles() {
        for (Rectangle_2 rectangle : rectangles) {
            rectangle.rotateRectangle();
        }
    }

    protected void moveRectangles(double elapsedTime) {
        for (Rectangle_2 rectangle : rectangles) {
            rectangle.move(10 * elapsedTime);
        }
    }

    private long lastTime = -1L;
    private Rectangle_2 rectangle_2;
    private int ticks = 0;
    private ArrayList<Rectangle_2> rectangles;
}

Board 只不过是一个可以渲染实体的表面

Board becomes nothing more then a surface onto which the entities can be rendered

public class Board extends JPanel {

    public Board(Rectangles engine) {
        game = engine;
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(400, 400);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        game.drawRectangles((Graphics2D) g);
    }

    private Rectangles game;
}

Rectangle_2 是一个简单的信息容器,它知道如何在有机会时自行绘制.你会注意到移动和旋转方法只是更新状态,它们什么都不做.

And Rectangle_2 is a simple container of information which knows how to paint itself when given the chance. You will note the movement and rotation methods just update the state, they do nothing else.

drawRectangle 首先创建提供的 Graphics2D 上下文的副本,然后再应用它的更改并渲染矩形,完成后,它调用 dispose 处理副本

drawRectangle first creates a copy of the supplied Graphics2D context, before it applies it's changes and renders the rectangle, when done, it calls dispose to dispose of the copy

public class Rectangle_2 {

    public Rectangle_2() {
        x = 0;
        y = 200;
        rectangle = new Rectangle((int) x, (int) y, 25, 25);
    }

    public void drawRectangle(Graphics2D g) {
        Graphics2D g2 = (Graphics2D) g.create();
        g2.rotate(angle, rectangle.getX() + rectangle.getWidth() / 2, rectangle.getY() + rectangle.getHeight() / 2);
        g2.setColor(Color.red);
        g2.draw(rectangle);
        g2.dispose();
    }

    public void rotateRectangle() {
        angle += 0.001;
    }

    public void move(double elapsedTime) {
        x = x + elapsedTime;
        rectangle.setLocation((int) x, (int) y);
    }

    public boolean collides(Rectangle r) {
        return r.intersects(rectangle);
    }

    @Override
    public String toString() {
        return "Pipe [x = " + x + ", y = " + y + ", rectangle = " + rectangle + "]";
    }

    public Rectangle getRectangle() {
        return rectangle;
    }

    public double getX() {
        return x;
    }

    private double x;
    private double y;
    private double angle = 0;
    private Rectangle rectangle;
}

这篇关于如何在 Java 中独立旋转对象/图像?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆