如何在 TimerListener 内部使用简单循环正确移动形状?

huangapple go评论78阅读模式
英文:

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 &lt;Shapes&gt; randomShapes = new ArrayList &lt;&gt;();
    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 &lt;= 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() &gt;= 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 &lt; 0 || x &gt; frameWidth - 40)
                        {
                            velX = velX * -1;
                        }
                        else
                        {
                            x = newX;
                        }
                        if (y &lt; 0 || y &gt; 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(&quot;Homework 6&quot;);
        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 &lt; 0 || x &gt; frameWidth - 40)
    {
        velX = velX * -1;
    }
    else
    {
        x = newX;
    }
    if (y &lt; 0 || y &gt; 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 &lt;ColoredShape&gt; randomShapes = new ArrayList &lt;&gt;();
//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() &lt; 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 &lt;= 0 || x &gt; 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 &lt;= 0 || y &gt; 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(&quot;Homework 6&quot;);
screenSaverFrame.setSize (FRAME_WIDTH, FRAME_HEIGHT);
screenSaverFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
screenSaverFrame.add (new MyScreenSaver ());
screenSaverFrame.setVisible (true);
}
} 

<hr>

如何在 TimerListener 内部使用简单循环正确移动形状?

huangapple
  • 本文由 发表于 2020年10月14日 12:53:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/64346806.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定