A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© qq892384796 中级黑马   /  2015-12-9 21:44  /  3572 人查看  /  1 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

      想必用过金山打字的小伙伴们都有问过里面的打字小游戏《太空大战》吧,其实使用Java代码是完全可以实现同样的功能的,不多说了,直接上效果图,感兴趣的同学不妨试着编写一个属于自己的游戏小项目。
    效果图:
       

     游戏基本规则:
1、初始分数1000分;
2、每打掉一个字母加50分;
3、打错字母或者字母落地一个扣除100分;
4、录入的键盘字母与屏幕上的字母核对,需要区分大小写;
5、当总分数小于0时,游戏结束,统计游戏存活时间。
    用到的素材:



       实现原理:我们只需要自定义一张游戏画布,在该画布中完成游戏逻辑与绘制,最后将画布(JPanle)加入到窗体中即可(JFrame)。屏幕中的字母是向下掉落,我们需要以一定的速度来改变这些字母的y坐标,并重新绘制到画布上,由于绘制速度过快,人眼睛自然会产生字母向下平移的视觉错觉,实现字母的平移效果完全可以使用线程来完成,而最近刚接触 定时任务(Timer、TimerTask),所以尝试用这两个类完成。
    实现键盘录入的字母与屏幕字母的对照,则加入键盘监听即可,JPanle子类实现KeyListener接口中的KeyPressed()方法来对比屏幕中的字母。
代码如下(注释已加):
  1. package playchar.game;

  2. import java.awt.Color;
  3. import java.awt.Font;
  4. import java.awt.Graphics;
  5. import java.awt.Image;
  6. import java.awt.Toolkit;
  7. import java.awt.event.KeyEvent;
  8. import java.awt.event.KeyListener;
  9. import java.util.Timer;
  10. import java.util.TimerTask;

  11. import javax.swing.JPanel;

  12. public class CharJPanel extends JPanel implements KeyListener{

  13.         private static final long serialVersionUID = 1L;
  14.        
  15.         //背景图片
  16.         Image back=Toolkit.getDefaultToolkit().getImage(CharJPanel.class.getResource("back.jpg"));
  17.         //爆炸图片
  18.         Image b0=Toolkit.getDefaultToolkit().getImage(CharJPanel.class.getResource("b0.jpg"));
  19.         Image b1=Toolkit.getDefaultToolkit().getImage(CharJPanel.class.getResource("b1.jpg"));
  20.         Image b2=Toolkit.getDefaultToolkit().getImage(CharJPanel.class.getResource("b2.jpg"));
  21.         Image b3=Toolkit.getDefaultToolkit().getImage(CharJPanel.class.getResource("b3.jpg"));
  22.        
  23.         //用于统计开始时间,以及结束时间
  24.         boolean  firstStart =false;                //首次启动标记
  25.         int num=3;                        //倒计时3秒标记
  26.         long start=0;                //用于存放游戏开始时间
  27.         long end =0;                //用于存放游戏结束时间
  28.        
  29.         int score=1000;                //初始分数1000分
  30.        
  31.         //用于存放屏幕中10个字母以及所对应的坐标,大小写
  32.         char[] c=new char[10];       
  33.         int[] x=new int [c.length];
  34.         int[] y=new int[c.length];
  35.         int[] caps=new int[c.length];
  36.        
  37.         Timer timer=null;                //定义定时任务对象
  38.        
  39.        
  40.         //xx,yy所代表的坐标是否被玩家打掉,被打掉时playflag置为true,其他时间false
  41.         int xx=0;
  42.         int yy=0;
  43.         boolean playflag=false;       

  44.        
  45.        
  46.         public CharJPanel(){                //构造时初始化
  47.                 firstStart=true;                //画板实例时,将第一次启动标志改变
  48.                 this.init();        //开始初始化       
  49.                 start=System.currentTimeMillis();        //画板被实例时,就获得计时开始
  50.         }       
  51.        
  52.         public void init(){                        //初始化方法
  53.                 for(int i=0;i<c.length;i++){
  54.                         c[i]=(char)(Math.random()*26+97);        //获得随机26个字母
  55.                         caps[i]=(int)(Math.random()*2);                //会的随机大小写,值为0小写,值为1大写       
  56.                         x[i]=checkX((int)(Math.random()*450+12),x);
  57.                         y[i]=(int)(Math.random()*300);
  58.                 }
  59.                 timer =new Timer();        //实例定时任务对象
  60.         }
  61.        
  62.         public int checkX(int temp_x,int x[]){        //检查字母坐标是否有重叠,有则重新生成坐标
  63.                 int xxx=temp_x;
  64.                 for(int i=0;i<c.length;i++){
  65.                         if(x[i]!=0){
  66.                                 if(Math.abs(xxx-x[i])<20){
  67.                                         xxx=checkX((int)(Math.random()*450+12),x);
  68.                                 }
  69.                         }
  70.                 }
  71.                 return xxx;
  72.         }
  73.        
  74.         public void paint(Graphics g)        //绘图
  75.         {
  76.                 super.paint(g);  //获得父类的绘图功能
  77.                
  78.                
  79.                 g.drawImage(back,0, 0, this);        //绘制背景图片
  80.                
  81.                 if(firstStart){        //启动游戏时,倒计时3秒
  82.                         g.setColor(Color.red);
  83.                         g.setFont(new Font("宋体",Font.BOLD,80));       
  84.                         g.drawString(""+num, 200, 200);
  85.                         num--;
  86.                                 try {
  87.                                         Thread.sleep(1000);                //画1次休息1秒
  88.                                 } catch (InterruptedException e) {
  89.                                         e.printStackTrace();
  90.                                 }
  91.                         if(num==-1){                //此处判断-1 而不是0 纯粹只是运行时效果较好原因
  92.                                 firstStart=false;        //倒计时结束标志
  93.                         }else{
  94.                                 //没结束则等待下一次绘制
  95.                                 return;
  96.                         }
  97.                 }
  98.                
  99.                 if(playflag){  //如果有打掉字母,则在此字母位置显示爆炸效果
  100.                         g.drawImage(b0,xx, yy-50, this);
  101.                         g.drawImage(b1,xx, yy-50, this);
  102.                         g.drawImage(b2,xx, yy-50, this);                               
  103.                         g.drawImage(b3,xx, yy-50, this);
  104.                         playflag=false;
  105.                 }
  106.                
  107.                 if(score<0){        //分数已负,游戏结束
  108.                         end=System.currentTimeMillis(); //获得结束时间
  109.                         //绘制结束背景
  110.                         Image black=Toolkit.getDefaultToolkit().getImage(CharJPanel.class.getResource("black.jpg"));
  111.                         Image over=Toolkit.getDefaultToolkit().getImage(CharJPanel.class.getResource("over.jpg"));
  112.                         g.drawImage(black,0, 0, this);
  113.                         g.drawImage(over, 0, 200, this);
  114.                         //设置  Game Over 提示
  115.                         g.setColor(Color.red);
  116.                         g.setFont(new Font("宋体",Font.BOLD,80));
  117.                         g.drawString("Game Over",50,300);
  118.                         //游戏结束时,将分数也变为红色值为0,并计算打印存活时间
  119.                         g.setFont(new Font("宋体",Font.BOLD,30));       
  120.                         g.drawString("分数:0",170,50);
  121.                         g.drawString("您共存活了:"+(end-start)/1000+"秒", 130, 150);
  122.                         timer.cancel();                //关闭定时任务
  123.                         return ;        //停止此次绘图
  124.                 }
  125.                

  126.                 //设置屏幕字母基本属性
  127.                 g.setColor(Color.black); //颜色
  128.                 g.setFont(new Font("Vineta BT",Font.BOLD,25)); //字体
  129.                 for(int i=0;i<c.length;i++){                //绘制字母
  130.                         if(caps[i]==1)
  131.                                 g.drawString(((c[i]=Character.toUpperCase(c[i]))+""),x[i],y[i]);
  132.                         else{
  133.                                 g.drawString(c[i]+"",x[i],y[i]);
  134.                         }
  135.                 }
  136.                
  137.                 //绘制分数
  138.                 g.setColor(Color.blue);
  139.                 g.setFont(new Font("宋体",Font.BOLD,30));
  140.                 g.drawString("分数:"+score,170,50);
  141.         }
  142.        
  143.        
  144.        
  145.         //定义一个方法,启动游戏
  146.         public void go(){
  147.                 //制定定时任务
  148.                 timer.schedule(new TimerTask(){                       
  149.                 //new TimerTask(){}匿名内部类,此处使用匿名内部类,完全是在他人的提醒下对代码的改进,并不利于理解,诺对此处产生困惑
  150.                 //建议还是写成内部类格式,并继承TimerTask类,覆写run()方法, 在此处就直接new 此内部类实例即可
  151.                         public void run() {
  152.                                
  153.                                 for(int i=0;i<c.length;i++){        //字母下落
  154.                                         y[i]++;
  155.                                         if(y[i]>560){        //如果已经掉落到底边界,则扣分,并从窗体最上方生成一个新的随机字母
  156.                                                 score-=100;
  157.                                                 y[i]=0;
  158.                                                 x[i]=checkX((int)(Math.random()*450+12),x);
  159.                                                 c[i]=(char)(Math.random()*26+97);
  160.                                                 caps[i]=(int)(Math.random()*2);
  161.                                         }
  162.                                 }
  163.                                 repaint(); //重画
  164.                         }
  165.                 },0,50) ;        //现在就启动,以后每50毫秒字母向下移动1像素并绘制一次
  166.                
  167.                
  168.         }

  169.         //键盘监听
  170.         public void keyPressed(KeyEvent key) {                //按下键盘某个键时,监听键盘输入的字符
  171.                
  172.                 char ckey=key.getKeyChar();                //获得键盘录入字母
  173.                
  174.                 if(ckey!=65535){        //排除大小写转换时扣分情况
  175.                         int index=-1;
  176.                         int temp_y=-1;
  177.                        
  178.                         for(int i=0;i<c.length;i++){                //遍历屏幕字母,是否有相同的
  179.                                 if((ckey==c[i])){
  180.                                         if(y[i]>temp_y){
  181.                                                 temp_y=y[i];
  182.                                                 index=i;
  183.                                         }
  184.                                 }
  185.                         }
  186.                         if(index!=-1){                //如果有相同的,则加分,并消除掉此字母,在窗体最上处生成新的字母替换
  187.                                 score+=50;
  188.                                 //保存被打掉的字母坐标,并将playflag 置 true
  189.                                 xx=x[index];
  190.                                 yy=y[index];
  191.                                 playflag=true;
  192.                                
  193.                                 //生成新的坐标
  194.                                 y[index]=0;
  195.                                 x[index]=checkX((int)(Math.random()*450+12),x);
  196.                                 c[index]=(char)(Math.random()*26+97);
  197.                                 caps[index]=(int)(Math.random()*2);
  198.                         }else{
  199.                                 //否则日录入的字母并不存在,扣100分
  200.                                 score-=100;
  201.                         }
  202.                 }
  203.         }

  204.         //以下两个监听事件,并未用到,置成空方法体即可
  205.         public void keyReleased(KeyEvent arg0) {}

  206.        
  207.         public void keyTyped(KeyEvent arg0) {}

  208. }
复制代码
程序入口:
  1. package playchar.game;

  2. import java.awt.Dimension;
  3. import java.awt.Toolkit;
  4. import javax.swing.JFrame;

  5. public class PlayCharGame {

  6.         public static void main(String[] args) {
  7.                 JFrame frame=new JFrame("PlayCharGame(区分大小写版)");   //游戏窗体
  8.                 frame.setSize(500,600);                                       
  9.                 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  10.                 frame.setMinimumSize(new Dimension(500,600));        //设置最小大小
  11.                 //设置窗体logo
  12.                 frame.setIconImage(Toolkit.getDefaultToolkit().getImage(PlayCharGame.class.getResource("logo.png")));
  13.        
  14.                 CharJPanel pan=new CharJPanel();        //绘画面板(自定义画布)       
  15.                 pan.go(); //开始游戏,启动定时任务
  16.        
  17.                 frame.add(pan);                //向窗体添加面板
  18.                 frame.addKeyListener(pan);        //绑定键盘事件

  19.                 frame.setVisible(true);        //显示窗体
  20.         }
  21. }
复制代码



PlayCharGM.zip

129.73 KB, 下载次数: 415

源码

1 个回复

倒序浏览
感覺很有趣,感謝分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马