简体   繁体   English

动画无法使用Java图形

[英]Animation not working Java Graphics

Completing a graphics program in Java, I'm trying to animate rain falling using a timer. 我正在用Java完成一个图形程序,以使雨水动画化。 Right now I am testing my code with a big blue rectangle so I can see where it's going but the animation isn't working for me. 现在,我正在用一个大的蓝色矩形测试我的代码,以便可以看到它的运行方向,但是动画对我不起作用。 I'm very new to Java graphics so I could be making mistakes that just aren't clear to me. 我对Java图形语言很陌生,所以我可能会犯一些我不清楚的错误。

When I try to repaint the square to move, and the paint function is called the whole screen blinks, this may be because I was using recursive functions to draw fractal trees, but I'm not sure. 当我尝试重新绘制正方形以进行移动,并且绘制功能被称为整个屏幕闪烁时,这可能是因为我正在使用递归功能绘制分形树,但我不确定。 Is there a way to keep everything I have drawn from being repainted and just call repaint on the rain? 有没有办法让我绘制的所有内容都不会被重新粉刷,只是在下雨时才叫重新粉刷? Any guidance or tips would be appreciated. 任何指导或技巧将不胜感激。

import java.awt.*;
import javax.swing.*;
import java.lang.Math;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class FractalTree extends JFrame {
    private int frameWidth = 1440;
    private int frameHeight = 850;
    private int rainX = 0;
    private int rainY = 0;

public FractalTree() 
{
    setBounds(1000, 1000, frameWidth, frameHeight ); //graphics window size
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    ActionListener listener = new TimerListener();
    final int DELAY = 1500;
    Timer t = new Timer(DELAY, listener);
    t.start();
    setResizable(false);

}

public void setRain(int newRainX, int newRainY)
{
    rainX = newRainX;
    rainY = newRainY;
}

public void setSkyGround(Graphics g)
{
   Color sky = new Color(180, 225, 255);
   g.setColor(sky);
   g.fillRect(0, 0, frameWidth, 550);

   Color sun = new Color(225, 225, 150);
   g.setColor(sun);

   g.fillOval(1380, -40, 100, 100);

   g.drawLine(frameWidth, 0, 1350, 550);
   g.drawLine(frameWidth, 0, 1450, 550);
   g.drawLine(1350, 550, 1450, 550);

   int xpoints[] = {frameWidth, 1450, 1350};
   int ypoints[] = {0, 550, 550};
   int npoints = 3;
   g.fillPolygon(xpoints, ypoints, npoints);

   g.drawLine(frameWidth, 0, 1080, 550);
   g.drawLine(frameWidth, 0, 880, 550);
   g.drawLine(880, 550, 1080, 550);

   int xpoints2[] = {frameWidth, 1080, 880};
   int ypoints2[] = {0, 550, 550};
   int npoints2 = 3;
   g.fillPolygon(xpoints2, ypoints2, npoints2);

   g.drawLine(frameWidth, 0, 480, 550);
   g.drawLine(frameWidth, 0, 280, 550);
   g.drawLine(480, 550, 280, 550);

   int xpoints3[] = {frameWidth, 480, 280};
   int ypoints3[] = {0, 550, 550};
   int npoints3 = 3;
   g.fillPolygon(xpoints3, ypoints3, npoints3);

   g.drawLine(frameWidth, 0, 0, 430);
   g.drawLine(frameWidth, 0, 0, 300);
   g.drawLine(0, 430, 0, 300);

   int xpoints4[] = {frameWidth, 0, 0};
   int ypoints4[] = {0, 430, 300};
   int npoints4 = 3;
   g.fillPolygon(xpoints4, ypoints4, npoints4);

   g.drawLine(frameWidth, 0, 0, 100);
   g.drawLine(frameWidth, 0, 0, 0);
   g.drawLine(0, 100, 0, 0);

   int xpoints5[] = {frameWidth, 0, 0};
   int ypoints5[] = {0, 0, 100};
   int npoints5 = 3;
   g.fillPolygon(xpoints5, ypoints5, npoints5);

   Color grassBackground = new Color(150, 255, 170);
   g.setColor(grassBackground);
   g.fillRect(0, 550, frameWidth, frameHeight);

}

public void drawTree(Graphics g, int x1, int y1, double angle, int depth, int red, int green, int blue) 
{
    if (depth == 0)
    { 
        Color doodle = new Color(red, green, blue);
        g.setColor(doodle);
        g.fillOval(x1, y1, 10, 10);  
    }
    else
    {
        Graphics2D g2 = (Graphics2D) g;
        g2.setStroke(new BasicStroke(depth));

        Color brown = new Color(100, 25, 0);
        g.setColor(brown);
        int x2 = x1 + (int) (Math.cos(Math.toRadians(angle)) * depth * 10);
        int y2 = y1 + (int) (Math.sin(Math.toRadians(angle)) * depth * 10);

        g.drawLine(x1, y1, x2, y2);

        drawTree(g, x2, y2, angle - 40, depth - 1, red, green, blue);
        drawTree(g, x2, y2, angle + 20, depth - 1, red, green, blue);
    }
}
public void realFlowers(Graphics g, int x, int y, int lenWid, int petals)
{
    //calculates the increment
    double inc = (2*Math.PI/petals);
    g.setColor(Color.YELLOW);
    //draws petals
    for(int i = 0; i < petals; i++){
        //keeps spacing consistent depandng on number of petals
        double value = i * inc;
        //draws petals with calculated spacing relative to number of petals
        g.fillOval((int)((lenWid)*Math.cos(value)+x-lenWid/4),(int)((lenWid)*Math.sin(value)+y-lenWid/4), lenWid + lenWid/2, lenWid + lenWid/2);
    }
    //draws middle flower bud;
    g.setColor(Color.ORANGE);
    g.fillOval(x - lenWid/4, y - lenWid/4, lenWid + lenWid/2 , lenWid + lenWid/2);
}

public void drawGrass(Graphics g, int width, int height, int interval, int red, int green, int blue)
{
    height = frameHeight - height;
    Color grass = new Color(red, green, blue);

    for(int i = 0; i < width; i= i + interval)
    {
        for(int j = frameHeight; j > height; j = j - interval)
        {
            g.setColor(grass);
            g.fillRect(i, j, 3, 5);
        }
    }
}

public void rainDrops(Graphics g, int x, int y, int w, int h)
{
    setRain(x, y);
    Color rain = new Color(0, 76, 153);
    g.setColor(rain);
    g.fillRect(x, y, w, h);
}

public void moveRainBy(int dx, int dy)
{
    rainX = rainX + dx;
    rainY = rainY + dy;
    repaint();
}

class TimerListener implements ActionListener
{
    public void actionPerformed(ActionEvent event)
    {
    moveRainBy(1, 1);
    }
}
public void paint(Graphics g) {

   setSkyGround(g);

   drawGrass(g, 1440, 315, 5, 0, 255, 0);
   drawGrass(g, 1430, 310, 10, 0, 204, 0);

   drawTree(g, 1085, 730, -90, 10, 255, 102, 102);
   drawTree(g, 250, 600, -90, 8, 255, 255, 255);
   drawTree(g, 1110, 740, -90, 4, 255, 102, 102);
   drawTree(g, 1060, 745, -90, 2, 255, 102, 102);

   realFlowers(g, 700,700, 8, 8);

   rainDrops(g, 200, 200, 30, 30);

}



public static void main(String[] args) {

    new FractalTree().setVisible(true);

}

} }

When I try to repaint the square to move, and the paint function is called the whole screen blinks 当我尝试重新绘制正方形以进行移动,并且绘制功能被称为整个屏幕闪烁时

This is because you've override paint of the a top level container ( JFrame ) which is not double buffered. 这是因为您已覆盖未进行双缓冲的顶级容器( JFrame )的paint

As a general recommendation, you should be basing your core functionality around a JPanel and override it's paintComponent method. 作为一般建议,您应该将核心功能基于JPanel并覆盖它的paintComponent方法。 Take a look at Performing Custom Painting and Painting in AWT and Swing for more details 看一下在AWT和Swing执行自定义绘画绘画以获取更多详细信息

You might like to also have a look at How to get the EXACT middle of a screen, even when re-sized and How can I set in the midst? 您可能还想看看如何获得屏幕的精确位置,即使在调整大小后又如何在屏幕中间进行 设置? for more details why it's not recommended to extend directly from JFrame and try to paint to it. 有关更多详细信息,为什么不建议直接从JFrame扩展并尝试对其进行绘制。

Is there a way to keep everything I have drawn from being repainted and just call repaint on the rain? 有没有办法让我绘制的所有内容都不会被重新粉刷,只是在下雨时才叫重新粉刷?

Painting is destructive, that is, each time paint/paintComponent is called, you are expected to repaint the entire state of the component from scratch. 绘画是破坏性的,也就是说,每次调用paint/paintComponent ,都应从头开始重新paint/paintComponent组件的整个状态。

You could use a buffering technique, using something like BufferedImage to paint your state to and simply have the paint methods draw the image, but that would depend on how complex a solution you want. 您可以使用缓冲技术,使用诸如BufferedImage来绘制状态,并简单地使用paint方法绘制图像,但这取决于您想要的解决方案的复杂程度。 If you were to use buffering technique, I would consider which elements are "static" and which elements are "dynamic". 如果要使用缓冲技术,我将考虑哪些元素是“静态”的,哪些元素是“动态”的。 Painting those static elements to the buffer and then, when paint is called, painting the dynamic elements over the top the buffer 将这些静态元素绘制到缓冲区,然后在调用绘制时在缓冲区顶部绘制动态元素

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM