如何在 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...
- 您需要一个独立的更新周期,独立于绘制周期
- 在应用任何转换之前,创建
Graphics
上下文的本地副本
- You need a independent update cycle, independent of the paint cycle
- 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;
}
相关文章