javaawtchessaffinetransform

Java.awt Affine Transform doesn't seem to update image location


I am trying to make a chess game in java, by having a class of pieces and a subclass for each piece. However, When I try to draw the pieces, The position doesn't seem to register.

Here is my Piece class:


import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.net.URL;

public class Piece {
    public int Id;
    public int color;
    public int state;
    public Image Sprite;
    public AffineTransform tx;
    public boolean dragged;
    public int x;
    public int y;

    public Piece(int Id, int color, int position){
        dragged = false;
        this.Id = Id;
        this.color = color;

        int x = 100*(position % 8);
        int y = 100*(position / 8);

        System.out.println(x);

        tx = AffineTransform.getTranslateInstance(x, y);
        init(x, y);
    }


    private void init  (double a, double b) {
        tx.setToTranslation(a, b);
        tx.scale(0.1, 0.1);
    }

    private void update(){
        tx.setToTranslation(x*1000, y*1000);
        tx.scale(0.1, 0.1);
    }

    protected Image getImage(String path) {

        Image tempImage = null;
        try {
            URL imageURL = Piece.class.getResource(path);
            tempImage    = Toolkit.getDefaultToolkit().getImage(imageURL);
        } catch (Exception e) {e.printStackTrace();}
        return tempImage;
    }

    public void paint(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        update();
        g2.drawImage(Sprite, tx, null);
    }
}

my pawn class:

public class Pawn extends Piece {

    public Pawn(int Id, int color, int position) {
        super(Id, color, position);
        this.state = 0;
        String path = "/imgs/Pieces/";
        if(color == 0){
            path += "W";
        } else{
            path += "B";
        }
        path += "_Pawn.png";
        Sprite = getImage(path);
    }

    
    
}

my Board class:

    
    Piece[][] board;

    public Board(){
        board = new Piece[8][8];
        for(int i = 0; i < 8; i++){
            board[1][i] = new Pawn(i, 1, 8+i);
        }

        for(int i = 0; i < 8; i++){
            board[6][i] = new Pawn(i, 0, 8+i);
        }
    }

    

}

and my main class:

import java.io.IOException;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Main extends JPanel implements ActionListener, MouseListener, KeyListener{

    Color GREEN = new Color( 41, 176,  59);
    Color WHITE = new Color(254, 255, 228);

    Board board = new Board();

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

    public void paint(Graphics g){
        super.paintComponent(g);
        boolean flag = true;
        for(int i = 0; i < 8; i++){

            
            for(int j = 0; j < 8; j++){
                if(flag){
                    g.setColor(WHITE);
                } else{
                    g.setColor(GREEN);
                }
                g.fillRect((j*100), (i*100), ((j+1)*100), ((i+1)*100));
                flag = !flag;
            }
            flag = !flag;
        }
        for(int i = 0; i < 8; i++){
            for(int j = 0; j < 8; j++){
                if(board.board[i][j] != null){
                    board.board[i][j].paint(g);
                }
            }
        }
    }
public Main() {
        JFrame f = new JFrame("Chess");
        f.setSize(new Dimension(800, 800));
        f.setBackground(Color.blue);
        f.add(this);
        f.setResizable(false);
        f.setLayout(new GridLayout(1,2));
        f.addMouseListener(this);
        f.addKeyListener(this);
        Timer t = new Timer(16, this);
        t.start();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }
}

I had previously written a game that implemented this techqnique, so I'm not sure what could have gone wrong with this one


Solution

  • It's really important to read the documentation, especially for something that is (to my simple brain), complicated.

    If you have a read of the documentation for AffineTransform#scale

    Concatenates this transform with a scaling transformation

    (emphis added by me)

    This is important, as it seems to apply that each time you call it, it will apply ANOTHER scaling operation.

    Based on your avaliable code, this means that when the Piece is created, a scale is applied and the each time it's painted, a new scale is applied, until you're basically scaled out of existence.

    Sooo. I took out your init (applied the scale within the constructor directly instead) and update methods and was able to get a basic result

    Scaling from 1.0, 0.75, 0.5, 0.25and0.1` (it's there but I had to reduce the size of the output)

    Example

    Runnable example...

    import java.awt.BasicStroke;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Font;
    import java.awt.FontMetrics;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Image;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.awt.geom.AffineTransform;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    
    public class Test {
    
        public static void main(String[] args) {
            new Test();
        }
    
        public Test() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        JFrame frame = new JFrame();
                        frame.add(new Main());
                        frame.pack();
                        frame.setLocationRelativeTo(null);
                        frame.setVisible(true);
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            });
        }
    
        public class Main extends JPanel implements ActionListener, MouseListener, KeyListener {
    
            Color GREEN = new Color(41, 176, 59);
            Color WHITE = new Color(254, 255, 228);
    
            Board board;
    
            public Main() throws IOException {
                board = new Board();
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(800, 800);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                super.paintComponent(g);
                boolean flag = true;
                for (int i = 0; i < 8; i++) {
    
                    for (int j = 0; j < 8; j++) {
                        if (flag) {
                            g.setColor(WHITE);
                        } else {
                            g.setColor(GREEN);
                        }
                        g.fillRect((j * 100), (i * 100), ((j + 1) * 100), ((i + 1) * 100));
                        flag = !flag;
                    }
                    flag = !flag;
                }
                for (int i = 0; i < 8; i++) {
                    for (int j = 0; j < 8; j++) {
                        if (board.board[i][j] != null) {
                            board.board[i][j].paint(g);
                        }
                    }
                }
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
            }
    
            @Override
            public void mouseClicked(MouseEvent e) {
            }
    
            @Override
            public void mousePressed(MouseEvent e) {
            }
    
            @Override
            public void mouseReleased(MouseEvent e) {
            }
    
            @Override
            public void mouseEntered(MouseEvent e) {
            }
    
            @Override
            public void mouseExited(MouseEvent e) {
            }
    
            @Override
            public void keyTyped(KeyEvent e) {
            }
    
            @Override
            public void keyPressed(KeyEvent e) {
            }
    
            @Override
            public void keyReleased(KeyEvent e) {
            }
        }
    
        public class Board {
    
            Piece[][] board;
    
            public Board() throws IOException {
                board = new Piece[8][8];
                for (int i = 0; i < 8; i++) {
                    board[1][i] = new Pawn(i, 1, 8 + i);
                }
    
                for (int i = 0; i < 8; i++) {
                    board[6][i] = new Pawn(i, 0, 16 + i);
                }
            }
    
        }
    
        public class Pawn extends Piece {
    
            public Pawn(int Id, int color, int position) throws IOException {
                super(Id, color, position);
                this.state = 0;
                String path = "/imgs/Pieces/";
                if (color == 0) {
                    path += "W";
                } else {
                    path += "B";
                }
                path += "_Pawn.png";
                Sprite = getImage(path);
            }
        }
    
        public class Piece {
    
            public int Id;
            public int color;
            public int state;
            public Image Sprite;
            public AffineTransform tx;
            public boolean dragged;
            public int x;
            public int y;
    
            public Piece(int Id, int color, int position) {
                dragged = false;
                this.Id = Id;
                this.color = color;
    
                x = 100 * (position % 8);
                y = 100 * (position / 8);
    
                System.out.println(x + "x" + y);
    
                tx = AffineTransform.getTranslateInstance(x, y);
                tx.scale(0.1, 0.1);
            }
    
            protected Image getImage(String path) throws IOException {
                BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
                Graphics2D g2d = img.createGraphics();
                g2d.setFont(new JLabel().getFont().deriveFont(Font.PLAIN, 16));
                g2d.setColor(Color.BLACK);
                FontMetrics fm = g2d.getFontMetrics();
    
                int cellX = x;
                int cellY = y;
    
                String text = x + "x" + y;
    
                int x = (100 - fm.stringWidth(text)) / 2;
                int y = ((100 - fm.getHeight()) / 2) + fm.getAscent();
    
                g2d.drawString(text, x, y);
    
                g2d.setStroke(new BasicStroke(16));
                g2d.drawRect(0, 0, 99, 99);
    
                g2d.dispose();
    
                return img;
            }
    
            public void paint(Graphics g) {
                Graphics2D g2 = (Graphics2D) g;
                g2.drawImage(Sprite, tx, null);
            }
        }
    }