首页 > 编程 > Java > 正文

Java编写掷骰子游戏

2019-11-26 14:48:39
字体:
来源:转载
供稿:网友

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

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

题目要求:《掷骰子》窗体小游戏,在该游戏中,玩家初始拥有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编写掷骰子游戏的全部内容,希望大家喜欢。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表