小弟是个Java新手,现打算实现一个简单的打字游戏程序。在制作过程中遇到疑难,望各路大侠帮忙给看看。
问题:在一个面板上面使用2个线程,分别控制各自的字母下落。感觉这种思路应该可行,但奇怪的是面板中没有任何应该显示的字母。(其他绘制的线都能正常显示)。为了给花时间帮忙的朋友以方便,我在下边对程序中的个别地方做了说明。
说明1:下面是我的绘图面板类中的paint方法的具体内容:
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2=(Graphics2D)g;
if(tf.level==5)//这里原为tf.level==0,即去执行游戏第0级的方法levelZero
{
levelZero(g2,this);
}
if(tf.level==0)//这里原为tf.level==1,即去执行游戏第1级的方法levelOne
{ //现为了解决问题的方便,将它改为0,直接从第1级开始游戏
levelOne(g2,this);
}
}
说明2:以下是游戏第1级的具体方法代码
boolean oneStart=false;//记录1级是否初始化开始
public void levelOne(Graphics2D g2,LetterDownJPanel ldp)//1级
{
g2.setColor(Color.BLUE);
g2.drawRect(5,5,ldp.getWidth()-10,ldp.getHeight()-15);
g2.drawLine(65,5,65,430);
g2.drawLine(125,5,125,430);
g2.drawLine(125,5,125,430);
g2.drawLine(185,5,185,430);
if(ldp.hit)
g2.setColor(Color.YELLOW);
else
g2.setColor(Color.RED);
g2.drawLine(0,ldp.getHeight()-18,ldp.getWidth(),ldp.getHeight()-18);
g2.setColor(Color.YELLOW);
g2.setFont(ldp.fontCool);
if(oneStart==false)//从这里开始使用了2个线程,分别代表2个字母的下落情况。
{
LetterThread lt1=new LetterThread(g2,ldp,68,0,300,"f");
LetterThread lt2=new LetterThread(g2,ldp,128,0,800,"s");
lt1.start();
lt2.start();
oneStart=true;
} 说明3:控制字母下落的线程类如下所述。我在必要的地方加入了测试语句,经测试发现上面说的
2个线程都已经正常的启动运行,字母下落其实也正常,但在面板中看不到效果。不知为何,怀疑是否是刷新的问题。
class LetterThread extends Thread //控制字母下落的线程类
{
Graphics2D g2=null;
LetterDownJPanel ldp=null;
int letterX;
int letterY;
boolean letterChange=false;
int sleeptime;
String s;
LetterThread(Graphics2D g2,LetterDownJPanel ldp,int x,int y,int time,String s)
{
this.g2=g2;
this.ldp=ldp;
this.letterX=x;
this.letterY=y;
this.sleeptime=time;
this.s=s;
}
public void run()
{
while(true)
{
this.ldp.paint(g2);//?????????????????????????
System.out.println("s="+this.s);
if(this.letterY>=450)
{
this.letterChange=true;
this.letterY=0;
if(ldp.hit==false) //如果字母没有被打中就落入屏幕底部
{
ldp.tf.labCool.setText("Miss!");
ldp.tf.labScore.setText(""+(Integer.parseInt(ldp.tf.labScore.getText())-50));
ldp.tf.pb.setValue(ldp.tf.pb.getValue()-3);
if(Integer.parseInt(ldp.tf.labScore.getText())<-2500||ldp.tf.pb.getValue()<=0)
{
int jo=JOptionPane.showConfirmDialog(null,"Game Over!!","游戏结束",JOptionPane.OK_OPTION);
if(jo==JOptionPane.OK_OPTION)
System.exit(0);
}
}
ldp.hit=false; //一个字母落完后,将hit标记仍然置回false
}
else
{
if(this.letterChange)
{
System.out.println("change letter !!");
this.s=""+ldp.letterRandom();
g2.drawString(this.s,this.letterX,this.letterY);
this.letterChange=false;
}
else
{
System.out.println(this.s);
System.out.println(this.letterX);
System.out.println(this.letterY);
g2.drawString(this.s,this.letterX,this.letterY);
}
try
{
Thread.sleep(this.sleeptime);
System.out.println("sleep"+sleeptime);
}
catch(Exception e1)
{
e1.printStackTrace();
}
this.letterY++;
System.out.println("y++"+this.letterY);
ldp.repaint();
ldp.tf.repaint();//窗体重绘,刷新整个窗体,保证每次都能看到面板上面的
//图像变化
}
}
}
}我在下一楼中放上全部代码,有些乱,恳请高手帮忙给瞅瞅。
问题:在一个面板上面使用2个线程,分别控制各自的字母下落。感觉这种思路应该可行,但奇怪的是面板中没有任何应该显示的字母。(其他绘制的线都能正常显示)。为了给花时间帮忙的朋友以方便,我在下边对程序中的个别地方做了说明。
说明1:下面是我的绘图面板类中的paint方法的具体内容:
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2=(Graphics2D)g;
if(tf.level==5)//这里原为tf.level==0,即去执行游戏第0级的方法levelZero
{
levelZero(g2,this);
}
if(tf.level==0)//这里原为tf.level==1,即去执行游戏第1级的方法levelOne
{ //现为了解决问题的方便,将它改为0,直接从第1级开始游戏
levelOne(g2,this);
}
}
说明2:以下是游戏第1级的具体方法代码
boolean oneStart=false;//记录1级是否初始化开始
public void levelOne(Graphics2D g2,LetterDownJPanel ldp)//1级
{
g2.setColor(Color.BLUE);
g2.drawRect(5,5,ldp.getWidth()-10,ldp.getHeight()-15);
g2.drawLine(65,5,65,430);
g2.drawLine(125,5,125,430);
g2.drawLine(125,5,125,430);
g2.drawLine(185,5,185,430);
if(ldp.hit)
g2.setColor(Color.YELLOW);
else
g2.setColor(Color.RED);
g2.drawLine(0,ldp.getHeight()-18,ldp.getWidth(),ldp.getHeight()-18);
g2.setColor(Color.YELLOW);
g2.setFont(ldp.fontCool);
if(oneStart==false)//从这里开始使用了2个线程,分别代表2个字母的下落情况。
{
LetterThread lt1=new LetterThread(g2,ldp,68,0,300,"f");
LetterThread lt2=new LetterThread(g2,ldp,128,0,800,"s");
lt1.start();
lt2.start();
oneStart=true;
} 说明3:控制字母下落的线程类如下所述。我在必要的地方加入了测试语句,经测试发现上面说的
2个线程都已经正常的启动运行,字母下落其实也正常,但在面板中看不到效果。不知为何,怀疑是否是刷新的问题。
class LetterThread extends Thread //控制字母下落的线程类
{
Graphics2D g2=null;
LetterDownJPanel ldp=null;
int letterX;
int letterY;
boolean letterChange=false;
int sleeptime;
String s;
LetterThread(Graphics2D g2,LetterDownJPanel ldp,int x,int y,int time,String s)
{
this.g2=g2;
this.ldp=ldp;
this.letterX=x;
this.letterY=y;
this.sleeptime=time;
this.s=s;
}
public void run()
{
while(true)
{
this.ldp.paint(g2);//?????????????????????????
System.out.println("s="+this.s);
if(this.letterY>=450)
{
this.letterChange=true;
this.letterY=0;
if(ldp.hit==false) //如果字母没有被打中就落入屏幕底部
{
ldp.tf.labCool.setText("Miss!");
ldp.tf.labScore.setText(""+(Integer.parseInt(ldp.tf.labScore.getText())-50));
ldp.tf.pb.setValue(ldp.tf.pb.getValue()-3);
if(Integer.parseInt(ldp.tf.labScore.getText())<-2500||ldp.tf.pb.getValue()<=0)
{
int jo=JOptionPane.showConfirmDialog(null,"Game Over!!","游戏结束",JOptionPane.OK_OPTION);
if(jo==JOptionPane.OK_OPTION)
System.exit(0);
}
}
ldp.hit=false; //一个字母落完后,将hit标记仍然置回false
}
else
{
if(this.letterChange)
{
System.out.println("change letter !!");
this.s=""+ldp.letterRandom();
g2.drawString(this.s,this.letterX,this.letterY);
this.letterChange=false;
}
else
{
System.out.println(this.s);
System.out.println(this.letterX);
System.out.println(this.letterY);
g2.drawString(this.s,this.letterX,this.letterY);
}
try
{
Thread.sleep(this.sleeptime);
System.out.println("sleep"+sleeptime);
}
catch(Exception e1)
{
e1.printStackTrace();
}
this.letterY++;
System.out.println("y++"+this.letterY);
ldp.repaint();
ldp.tf.repaint();//窗体重绘,刷新整个窗体,保证每次都能看到面板上面的
//图像变化
}
}
}
}我在下一楼中放上全部代码,有些乱,恳请高手帮忙给瞅瞅。
* *
* 打字游戏 *
* *
********************************/
//打字游戏的基本功能实现.import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JLabel;
import java.awt.Color;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.lang.Thread;
import java.util.EventListener;
import javax.swing.JOptionPane;
import javax.swing.JComponent;
import java.lang.Thread;
import java.lang.Runnable;
class TWFrame extends JFrame implements KeyListener
{
JProgressBar pb=new JProgressBar(0,100);
JPanel pl=new JPanel();
LetterDownJPanel ldp=new LetterDownJPanel(this);
JPanel plRight=new JPanel();
JPanel plRup=new JPanel();
JPanel plRdown=new JPanel();
JPanel plLevel=new JPanel();
JLabel labScore=new JLabel("0");
JLabel labCool=new JLabel("");
JLabel labLevelNumber=new JLabel("0",JLabel.RIGHT);
JLabel labLevel=new JLabel("级",JLabel.LEFT);
Font fontScore=new Font("宋体",Font.BOLD,70);
Font fontCool=new Font("华文彩云",Font.BOLD,70);
Font fontCoolmin=new Font("华文彩云",Font.BOLD,60);
Font fontLevel=new Font("华文行楷",Font.BOLD,40);
int level=0;//级别
TWFrame()
{
this.setBounds(180,180,500,450);
this.setTitle("六指盘魔 打字游戏");
this.setLayout(new BorderLayout());
this.add(pb,BorderLayout.SOUTH);
pb.setForeground(Color.RED);
pb.setValue(100);
pb.setStringPainted(true);
this.add(pl);
pl.setLayout(new GridLayout(1,2));
pl.add(ldp);
ldp.setBackground(Color.BLACK);
pl.add(plRight);
plRight.setLayout(new GridLayout(5,1));
plRight.add(plRup);
plRight.add(plRdown);
plRight.add(plLevel);
plRup.add(labScore);
labScore.setForeground(Color.BLUE);
labScore.setFont(fontScore);
plRdown.add(labCool);
labCool.setFont(fontCool);
labCool.setForeground(Color.RED);
plLevel.add(labLevelNumber);
plLevel.add(labLevel);
plLevel.setBackground(Color.BLACK);
labLevelNumber.setFont(fontLevel);
labLevelNumber.setForeground(Color.GREEN);
labLevel.setFont(fontLevel);
labLevel.setForeground(Color.GREEN);
this.addKeyListener(this);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public void keyTyped(KeyEvent e)
{
System.out.println(e.getKeyChar());
if((""+e.getKeyChar()).equals(ldp.s)&&ldp.letterY>=355&&ldp.letterY<=400)
{
this.labCool.setText("Cool!");
this.labScore.setText(""+(Integer.parseInt(this.labScore.getText())+100));
ldp.hit=true;
ldp.s="";//打中就让字母消失
if(Integer.parseInt(this.labScore.getText())==1500)
{
this.level=1;
this.labLevelNumber.setText("1");
}
}
else
{
this.labCool.setText("Miss!");
this.labScore.setText(""+(Integer.parseInt(this.labScore.getText())-50));
this.pb.setValue(this.pb.getValue()-3);
if(Integer.parseInt(this.labScore.getText())<-2500||this.pb.getValue()<=0)
{
int jo=JOptionPane.showConfirmDialog(null,"Game Over!!","游戏结束",JOptionPane.OK_OPTION);
if(jo==JOptionPane.OK_OPTION)
System.exit(0);
}
}
} public void keyPressed(KeyEvent e){}
public void keyReleased(KeyEvent e){}
}
{
Font fontCool=new Font("宋体",Font.BOLD|Font.ITALIC,70);
int letterX=100;
int letterY=0;
boolean letterChange=false; //是否变换新的字母
boolean hit=false; //是否打中字母
String s="f"; //初始时显示的字母为F
TWFrame tf=null;
LetterDownJPanel(TWFrame tf)
{
this.tf=tf;
}
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2=(Graphics2D)g;
if(tf.level==5)
{
levelZero(g2,this);
}
if(tf.level==0)
{
levelOne(g2,this);
}
}
public char letterRandom() //产生随机字母的方法
{
int r;
r=(int)(Math.random()*26+1);
char c=(char)('a'+r);
return(c);
}
public void levelZero(Graphics2D g2,LetterDownJPanel ldp)//0级
{
g2.setColor(Color.BLUE);
g2.drawRect(5,5,ldp.getWidth()-10,ldp.getHeight()-15);
g2.drawLine(90,5,90,430);
g2.drawLine(150,5,150,430);
if(ldp.hit)
g2.setColor(Color.YELLOW);
else
g2.setColor(Color.RED);
g2.drawLine(0,ldp.getHeight()-18,ldp.getWidth(),ldp.getHeight()-18);
g2.setColor(Color.YELLOW);
g2.setFont(ldp.fontCool);
if(ldp.letterY>=450)
{
ldp.letterChange=true;
ldp.letterY=0; if(ldp.hit==false) //如果字母没有被打中就落入屏幕底部
{
ldp.tf.labCool.setText("Miss!");
ldp.tf.labScore.setText(""+(Integer.parseInt(ldp.tf.labScore.getText())-50));
ldp.tf.pb.setValue(ldp.tf.pb.getValue()-3);
if(Integer.parseInt(ldp.tf.labScore.getText())<-2500||ldp.tf.pb.getValue()<=0)
{
int jo=JOptionPane.showConfirmDialog(null,"Game Over!!","游戏结束",JOptionPane.OK_OPTION);
if(jo==JOptionPane.OK_OPTION)
System.exit(0);
}
}
ldp.hit=false; //一个字母落完后,将hit标记仍然置回false
}
else
{
if(ldp.letterChange)
{
ldp.s=""+this.letterRandom();
g2.drawString(ldp.s,ldp.letterX,ldp.letterY);
ldp.letterChange=false;
}
else
g2.drawString(ldp.s,ldp.letterX,ldp.letterY);
try
{
Thread.sleep(5);
}
catch(Exception e1)
{
e1.printStackTrace();
}
ldp.letterY++;
ldp.repaint();
ldp.tf.repaint();//窗体重绘,刷新整个窗体,保证每次都能看到面板上面的
//图像变化
}
}
boolean oneStart=false;//记录1级是否初始化开始
public void levelOne(Graphics2D g2,LetterDownJPanel ldp)//1级
{
g2.setColor(Color.BLUE);
g2.drawRect(5,5,ldp.getWidth()-10,ldp.getHeight()-15);
g2.drawLine(65,5,65,430);
g2.drawLine(125,5,125,430);
g2.drawLine(125,5,125,430);
g2.drawLine(185,5,185,430);
if(ldp.hit)
g2.setColor(Color.YELLOW);
else
g2.setColor(Color.RED);
g2.drawLine(0,ldp.getHeight()-18,ldp.getWidth(),ldp.getHeight()-18);
g2.setColor(Color.YELLOW);
g2.setFont(ldp.fontCool);
if(oneStart==false)
{
LetterThread lt1=new LetterThread(g2,ldp,68,0,300,"f");
LetterThread lt2=new LetterThread(g2,ldp,128,0,800,"s");
lt1.start();
lt2.start();
oneStart=true;
}
}
}
{
Graphics2D g2=null;
LetterDownJPanel ldp=null;
int letterX;
int letterY;
boolean letterChange=false;
int sleeptime;
String s;
LetterThread(Graphics2D g2,LetterDownJPanel ldp,int x,int y,int time,String s)
{
this.g2=g2;
this.ldp=ldp;
this.letterX=x;
this.letterY=y;
this.sleeptime=time;
this.s=s;
}
public void run()
{
while(true)
{
this.ldp.paint(g2);//?????????????????????????
System.out.println("s="+this.s);
if(this.letterY>=450)
{
this.letterChange=true;
this.letterY=0;
if(ldp.hit==false) //如果字母没有被打中就落入屏幕底部
{
ldp.tf.labCool.setText("Miss!");
ldp.tf.labScore.setText(""+(Integer.parseInt(ldp.tf.labScore.getText())-50));
ldp.tf.pb.setValue(ldp.tf.pb.getValue()-3);
if(Integer.parseInt(ldp.tf.labScore.getText())<-2500||ldp.tf.pb.getValue()<=0)
{
int jo=JOptionPane.showConfirmDialog(null,"Game Over!!","游戏结束",JOptionPane.OK_OPTION);
if(jo==JOptionPane.OK_OPTION)
System.exit(0);
}
}
ldp.hit=false; //一个字母落完后,将hit标记仍然置回false
}
else
{
if(this.letterChange)
{
System.out.println("change letter !!");
this.s=""+ldp.letterRandom();
g2.drawString(this.s,this.letterX,this.letterY);
this.letterChange=false;
}
else
{
System.out.println(this.s);
System.out.println(this.letterX);
System.out.println(this.letterY);
g2.drawString(this.s,this.letterX,this.letterY);
}
try
{
Thread.sleep(this.sleeptime);
System.out.println("sleep"+sleeptime);
}
catch(Exception e1)
{
e1.printStackTrace();
}
this.letterY++;
System.out.println("y++"+this.letterY);
ldp.repaint();
ldp.tf.repaint();//窗体重绘,刷新整个窗体,保证每次都能看到面板上面的
//图像变化
}
}
}
}class Test
{
public static void main(String[] args)
{
JFrame.setDefaultLookAndFeelDecorated(true);
new TWFrame();
}
}
//代码结束
第一,从线程的角度来讲,这么做的了,你要同步和互斥。
第二,从设计的角度看,最好画图的部分是MVC模式的,而文档到视图的部分,应该在一个线程内操作,这样也简单。