我正在尝试在 Java 中实现 Convay 的生命游戏中实现缩放和平移功能。问题如下:
每次我们尝试通过拖动鼠标进行平移时,我们的视线都会出现在屏幕的左上角。这是负责实现此功能的类
package input;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import renderer.Renderer;
public class PanningHandler extends MouseAdapter {
private Renderer renderer;
public PanningHandler(Renderer renderer) {
this.renderer = renderer;
}
@Override
public void mouseDragged(MouseEvent e) {
// Check if the right mouse button is pressed (RMB)
if ((e.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) != 0) {
handleRMBDrag(e);
}
}
private void handleRMBDrag(MouseEvent e) {
int deltaX = e.getX() - renderer.getLastMouseX();
int deltaY = e.getY() - renderer.getLastMouseY();
// Calculate new pan offset
int newPanOffsetX = renderer.getPanOffsetX() - deltaX;
int newPanOffsetY = renderer.getPanOffsetY() - deltaY;
// Calculate maximum allowed values based on the size of the display area
int maxPanOffsetX = getMaxPanOffsetX(); // Adjust this based on your requirements
int maxPanOffsetY = getMaxPanOffsetY(); // Adjust this based on your requirements
// Limit the pan offset to avoid going out of bounds
newPanOffsetX = Math.max(0, Math.min(newPanOffsetX, maxPanOffsetX));
newPanOffsetY = Math.max(0, Math.min(newPanOffsetY, maxPanOffsetY));
// Set the new pan offset and repaint
renderer.setPanOffsetX(newPanOffsetX);
renderer.setPanOffsetY(newPanOffsetY);
renderer.getFrame().repaint();
// Update last mouse coordinates for the next iteration
renderer.setLastMouseX(e.getX());
renderer.setLastMouseY(e.getY());
}
// Rest of the code remains unchanged
private int getMaxPanOffsetX() {
return (int) (renderer.getWidth() * 10 * renderer.getZoomFactor() - renderer.getFrame().getWidth());
}
private int getMaxPanOffsetY() {
return (int) (renderer.getHeight() * 10 * renderer.getZoomFactor() - renderer.getFrame().getHeight());
}
}
这是渲染器中的一些位,负责绘制正方形和平移。
public class Renderer {
private double zoomFactor = 1.0;
private boolean gameState = false;
private final Color BLACK = Color.BLACK;
private final Color WHITE = Color.WHITE;
private JFrame frame;
private static Renderer instance;
private int height = 100; // TODO - Handle the case when our grid becomes very large (e.g 1000x1000)
private int width = 100;
private boolean[][] grid = new boolean[height][width];
private Logic logic = new Logic(); // instantiate Logic class
private int lastMouseX = -1;
private int lastMouseY = -1;
private int panOffsetX = 0;
private int panOffsetY = 0;
private void configFrame() {
frame.pack();
frame.setSize(width * 10, height * 10);
frame.getContentPane().setBackground(BLACK);
// ...
frame.addMouseMotionListener(new PanningHandler(this)); // TODO - make it work
// ...
frame.add(new MyPanel());
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
/**
* Inner class representing the drawing panel inside the JFrame.
*/
class MyPanel extends JPanel {
public MyPanel() {
setBackground(BLACK); // Set the background color to black
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
drawSquares(g);
}
}
/**
* Draws squares on the panel based on the current state of the grid.
*
* @param g The Graphics object used for drawing.
*/
public void drawSquares(Graphics g) {
int squareSize = (int) (10 * zoomFactor);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int x = (int) (j * squareSize - panOffsetX);
int y = (int) (i * squareSize - panOffsetY);
if (grid[i][j]) {
g.setColor(WHITE);
g.fillRect(x, y, squareSize, squareSize);
} else {
g.setColor(BLACK);
g.fillRect(x, y, squareSize, squareSize);
}
}
}
}
/**
* Updates the grid based on the Game of Life rules.
* Repaints the frame to reflect the changes.
*/
public void updateGrid() {
if (gameState) {
grid = logic.gridUpdate(grid);
frame.repaint();
}
}
// ... (rest of the code)
}
我知道如果我们取消新的 PanOffsetX/Y 限制,
// Limit the pan offset to avoid going out of bounds
newPanOffsetX = Math.max(0, Math.min(newPanOffsetX, maxPanOffsetX));
newPanOffsetY = Math.max(0, Math.min(newPanOffsetY, maxPanOffsetY));
然后它很快就会变成负数。每次当我们开始在任何位置拖动鼠标时 方向——我们让事情变得更糟。这可能就是它回到左上角的原因。
非常感谢有关此问题的任何帮助,干杯!
我设法修复了这个错误。通过更改我的 MyMouseListener。
旧版本代码
package input;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.SwingUtilities;
import renderer.Renderer;
/**
* Custom MouseAdapter for handling mouse events in the Renderer.
* This adapter is responsible for processing mouse clicks, releases, and drag events.
*/
public class MyMouseListener extends MouseAdapter {
private final Renderer renderer;
/**
* Constructs a new MyMouseListener with the specified Renderer.
*
* @param renderer The Renderer associated with this adapter.
*/
public MyMouseListener(Renderer renderer) {
this.renderer = renderer;
}
/**
* Invoked when the mouse is clicked.
* Calls the handleMouseClick method to update the grid based on the mouse click.
*
* @param e The MouseEvent representing the mouse click event.
*/
@Override
public void mouseClicked(MouseEvent e) {
// Check if the left mouse button is pressed (LMB).
// for some reason the never version BUTTON1_DOWN_MASK doesn't work, so I used the older version
if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) {
handleLMBClick(e);
}
}
/**
* Handles the mouse click event by updating the grid according to the click position.
*
* @param e The MouseEvent representing the mouse click event.
*/
public void handleLMBClick(MouseEvent e) {
int squareSize = (int) (10 * renderer.getZoomFactor());
int x = (int) ((e.getX() + renderer.getPanOffsetX()) / squareSize);
int y = (int) ((e.getY() + renderer.getPanOffsetY() - 40) / squareSize);
// Clamp the indices to valid grid bounds
x = Math.min(Math.max(0, x), renderer.getWidth() - 1);
y = Math.min(Math.max(0, y), renderer.getHeight() - 1);
renderer.reverseElement(y, x);
System.out.println("Mouse Clicked: " + x + "," + y);
renderer.getFrame().repaint(); // Repaint the frame to update the drawing
}
/**
* Invoked when the mouse is released.
* Resets the last mouse coordinates to -1, indicating no ongoing drag.
*
* @param e The MouseEvent representing the mouse release event.
*/
// @Override
// public void mouseReleased(MouseEvent e) {
// renderer.setLastMouseX(-1);
// renderer.setLastMouseY(-1);
// }
}
新版本代码
package input;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.SwingUtilities;
import renderer.Renderer;
/**
* Custom MouseAdapter for handling mouse events in the Renderer.
* This adapter is responsible for processing mouse clicks, releases, and drag
* events.
*/
public class MyMouseListener extends MouseAdapter {
private final Renderer renderer;
/**
* Constructs a new MyMouseListener with the specified Renderer.
*
* @param renderer The Renderer associated with this adapter.
*/
public MyMouseListener(Renderer renderer) {
this.renderer = renderer;
}
/**
* Handles the mouse pressed event, updating the grid based on the click
* position.
* If the right mouse button is pressed, it records the initial mouse
* coordinates for panning.
* If the left mouse button is pressed, it calculates the grid indices and
* toggles the cell state.
* @param e The MouseEvent representing the mouse click event.
*/
@Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
renderer.setLastMouseX(e.getX());
renderer.setLastMouseY(e.getY());
} else {
int squareSize = (int) (10 * renderer.getZoomFactor());
int x = (int) ((e.getX() + renderer.getPanOffsetX()) / squareSize);
int y = (int) ((e.getY() + renderer.getPanOffsetY() - 40) / squareSize);
// Clamp the indices to valid grid bounds
x = Math.min(Math.max(0, x), renderer.getWidth() - 1);
y = Math.min(Math.max(0, y), renderer.getHeight() - 1);
renderer.reverseElement(y, x);
System.out.println("Mouse Clicked: " + x + "," + y);
renderer.getFrame().repaint(); // Repaint the frame to update the drawing
}
}
}