JPanel 中的多个动画(线程)
Multiple animations(threads) in a JPanel
我正尝试在 Java 中编写棋盘游戏代码。
我有 11 个 classes,包括 Main。 Board class 扩展 JPanel 并绘制棋盘图像和骰子图像。 class Player 扩展 JCoponent 并实现 Runnable(Thread)。每个玩家实例都是一个棋子动画,它正在棋盘上移动。玩家 class 在棋盘上画兵。
模式
代码的样子:
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.
问题是我不能同时在棋盘上放置一个以上的棋子。我已经尝试在另一个 class 中重新绘制所有玩家(作为非动画),但没有成功。我也试过 JLayeredPane 但也许我做错了什么。很遗憾,我无法更改上述模式,所以请不要提出此建议。
预先感谢您的帮助。
P.S:我不能post任何代码,因为它太大了。
P.P.S: 如果你问我,会给出更多的说明。
编辑:我修改我的问题。是否可以在同一个面板上同时播放两个动画?如果答案是肯定的..我该怎么做?
也许您的问题是尝试开发一个程序,每个对象都有一个线程,最流行的游戏 运行 有一个线程,最多两个。原因:线程之间同步会很复杂,更何况你的性能会很差。即使 Java 中的图形引擎也是单线程的,这意味着您不会同时有两个线程绘图。
很可能同时移动许多组件。使用 javax.swing.Timer 或 SwingWorker 使其工作。
这是一个向您展示这一点的简单示例。它将 16 个棋子放在棋盘上,并将它们从一个地方随机移动到另一个地方。
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();
}
});
}
}
我正尝试在 Java 中编写棋盘游戏代码。
我有 11 个 classes,包括 Main。 Board class 扩展 JPanel 并绘制棋盘图像和骰子图像。 class Player 扩展 JCoponent 并实现 Runnable(Thread)。每个玩家实例都是一个棋子动画,它正在棋盘上移动。玩家 class 在棋盘上画兵。
模式
代码的样子:
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.
问题是我不能同时在棋盘上放置一个以上的棋子。我已经尝试在另一个 class 中重新绘制所有玩家(作为非动画),但没有成功。我也试过 JLayeredPane 但也许我做错了什么。很遗憾,我无法更改上述模式,所以请不要提出此建议。
预先感谢您的帮助。
P.S:我不能post任何代码,因为它太大了。
P.P.S: 如果你问我,会给出更多的说明。
编辑:我修改我的问题。是否可以在同一个面板上同时播放两个动画?如果答案是肯定的..我该怎么做?
也许您的问题是尝试开发一个程序,每个对象都有一个线程,最流行的游戏 运行 有一个线程,最多两个。原因:线程之间同步会很复杂,更何况你的性能会很差。即使 Java 中的图形引擎也是单线程的,这意味着您不会同时有两个线程绘图。
很可能同时移动许多组件。使用 javax.swing.Timer 或 SwingWorker 使其工作。
这是一个向您展示这一点的简单示例。它将 16 个棋子放在棋盘上,并将它们从一个地方随机移动到另一个地方。
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();
}
});
}
}