Java编写掷骰子游戏

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

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

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

(0)

相关推荐

  • Java完美实现2048小游戏

    完美地模仿了2048游戏,是根据网友的一个2048改的. Block.java import javax.swing.*; import java.awt.*; public class Block extends JLabel { private int value; public Block() { value = 0;//初始化值为0 setFont(new Font("font", Font.PLAIN, 40));//设定字体 setBackground(Color.gray

  • java使用OGEngine开发2048

    最近有一款2048的游戏非常火,本文将来介绍一下使用OGEngine游戏引擎开发游戏2048. OGEngine引擎是开源的,我们很容易找到,搭建起来也很方便,我们只需在Android工程下添加OGEngine的jar包或者直接引用源码就可以了. 源码下载:http://www.ogengine.com/download/resources.jsp private void initView() { // 游戏背景 AnimatedSprite game_bg = new AnimatedSpr

  • java实现的简单猜数字游戏代码

    本文实例讲述了java实现的简单猜数字游戏代码.分享给大家供大家参考. 具体代码如下: 复制代码 代码如下: import java.util.InputMismatchException; import java.util.Scanner; public class Main {         public static void main(String[] args) {                 // 产生一个随机数                 int number = (in

  • java实现五子棋小游戏

    java实现五子棋小游戏 package Gomoku; import java.awt.Toolkit; import javax.swing.JFrame; public class GomokuFrame extends JFrame { //定义一个操作面板 OperatorPane op=null; public GomokuFrame() { //设置名称 this.setTitle("五子棋"); //设置窗口大小 this.setSize(510,510); //设置窗

  • Java编写迷宫小游戏

    缘起: 去年(大三上学期)比较喜欢写小游戏,于是想试着写个迷宫试一下. 程序效果: 按下空格显示路径: 思考过程: 迷宫由一个一个格子组成,要求从入口到出口只有一条路径. 想了一下各种数据结构,似乎树是比较合适的,从根节点到每一个子节点都只有一条路径.假设入口是根节点,出口是树中某个子节点,那么,从根节点到该子节点的路径肯定是唯一的. 所以如果能构造一棵树把所有的格子都覆盖到,也就能够做出一个迷宫了. 另外还要求树的父节点和子节点必须是界面上相邻的格子. 在界面显示时,父节点和子节点之间共用的边

  • Java基于swing实现的弹球游戏代码

    本文实例讲述了Java基于swing实现的弹球游戏代码.分享给大家供大家参考. 主要功能代码如下: 复制代码 代码如下: package Game; import java.awt.Graphics; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Random;

  • java编写贪吃蛇小游戏

    废话不多说,直接奉上代码: Frame.java package snake; import java.awt.Graphics; import java.awt.Menu; import java.awt.MenuBar; import java.awt.MenuItem; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import

  • java基于swing实现的五子棋游戏代码

    本文实例讲述了java基于swing实现的五子棋游戏代码.分享给大家供大家参考. 主要功能代码如下: 复制代码 代码如下: import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Main extends JFrame implements ActionListener{         private static final long serialVersionUID = 1L;      

  • Java制作智能拼图游戏原理及代码

    今天突发奇想,想做一个智能拼图游戏来给哄女友. 需要实现这些功能 第一图片自定义 第二宫格自定义,当然我一开始就想的是3*3 4*4 5*5,没有使用3*5这样的宫格. 第三要实现自动拼图的功能,相信大家知道女人耍游戏都不是很厉害,所以这个自动拼图功能得有. 其他什么暂停.排行就不写了! 现在重点问题出来了 要实现自动拼图功能似乎要求有点高哦!计算机有可不能像人一样只能: 先追究下本质 拼图游戏其实就是排列问题: 排列有这么一个定义:在一个1,2,...,n的排列中,如果一对数的前后位置与大小顺

  • java版实现2048游戏功能

    本文实例为大家分享了java实现2048游戏功能的具体代码,供大家参考,具体内容如下 功能要求:2048的基本界面,能够实现2048的游戏功能. 总思路:两个类:Game和GameListener. Game负责界面的实现和paint方法的重写 GameListener负责实现键盘和鼠标事件的处理.移动方法,相加方法,输赢判断和随机数的出现都要在键盘监听的方法中实现. 实现分析:要实现2048游戏,首先需要考虑2048都有些什么? 界面实现: 2048的游戏界面很简单,就是一些方格和数字.要实现

随机推荐