掷骰子游戏窗体实现--Java初级小项目

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

掷骰子

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

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

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

1//3个线程控制3颗骰子2Thread t1 =newThread();3Thread t2 =newThread();4Thread t3 =newThread();5//启动3个线程6t1.start();7t2.start();8t3.start();9//将3个线程加入主线程10t1.join();11t2.join();12t3.join();

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

代码如下:

publicvoidactionPerformed(ActionEvent e) {newThread(newRunnable() {

@Overridepublicvoidrun() {//将外部线程类转移到窗体内部}

}).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.窗体

1packagecom.sxt.dice;23importjava.awt.Color;45publicclassDiceFrameextendsJFrameimplementsActionListener, Observer {67/**8* 《掷骰子》控制台小游戏,在该游戏中,玩家初始拥有1000的金钱,每次输入押大还是押小,9* 以及下注金额,随机3个骰子的点数,如果3个骰子的总点数小于等于9,则开小,否则开大,10* 然后判断玩家是否押对,如果未押对则扣除下注金额,如果押对则奖励和玩家下注金额相同的金钱。11*12* 运用观察者模式 3个子线程分别控制3个骰子,都已经结束时,通知观察者窗体,窗体观察到所有子线程都结束时,计算游戏结果13*14*/1516PRivatestaticfinallongserialVersionUID = 1L;17privateJTextField txtPut;18privateJButton btnStart;19privateJLabel labResult;20privateJComboBox<String>comboBox;21privateJLabel labBigOrSmall;22privateJLabel labPut;23privateJLabel labSumMoney;24privateJLabel labDice3;25privateJLabel labDice2;26privateJLabel labDice1;27privateJLabel labSum;28privateJLabel labMes;2930privatestaticList<Icon> imgs =newArrayList<Icon>();3132publicstaticvoidmain(String[] args) {33newDiceFrame();34}3536publicDiceFrame() {37this.setLocationRelativeTo(null);38this.setBounds(200, 50, 380, 297);39this.setDefaultCloSEOperation(JFrame.DISPOSE_ON_CLOSE);40getContentPane().setLayout(null);41this.setResizable(false);4243labDice1 =newJLabel("");44labDice1.setIcon(newImageIcon("img/dices.jpg"));45labDice1.setBounds(30, 50, 96, 96);46getContentPane().add(labDice1);4748labSum =newJLabel("\u5269\u4F59\u91D1\u989D\uFF1A");49labSum.setBounds(10, 10, 69, 23);50getContentPane().add(labSum);5152labDice2 =newJLabel("");53labDice2.setIcon(newImageIcon("img/dices.jpg"));54labDice2.setBounds(136, 50, 96, 96);55getContentPane().add(labDice2);5657labDice3 =newJLabel("");58labDice3.setIcon(newImageIcon("img/dices.jpg"));59labDice3.setBounds(242, 50, 96, 96);60getContentPane().add(labDice3);6162labSumMoney =newJLabel("3000");63labSumMoney.setForeground(Color.red);64labSumMoney.setBounds(86, 10, 63, 23);65getContentPane().add(labSumMoney);6667labPut =newJLabel("\u672C\u6B21\u4E0B\u6CE8\uFF1A");68labPut.setToolTipText("0.0");69labPut.setBounds(10, 199, 69, 23);70getContentPane().add(labPut);7172txtPut =newJTextField();73txtPut.setBounds(80, 200, 69, 21);74getContentPane().add(txtPut);75txtPut.setColumns(10);7677labBigOrSmall =newJLabel("\u62BC\uFF1A");78labBigOrSmall.setBounds(45, 232, 34, 27);79getContentPane().add(labBigOrSmall);8081comboBox =newJComboBox<String>();82comboBox.setBounds(80, 234, 69, 23);83getContentPane().add(comboBox);84comboBox.addItem("大");85comboBox.addItem("小");8687labResult =newJLabel("");88labResult.setBounds(136, 156, 126, 27);89getContentPane().add(labResult);9091btnStart =newJButton("START");92btnStart.setBounds(263, 199, 88, 58);93getContentPane().add(btnStart);9495labMes =newJLabel("<html><font size=5 color=red>*</font></html>");96labMes.setBounds(152, 203, 101, 15);97getContentPane().add(labMes);9899this.setVisible(true);100101imgs.add(newImageIcon("img/1.png"));102imgs.add(newImageIcon("img/2.png"));103imgs.add(newImageIcon("img/3.png"));104imgs.add(newImageIcon("img/4.png"));105imgs.add(newImageIcon("img/5.png"));106imgs.add(newImageIcon("img/6.png"));107108btnStart.addActionListener(this);109}110111@Override112publicvoidactionPerformed(ActionEvent e) {113if(e.getSource() ==btnStart) {114115//清除上次游戏的结果116labResult.setText("");117118//获取当前下注金额,用户余额,用户押大还是押小119String txt =txtPut.getText().trim();120String remain =labSumMoney.getText().trim();121122//余额不足,不能开始游戏,提示用户充值123if(Integer.parseInt(remain) <= 0) {124JOptionPane.showMessageDialog(null, "当前余额不足,请充值!");125return;126}127128//下注金额合法性检查129if(txt.length() == 0) {130//提示用户输入131labMes.setText("*请输入下注金额");132labMes.setForeground(Color.RED);133return;134}135//检查用户下注金额是否在有效范围内136if(Integer.parseInt(txt) <= 0137|| Integer.parseInt(txt) >Integer.parseInt(remain)) {138txtPut.setText("");139labMes.setText("下注金额应在0~" + remain + "之间");140return;141}142143//游戏开始后相关项不可更改144txtPut.setEnabled(false);145labMes.setText("");146comboBox.setEnabled(false);147148//在主线程上开t1,t2,t3 3个子线程149Thread t1 =newThread() {150@Override151publicvoidrun() {152//每个子线程上再开子子线程,控制图标变换153IconThread t11 =newIconThread(labDice1, imgs);154//给t11添加观察者,即当前窗体155t11.addObserver(DiceFrame.this);156newThread(t11).start();157}158};159160Thread t2 =newThread() {161@Override162publicvoidrun() {163IconThread t21 =newIconThread(labDice2, imgs);164t21.addObserver(DiceFrame.this);165newThread(t21).start();166}167};168169Thread t3 =newThread() {170@Override171publicvoidrun() {172IconThread t31 =newIconThread(labDice3, imgs);173t31.addObserver(DiceFrame.this);174newThread(t31).start();175}176};177178t1.start();179t2.start();180t3.start();181}182183}184185/**186* 获取骰子点数和187*188*@paramlab189*@returnsum190*/191privateintresult(JLabel lab) {192//获取当前骰子图片193Icon icon =lab.getIcon();194intsum = 0;195for(inti = 0; i < imgs.size(); i++) {196if(icon.equals(imgs.get(i))) {197sum += (i + 1);198

break;199}200}201returnsum;202}203204//构建所有被观察者的集合205Vector<Observable> allObservables =newVector<Observable>();206207@Override208publicvoidupdate(Observable o, Object arg) {209System.out.println(o + ".................");210//如果集合中不包含当前被观察者,将此被观察者加入集合211if(allObservables.contains(o) ==false) {212allObservables.add(o);213}214215//如果集合中被观察者个数为3,说明3个骰子线程已经全部结束216if(allObservables.size() == 3) {217//获取当前下注金额,用户余额,用户押大还是押小218String txt =txtPut.getText().trim();219String remain =labSumMoney.getText().trim();220String bigOrSmall =comboBox.getSelectedItem().toString();221//获取每个骰子点数222intsum1 =result(labDice1);223intsum2 =result(labDice2);224intsum3 =result(labDice3);225System.out.println(sum1 + "-" + sum2 + "-" +sum3);226intsum = sum1 + sum2 +sum3;227System.out.println(sum);228229if(sum > 9 && "大".equals(bigOrSmall) || sum <= 9230&& "小".equals(bigOrSmall)) {231232//奖励玩家相应金额233remain =String.valueOf(Integer.parseInt(remain)234+Integer.parseInt(txt));235labSumMoney.setText(remain);236237//显示游戏结果238labResult.setText("WIN");239labResult.setForeground(Color.GREEN);240labResult.setFont(newFont("宋体", Font.BOLD, 40));241242}else{243//扣除玩家相应金额244remain =String.valueOf(Integer.parseInt(remain)245-Integer.parseInt(txt));246labSumMoney.setText(remain);247248labResult.setText("FAIL");249labResult.setForeground(Color.red);250labResult.setFont(newFont("宋体", Font.BOLD, 40));251252}253txtPut.setEnabled(true);254comboBox.setEnabled(true);255//本次游戏结束后移除集合中所有线程256allObservables.removeAll(allObservables);257}258}259260}

2.线程

1packagecom.sxt.dice;23importjava.util.List;4importjava.util.Observable;5importjava.util.Random;67importjavax.swing.Icon;8importjavax.swing.JLabel;910publicclassIconThreadextendsObservableimplementsRunnable {11/**12* 运用观察者模式,将子线程作为被观察对象,一旦子线程运行完,发生改变,通知观察者13*/14JLabel lab;1516Random random =newRandom();17List<Icon>imgs;1819publicIconThread(JLabel lab, List<Icon>imgs) {20this.lab =lab;21this.imgs =imgs;2223}2425@Override26publicvoidrun() {27//设置每颗骰子转动30次28intcount = 30;29while(count > 0) {3031//获取一个随机数[0~6)32intindex = random.nextInt(6);33//从imgs集合中取相应图片放入lab中34lab.setIcon(imgs.get(index));35count--;3637try{38Thread.sleep(50);39}catch(InterruptedException e) {40//TODO Auto-generated catch block41e.printStackTrace();42}43}4445this.setChanged();//子线程运行完,发生改变46this.notifyObservers();//通知观察者47}48}

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航