JPanel中的多个动画(线程)

时间:2021-10-27 11:31:12

I am trying to code a board game in Java.

我正在尝试用Java编写一个棋盘游戏。

I have 11 classes including Main. Board class which extends JPanel and draws the board image as well as the dice image. The class Player which extends JCoponent and implements Runnable(Thread). Every player instance is a pawn-animation that it is moving across the board. The player class draws the pawn on the board.

我有11节课,包括Main。扩展JPanel的Board类,它绘制棋盘图像和骰子图像。扩展JCoponent和实现Runnable(线程)的类播放器。每个玩家实例都是一个在棋盘上移动的典当动画。牌手职业在棋盘上画卒。

Pattern
How the code it looks like :

模式代码是什么样子的:

Board b=new Board(); 
Player p=new Player();
b.add(p);
JPanel panel=new JPanel();
panel.add(b);
add(panel); //adding the panel to the frame.

The problem is that I can't have more than one pawn simultaneously on the board. I have already tried to re-paint all the players (as non-animation) in another class but it didn't work. I also tried JLayeredPane but maybe I am doing something wrong. Unfortunately, I can't change the above pattern so don't make this suggestion.

问题是我不能同时在棋盘上有一个以上的卒。我已经试过重新绘制其他类中的所有玩家(非动画),但是没有效果。我也尝试了JLayeredPane,但是也许我做错了什么。不幸的是,我不能改变上面的模式,所以不要提出这个建议。

Thank you in advance for your help.

事先谢谢你的帮助。

P.S: I can't post any code because its huge.
P.P.S: more clarifications will be given, if you ask me.

P。S:我不能发任何代码,因为它太大了。最大功率如果你问我,我们会给你更多的解释。

EDIT: I reform my question. Is it possible to have two animations simultaneously on the same panel? if the answer is a yes ..how I can do that?

编辑:我修改我的问题。是否可以同时在同一个面板上有两个动画?如果答案是肯定的。我怎么做呢?

2 个解决方案

#1


2  

It's most likely possible to have many components moving all at once. Either use javax.swing.Timer ou SwingWorker for this to work.

很有可能有很多组件同时移动。要么使用javax.swing。这个工作的计时员。

Here is a quick example showing you this. It puts 16 pawns on a board and moves them randomly from one place to another.

下面是一个简单的例子。它把16根棋子放在棋盘上,随机地从一个地方移动到另一个地方。

JPanel中的多个动画(线程)

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestAnimation {

    private static final String PAWN_URL = "http://files.chesskidfiles.com/images_users/tiny_mce/BoundingOwl/bishop_happywhite.png";

    private Image pawn;

    private Map<Location, Pawn> pawnLocations = new HashMap<>();

    private Board board;

    private Timer timer;

    private JLayeredPane glassPane;

    public TestAnimation() {
        try {
            pawn = new ImageIcon(new URL(PAWN_URL)).getImage();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }

    private static class Location {
        public final int row;
        public final int col;

        public Location(int row, int col) {
            super();
            this.row = row;
            this.col = col;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + col;
            result = prime * result + row;
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            Location other = (Location) obj;
            return (col == other.col && row == other.row);
        }
    }

    private static class Cell extends JPanel {

        private final Location location;

        public Cell(Location location) {
            super(new BorderLayout());
            this.location = location;
            setOpaque(true);
            setBackground(((location.row + location.col) % 2) == 0 ? Color.WHITE : Color.BLACK);
        }

        @Override
        protected void addImpl(Component comp, Object constraints, int index) {
            while (getComponentCount() > 0) {
                remove(0);
            }
            super.addImpl(comp, constraints, index);
        }
    }

    private static class Board extends JPanel {

        private Map<Location, Cell> cells = new HashMap<>();

        public Board() {
            super(new GridLayout(8, 8));
            for (int i = 0; i < 8; i++) {
                for (int j = 0; j < 8; j++) {
                    Cell cell = new Cell(new Location(i, j));
                    add(cell);
                    cells.put(new Location(i, j), cell);
                }
            }
        }

        public void add(Pawn pawn, Location location) {
            cells.get(location).add(pawn);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }

        public Cell getCell(Location location) {
            return cells.get(location);
        }
    }

    private class Pawn extends JComponent {
        public Pawn() {
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(pawn, 0, 0, getWidth(), getHeight(), this);
        }
    }

    protected void initUI() {
        JFrame frame = new JFrame(TestAnimation.class.getSimpleName());
        board = new Board();
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 2; j++) {
                Location location = new Location(i, j);
                Pawn aPawn = new Pawn();
                board.add(aPawn, location);
                pawnLocations.put(location, aPawn);
            }
        }
        for (int i = 0; i < 8; i++) {
            for (int j = 6; j < 8; j++) {
                Location location = new Location(i, j);
                Pawn aPawn = new Pawn();
                board.add(aPawn, location);
                pawnLocations.put(location, aPawn);
            }
        }
        timer = new Timer(7000, new Animation());
        timer.setInitialDelay(0);
        timer.setRepeats(true);
        timer.setCoalesce(false);
        glassPane = new JLayeredPane();
        glassPane.setOpaque(false);
        frame.add(board);
        frame.setGlassPane(glassPane);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
        timer.start();
        glassPane.setVisible(true);
    }

    public class Animation implements ActionListener {

        private Map<Location, Pawn> futureLocations;

        private Random random = new Random();

        private Timer subTimer;

        private List<Pawn> movingPawns;

        private Map<Pawn, Point> originalCoordinates = new HashMap<>();
        private Map<Pawn, Point> futureCoordinates = new HashMap<>();

        @Override
        public void actionPerformed(ActionEvent e) {
            futureLocations = new HashMap<>();
            movingPawns = new ArrayList<>();
            for (Pawn p : pawnLocations.values()) {
                int row = random.nextInt(8);
                int col = random.nextInt(8);
                Location location;
                while (futureLocations.containsKey((location = new Location(row, col)))) {
                    row = random.nextInt(8);
                    col = random.nextInt(8);
                }
                futureLocations.put(location, p);
                Cell futureCell = board.getCell(location);
                futureCoordinates.put(p, SwingUtilities.convertPoint(futureCell, 0, 0, glassPane));
                movingPawns.add(p);
            }
            for (Pawn p : movingPawns) {
                Point locationInGlassPane = SwingUtilities.convertPoint(p.getParent(), 0, 0, glassPane);
                glassPane.add(p);
                p.setLocation(locationInGlassPane);
                originalCoordinates.put(p, locationInGlassPane);
            }
            subTimer = new Timer(50, new AnimationSteps());
            subTimer.setInitialDelay(0);
            subTimer.setCoalesce(true);
            subTimer.setRepeats(true);
            subTimer.start();
        }

        public class AnimationSteps implements ActionListener {

            private int step = 0;

            @Override
            public void actionPerformed(ActionEvent e1) {
                if (step < 50 + 1) {
                    for (Pawn p : movingPawns) {
                        Point p1 = originalCoordinates.get(p);
                        Point p2 = futureCoordinates.get(p);
                        int x = (int) (p1.x + ((p2.x - p1.x) * (double) step / 50));
                        int y = (int) (p1.y + ((p2.y - p1.y) * (double) step / 50));
                        p.setLocation(x, y);
                    }
                } else {
                    for (Entry<Location, Pawn> e : futureLocations.entrySet()) {
                        board.add(e.getValue(), e.getKey());
                    }
                    board.revalidate();
                    subTimer.stop();
                    pawnLocations = futureLocations;
                }
                step++;

            }

        }
    }

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
            UnsupportedLookAndFeelException {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestAnimation().initUI();
            }
        });
    }
}

#2


0  

Maybe your problem is trying to develop a program with a thread for each object, most popular games run with a single thread, two at most. The reason: It will be very complex to synchronize threads with each other, not to mention that your performance will be poor. Even the graphics engine in Java is single threaded and that means you won't have two threads drawing at the same time.

也许你的问题是要开发一个程序,每个对象都有一个线程,最流行的游戏用一个线程运行,最多两个线程。原因是:线程之间的同步非常复杂,更不用说性能会很差。甚至Java中的图形引擎也是单线程的,这意味着您不会同时绘制两个线程。

#1


2  

It's most likely possible to have many components moving all at once. Either use javax.swing.Timer ou SwingWorker for this to work.

很有可能有很多组件同时移动。要么使用javax.swing。这个工作的计时员。

Here is a quick example showing you this. It puts 16 pawns on a board and moves them randomly from one place to another.

下面是一个简单的例子。它把16根棋子放在棋盘上,随机地从一个地方移动到另一个地方。

JPanel中的多个动画(线程)

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestAnimation {

    private static final String PAWN_URL = "http://files.chesskidfiles.com/images_users/tiny_mce/BoundingOwl/bishop_happywhite.png";

    private Image pawn;

    private Map<Location, Pawn> pawnLocations = new HashMap<>();

    private Board board;

    private Timer timer;

    private JLayeredPane glassPane;

    public TestAnimation() {
        try {
            pawn = new ImageIcon(new URL(PAWN_URL)).getImage();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }

    private static class Location {
        public final int row;
        public final int col;

        public Location(int row, int col) {
            super();
            this.row = row;
            this.col = col;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + col;
            result = prime * result + row;
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            Location other = (Location) obj;
            return (col == other.col && row == other.row);
        }
    }

    private static class Cell extends JPanel {

        private final Location location;

        public Cell(Location location) {
            super(new BorderLayout());
            this.location = location;
            setOpaque(true);
            setBackground(((location.row + location.col) % 2) == 0 ? Color.WHITE : Color.BLACK);
        }

        @Override
        protected void addImpl(Component comp, Object constraints, int index) {
            while (getComponentCount() > 0) {
                remove(0);
            }
            super.addImpl(comp, constraints, index);
        }
    }

    private static class Board extends JPanel {

        private Map<Location, Cell> cells = new HashMap<>();

        public Board() {
            super(new GridLayout(8, 8));
            for (int i = 0; i < 8; i++) {
                for (int j = 0; j < 8; j++) {
                    Cell cell = new Cell(new Location(i, j));
                    add(cell);
                    cells.put(new Location(i, j), cell);
                }
            }
        }

        public void add(Pawn pawn, Location location) {
            cells.get(location).add(pawn);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }

        public Cell getCell(Location location) {
            return cells.get(location);
        }
    }

    private class Pawn extends JComponent {
        public Pawn() {
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(pawn, 0, 0, getWidth(), getHeight(), this);
        }
    }

    protected void initUI() {
        JFrame frame = new JFrame(TestAnimation.class.getSimpleName());
        board = new Board();
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 2; j++) {
                Location location = new Location(i, j);
                Pawn aPawn = new Pawn();
                board.add(aPawn, location);
                pawnLocations.put(location, aPawn);
            }
        }
        for (int i = 0; i < 8; i++) {
            for (int j = 6; j < 8; j++) {
                Location location = new Location(i, j);
                Pawn aPawn = new Pawn();
                board.add(aPawn, location);
                pawnLocations.put(location, aPawn);
            }
        }
        timer = new Timer(7000, new Animation());
        timer.setInitialDelay(0);
        timer.setRepeats(true);
        timer.setCoalesce(false);
        glassPane = new JLayeredPane();
        glassPane.setOpaque(false);
        frame.add(board);
        frame.setGlassPane(glassPane);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
        timer.start();
        glassPane.setVisible(true);
    }

    public class Animation implements ActionListener {

        private Map<Location, Pawn> futureLocations;

        private Random random = new Random();

        private Timer subTimer;

        private List<Pawn> movingPawns;

        private Map<Pawn, Point> originalCoordinates = new HashMap<>();
        private Map<Pawn, Point> futureCoordinates = new HashMap<>();

        @Override
        public void actionPerformed(ActionEvent e) {
            futureLocations = new HashMap<>();
            movingPawns = new ArrayList<>();
            for (Pawn p : pawnLocations.values()) {
                int row = random.nextInt(8);
                int col = random.nextInt(8);
                Location location;
                while (futureLocations.containsKey((location = new Location(row, col)))) {
                    row = random.nextInt(8);
                    col = random.nextInt(8);
                }
                futureLocations.put(location, p);
                Cell futureCell = board.getCell(location);
                futureCoordinates.put(p, SwingUtilities.convertPoint(futureCell, 0, 0, glassPane));
                movingPawns.add(p);
            }
            for (Pawn p : movingPawns) {
                Point locationInGlassPane = SwingUtilities.convertPoint(p.getParent(), 0, 0, glassPane);
                glassPane.add(p);
                p.setLocation(locationInGlassPane);
                originalCoordinates.put(p, locationInGlassPane);
            }
            subTimer = new Timer(50, new AnimationSteps());
            subTimer.setInitialDelay(0);
            subTimer.setCoalesce(true);
            subTimer.setRepeats(true);
            subTimer.start();
        }

        public class AnimationSteps implements ActionListener {

            private int step = 0;

            @Override
            public void actionPerformed(ActionEvent e1) {
                if (step < 50 + 1) {
                    for (Pawn p : movingPawns) {
                        Point p1 = originalCoordinates.get(p);
                        Point p2 = futureCoordinates.get(p);
                        int x = (int) (p1.x + ((p2.x - p1.x) * (double) step / 50));
                        int y = (int) (p1.y + ((p2.y - p1.y) * (double) step / 50));
                        p.setLocation(x, y);
                    }
                } else {
                    for (Entry<Location, Pawn> e : futureLocations.entrySet()) {
                        board.add(e.getValue(), e.getKey());
                    }
                    board.revalidate();
                    subTimer.stop();
                    pawnLocations = futureLocations;
                }
                step++;

            }

        }
    }

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
            UnsupportedLookAndFeelException {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestAnimation().initUI();
            }
        });
    }
}

#2


0  

Maybe your problem is trying to develop a program with a thread for each object, most popular games run with a single thread, two at most. The reason: It will be very complex to synchronize threads with each other, not to mention that your performance will be poor. Even the graphics engine in Java is single threaded and that means you won't have two threads drawing at the same time.

也许你的问题是要开发一个程序,每个对象都有一个线程,最流行的游戏用一个线程运行,最多两个线程。原因是:线程之间的同步非常复杂,更不用说性能会很差。甚至Java中的图形引擎也是单线程的,这意味着您不会同时绘制两个线程。