英文:
How Do I Properly Move Shapes with a Simple Loop inside of a TimerListener?
问题
以下是翻译好的部分:
我正在尝试制作一个简单的屏幕保护程序,我认为其他方面我都已经正确实现了。我只是不知道如何使形状移动。再仔细看看代码,我觉得可能与我实现形状本身的方式有关(if (line)等等)?我已经查看了关于这个问题的其他答案,但我在我的代码实现方式中没有找到我正在寻找的答案。任何建议都非常有帮助,谢谢!
另外,只是附带一提,对于“if”条件,-40是必要的吗?我记得在某个地方听说过在帧之间留下一点空间是有用的,但我记不清原因了。
以下是循环的部分:
for (Shapes shapeMove : randomShapes)
{
if (x < 0 || x > frameWidth - 40)
{
velX = velX * -1;
}
else
{
x = newX;
}
if (y < 0 || y > frameHeight - 40)
{
velY = velY * -1;
}
else
{
y = newY;
}
}
我正在考虑将循环的内容放入一个void方法中,但我真的认为这是不必要的。
以下是我的Shapes类:
import java.awt.*;
public class Shapes
{
private final Color color;
private final Shape shape;
public Shapes (Color color, Shape shape)
{
this.color = color;
this.shape = shape;
}
public Color getColor ()
{
return color;
}
public Shape getShape ()
{
return shape;
}
public void paint(Graphics2D g2d)
{
g2d.setColor(color);
g2d.draw(shape);
g2d.fill(shape);
}
}
英文:
I am trying to make a simple screen-saver, and I think I have everything else implemented properly. I just don't know how to make the shapes move. Looking at the code a bit more, I think it has something to do with the way I might have implemented the shapes themselves (the if (line), etc.)? I have looked at other answers regarding this question, but I couldn't quite find the answer I was looking for with the way my code is implemented. Any advice is super helpful, thank you!
Also, just for a side note, is the -40 necessary for the "if" conditions? I thought I heard somewhere that it is useful to leave a little space in-between the frame, but I can't remember why.
import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
public class MyScreenSaver extends JComponent
{
ArrayList <Shapes> randomShapes = new ArrayList <>();
Shapes randomShape;
public MyScreenSaver ()
{
class TimerListener implements ActionListener
{
@Override
public void actionPerformed(ActionEvent event)
{
// Create random generation of colors and shapes...
Shape shape = null;
int frameWidth = 800;
int frameHeight = 500;
for (int i = 1; i <= 10; i ++)
{
Random rng = new Random();
boolean line = rng.nextBoolean();
boolean rectangle = rng.nextBoolean();
int red = ((int) (Math.random() * 255));
int green = ((int) (Math.random() * 255));
int blue = ((int) (Math.random() * 255));
Color color = new Color (red, green, blue);
int width = (10 + (int) (40 * Math.random()));
int height = (10 + (int) (40 * Math.random()));
int x = (int) (Math.random() * (getWidth() - width));
int y = (int) (Math.random() * (getHeight() - height));
int velX = 2;
int velY = 2;
int newX = velX + x;
int newY = velY + y;
if (line)
{
shape = new Line2D.Double(x, y, x + width, y + height);
}
else if (rectangle)
{
shape = new Rectangle2D.Double(x, y, width, height);
}
else
{
shape = new Ellipse2D.Double(x, y, width, height);
}
// Here, we want the shapes to stop appearing after reaching a certain size...
if (randomShapes.size() >= 20)
{
break;
}
Shapes randomShape = new Shapes (color, shape);
// Add the shapes to the randomShapes ArrayList...
randomShapes.add (randomShape);
// Here, we are moving the shapes...
for (Shapes shapeMove : randomShapes)
{
if (x < 0 || x > frameWidth - 40)
{
velX = velX * -1;
}
else
{
x = newX;
}
if (y < 0 || y > frameHeight - 40)
{
velY = velY * -1;
}
else
{
y = newY;
}
}
repaint();
}
}
}
ActionListener listener = new TimerListener();
final int DELAY = 100;
Timer t = new Timer(DELAY, listener);
t.start();
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (Shapes shape : randomShapes)
{
System.out.println (randomShapes.size());
shape.paint(g2d);
}
g2d.dispose();
}
public static void main (String [] args)
{
// Set up the main frame...
final int FRAME_WIDTH = 800;
final int FRAME_HEIGHT = 500;
JFrame screenSaverFrame = new JFrame ();
screenSaverFrame.setTitle("Homework 6");
screenSaverFrame.setSize (FRAME_WIDTH, FRAME_HEIGHT);
screenSaverFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final MyScreenSaver component = new MyScreenSaver ();
screenSaverFrame.add (component);
screenSaverFrame.setVisible (true);
}
}
Here is the loop specifically...
for (Shapes shapeMove : randomShapes)
{
if (x < 0 || x > frameWidth - 40)
{
velX = velX * -1;
}
else
{
x = newX;
}
if (y < 0 || y > frameHeight - 40)
{
velY = velY * -1;
}
else
{
y = newY;
}
}
I was thinking about placing the contents of the loop inside a void method, but I really don't think that is necessary.
Also, here is my Shape class as well.
import java.awt.*;
public class Shapes
{
private final Color color;
private final Shape shape;
public Shapes (Color color, Shape shape)
{
this.color = color;
this.shape = shape;
}
public Color getColor ()
{
return color;
}
public Shape getShape ()
{
return shape;
}
public void paint(Graphics2D g2d)
{
g2d.setColor(color);
g2d.draw(shape);
g2d.fill(shape);
}
}
答案1
得分: 1
以下是基于您的代码的翻译部分:
以下是基于您的代码的部分。请注意记录更改的注释:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
public class MyScreenSaver extends JComponent
{
private final ArrayList<ColoredShape> randomShapes = new ArrayList<>();
//定义常量
private static final int FRAME_WIDTH = 800, FRAME_HEIGHT = 500, DELAY = 100, MAX_SHAPE_HEIGHT = 40,
MAX_SHAPE_WIDTH = 40, MIN_SHAPE_HEIGHT = 10, MIN_SHAPE_WIDTH = 40, MAX_SHAPE_COUNT = 20,
LINE_WIDTH = 5, X_STEP = 5, Y_STEP = 5;
//定义形状类型
enum ShapeType {LINE, RECTANGLE, ELIPSE};
public MyScreenSaver()
{
ActionListener listener = new TimerListener();
Timer t = new Timer(DELAY, listener);
t.start();
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(LINE_WIDTH));
for (ColoredShape shape : randomShapes) //绘制存储的形状
{
shape.paint(g2d);
}
g2d.dispose();
}
//由计时器重复调用。每次都会向集合中添加一个形状,移动所有形状并重绘
class TimerListener implements ActionListener
{
@Override
public void actionPerformed(ActionEvent event)
{
// 创建颜色、形状和位置的随机生成,最多达到 MAX_SHAPE_COUNT
if (randomShapes.size() < MAX_SHAPE_COUNT)
{
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
Color color = new Color(red, green, blue);
int width = MIN_SHAPE_WIDTH + (int) (MAX_SHAPE_WIDTH * Math.random());
int height = MIN_SHAPE_HEIGHT + (int) (MAX_SHAPE_HEIGHT * Math.random());
int x = (int) (Math.random() * (getWidth() - width));
int y = (int) (Math.random() * (getHeight() - height));
// 选择随机的形状类型
int typeIndex = (int) (Math.random() * ShapeType.values().length);
ShapeType type = ShapeType.values()[typeIndex];
// 将形状添加到 randomShapes ArrayList 中...
randomShapes.add(new ColoredShape(type, color, x, y, width, height));
}
// 移动形状...
for (ColoredShape shape : randomShapes)
{
int x = shape.getX(); // 获取当前 x 位置
if (x <= 0 || x > getWidth() - shape.getWidth())
{
shape.setXDirection(-1 * shape.getXDirection()); // 改变方向
}
shape.setX(shape.getX() + shape.getXDirection() * X_STEP); // 增量
int y = shape.getY();
if (y <= 0 || y > getHeight() - shape.getHeight())
{
shape.setYDirection(-1 * shape.getYDirection());
}
shape.setY(shape.getY() + shape.getYDirection() * Y_STEP);
}
repaint();
}
}
public class ColoredShape
{
private int x, y;
private final int width, height;
private int xDirection, yDirection;
private final Color color;
private final ShapeType type;
public ColoredShape(ShapeType type, Color color, int x, int y, int width, int height)
{
this.type = type;
this.color = color;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
xDirection = yDirection = 1; //1 表示增加值,-1 表示减少值
}
public Color getColor()
{
return color;
}
private Shape constructShape()
{
// 使用更新后的边界构造新形状
if (type == ShapeType.LINE)
return new Line2D.Double(x, y, x + width, y + height);
else if (type == ShapeType.RECTANGLE)
return new Rectangle2D.Double(x, y, width, height);
else
return new Ellipse2D.Double(x, y, width, height);
}
public void paint(Graphics2D g2d)
{
g2d.setColor(color);
Shape shape = constructShape();
g2d.draw(shape);
g2d.fill(shape);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getXDirection() {
return xDirection;
}
public void setXDirection(int xDirextion) {
xDirection = xDirextion;
}
public int getYDirection() {
return yDirection;
}
public void setYDirection(int yDirection) {
this.yDirection = yDirection;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
public static void main(String[] args)
{
// 设置主框架...
JFrame screenSaverFrame = new JFrame();
screenSaverFrame.setTitle("作业 6");
screenSaverFrame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
screenSaverFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
screenSaverFrame.add(new MyScreenSaver());
screenSaverFrame.setVisible(true);
}
}
英文:
The following mre is based on your code. Note the comments documenting the changes made:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
public class MyScreenSaver extends JComponent
{
private final ArrayList <ColoredShape> randomShapes = new ArrayList <>();
//define constants
private static final int FRAME_WIDTH = 800, FRAME_HEIGHT = 500, DELAY = 100, MAX_SHAPE_HEIGHT = 40,
MAX_SHAPE_WIDTH = 40, MIN_SHAPE_HEIGHT = 10, MIN_SHAPE_WIDTH = 40, MAX_SHAPE_COUNT = 20,
LINE_WIDTH = 5, X_STEP = 5, Y_STEP = 5;
//define shape types
enum ShapeType {LINE, RECTANGLE, ELIPSE};
public MyScreenSaver ()
{
ActionListener listener = new TimerListener();
Timer t = new Timer(DELAY, listener);
t.start();
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(LINE_WIDTH));
for (ColoredShape shape : randomShapes) //draw stored shapes
{
shape.paint(g2d);
}
g2d.dispose();
}
//invoked repeatedly by Timer. Each time it adds a shape to the collection
//moves all shapes and repaints
class TimerListener implements ActionListener
{
@Override
public void actionPerformed(ActionEvent event)
{
// Create random generation of colors and shapes and location
//up to MAX_SHAPE_COUNT
if (randomShapes.size() < MAX_SHAPE_COUNT)
{
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
Color color = new Color (red, green, blue);
int width = MIN_SHAPE_WIDTH + (int) (MAX_SHAPE_WIDTH * Math.random());
int height = MIN_SHAPE_HEIGHT + (int) (MAX_SHAPE_HEIGHT* Math.random());
int x = (int) (Math.random() * (getWidth() - width));
int y = (int) (Math.random() * (getHeight() - height));
//select a random shape type
int typeIndex = (int) (Math.random()* ShapeType.values().length);
ShapeType type = ShapeType.values()[typeIndex];
// Add the shapes to the randomShapes ArrayList...
randomShapes.add (new ColoredShape (type,color,x, y,width,height));
}
//move the shapes...
for (ColoredShape shape : randomShapes)
{
int x = shape.getX();//get current x position
if (x <= 0 || x > getWidth() - shape.getWidth())
{
shape.setXDirection(-1*shape.getXDirection());//change direction
}
shape.setX(shape.getX() + shape.getXDirection()*X_STEP);//increment
int y = shape.getY();
if (y <= 0 || y > getHeight()- shape.getHeight())
{
shape.setYDirection(-1*shape.getYDirection());
}
shape.setY(shape.getY() + shape.getYDirection()*Y_STEP);
}
repaint();
}
}
public class ColoredShape
{
private int x, y;
private final int width, height;
private int xDirection, yDirection;
private final Color color;
private final ShapeType type;
public ColoredShape(ShapeType type, Color color, int x, int y, int width, int height)
{
this.type = type;
this.color = color;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
xDirection = yDirection = 1; //1 means increase value, -1 decrease value
}
public Color getColor ()
{
return color;
}
private Shape constructShape ()
{
//construct new shape using updated bounds
if(type == ShapeType.LINE)
return new Line2D.Double(x, y, x + width, y + height);
else if (type == ShapeType.RECTANGLE)
return new Rectangle2D.Double(x, y, width, height);
else
return new Ellipse2D.Double(x, y, width, height);
}
public void paint(Graphics2D g2d)
{
g2d.setColor(color);
Shape shape = constructShape();
g2d.draw(shape);
g2d.fill(shape);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getXDirection() {
return xDirection;
}
public void setXDirection(int xDirextion) {
xDirection = xDirextion;
}
public int getYDirection() {
return yDirection;
}
public void setYDirection(int yDirection) {
this.yDirection = yDirection;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
public static void main (String [] args)
{
// Set up the main frame...
JFrame screenSaverFrame = new JFrame ();
screenSaverFrame.setTitle("Homework 6");
screenSaverFrame.setSize (FRAME_WIDTH, FRAME_HEIGHT);
screenSaverFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
screenSaverFrame.add (new MyScreenSaver ());
screenSaverFrame.setVisible (true);
}
}
<hr>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论