Java Component.setBounds调用Component.repaint?
所以我在做一个游戏,我有Java Component.setBounds调用Component.repaint?,java,multithreading,swing,Java,Multithreading,Swing,所以我在做一个游戏,我有EnemyAI和player,它们都扩展了JPanel。世界有一个null布局,所以我使用setBounds()将实体(player和AI)移动(实际上我只是移动世界图像)并正确定位。但是,当我添加(看起来,我测试的是尽可能小的数字)5时,它完全自己调用repaint()。这会使玩家在视觉上原地行走。我添加的实体越多,间隔越快(即5个实体调用repaint()的速度比500慢得多) 注意:window在下面的类中只是一个JFrame 主要类别: public class
EnemyAI
和player
,它们都扩展了JPanel
。世界有一个null
布局,所以我使用setBounds()
将实体(player
和AI
)移动(实际上我只是移动世界图像)并正确定位。但是,当我添加(看起来,我测试的是尽可能小的数字)5时,它完全自己调用repaint()
。这会使玩家在视觉上原地行走。我添加的实体越多,间隔越快(即5个实体调用repaint()
的速度比500慢得多)
注意:window
在下面的类中只是一个JFrame
主要类别:
public class Game(){
public static boolean fighting = false;
public static void startGame(){
WorldPanel game = new WorldPanel();
game.setPreferredSize(new Dimension(window.getWidth(), window.getHeight()));
PlayerPane player = new PlayerPane(32,32, "Player 1");
game.addKeyListener(new KeyListener(){
public void keyPressed(KeyEvent arg0) {
if(fighting == false){
move(player, game, arg0.isShiftDown(), arg0.getKeyCode());
} else {
System.out.println("Fighting = " + fighting);
}
}
@Override
public void keyReleased(KeyEvent arg0) {
gameTimer.stop();
player.setIndex(0);
game.repaint();
}
@Override
public void keyTyped(KeyEvent arg0) {
}
});
window.add(game);
game.setLayout(null);
game.requestFocus();
setImages(player, PLAYER_DOWN);
player.setDrawY(349);
player.setDrawX(493);
player.updateBounds();
game.add(player);
entities.add(player);
addEntities(game);
redoWindow();
}
public static void updateEntityBounds(){
PlayerPane player = null;
EnemyAI enemy = null;
for(int i = 0; i < entities.size(); i++){
if(i == 0){
player = (PlayerPane) entities.get(i);
} else {
enemy = (EnemyAI) entities.get(i);
if(enemy.getBounds().intersects(player.getBounds())){
startFight(i);
}
}
if(player != null){
player.updateBounds();
}
if(enemy != null){
enemy.updateBounds();
}
}
}
public static void addEntities(WorldPanel game){
EnemyAI enemies[] = new EnemyAI[5];
for(int i = 0; i < enemies.length; i++){
if(i%6 == 0){
try{
enemies[i] = new EnemyAI(32,32, ImageIO.read(new File("H:\\Java\\Game\\src\\res\\SlimeLv3Still.png")));
enemies[i].start();
}catch(IOException e){
e.printStackTrace();
}
}else if (i % 2 == 0){
try{
enemies[i] = new EnemyAI(32,32, ImageIO.read(new File("H:\\Java\\Game\\src\\res\\SlimeLv2Still.png")));
enemies[i].setEnX(enemies[i].getRandomX());
enemies[i].setEnY(enemies[i].getRandomY());
enemies[i].start();
}catch(IOException e){
e.printStackTrace();
}
} else {
try{
enemies[i] = new EnemyAI(32,32, ImageIO.read(new File("H:\\Java\\Game\\src\\res\\SlimeLv1Still.png")));
enemies[i].setEnX(enemies[i].getRandomX());
enemies[i].setEnY(enemies[i].getRandomY());
enemies[i].start();
}catch(IOException e){
e.printStackTrace();
}
}
game.add(enemies[i]);
entities.add(enemies[i]);
}
}
public static void move(PlayerPane player, WorldPanel game, boolean shiftDown, int keyPressed){
gameTimer = new Timer(50, new ActionListener(){
public void actionPerformed(ActionEvent e){
updateEntityBounds();
redoWindow();
gameTimer.stop();
}
});
if(gameTimer.isRepeats()){
gameTimer.setRepeats(false);
}
if(shiftDown){
if(keyPressed == KeyEvent.VK_W && ((game.getImageY() == 0 && player.getDrawY() > 10) || player.getDrawY() >= 349)){
player.setDrawY(player.getDrawY() - 2);
setImages(player, PLAYER_UP);
gameTimer.start();
} else
if(keyPressed == KeyEvent.VK_S && ((game.getImageY() == -3868 && player.getDrawY() < 681) || player.getDrawY() <= 349)){
player.setDrawY(player.getDrawY() + 2);
setImages(player, PLAYER_DOWN);
gameTimer.start();
} else
if(keyPressed == KeyEvent.VK_A && ((game.getImageX() == 0 && player.getDrawX() > 10) || player.getDrawX() > 493 )){
player.setDrawX(player.getDrawX() - 2);
setImages(player, PLAYER_LEFT);
gameTimer.start();
} else
if(keyPressed == KeyEvent.VK_D && ((game.getImageX() == -5126 && player.getDrawX() < player.getHeight() - 10) || player.getDrawX() < 493 )){
player.setDrawX(player.getDrawX() + 2);
setImages(player, PLAYER_RIGHT);
gameTimer.start();
} else
if(keyPressed == KeyEvent.VK_W && game.getImageY() < 0){
if(game.getImageY() == -1){
game.setImageY(game.getImageY() + 1);
} else {
game.setImageY(game.getImageY() + 2);
}
for(int i = 1; i < entities.size(); i++){
EnemyAI enemy = (EnemyAI)entities.get(i);
enemy.setEnY(enemy.getEnY() + 2);
}
setImages(player, PLAYER_UP);
gameTimer.start();
} else
if(keyPressed == KeyEvent.VK_A && game.getImageX() < 0){
if(game.getImageX() == -1){
game.setImageX(game.getImageX() + 1);
} else {
game.setImageX(game.getImageX() + 2);
}
for(int i = 1; i < entities.size(); i++){
EnemyAI enemy = (EnemyAI)entities.get(i);
enemy.setEnX(enemy.getEnX() + 2);
}
setImages(player, PLAYER_LEFT);
gameTimer.start();
} else
if(keyPressed == KeyEvent.VK_S && game.getImageY() > -3868){
if(game.getImageY() == -3867){
game.setImageY(game.getImageY() - 1);
} else {
game.setImageY(game.getImageY() - 2);
}
for(int i = 1; i < entities.size(); i++){
EnemyAI enemy = (EnemyAI)entities.get(i);
enemy.setEnY(enemy.getEnY() - 2);
}
setImages(player, PLAYER_DOWN);
gameTimer.start();
} else
if(keyPressed == KeyEvent.VK_D && game.getImageX() > -5126){
if(game.getImageX() == -5125){
game.setImageX(game.getImageX() - 1);
} else {
game.setImageX(game.getImageX() - 2);
}
for(int i = 1; i < entities.size(); i++){
EnemyAI enemy = (EnemyAI)entities.get(i);
enemy.setEnX(enemy.getEnX() - 2);
}
setImages(player, PLAYER_RIGHT);
gameTimer.start();
}
} else {
if(keyPressed == KeyEvent.VK_W && ((game.getImageY() == 0 && player.getDrawY() > 10) || player.getDrawY() > 349)){
player.setDrawY(player.getDrawY() - 1);
setImages(player, PLAYER_UP);
gameTimer.start();
} else
if(keyPressed == KeyEvent.VK_S && ((game.getImageY() == -3868 && player.getDrawY() < 681) || player.getDrawY() < 349)){
player.setDrawY(player.getDrawY() + 1);
setImages(player, PLAYER_DOWN);
gameTimer.start();
} else
if(keyPressed == KeyEvent.VK_A && ((game.getImageX() == 0 && player.getDrawX() > 10) || player.getDrawX() > 493 )){
player.setDrawX(player.getDrawX() - 1);
setImages(player, PLAYER_LEFT);
gameTimer.start();
} else
if(keyPressed == KeyEvent.VK_D && ((game.getImageX() == -5126 && player.getDrawX() < player.getHeight() - 10) || player.getDrawX() < 493 )){
player.setDrawX(player.getDrawX() + 1);
setImages(player, PLAYER_RIGHT);
gameTimer.start();
} else
if(keyPressed == KeyEvent.VK_W && game.getImageY() < 0){
game.setImageY(game.getImageY() + 1);
setImages(player, PLAYER_UP);
for(int i = 1; i < entities.size(); i++){
EnemyAI enemy = (EnemyAI)entities.get(i);
enemy.setEnY(enemy.getEnY() + 1);
}
gameTimer.start();
} else
if(keyPressed == KeyEvent.VK_A && game.getImageX() < 0){
game.setImageX(game.getImageX() + 1);
setImages(player, PLAYER_LEFT);
for(int i = 1; i < entities.size(); i++){
EnemyAI enemy = (EnemyAI)entities.get(i);
enemy.setEnX(enemy.getEnX() + 1);
}
gameTimer.start();
} else
if(keyPressed == KeyEvent.VK_S && game.getImageY() > -3868){
game.setImageY(game.getImageY() - 1);
setImages(player, PLAYER_DOWN);
for(int i = 1; i < entities.size(); i++){
EnemyAI enemy = (EnemyAI)entities.get(i);
enemy.setEnY(enemy.getEnY() - 1);
}
gameTimer.start();
} else
if(keyPressed == KeyEvent.VK_D && game.getImageX() > -5126){
game.setImageX(game.getImageX() - 1);
setImages(player, PLAYER_RIGHT);
for(int i = 1; i < entities.size(); i++){
EnemyAI enemy = (EnemyAI)entities.get(i);
enemy.setEnX(enemy.getEnX() - 1);
}
gameTimer.start();
}
}
}
}
EnemyAI类:
public class EnemyAI extends AI{
private static final long serialVersionUID = -2417438750134536982L;
private Rectangle rect;
private BufferedImage backgroundImg;
private int HP = 1;
private int damage = 15;
public EnemyAI(int width, int height, BufferedImage backgroundImg){
super();
rect = new Rectangle(width, height);
this.backgroundImg = backgroundImg;
}
@Override
public void paintComponent(Graphics g) {
try{
g.drawImage(ImageIO.read(new File("H:\\Java\\Game\\src\\res\\TransparentImg.png")), 0,0,null);
}catch(IOException e){
e.printStackTrace();
}
g.drawImage(backgroundImg, 0, 0, null);
}
public boolean intersects(Rectangle r){
return rect.intersects(r);
}
public int getRandomX(){
Random ran = new Random();
int rand = ran.nextInt(6144);
return rand;
}
public int getRandomY(){
Random ran = new Random();
int rand = ran.nextInt(4608);
return rand;
}
public int getHP(){
return HP;
}
public void setHP(int hp){
HP = hp;
}
public int getDamage(){
return damage;
}
}
上述类扩展的AI类:
public abstract class AI extends JPanel implements Runnable{
private static final long serialVersionUID = 283692586329054555L;
private boolean running = false;
private Thread moveThread;
private int x = 0, y = 0;
public AI(){
moveThread = new Thread(this);
}
public void start(){
running = true;
moveThread.start();
}
public void stop(){
running = false;
}
public boolean isRunning(){
return running;
}
public void run(){
while(running){
if(Game.fighting == false){
Random direction = new Random();
int dir = direction.nextInt(4);
switch(dir){
case 1:
if(this.getX() < Game.getWindowWidth()){
this.setEnX(this.getX() + 1);
}
break;
case 2:
if(this.getX() > 0){
this.setEnX(this.getX() - 1);
}
break;
case 3:
if(this.getX() < Game.getWindowHeight()){
this.setEnY(this.getY() + 1);
}
break;
case 4:
if(this.getX() < 0){
this.setEnY(this.getY() - 1);
}
break;
}
updateBounds();
try{
Thread.sleep(200);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
public void setEnX(int x){
this.x = x;
}
public void setEnY(int y){
this.y = y;
}
public int getEnX(){
return x;
}
public int getEnY(){
return y;
}
public void updateBounds(){
setBounds(x, y, 32,32);
}
public abstract void paintComponent(Graphics g);
}
公共抽象类AI扩展JPanel实现可运行{
私有静态最终长serialVersionUID=28369205455L;
私有布尔运行=false;
私有线程移动线程;
私有整数x=0,y=0;
公共AI(){
moveThread=新线程(此);
}
公开作废开始(){
运行=真;
moveThread.start();
}
公共停车场(){
运行=错误;
}
公共布尔值正在运行(){
返回运行;
}
公开募捐{
(跑步时){
if(Game.fighting==false){
随机方向=新随机();
int dir=方向nextInt(4);
交换机(dir){
案例1:
if(this.getX()0){
this.setEnX(this.getX()-1);
}
打破
案例3:
if(this.getX()
我知道我刚才向你们扔了很多代码。我试着不这样做,但回头看,我试图提供一个运行的示例。如果我遗漏了任何代码,告诉我,我会添加它
无论如何,我需要知道的是如何使setBounds()
停止调用repaint()
(而不仅仅是使用少于5个实体
)。另外,我在添加实体时删除了EnemyAI.start()
,它确实停止了它。因此,我有理由相信问题出在AI
classrun()
方法中。它几乎只调用setBounds()
这是一种正常行为,这就是为什么不能修改paintComponent
中的状态。我们无法控制重绘何时发生:系统有时会自己进行重绘
下面是我的意思的一个例子,你不应该这么做:
public class PlayerPane extends JPanel{
...
public void paintComponent(Graphics g){
...
// modifying index
if(index == images.length-1){
index = 0;
} else {
index++;
}
}
}
您需要遍历所有代码,在paintComponent
中查找您修改过的每个变量,然后将其移到其他地方
作为旁注,您还应该移动ImageIO.read
调用,以便它们不在paintComponent
内。当程序启动时,将图像加载一次,加载到静态
变量或类似的内容中
作为一般提示,您应该只通过绘制动画来查看动画,而不是尝试为组件设置动画。从长远来看,这会给你带来巨大的好处
总而言之:
- 保持
paintComponent
无状态
- 在非UI对象中使用游戏/动画状态包装图像
- 在
paintComponent
中绘制这些图像
下面是一个简单的示例,通过设置从窗口落下的形状的动画来演示这一点:
import java.net.*;
import javax.swing.*;
import javax.imageio.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.Graphics;
import java.util.List;
import java.util.ArrayList;
import java.util.Random;
class FallingShapes implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new FallingShapes());
}
@Override
public void run() {
List<Entity> entities = new ArrayList<Entity>();
int w = 0;
int h = 0;
for (BufferedImage img : Resources.images) {
entities.add(new Entity(img));
w += img.getWidth();
h += img.getHeight();
}
PaintPanel p = new PaintPanel(entities);
p.setPreferredSize(new Dimension(w, (2 * h)));
JFrame f = new JFrame();
f.setContentPane(p);
f.pack();
f.setLocationRelativeTo(null);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
new Animator((1000 / 60), p, entities).start();
}
static class Animator implements ActionListener {
int period;
JPanel context;
int height;
List<Entity> entities;
Animator(int period, JPanel context, List<Entity> entities) {
this.context = context;
this.height = context.getHeight();
this.period = period;
this.entities = entities;
}
@Override
public void actionPerformed(ActionEvent a) {
for (Entity e : entities) {
double dist =
(period / 1000.0) * (height * e.rate);
e.y += dist;
e.y %= height;
}
context.repaint();
}
void start() {
Random r = new Random();
int x = 0;
for (Entity e : entities) {
e.x = x;
e.y = r.nextInt(height);
e.rate = (0.25 + (0.75 * r.nextDouble()));
x += e.width;
}
new Timer(period, this).start();
}
}
static class Entity {
BufferedImage img;
double x, y, rate;
int width, height;
Entity(BufferedImage img) {
this.img = img;
this.width = img.getWidth();
this.height = img.getHeight();
}
void paint(Graphics g, JPanel context) {
int x = (int) Math.round(this.x);
int y = (int) Math.round(this.y);
g.drawImage(img, x, y, null);
int cHeight = context.getHeight();
if ((y + height) > cHeight) {
g.drawImage(img, x, y - cHeight, null);
}
}
}
static class PaintPanel extends JPanel {
List<Entity> entities;
PaintPanel(List<Entity> entities) {
this.entities = entities;
setBackground(Color.white);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Entity e : entities) {
e.paint(g, this);
}
}
}
static class Resources {
static final String[] paths = {
"http://i.stack.imgur.com/wCF8S.png",
"http://i.stack.imgur.com/5v2TX.png",
"http://i.stack.imgur.com/F0JHK.png",
"http://i.stack.imgur.com/4EVv1.png",
"http://i.stack.imgur.com/xj49g.png",
};
static final List<BufferedImage> images =
new ArrayList<BufferedImage>();
static {
for (String path : paths) {
try {
images.add(ImageIO.read(new URL(path)));
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
}
}
import java.net.*;
导入javax.swing.*;
导入javax.imageio.*;
导入java.awt.image.*;
导入java.awt.event.*;
导入java.awt.Dimension;
导入java.awt.Color;
导入java.awt.Graphics;
导入java.util.List;
导入java.util.ArrayList;
导入java.util.Random;
类FallingShape实现可运行{
公共静态void main(字符串[]args){
调用器(新的FallingShapes());
}
@凌驾
公开募捐{
列表实体=新的ArrayList();
int w=0;
int h=0;
for(buffereImage img:Resources.images){
实体。添加(新实体(img));
w+=img.getWidth();
h+=img.getHeight();
}
PaintPanel p=新的PaintPanel(实体);
p、 设置首选尺寸(新尺寸(w,(2*h));
JFrame f=新的JFrame();
f、 setContentPane(p);
f、 包装();
f、 setLocationRelativeTo(空);
f、 可设置大小(假);
f、 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f、 setVisible(真);
新的动画师((1000/60),p,实体;
}
静态类Animator实现ActionListener{
整数周期;
JPanel语境;
内部高度;
列表实体
import java.net.*;
import javax.swing.*;
import javax.imageio.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.Graphics;
import java.util.List;
import java.util.ArrayList;
import java.util.Random;
class FallingShapes implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new FallingShapes());
}
@Override
public void run() {
List<Entity> entities = new ArrayList<Entity>();
int w = 0;
int h = 0;
for (BufferedImage img : Resources.images) {
entities.add(new Entity(img));
w += img.getWidth();
h += img.getHeight();
}
PaintPanel p = new PaintPanel(entities);
p.setPreferredSize(new Dimension(w, (2 * h)));
JFrame f = new JFrame();
f.setContentPane(p);
f.pack();
f.setLocationRelativeTo(null);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
new Animator((1000 / 60), p, entities).start();
}
static class Animator implements ActionListener {
int period;
JPanel context;
int height;
List<Entity> entities;
Animator(int period, JPanel context, List<Entity> entities) {
this.context = context;
this.height = context.getHeight();
this.period = period;
this.entities = entities;
}
@Override
public void actionPerformed(ActionEvent a) {
for (Entity e : entities) {
double dist =
(period / 1000.0) * (height * e.rate);
e.y += dist;
e.y %= height;
}
context.repaint();
}
void start() {
Random r = new Random();
int x = 0;
for (Entity e : entities) {
e.x = x;
e.y = r.nextInt(height);
e.rate = (0.25 + (0.75 * r.nextDouble()));
x += e.width;
}
new Timer(period, this).start();
}
}
static class Entity {
BufferedImage img;
double x, y, rate;
int width, height;
Entity(BufferedImage img) {
this.img = img;
this.width = img.getWidth();
this.height = img.getHeight();
}
void paint(Graphics g, JPanel context) {
int x = (int) Math.round(this.x);
int y = (int) Math.round(this.y);
g.drawImage(img, x, y, null);
int cHeight = context.getHeight();
if ((y + height) > cHeight) {
g.drawImage(img, x, y - cHeight, null);
}
}
}
static class PaintPanel extends JPanel {
List<Entity> entities;
PaintPanel(List<Entity> entities) {
this.entities = entities;
setBackground(Color.white);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Entity e : entities) {
e.paint(g, this);
}
}
}
static class Resources {
static final String[] paths = {
"http://i.stack.imgur.com/wCF8S.png",
"http://i.stack.imgur.com/5v2TX.png",
"http://i.stack.imgur.com/F0JHK.png",
"http://i.stack.imgur.com/4EVv1.png",
"http://i.stack.imgur.com/xj49g.png",
};
static final List<BufferedImage> images =
new ArrayList<BufferedImage>();
static {
for (String path : paths) {
try {
images.add(ImageIO.read(new URL(path)));
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
}
}