如何在 TimerListener 内使用简单循环正确移动形状? [英] How Do I Properly Move Shapes with a Simple Loop inside of a TimerListener?

查看:22
本文介绍了如何在 TimerListener 内使用简单循环正确移动形状?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作一个简单的屏幕保护程序,并且我认为我已经正确实施了其他所有内容.我只是不知道如何让形状移动.再看一下代码,我认为这与我可能自己实现形状的方式(if(线)等)有关?我已经查看了关于这个问题的其他答案,但我无法通过我的代码实现方式找到我正在寻找的答案.任何建议都非常有帮助,谢谢!

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!

此外,仅作为旁注,if"需要 -40状况?我好像听说过在框架之间留一点空间很有用,但我不记得为什么.

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;
    }
}

我曾考虑将循环的内容放在 void 方法中,但我真的认为这没有必要.

I was thinking about placing the contents of the loop inside a void method, but I really don't think that is necessary.

此外,这里还有我的 Shape 类.

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);
    }
}

推荐答案

以下 mre 是基于您的代码.请注意记录所做更改的注释:

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);
    }
} 

<小时>

这篇关于如何在 TimerListener 内使用简单循环正确移动形状?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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