当前位置: 移动技术网 > IT编程>开发语言>Java > Java编写掷骰子游戏

Java编写掷骰子游戏

2019年07月22日  | 移动技术网IT编程  | 我要评论

废话不多说了,直接奔主题。

**多线程&&观察者模式

题目要求:《掷骰子》窗体小游戏,在该游戏中,玩家初始拥有1000的金钱,每次输入押大还是押小,以及下注金额,随机3个骰子的点数,如果3个骰子的总点数小于等于9,则开小,否则开大,然后判断玩家是否押对,如果未押对则扣除下注金额,如果押对则奖励和玩家下注金额相同的金钱。

分析:这个题目要求灵活运用多线程的相关知识,达到点击开始按钮时,有3个线程启动,分别控制3颗骰子的转动,在3颗骰子全部转完以后,回到主线程计算游戏结果。

 //个线程控制颗骰子
 thread t = new thread();
 thread t = new thread();
 thread t = new thread();
 //启动个线程
 t.start();
 t.start();
 t.start();
 //将个线程加入主线程
 t.join();
 t.join();
 t.join();

but,,,写完代码以后发现,这样做虽然能够保证游戏能够正确运行,但是当我点击开始按钮时,由于3个骰子线程都是直接开在主线程上的,点击开始按钮时,按钮出现下沉情况,子线程一直在后台运行,我窗体中的图片根本不会发生改变,而是直接显示最后的结果,意思就是骰子一直在后台转动,不在前台的窗体中及时更新显示。后来在网上苦苦找寻,大神们说如果想要通过点击jbutton使窗体中的jlabel/jtextfeild等其他组件及时更新,直接在jbutton的监听事件的实现方法里面直接创建匿名线程,也就是说直接在actionperformed()方法中修改代码即可,这样能保证你的组件中内容的及时变换,实现非常炫酷的效果。

代码如下:

public void actionperformed(actionevent e) {
 new thread(new runnable() {
  @override
  public void run() {
   //将外部线程类转移到窗体内部
  }
 }).start();
}

 but,,,but,,,   虽然非常炫酷了,能够实现图片的及时更新了,游戏结果却错了,每次我的骰子还在转动呢,我的游戏结果却早早的就出来了。

原因:3根骰子线程属于子线程,窗体线程属于主线程,问题就在于:子线程可以通过变成精灵线程来保持与主线程的同生死,但是主线程却无法控制子线程何时死亡,只有等待子线程执行完所属的run()方法,结束线程后才知道。

解决方法:在主线程(main)中开3个子线程(t1,t2,t3),在每个子线程上再开一个子子线程(t11,t21,t31)。

t1,t2,t3只运行一次,负责创建子子线程;t11,t21,t31每个线程运行多次,负责控制窗体中的图标及时更新。

这样主线程就不受子线程的影响,开始按钮也不回出现下沉的情况。

但是同样在此处使用join方法也是hold不住子线程的,毕竟t1,t2,t3只运行了一次,join对他们来说根本不起作用,想要掌控t11,t21,t31,最容易理解的办法,就是使用观察者模式了。

将窗体看做观察者,子线程看做被观察者。子线程运行完时,通知观察者我已经运行完成,当观察者观察到子线程全都运行完时,才开始运行后续步骤。

全部代码:

1.窗体

 package com.sxt.dice;
 import java.awt.color;
 public class diceframe extends jframe implements actionlistener, observer {
  /**
  * 《掷骰子》控制台小游戏,在该游戏中,玩家初始拥有的金钱,每次输入押大还是押小,
  * 以及下注金额,随机个骰子的点数,如果个骰子的总点数小于等于,则开小,否则开大,
  * 然后判断玩家是否押对,如果未押对则扣除下注金额,如果押对则奖励和玩家下注金额相同的金钱。
  * 
  * 运用观察者模式 个子线程分别控制个骰子,都已经结束时,通知观察者窗体,窗体观察到所有子线程都结束时,计算游戏结果
  * 
  */
  private static final long serialversionuid = l;
  private jtextfield txtput;
  private jbutton btnstart;
  private jlabel labresult;
  private jcombobox<string> combobox;
  private jlabel labbigorsmall;
  private jlabel labput;
  private jlabel labsummoney;
  private jlabel labdice;
  private jlabel labdice;
  private jlabel labdice;
  private jlabel labsum;
  private jlabel labmes;
  private static list<icon> imgs = new arraylist<icon>();
  public static void main(string[] args) {
   new diceframe();
  }
  public diceframe() {
   this.setlocationrelativeto(null);
   this.setbounds(, , , );
   this.setdefaultcloseoperation(jframe.dispose_on_close);
   getcontentpane().setlayout(null);
   this.setresizable(false);
   labdice = new jlabel("");
   labdice.seticon(new imageicon("img/dices.jpg"));
   labdice.setbounds(, , , );
   getcontentpane().add(labdice);
   labsum = new jlabel("\u\uf\ud\ud\uffa");
   labsum.setbounds(, , , );
   getcontentpane().add(labsum);
   labdice = new jlabel("");
   labdice.seticon(new imageicon("img/dices.jpg"));
   labdice.setbounds(, , , );
   getcontentpane().add(labdice);
   labdice = new jlabel("");
   labdice.seticon(new imageicon("img/dices.jpg"));
   labdice.setbounds(, , , );
   getcontentpane().add(labdice);
   labsummoney = new jlabel("");
   labsummoney.setforeground(color.red);
   labsummoney.setbounds(, , , );
   getcontentpane().add(labsummoney);
   labput = new jlabel("\uc\ub\ueb\uce\uffa");
   labput.settooltiptext(".");
   labput.setbounds(, , , );
   getcontentpane().add(labput);
   txtput = new jtextfield();
   txtput.setbounds(, , , );
   getcontentpane().add(txtput);
   txtput.setcolumns();
   labbigorsmall = new jlabel("\ubc\uffa");
   labbigorsmall.setbounds(, , , );
   getcontentpane().add(labbigorsmall);
   combobox = new jcombobox<string>();
   combobox.setbounds(, , , );
   getcontentpane().add(combobox);
   combobox.additem("大");
   combobox.additem("小");
   labresult = new jlabel("");
   labresult.setbounds(, , , );
   getcontentpane().add(labresult);
   btnstart = new jbutton("start");
   btnstart.setbounds(, , , );
   getcontentpane().add(btnstart);
   labmes = new jlabel("<html><font size= color=red>*</font></html>");
   labmes.setbounds(, , , );
   getcontentpane().add(labmes);
   this.setvisible(true);
   imgs.add(new imageicon("img/.png"));
   imgs.add(new imageicon("img/.png"));
   imgs.add(new imageicon("img/.png"));
   imgs.add(new imageicon("img/.png"));
   imgs.add(new imageicon("img/.png"));
   imgs.add(new imageicon("img/.png"));
   btnstart.addactionlistener(this);
  }
  @override
  public void actionperformed(actionevent e) {
   if (e.getsource() == btnstart) {
    // 清除上次游戏的结果
    labresult.settext("");
    // 获取当前下注金额,用户余额,用户押大还是押小
    string txt = txtput.gettext().trim();
    string remain = labsummoney.gettext().trim();
    // 余额不足,不能开始游戏,提示用户充值
    if (integer.parseint(remain) <= ) {
     joptionpane.showmessagedialog(null, "当前余额不足,请充值!");
     return;
    }
    // 下注金额合法性检查
    if (txt.length() == ) {
     // 提示用户输入
     labmes.settext("*请输入下注金额");
     labmes.setforeground(color.red);
     return;
    }
    // 检查用户下注金额是否在有效范围内
    if (integer.parseint(txt) <= 
      || integer.parseint(txt) > integer.parseint(remain)) {
     txtput.settext("");
     labmes.settext("下注金额应在~" + remain + "之间");
     return;
    }
    // 游戏开始后相关项不可更改
    txtput.setenabled(false);
    labmes.settext("");
    combobox.setenabled(false);
    //在主线程上开t,t,t 个子线程
    thread t = new thread() {
     @override
     public void run() {
      //每个子线程上再开子子线程,控制图标变换
      iconthread t = new iconthread(labdice, imgs);
      //给t添加观察者,即当前窗体
      t.addobserver(diceframe.this);
      new thread(t).start();
     }
    };
    thread t = new thread() {
     @override
     public void run() {
      iconthread t = new iconthread(labdice, imgs);
      t.addobserver(diceframe.this);
      new thread(t).start();
     }
    };
    thread t = new thread() {
     @override
     public void run() {
      iconthread t = new iconthread(labdice, imgs);
      t.addobserver(diceframe.this);
      new thread(t).start();
     }
    };
    t.start();
    t.start();
    t.start();
   }
  }
  /**
  * 获取骰子点数和
  * 
  * @param lab
  * @return sum
  */
  private int result(jlabel lab) {
   // 获取当前骰子图片
   icon icon = lab.geticon();
   int sum = ;
   for (int i = ; i < imgs.size(); i++) {
    if (icon.equals(imgs.get(i))) {
     sum += (i + );
     break;
    }
   }
   return sum;
  }
  // 构建所有被观察者的集合
  vector<observable> allobservables = new vector<observable>();
  @override
  public void update(observable o, object arg) {
   system.out.println(o + ".................");
   // 如果集合中不包含当前被观察者,将此被观察者加入集合
   if (allobservables.contains(o) == false) {
    allobservables.add(o);
   }
   // 如果集合中被观察者个数为,说明个骰子线程已经全部结束
   if (allobservables.size() == ) {
    // 获取当前下注金额,用户余额,用户押大还是押小
    string txt = txtput.gettext().trim();
    string remain = labsummoney.gettext().trim();
    string bigorsmall = combobox.getselecteditem().tostring();
    // 获取每个骰子点数
    int sum = result(labdice);
    int sum = result(labdice);
    int sum = result(labdice);
    system.out.println(sum + "-" + sum + "-" + sum);
    int sum = sum + sum + sum;
    system.out.println(sum);
    if (sum > && "大".equals(bigorsmall) || sum <= 
      && "小".equals(bigorsmall)) {
     // 奖励玩家相应金额
     remain = string.valueof(integer.parseint(remain)
       + integer.parseint(txt));
     labsummoney.settext(remain);
     // 显示游戏结果
     labresult.settext("win");
     labresult.setforeground(color.green);
     labresult.setfont(new font("宋体", font.bold, ));
    } else {
     // 扣除玩家相应金额
     remain = string.valueof(integer.parseint(remain)
       - integer.parseint(txt));
     labsummoney.settext(remain);
     labresult.settext("fail");
     labresult.setforeground(color.red);
     labresult.setfont(new font("宋体", font.bold, ));
    }
    txtput.setenabled(true);
    combobox.setenabled(true);
    // 本次游戏结束后移除集合中所有线程
    allobservables.removeall(allobservables);
   }
  }
 }

2.线程

 package com.sxt.dice;
 import java.util.list;
 import java.util.observable;
 import java.util.random;
 import javax.swing.icon;
 import javax.swing.jlabel;
 public class iconthread extends observable implements runnable {
  /**
  * 运用观察者模式,将子线程作为被观察对象,一旦子线程运行完,发生改变,通知观察者
  */
  jlabel lab;
  random random = new random();
  list<icon> imgs;
  public iconthread(jlabel lab, list<icon> imgs) {
   this.lab = lab;
   this.imgs = imgs;
  }
  @override
  public void run() {
   //设置每颗骰子转动次
   int count = ;
   while (count > ) {
    //获取一个随机数[~)
    int index = random.nextint();
    //从imgs集合中取相应图片放入lab中
    lab.seticon(imgs.get(index));
    count--;
    try {
     thread.sleep();
    } catch (interruptedexception e) {
     // todo auto-generated catch block
     e.printstacktrace();
    }
   }
   this.setchanged();// 子线程运行完,发生改变
   this.notifyobservers();// 通知观察者
  }
 }

以上所述就是关于java编写掷骰子游戏的全部内容,希望大家喜欢。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网