问题描述
- java中panel实现线程接口以后,要调用repaint函数时,不进run函数
- 具体情况是 mypanel类实现了线程接口,在run函数中定义了sleep(100)后调用repaint函数,做一个小坦克游戏,在repaint之前要判断是否击中坦克,击中后要显示三张图片来体现爆炸效果,可是经过调试发现,每次第一次击中的时候,都是直接好多次repaint,没有休眠,后来发现根本就没有进mypanel的run()方法,好像有另一个其他线程再调用paint。这是怎么回事?感谢大家了
package com.TankGame;
import java.awt.*;
import java.util.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
public class MyTankGame1 extends JFrame{public static void main(String[] args) { // TODO Auto-generated method stub MyTankGame1 tankgame = new MyTankGame1();}//构造函数public MyTankGame1(){ MyPanel mp = new MyPanel(); //启动mp线程 Thread t = new Thread(mp); t.start(); this.add(mp); this.addKeyListener(mp); this.setIconImage(new ImageIcon(""TankImage/TANK.jpg"").getImage()); this.setTitle(""坦克大战""); this.setLocation(350 100); this.setSize(500 400); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true);}
}
//我的面板类
class MyPanel extends JPanel implements KeyListenerRunnable{
//定义一个玩家的坦克
MyTank mytank = null;Vector<EnemyTank> ets= new Vector<EnemyTank>();//定义爆炸效果集合Vector<Boom> boom = new Vector<Boom>();int enSize = 8;//定义三张图片三张图片组成一次爆炸Image image1 = null;Image image2 = null;Image image3 = null;//构造函数public MyPanel(){ mytank = new MyTank(100250); mytank.setType(0); for(int i=0;i<enSize;i++){ EnemyTank et = new EnemyTank((i+1)*500); et.setType(1); et.setDirect(1); et.setType(1); ets.add(et); } //初始化图片 image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource(""/1.jpg"")); image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource(""/2.jpg"")); image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource(""/3.jpg""));}public void hittank(Bullet bEnemyTank et){ //判断该坦克的方向 switch(et.direct){ //方向朝上或者下 case 0: case 1: if(b.x>et.x&&b.x<et.x+20&&b.y>et.y&&b.y<et.y+30){ //击中 //子弹死亡 坦克死亡 b.isAlive=false; et.isLive=false; //创建一个爆炸效果,放入boom Boom bom = new Boom(et.xet.y); boom.add(bom); } case 2: case 3: if(b.x>et.x-5&&b.x<et.x+25&&b.y>et.y+5&&b.y<et.y+25){ //击中 b.isAlive=false; et.isLive=false; Boom bom = new Boom(et.xet.y); boom.add(bom); } }}//方向:上下左右,对应0123public void paint(Graphics g){ super.paint(g); System.out.println(""xx""); g.fillRect(0 0 500 500); this.drawTank(this.mytank.getX() this.mytank.getY() g this.mytank.getDirect() this.mytank.getType() ); //从ss中画出所有子弹 for(int i=0;i<this.mytank.ss.size();i++){ Bullet b = mytank.ss.get(i); if(b!=null&&b.isAlive==true){ g.drawRect(b.x b.y 1 1); } if(b.isAlive==false){ //从ss中删掉该子弹 mytank.ss.remove(b); } } for(int i=0;i<ets.size();i++){ EnemyTank et = ets.get(i); if(et.isLive){ this.drawTank(et.getX() et.getY() g et.getDirect() et.getType()); } } //画出爆炸 System.out.println(boom.size()); for(int j=0;j<boom.size();j++){ Boom bom = boom.get(j); if(bom.life>6){ g.drawImage(image1 bom.x bom.y 30 30 this); }else if(bom.life>3){ g.drawImage(image2 bom.x bom.y 30 30 this); }else{ g.drawImage(image3 bom.x bom.y 30 30 this); } //让爆炸进行 bom.lifeDown(); if(bom.life==0){ boom.remove(bom); } } }//画出坦克的函数public void drawTank(int xint yGraphics gint directint type){ switch(type){ case 0: g.setColor(Color.cyan); break; case 1: g.setColor(Color.yellow); break; } switch(direct){ case 0://向上走 g.fill3DRect(x y 5 30 false); g.fill3DRect(x+15 y 5 30 false); g.fill3DRect(x+5 y+5 10 20false); g.fillOval(x+5 y+10 10 10); g.drawLine(x+10 y+15 x+10 y); g.drawOval(x+5 y+10 10 10); break; case 3://向右走 g.fill3DRect(x-5 y+5 30 5 false); g.fill3DRect(x-5 y+20 30 5 false); g.fill3DRect(x y+10 20 10 false); g.fillOval(x+5 y+10 10 10); g.drawLine(x+10 y+15 x+25 y+15); g.drawOval(x+5 y+10 10 10); break; case 1://向下走 g.fill3DRect(x y 5 30 false); g.fill3DRect(x+15 y 5 30 false); g.fill3DRect(x+5 y+5 10 20false); g.fillOval(x+5 y+10 10 10); g.drawLine(x+10 y+15 x+10 y+30); g.drawOval(x+5 y+10 10 10); break; case 2://向右走 g.fill3DRect(x-5 y+5 30 5 false); g.fill3DRect(x-5 y+20 30 5 false); g.fill3DRect(x y+10 20 10 false); g.fillOval(x+5 y+10 10 10); g.drawLine(x+10 y+15 x-5 y+15); g.drawOval(x+5 y+10 10 10); break; } }@Overridepublic void keyTyped(KeyEvent e) {}@Overridepublic void keyPressed(KeyEvent e) { // TODO Auto-generated method stub if(e.getKeyCode()==KeyEvent.VK_UP){ this.mytank.setDirect(0); this.repaint(); this.mytank.moveUp(); } else if(e.getKeyCode()==KeyEvent.VK_DOWN){ this.mytank.setDirect(1); this.repaint(); this.mytank.moveDown(); } else if(e.getKeyCode()==KeyEvent.VK_LEFT){ this.mytank.setDirect(2); this.repaint(); this.mytank.moveLeft(); } else if(e.getKeyCode()==KeyEvent.VK_RIGHT){ this.mytank.setDirect(3); this.repaint(); this.mytank.moveRight(); }}@Overridepublic void keyReleased(KeyEvent e) { // TODO Auto-generated method stub if(e.getKeyCode()==KeyEvent.VK_SPACE){ if(this.mytank.ss.size()<=4){ this.mytank.fire(); } }}@Overridepublic void run() { // TODO Auto-generated method stub //每隔100毫秒重绘 while(true){ System.out.println(""sleep""); try { Thread.sleep(30); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //判断是否击中 for(int i=0;i<mytank.ss.size();i++){ Bullet mb = mytank.ss.get(i); //判断子弹是否有效 if(mb.isAlive){ //取出每一个坦克,与子弹判断是否击中 for(int j=0;j<ets.size();j++){ //取出坦克 EnemyTank et = ets.get(j); if(et.isLive){ this.hittank(mb et); } } } } this.repaint(); }}
}
//子弹类
class Bullet implements Runnable{
int x;
int y;
int direct;
int speed=1;
boolean isAlive = true;
public Bullet(int xint yint direct){
this.x=x;
this.y=y;
this.direct = direct;
}
@Override
public void run() {
// TODO Auto-generated method stubwhile(true){ try { Thread.sleep(25); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } switch(direct){ case 0: y-=speed; break; case 1: y+=speed; break; case 2: x-=speed; break; case 3: x+=speed; break; } //子弹何时死亡? //判断子弹到达边界 if(x<-1||x>501||y<-1||y>501){ this.isAlive=false; break; } }}
}
//坦克类
class Tank{
//坦克的种类
int type;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
//坦克的速度
int speed = 1;
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public int getDirect() {
return direct;
}
public void setDirect(int direct) {
this.direct = direct;
}
int direct = 0;
//坦克的横纵坐标
int x=0;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
int y=0;
public Tank(int xint y){
this.x=x;
this.y=y;}
}
class MyTank extends Tank{
Bullet mb = null;
public MyTank(int xint y){
super(xy);}Vector<Bullet> ss = new Vector<Bullet>();//开火能力public void fire(){ switch(this.direct){ case 0: mb = new Bullet(this.getX()+10this.getY()0); ss.add(mb); break; case 1: mb = new Bullet(this.getX()+10this.getY()+301); ss.add(mb); break; case 2: mb = new Bullet(this.getX()-5this.getY()+152); ss.add(mb); break; case 3: mb = new Bullet(this.getX()+25this.getY()+153); ss.add(mb); break; } Thread t = new Thread(mb); t.start();}public void moveUp(){ y-=speed;}public void moveRight(){ x+=speed;}public void moveDown(){ y+=speed;}public void moveLeft(){ x-=speed;}
}
class EnemyTank extends Tank{
boolean isLive = true;public EnemyTank(int xint y){ super(x y);}
}
class Boom{
int x;
int y;
int life = 9;//爆炸的时间过程
boolean isLive = true;
public Boom(int x int y){
this.x=x;
this.y=y;
}
//过程减少
public void lifeDown(){
if(life>0){
life--;
}else{
this.isLive=false;
}
}
}
解决方案
把MyPanel构造函数部分中初始化爆炸图片的代码换成下面的内容。第一次击中就可以了。
try { image1 = ImageIO.read(Panel.class.getResource(""/1.png"")); image2 = ImageIO.read(Panel.class.getResource(""/2.png"")); image3 = ImageIO.read(Panel.class.getResource(""/3.png"")); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
看网上说是Toolkit.getDefaultToolkit().getImage(url)方法不好用,你可以看看下面的资料。
http://javapub.iteye.com/blog/682257
具体为什么就不是很清楚了,用Toolkit方法拿到的Image对象宽高都是-1,第一次击中之后又能显示了,此时的宽高才是正常的。
解决方案二:
这种问题,建议你贴代码出来,通过文字不好判断。