类似金山打字的窗口打字游戏代码版
本游戏兴之所起就写了几个夜,不咋地,都是自己太辣鸡
四个类,什么封装、对象也没用到,实现东西不多,代码也很少
1.主程序测试实现类:DemoTest
import javax.swing.*;
public class DemoTest {
public static void main(String[] args) {
//加入 while (),使程序可以失败后再次开始,不建议在这里面加,程序会很乱
while (true) {
if (MyPanel.rebuild == 0) {
MyPanel.rebuild = 1;
//创建一个窗口
JFrame frame = new JFrame();
//加个窗体名字
frame.setTitle("打字游戏");
//设置窗口的大小(先设置大小,再写居中操作,否则会出现右偏移)
frame.setSize(1000, 800);
//实现窗口居中
frame.setLocationRelativeTo(null);
//新增,点击叉号强制关闭程序,因为会有线程未结束导致控制台程序一直运行不结束
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//新建画布对象
MyPanel myPanel = new MyPanel();
//将画布对象添加至窗体中
frame.add(myPanel);
//注册键盘事件,在Mypanel中重写方法
frame.addKeyListener(myPanel);
myPanel.addKeyListener(myPanel);
//加入线程,把画布元素放入线程
Thread thread = new Thread(myPanel);
//运行线程
thread.start();
//窗口的可视化
frame.setVisible(true);
}
}
}
}
2.主要方法设计类:MyPanel
import javax.imageio.ImageIO;
import javax.swing.*;
import java.applet.AudioClip;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.text.NumberFormat;
//继承面板类
public class MyPanel extends JPanel implements Runnable, KeyListener {
//新建需要的图像对象
private BufferedImage bg, start_img, gameover;
private AddBackgroundImage ground1;
private AddBackgroundImage ground2;
private AddBackgroundImage ground3;
//设置音乐全局变量,这样引入音乐类不会出现问题,否则不小心搞进线程里面
// 轻则音乐播放异常,重则程序加电脑一起拜拜
private AudioClip audioClip=null;
//添加容器放随机数
private char[] chars=new char[10];
private int[] x=new int[10];
private int[] y=new int[10];
//新增字母颜色容器
Color[] color=new Color[10];
//加入积分器,初始0,成功加分
int score=0;
//加入生命,初始为10,失败结束游戏
int error=10;
//加入键入次数和键入消除成功次数变量
double key1=0;
volatile double key2=0;
//加入键入正确率变量
String errortype=null;
//开启和暂停按钮 以及重新开始游戏按钮
private static boolean open=false;
private static boolean pause=false;
static volatile int rebuild=0;
//重载方法
public MyPanel() {
try {
//引入AudioClip音乐类,添加音乐文件,使用play()方法播放
//因为加载原因,刚开始会有个空白期,文件越大,加载越慢,而且会卡,慎用
audioClip = Addmusic.loadSound("src/music/bgmusic1.mp3");
//音乐播放
audioClip.play();
//这是不进入游戏时的音乐循环
//音乐循环
audioClip.loop();
//加载运动图片
ground1 = new AddBackgroundImage("src/images/ground1.png");
ground2 = new AddBackgroundImage("src/images/ground23.jpg");
ground3 = new AddBackgroundImage("src/images/ground3.jpg");
//加载背景图片
//图片加载方式对于一些ps或者电脑画图出来的图会报异常,加上绝对路径或者把src加上就行.
/* bg=ImageIO.read(new File("images/bg2.png"));*/
//背景会被运动图片覆盖,可以调整放置位置或者不用
bg = ImageIO.read(new File("src/images/start.jpg"));
/*//加载开始图片
start_img=ImageIO.read(new File("images/start2.png"));*/
//加载结束图片
gameover = ImageIO.read(new File("src/images/gameover.png"));
} catch (IOException e) {
e.printStackTrace();
}
//遍历生成随机数十次
for (int i = 0; i < 10; i++) {
chars[i] = (char) (Math.random() * 26 + 97);
x[i] = 10 + (int) (Math.random() * 970);
y[i] = 50 + (int) (Math.random() * 300);
//连接随机颜色方法为每个索引生成随机颜色
color[i] = getrandomColor();
}
}
/*
* 重写print方法添加画板元素*/
@Override
public void paint (Graphics g) {
if (!open) {
super.paint(g);
//在画笔中添加图像 (图像对象,x坐标,y坐标,通知对象)(被运动图像覆盖显示不出来)
g.drawImage(bg, 0, 0, null);
}
//设置条件,错误数大于0可以开始游戏
if (error > 0 && open) {
//看资料说这个就是清除刷新闪烁问题的关键代码
super.paint(g);
//在画笔中添加图像 (图像对象,x坐标,y坐标,通知对象)(被运动图像覆盖显示不出来)
g.drawImage(bg, 0, 0, null);
if (score < 500) {
//加入模式字体颜色背景
mode(g, ground1);
//在窗口绘制成绩
g.drawString("智障模式", 800, 40);
}
if (score >= 500 && score < 1200) {
//加入模式字体颜色背景
mode(g, ground2);
//在窗口绘制成绩
g.drawString("菜鸡模式", 800, 40);
}
if (score >= 1200) {
//加入模式字体颜色背景
mode(g, ground3);
//在窗口绘制成绩
g.drawString("正常模式", 800, 40);
}
//设置积分颜色
g.setColor(Color.red);
//新增成绩显示在屏幕上以及字体和大小
g.setFont(new Font("华文新魏", Font.PLAIN, 20));
//在窗口绘制成绩
g.drawString("你的成绩为:" + score, 10, 20);
g.drawString("你还可以错:" + error + "个", 10, 50);
//设置元素的颜色,(放在前面,要不然第一次生成的字母没颜色) //新增添加随机色,在下面循环里
/*g.setColor(Color.BLUE);*/
for (int i = 0; i < 10; i++) {
//有了索引,就把他放进循环里去
g.setColor(color[i]);
//加一个显示的字母大小
g.setFont(new Font("TimesRoman", Font.PLAIN, 25));
//添加元素 出现的元素,元素的x轴,元素的y轴
// (char)random()*26+97就是转成ascll码是这个随机数的字符
//(int)(Math.random()*1000)生成随机数时候,(随机数小括号括起来,不然强转整形失败,只会是0)
//x,y值加点数放置是因为窗口有边缘.防止超界覆盖
g.drawString(new Character(chars[i]).toString().toUpperCase(), x[i], y[i]);
}
}
if (error <= 0) {
//成绩小于零重绘界面
removeAll();
//设置失败结束背景
g.drawImage(gameover, 0, 0, null);
//设置结束积分颜色
g.setColor(Color.red);
//新增成绩显示在屏幕上以及字体和大小
g.setFont(new Font("TimesRoman", Font.PLAIN, 30));
//在窗口绘制成绩
g.drawString("成绩为" + score + ",输了,败狗", 340, 300);
g.drawString("键入正确率为:"+errortype+"%" , 300, 340);
//错误数为0的时候音乐停止(自己改写时候可以在这里面加一个失败后的音乐)
audioClip.stop();
}
}
//重写线程方法
@Override
public void run () {
//线程运行时也使音乐循环
//音乐循环
audioClip.loop();
//使用synchronized锁实现线程等待和唤醒,安全有保险
synchronized (MyPanel.class) {
//根据成绩大于0循环
while (score >= 0 & score < 500 & error > 0) {
//运动图片在x轴方法中运动
ground1.step1();
for (int i = 0; i < 10; i++) {
//每个y轴默认不断递增1,向下走
y[i] +=1;
//重绘窗口
Rebuild(i);
//加入暂停和开始方法
PauseAndOpen();
}
while (score >= 500 & score <= 1200 && error > 0) {
//运动图片在方法中运动
ground2.step2();
for (int i = 0; i < 10; i++) {
//每个y轴默认不断递增1,向下走
y[i] += 3;
//重绘窗口
Rebuild(i);
//加入暂停和开始方法
PauseAndOpen();
}
}
while (score >= 1200 && error > 0) {
//运动图片在方法中运动
ground3.step2();
for (int i = 0; i < 10; i++) {
//每个y轴默认不断递增1,向下走
y[i] += 5;
//重新生成索引元素的方法
Rebuild(i);
//加入暂停和开始方法
PauseAndOpen();
}
}
}
//待写消除窗口上全部画布信息
}
}
//抽取出来的 重新生成索引元素的方法
private void Rebuild ( int i){
//重绘窗口
repaint();
//窗口超界重新生成
if (y[i] > 780) {
//i索引y轴归零
y[i] = 0;
//i索引重新生成字母
chars[i] = (char) (Math.random() * 26 + 97);
//i索引重新生成x轴,这样可以让他从最顶端出来
x[i] = 10 + (int) (Math.random() * 1000);
/*y[i]=50+(int)(Math.random()*300);*/
//超界就减分
error -= 1;
}
try {
//暂停2秒,生成新的元素,抛出异常
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//抽取出来的 开始暂停方法
private void PauseAndOpen () {
if (pause) {
try {
MyPanel.class.wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (!pause) {
synchronized (MyPanel.class) {
MyPanel.class.notifyAll();
}
}
}
//抽取出来的 加入字体颜色背景的方法
private void mode (Graphics g, AddBackgroundImage ground){
g.drawImage(ground.image, ground.x, ground.y, null);
g.setColor(Color.blue);
//新增显示在屏幕上以及字体和大小
g.setFont(new Font("华文新魏", Font.PLAIN, 30));
}
//键盘录入 e.getKeyChar()就是你按得键的值
@Override
public void keyTyped (KeyEvent e){
//获取输入的键值
char keyChar = e.getKeyChar();
//只要键入就增加变量
if (keyChar !=0&&keyChar!=32) {
key1++;
System.out.println("键入次数"+key1);
}
//存储最下面字母的值,避免出现一次消除完画布上相同字母
int below = -1;
//存储最下面字母索引
int belowindex = -1;
//遍历复制一份
for (int i = 0; i < 10; i++) {
//如果输入的值等于生成的字母
if (keyChar == chars[i]) {
//y[i]初始必大于-1;获取值和索引
if (y[i] > below) {
below = y[i];
belowindex = i;
}
}
}
//根据belowindex,如果匹配刷新最下面元素
if (belowindex != -1) {
//最下面i索引y轴归零
y[belowindex] = 0;
//最下面i索引重新生成字母
chars[belowindex] = (char) (Math.random() * 26 + 97);
//最下面i索引消除,重新生成x轴从最上面落下
x[belowindex] = 10 + (int) (Math.random() * 1000);
//y轴用不到,如果想要直接在屏幕上随机生成,不是最上面落下可以生成的y轴
/* y[i] = 50 + (int) (Math.random() * 300);*/
//成功就加分
score += 20;
//键入成功变量
key2++;
System.out.println("键入成功次数"+key2);
}
//这个是键入的和键入正确的一个对比,判定键入正确率,看是不是乱敲
if ((key1+key2)!=0){
// 创建一个数值格式化对象
NumberFormat numberFormat = NumberFormat.getInstance();
// 设置精确到小数点后2位
numberFormat.setMaximumFractionDigits(2);
errortype = numberFormat.format((key2/key1 )* 100.00);
}else {
errortype="为什么打开不玩,渣男 0";
}
}
@Override
public void keyPressed (KeyEvent e){
//键盘按压事件,触发开始暂停
int action = e.getKeyCode();
switch (action) {
case 32:
//32,码为空格键
open = (!open);
System.out.println("open" + open);
break;
//10,码为enter键
case 10:
pause = (!pause);
System.out.println("passe" + pause);
break;
//16,码为esc退出键
case 27:
rebuild=0;
System.out.println("重置键"+rebuild);
}
}
@Override
public void keyReleased (KeyEvent e){
}
//添加一个生成随机r,g,b三原色的方法,必须是静态的,其他方法可调用,返回值为color类型
public static Color getrandomColor () {
//r,g,b三原色范围都是在255以内;
int r, g, b;
//取155之内,因为色值越小颜色越深,区别于背景
r = (int) (Math.random() *155);
g = (int) (Math.random() * 155);
b = (int) (Math.random() * 155);
Color color = new Color(r, g, b);
return color;
}
}
3.背景图片移动类(还不如放第二个里面呢,多余):AddBackgroundImage
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class AddBackgroundImage{
//加载图像的对象
BufferedImage image;
int x;
int y;
public AddBackgroundImage (String file){
//定义x,y轴起始方向
x=0;
y=0;
//读取图像
try {
image= ImageIO.read(new File(file));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//写地面运动的方法,x轴移动
public void step1(){
x--;
//为了保证地面重复运动我们增加判断,因为我的背景图长2000像素,减去占用的1000窗口
//所以-1000重置刚好接上
if (x==-1000) {
x=0;
}
}
//写地面运动的方法,y轴移动
public void step2(){
y--;
//y轴-800重置刚好接上
if (y==-800) {
y=0;
}
}
}
4.背景音乐类(同3所述):Addmusic
import javax.swing.*;
import java.applet.AudioClip;
import java.net.MalformedURLException;
import java.net.URL;
public class Addmusic {
//创建静态返回值为AudioClip音乐类的方法
public static AudioClip loadSound(String filename) {
//设置播放地址是URl形式
URL url = null;
try {
url = new URL("file:" + filename);
}
catch (MalformedURLException e) {}
//return一下AudioClip音乐类等待调用,可传输播放的格式mp3,wav都可以
return JApplet.newAudioClip(url);
}
}