Search code examples
javaswingjava-2dpaintcomponent

Graphics2D animation, cant understand why paintComponent only draws the shape one time and then stops


Graphics2D animation, cant understand why paintComponent only draws the shape one time and then stops. I Also can't understand why my timer counter variable isn't incrementing. I've been banging my head against this for over an hour, can anyone nudge me in the right direction?

Tetri

package Tetris;
import javax.swing.JLabel;
import java.util.ArrayList;
public class Tetri {

private int xCoords= (int)(Math.random()*10);
private int yCoords=0;
private int shapeType;
private int orientation=0;

public Tetri(int shapeT){
    shapeType = shapeT;

}
public int getOrient(){
    return orientation;
}
public void setOrient(int orient){
    orientation = orient;
}
public void setXCoords(int coords){
    xCoords = coords;

}
public int getXCoords(){

    return xCoords;
}
public void setYCoords(int coords){
    yCoords = coords;
}
public int getYCoords(){

    return yCoords;
}

public int getShape(){

    return shapeType;
}



}

MovingRectangle

package Tetris;
import javax.swing.JFrame;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JPanel;
import java.awt.Color;
import javax.swing.Timer;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.ArrayList;
public class MovingRectangle {

public static void main(String[] args){
    new MovingRectangle();
}

public MovingRectangle() {
    EventQueue.invokeLater(new Runnable(){
        @Override
        public void run(){
            JFrame frame = new JFrame("Tetris");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new GridLayout(0,1));
            frame.add(new TestPane(Color.RED));
            frame.setSize(1000,800);
            frame.setVisible(true);

        }

    });
}

TestPane

public class TestPane extends JPanel {

    private Graphics g0;
    private int unit = 50;
    private ArrayList<Tetri> shapeList = new ArrayList<Tetri>();
    int timercount =1;

    public TestPane(Color foreground){
        setForeground(foreground);
        this.setBackground(Color.BLUE);
        Timer timer = new Timer(2000,new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e){
            System.out.println("timercount :"+timercount);
            timercount = timercount++;
            shapeList.add(new Tetri((int)(Math.random()*2)));
            System.out.println("shapeList size : "+shapeList.size());
            repaint();
            }
        });
        timer.start();

    }
    @Override
    public void paintComponent(Graphics g){
        g0 = g;
        super.paintComponent(g);
        if(shapeList.size()>0){

        Tetri current = shapeList.get(0);

            if(current.getShape()==0){
                                                             createShape0(current.getXCoords(),current.getYCoords(),current.getOrient());
            }
            if(current.getShape()==1){
                createShape1(current.getXCoords(),current.getYCoords(),current.getOrient());
            }
            current.setYCoords(current.getYCoords()+50);
        }
        else{shapeList.add(new Tetri((int)(Math.random()*2)));}


    }
    public void createShape0(int xc,int yc,int orien){
        int yPixel= yc*50;
        int xPixel= xc*50;

        Graphics2D g2d = (Graphics2D) g0.create();
        g2d.setColor(Color.RED);
        if(orien==0){
            g2d.drawRect(xPixel, yPixel, unit*4, unit);
        }
        if(orien==1){
            g2d.drawRect(xPixel, yPixel, unit, unit*4);
        }



    }
    public void createShape1(int xc,int yc, int orien){
        int yPixel= yc*50;
        int xPixel= xc*50;

        Graphics2D g2d = (Graphics2D) g0.create();
        g2d.setColor(Color.GREEN);
        if(orien==0){
        g2d.drawRect(xPixel, yPixel, unit*3, unit);
        g2d.drawRect(xPixel+50, yPixel+50,unit,unit);
        }
        if(orien==1){
        g2d.drawRect(xPixel+50, yPixel-50, unit, unit*3);
        g2d.drawRect(xPixel, yPixel,unit,unit);
        }
        if(orien==2){
            g2d.drawRect(xPixel, yPixel, unit*3, unit);
            g2d.drawRect(xPixel+50, yPixel-50,unit,unit);
        }
        if(orien==3){
            g2d.drawRect(xPixel+50, yPixel-50, unit, unit*3);
            g2d.drawRect(xPixel+100, yPixel,unit,unit);
        }
    }

}
}

Solution

  • I have a list of things, but lets start with the most obvious.

    You "movement" calculations are way off.

    int yPixel = yc * 50;
    int xPixel = xc * 50;
    

    This is causing your shape to "jump" expectational larger distances...in fact, I can't find any reason for you to "modify" these values at all. Simply making them read as...

    int yPixel = yc;
    int xPixel = xc;
    

    Got the shape moving just fine...

    Code Review

    • Don't maintain any references to any graphics context you didn't create. These references can be shared amongst the other UI components and there is no guarantee that the reference is in one paint cycle, will be the same on the next. If you want to paint to a graphics context, pass it as parameter to the method that needs to do the painting.
    • If you create a graphics context (Graphics2D g2d = (Graphics2D) g.create();) then you are responsible for disposing of it (g2d.dispose()) when you are done with it. Otherwise you will slowly consume system resources until your application crashes (talking from experience - it's a hard bug to find ;))

    You seem to be going about the process the hard way. You should create a class for each Shape, based off the Tetri that knows how to "draw" itself. That way you would simple pass the graphics context to it in your paint loop and not care. This makes is significantly easier to add new pieces over time.

    If you base each of these pieces off a java.awt.Shape, it becomes significantly easier to transform the shape and rotate them.

    Take a look at 2D Graphics, in particular, Working with Geometry