新建一个项目,然后在src里面建一个MyGame.java文件,
把代码粘到刚才新建的MyGame.java,
然后把两张图放到src下,就行了
一、代码
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.*;public class MyGame {static UIFrame uiFrame;//主界面static playGame playgame;//正式游戏开始界面public static void main(String[] args) {uiFrame = new UIFrame("打字游戏");playgame = new playGame();}/*游戏主界面*/static class UIFrame extends JFrame {int width = 500;int height = 700;Font X = new Font("方正舒体", Font.PLAIN, 30);JLabel playjb = new JLabel("开始游戏");JLabel rulejb = new JLabel("规则");JLabel exitjb = new JLabel("退出游戏");JFrame f1 = new JFrame("规则");/*主界面设置*/public UIFrame(String text) {super(text);this.setLayout(null);this.setSize(width, height);this.setLocationRelativeTo(null);this.setResizable(false);this.getLayeredPane().setLayout(null);JPanel imgPanel = (JPanel) this.getContentPane();imgPanel.setOpaque(false);imgPanel.setBounds(0, 0, width, height);imgPanel.setLayout(null);ImageIcon icon = new ImageIcon("src/bg.jpg");JLabel label = new JLabel(icon);label.setBounds(0, 0, this.getWidth(), this.getHeight());icon.setImage(icon.getImage().getScaledInstance(label.getWidth(), label.getHeight(), Image.SCALE_DEFAULT));this.getLayeredPane().add(label, Integer.valueOf(Integer.MIN_VALUE));Title title = new Title();//新建一个标题对象this.add(title);//往窗口中加入标题面板Thread t = new Thread(title);//将标题面板加入一个线程t.start();//启动线程,实现标题面板下落buildButton();add_JB_Listener();setruleJF();this.setVisible(true);}/*设置按钮规格*/public void buildButton() {playjb.setForeground(Color.red);rulejb.setForeground(Color.red);exitjb.setForeground(Color.red);playjb.setFont(X);rulejb.setFont(X);exitjb.setFont(X);playjb.setBounds(width / 3, height * 2 / 6, width / 3, 50);rulejb.setBounds(width / 3, height * 3 / 6, width / 3, 50);exitjb.setBounds(width / 3, height * 4 / 6, width / 3, 50);playjb.setHorizontalAlignment(JLabel.CENTER);rulejb.setHorizontalAlignment(JLabel.CENTER);exitjb.setHorizontalAlignment(JLabel.CENTER);this.add(playjb);this.add(rulejb);this.add(exitjb);}/*设置规则窗口*/public void setruleJF(){JLabel text1 = new JLabel("<html><body>"+"基本规则:点击开始游戏后可以选择生命值,确认后游戏正式开始游戏开始后会自动下落四个三位"+"<br>"+" "+"数,在输入框中输入其中之一会自动消除这个三位数," +"得分增加,并产生新数字,当数字"+"<br>"+" "+"掉落到屏幕底部时生命值减一,生命值为0游戏结束。(PS:在输入框中输入空格游戏暂"+"<br>"+" "+"停,输入任意数字则继续)" +"<br>"+"<br>"+"难度介绍:游戏难度会随着得分的增加而自动增加,也可使用滑块自己调整数字下落难度等级。"+"<br>"+"<br>"+"闪烁模式:游戏开始后可以点击开始闪烁按钮来开始闪烁模式,此时数字会隔一段时间消失再出现。"+"<br>"+"<br>"+"好好享受吧!"+"</body></html>");text1.setVerticalAlignment(JLabel.NORTH);//使其文本位于JLabel顶部text1.setFont(new Font("宋体", Font.PLAIN, 20));f1.add(text1);//f1为显示规则的窗口f1.setResizable(false);f1.setSize(2 * width - 100, height / 2);f1.setLocationRelativeTo(null);}/*按钮添加监听器*/public void add_JB_Listener() {playjb.addMouseListener(new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {setVisible(false);Chooselife chooselife = new Chooselife();}@Overridepublic void mouseEntered(MouseEvent e) {playjb.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.LIGHT_GRAY));}@Overridepublic void mouseExited(MouseEvent e) {playjb.setBorder(null);}});rulejb.addMouseListener(new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {f1.setVisible(true);}public void mouseEntered(MouseEvent e) {rulejb.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.LIGHT_GRAY));}@Overridepublic void mouseExited(MouseEvent e) {rulejb.setBorder(null);}});exitjb.addMouseListener(new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {System.exit(0);}public void mouseEntered(MouseEvent e) {exitjb.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.LIGHT_GRAY));}@Overridepublic void mouseExited(MouseEvent e) {exitjb.setBorder(null);}});}}/*选择生命界面*/static class Chooselife extends JFrame {static Boolean gamePlayflag = false;//第一次开始游戏则为false,否则为true,Chooselife() {setTitle("选择生命值");setAlwaysOnTop(true);//置于顶部setLayout(null);setSize(300, 100);setLocationRelativeTo(null);setResizable(false);setBotton();//设按钮setVisible(true);}/*设置按钮*/void setBotton() {ButtonGroup lives = new ButtonGroup();//新建按钮组实现互斥JRadioButton one = new JRadioButton("1", true);//按钮默认选择1JRadioButton two = new JRadioButton("2", false);JRadioButton three = new JRadioButton("3", false);lives.add(one);//按钮添加进按钮组lives.add(two);lives.add(three);JPanel chooselifejp = new JPanel();chooselifejp.setBounds(0, 0, getWidth(), getHeight() - 60);chooselifejp.add(one);//按钮添加进JPanelchooselifejp.add(two);chooselifejp.add(three);add(chooselifejp);//JPanel添加到JFrameJButton play = new JButton("开始");play.setBounds(getWidth() / 3 + 10, chooselifejp.getHeight(), 70, 25);add(play);/*给开始按钮添加监听器,设置选中的生命值*/play.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {if (one.isSelected()) {playgame.life = 1;//开始游戏后将生命值设成1} else if (two.isSelected()) {playgame.life = 2;} else {playgame.life = 3;}/*后面实现重玩再讲*/playgame.templife =playgame.life;//为实现重玩功能而新建的临时变量templife,用来保存当前的生命值。if (!gamePlayflag) {//第一次游戏playgame.begin();//调用begin函数来新设置一些变量和线程、控件规格gamePlayflag = true;} else {playgame.injp.replay_func();//选择完生命值之后,使用第一次游戏使用的那些变量、线程、控件,// 然后用重玩的函数功能重置一些变量即可实现开始新一轮游戏的效果playgame.PlayJF.setVisible(true);//显示正式游戏界面}dispose();}});}}static class playGame {static int life=1;static int templife=1;static int width = 500;static int height = 700;static int N = 4;//数字列数static int x[] = new int[N];static int y[] = new int[N];static String[] num = new String[N];JFrame PlayJF = new JFrame("打字游戏");Image lifeicon = Toolkit.getDefaultToolkit().getImage("src/life.jpg");static int difficult_level = 1;//下落难度static int mindifficult_level = 1;//最小下落难度static int shanshuo_level = 1;//闪烁难度Boolean terminateflag = false;Boolean beginflag = false;Boolean shanshuoflag = false;Boolean zantingshanshuoflag = false;//闪烁且暂停Boolean Gameoverflag = false;JTextField in = new JTextField(3);JLabel showtext = new JLabel();int score;int count = 3;int allcount;int correctcount;int lianjicount;Boolean lianjiflag = false;MyPanel mp;messageJP injp;/*第一次开始游戏调用*/public void begin() {getrandnum();PlayJF.setSize(width, height);mp = new MyPanel();injp = new messageJP();PlayJF.setResizable(false);PlayJF.setLocationRelativeTo(null);PlayJF.getLayeredPane().setLayout(null);JPanel imgPanel = (JPanel) PlayJF.getContentPane();imgPanel.setOpaque(false);imgPanel.setBounds(0, 0, width, height);imgPanel.setLayout(null);ImageIcon icon = new ImageIcon("src/bg.jpg");JLabel label = new JLabel(icon);label.setBounds(0, 0, PlayJF.getWidth(), PlayJF.getHeight());icon.setImage(icon.getImage().getScaledInstance(label.getWidth(), label.getHeight(), Image.SCALE_DEFAULT));PlayJF.getLayeredPane().add(label, Integer.valueOf(Integer.MIN_VALUE));PlayJF.getContentPane().add(mp);PlayJF.getContentPane().add(injp, Integer.valueOf(Integer.MAX_VALUE));Thread t = new Thread(mp);t.start();PlayJF.setVisible(true);in.requestFocus();}/*产生四个随机三位数*/public static void getrandnum() {int i, j;for (i = 0; i < N; i++) {//生成数字的字符形式,设置初始横纵坐标num[i] = Integer.toString((int) (Math.random() * 900 + 100));//生成100到999之间随机数x[i] = (int) (0.1 * width + i * 0.20 * width);y[i] = 50;}for (i = 0; i < N; i++) {for (j = i + 1; j < N; j++) {while (num[j].charAt(0) == num[i].charAt(0)) {//若数字与前面的数字首位相同,则重新生成该数字num[j] = Integer.toString((int) (Math.random() * 900 + 100));}}}}/*数字下落面板*/class MyPanel extends JPanel implements Runnable {int width = PlayJF.getWidth();int height = 500;long time;//记录时间,用于闪烁功能的实现public MyPanel() {setOpaque(false);setBounds(0, 0, width, height);setBackground(Color.BLACK);}public void paint(Graphics g) {super.paint(g);if (Gameoverflag) {//游戏结束g.setColor(Color.RED);g.setFont(new Font("宋体", Font.BOLD, 35));g.drawString("游戏结束!", width / 3, height / 2);g.drawString("您的分数为"+score,width / 3-15,height/2+35);gameoverwork();} else {if (!beginflag) {//倒计时g.setColor(Color.RED);g.setFont(new Font("宋体", Font.PLAIN, 50));if (count == 0) {g.drawString("Go!", width / 2, height / 2);in.setEditable(true);} else {in.requestFocus();g.drawString(String.valueOf(count), width / 2, height / 2);}} else {//数字开始掉落g.setFont(new Font("宋体", Font.PLAIN, 20));g.setColor(Color.WHITE);for (int i = 0; i < N; i++) {if (shanshuoflag) {//进入闪烁模式if (zantingshanshuoflag == false) {//闪烁模式且不在暂停状态if (time % 3000 < 500 * shanshuo_level == false) {//闪烁:若时间满足条件,则绘出数字,否则不绘出数字g.drawString(num[i], x[i], y[i]);}} else {//闪烁模式且暂停,直接显示数字g.drawString(num[i], x[i], y[i]);}} else {//不是闪烁则正常绘出数字g.drawString(num[i], x[i], y[i]);}}if (terminateflag) {//画出暂停字样g.setColor(Color.BLUE);g.setFont(new Font("宋体", Font.BOLD, 30));g.drawString("暂停中...", width / 4, height / 2);g.setFont(new Font("宋体", Font.BOLD, 20));g.drawString("输入任意数字继续...", width / 4, height / 2 + 30);if (shanshuoflag) {zantingshanshuoflag = true;//如果是暂停而且是闪烁状态,}} else {//不暂停,每次数字纵坐标加一,掉落到底部生命值减一,重置所有数字纵坐标。for (int i = 0; i < N; i++) {y[i] = y[i] + 1;if (y[i] > getHeight()&&templife>0) {templife--;for(int j=0;j<N;j++){y[j]=50;}}}if(templife==0){//游戏结束Gameoverflag=true;}}g.setColor(Color.WHITE);g.setFont(new Font("宋体", Font.PLAIN, 20));g.drawString("得分:" + score, 2, 20);g.drawString("生命值:", 270, 20);for (int i = 0; i < templife; i++) {g.drawImage(lifeicon, 350 + i * 21, 1, 20, 20, this);//在指定位置根据生命值绘出爱心桃}}}}/*清空输入框和无法输入*/public void gameoverwork(){in.setText("");in.setEditable(false);}@Overridepublic void run() {long startTime = System.currentTimeMillis();//记录游戏开始时间while (true) {/*倒计时*/if (!beginflag) {in.setEditable(false);repaint();try {Thread.sleep(1000);count--;if (count == -1) {beginflag = true;}} catch (InterruptedException e) {e.printStackTrace();}} else {//绘出数字repaint();try {Thread.sleep(40 - difficult_level * 5);} catch (InterruptedException e) {e.printStackTrace();}long endTime = System.currentTimeMillis();time = endTime - startTime;//记录从开始到执行这次重绘函数后总共经历的时间}}}}/*功能面板类*/class messageJP extends JPanel {JSlider difficultJS = new JSlider(1, 5, 1);//游戏难度滑块JLabel difficultJL = new JLabel();//显示“当前游戏难度为多少”的字样JSlider shanshuo_levelJS = new JSlider(1, 3, 1);//闪烁难度的滑块JLabel shanshuo_levelJL = new JLabel();//显示“闪烁难度等级”的字样JLabel termiJL = new JLabel();//显示“输入空格暂停”字样JButton replay = new JButton("重玩");JButton gotomain = new JButton("返回主界面");JButton shanshuoJB = new JButton("开启闪烁");String input;messageJP() {setLayout(null);setBounds(0, mp.getHeight(), PlayJF.getWidth(), PlayJF.getHeight() - mp.getHeight());set_difficultJS();set_replay();set_gotomain();set_shanshuoJB();set_in();set_termiJL();set_showtext();}/*设置输入框的一些功能*/void set_in() {in.setCaretPosition(in.getText().length());in.setBounds(width / 4, getHeight() - 70, width / 3, 30);in.setFont(new Font("宋体", Font.PLAIN, 15));in.addKeyListener(new KeyAdapter() {public void keyTyped(KeyEvent e) {System.out.println("KeyTyped:"+in.getText());}public void keyPressed(KeyEvent e) {super.keyPressed(e);System.out.println("KeyPressed:"+in.getText());if (e.getKeyChar() == KeyEvent.VK_SPACE) {//判断输入是否为空格if (terminateflag) {terminateflag = false;} else {terminateflag = true;}}}public void keyReleased(KeyEvent e) {System.out.println("KeyReleased:"+in.getText());String s = in.getText().replaceAll(" ", "");in.setText(s);if(terminateflag==true&&e.getKeyChar()!=KeyEvent.VK_SPACE){terminateflag = false;}if (in.getText().length() >= 3) {allcount++;input = in.getText();in.setText("");lianjiflag = false;for (int i = 0; i < N; i++) {if (input.equals(num[i])) {y[i] = 50;score += 10 * difficult_level;correctcount++;lianjiflag = true;if (mindifficult_level < 5 && score > 200) {mindifficult_level = score / 100;difficultJS.setMinimum(mindifficult_level);//设置滑块的最小难度if (difficult_level < mindifficult_level) {difficult_level = mindifficult_level;//如果当前难度比最小难度低,调整最小难度}difficultJS.setValue(difficult_level);}difficultJL.setText("下落等级:" + difficult_level);num[i] = Integer.toString((int) (Math.random() * 900 + 100));while (true) {for (int j = 0; j < N; j++) {if (num[i].charAt(0) == num[j].charAt(0) && i != j) {num[i] = Integer.toString((int) (Math.random() * 900 + 100));j = -1;}}break;}}}if (lianjiflag) {lianjicount++;} else {lianjicount = 0;}}showtext.setText("<html>输入总次数:" + allcount + "<br/>正确次数:" + correctcount + "<br/>当前连击数:" + lianjicount + " <br/></html>");}});add(in);}/*输入空格暂停字样*/void set_termiJL() {termiJL.setText("输入空格暂停");termiJL.setFont(new Font("宋体", Font.PLAIN, 15));termiJL.setForeground(Color.RED);termiJL.setBounds(width / 4, getHeight() - 95, width / 3, 30);add(termiJL);}/*难度等级滑块*/void set_difficultJS() {difficultJS.setBounds(10, getHeight() - 110, 80, 40);difficultJS.setMajorTickSpacing(1);difficultJS.setSnapToTicks(true);difficultJS.setPaintTicks(true);difficultJS.setPaintLabels(true);difficultJS.addChangeListener(new ChangeListener() {@Overridepublic void stateChanged(ChangeEvent e) {difficult_level = difficultJS.getValue();difficultJL.setText("下落等级:" + difficult_level);}});difficultJL.setBounds(10, getHeight() - 85, 100, 50);difficultJL.setFont(new Font("方正姚体", Font.PLAIN, 15));difficultJL.setText("下落等级:" + difficult_level);add(difficultJL);add(difficultJS, Integer.valueOf(Integer.MIN_VALUE));}/*重玩按钮的功能*/void set_replay() {replay.setBounds(width * 3 / 4 + 10, 0, 100, 50);add(replay);replay.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {replay_func();}});}/*返回主界面功能*/void set_gotomain() {gotomain.setBounds(width * 3 / 4 + 10, 55, 100, 50);add(gotomain);gotomain.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {PlayJF.setVisible(false);uiFrame.setVisible(true);}});}/*闪烁按钮及其功能*/void set_shanshuoJB() {shanshuoJB.setBounds(width * 3 / 4 + 10, 110, 100, 50);shanshuo_levelJS.setBounds(10, 5, 80, 40);shanshuo_levelJS.setSnapToTicks(true);shanshuo_levelJS.setPaintTicks(true);shanshuo_levelJS.setPaintLabels(true);shanshuo_levelJS.setMajorTickSpacing(1);shanshuo_levelJL.setFont(new Font("方正姚体", Font.PLAIN, 15));shanshuo_levelJL.setText("闪烁等级:" + shanshuo_level);shanshuo_levelJL.setBounds(10, 30, 80, 70);shanshuo_levelJS.setVisible(false);shanshuo_levelJL.setVisible(false);add(shanshuoJB);add(shanshuo_levelJS);add(shanshuo_levelJL);shanshuoJB.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {if (shanshuoflag) {//当前模式是闪烁模式shanshuoflag = false;shanshuo_levelJS.setVisible(false);//隐藏闪烁难度调节滑块shanshuo_levelJL.setVisible(false);shanshuoJB.setText("开启闪烁");shanshuo_level = 1;shanshuo_levelJS.setValue(1);} else {shanshuoflag = true;shanshuo_levelJS.setVisible(true);shanshuo_levelJL.setVisible(true);shanshuoJB.setText("关闭闪烁");}}});shanshuo_levelJS.addChangeListener(new ChangeListener() {@Overridepublic void stateChanged(ChangeEvent e) {shanshuo_level = shanshuo_levelJS.getValue();shanshuo_levelJL.setText("闪烁等级:" + shanshuo_level);}});}/*显示一些统计信息*/void set_showtext() {showtext.setFont(new Font("方正姚体", Font.PLAIN, 15));showtext.setBounds(width / 4, 10, getWidth() / 3, getHeight() / 2);showtext.setText("<html>输入总次数:" + allcount + "<br/>正确次数:" + correctcount + "<br/>当前连击数:" + lianjicount + " <br/></html>");showtext.setBorder(BorderFactory.createLineBorder(Color.GRAY));add(showtext);}/*实现重玩功能的函数*/void replay_func() {//就是重置一些变量in.setEditable(true);difficult_level = 1;difficultJS.setMinimum(1);difficultJS.setMaximum(5);difficultJS.setValue(1);templife=life;shanshuo_level = 1;shanshuo_levelJS.setValue(1);shanshuo_levelJS.setVisible(false);shanshuo_levelJL.setVisible(false);terminateflag=false;getrandnum();score = 0;count = 3;lianjicount = 0;allcount = 0;correctcount = 0;in.setText("");showtext.setText("<html>输入总次数:" + allcount + "<br/>正确次数:" + correctcount + "<br/>当前连击数:" + lianjicount + " <br/></html>");lianjiflag = false;shanshuoflag = false;shanshuoJB.setText("开启闪烁");beginflag = false;Gameoverflag = false;in.requestFocus();}}}}/*在一个面板上实现标题自动下落*/
class Title extends JPanel implements Runnable {int width = 500;int height = 250;int N = 4;int[] x = new int[N];//存储标题中的每个字的横坐标int[] y = new int[N];//存储标题中的每个字的纵坐标String[] strs = new String[]{"打", "字", "游", "戏"};Title() {setBounds(0, 0, width, height);//设置面板大小setOpaque(false);//透明setplace();//设置标题每个字初始的横纵坐标}void setplace() {for (int i = 0; i < N; i++) {x[i] = (int) (width * 0.15 + i * 0.2 * width);y[i] = 10;}}@Overridepublic void paint(Graphics g) {super.paint(g);g.setColor(Color.RED);//设置画笔颜色为红g.setFont(new Font("方正姚体", Font.PLAIN, 50));//设置画笔字体for (int i = 0; i < N; i++) {g.drawString(strs[i], x[i], y[i]);//在指定位置画出标题的字y[i]++;//标题的字纵坐标下移一像素if (y[i] > height - 50) {//如果到达height-50,则保持在那个位置y[i] = height - 50;}}}@Overridepublic void run() {while (true) {try {Thread.sleep(10);//实现每10毫秒重绘一次} catch (InterruptedException e) {e.printStackTrace();}repaint();//调用重绘函数}}
}
二、图片
- bg.jpg
- life.jpg