Java小游戏:恐龙快跑(Running Dinosaur)

一、前言

用Java写一个小游戏,按空格键跳跃,躲避障碍,可调整速度,可关闭背景音乐,可查看成绩。
Java小游戏:恐龙快跑(Running Dinosaur)_第1张图片
Java小游戏:恐龙快跑(Running Dinosaur)_第2张图片

二、结构

图一:
Java小游戏:恐龙快跑(Running Dinosaur)_第3张图片
图二:
Java小游戏:恐龙快跑(Running Dinosaur)_第4张图片

三、代码

1.启动main

package lyrics.main;

import java.awt.EventQueue;

import org.apache.log4j.Logger;

import lyrics.ui.MainFrameUI;

/**
 * StartGame 
 * 
 * @author lyrics
 * @since 2020/07/05
 */
public class StartGame {
	private final static Logger log = Logger.getLogger(StartGame.class);

	public static void main(String[] args) {
		log.info("The running dinosaur is Starting......");
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					MainFrameUI.getInstance();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

}

2.UI界面

2.1 主界面 MainFrameUI

package lyrics.ui;

import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import java.awt.BorderLayout;
import java.awt.Container;
import javax.swing.JTextArea;

import lyrics.service.FreshService;
import lyrics.service.SoundSevice;
/**
 * MainFrameUI
 * 
 * @author lyrics
 * @since 2020/07/05
 */
public class MainFrameUI extends JFrame{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static JTextArea txtrWelcomToPlay;
	private static MainFrameUI instance = new MainFrameUI();
	public static MainFrameUI getInstance() {
		return instance;
	}

	/**
	 * Create the application.
	 */
	private MainFrameUI() {
		initFrame();
		initMenu();
		initGamePanel();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initFrame() {
		setTitle("Running Dinosaur");
		setBounds(0, 0, 800, 400);
		getContentPane().setLayout(new BorderLayout(0, 0));
		setResizable(false);
		setVisible(true);
		setLocationRelativeTo(null);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
	}
	private void initMenu() {
		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		JMenu mnGame = new JMenu("Game");
		menuBar.add(mnGame);
		JMenuItem mntmNew = new JMenuItem("New");
		mnGame.add(mntmNew);
		JMenuItem mntmScore = new JMenuItem("Score");
		mnGame.add(mntmScore);
		
		JMenuItem mntmGrade = new JMenuItem("Grade");
		mnGame.add(mntmGrade);
		JMenu mnMusic = new JMenu("Music");
		mnGame.add(mnMusic);
		JMenuItem mntmSilent = new JMenuItem("Silent");
		mnMusic.add(mntmSilent);
		JMenuItem mntmPlay = new JMenuItem("Play");
		mnMusic.add(mntmPlay);
		mntmNew.addActionListener(event -> {
			initGamePanel();
		});
		mntmGrade.addActionListener(event -> {
			FreshService.FRESH_TIME +=10;
			if(FreshService.FRESH_TIME>50){
				FreshService.FRESH_TIME = 10;
			}
		});
		mntmScore.addActionListener(event -> {
			new ScoreUI().setLocationRelativeTo(MainFrameUI.instance);;
		});
		mntmSilent.addActionListener(event -> {
			if(!SoundSevice.isSilent()) {
				SoundSevice.stopBackGroundMusic();
				SoundSevice.setSilent(true);
			}
		});
		mntmPlay.addActionListener(event -> {
			if(SoundSevice.isSilent()) {
				SoundSevice.setSilent(false);
				SoundSevice.playBackGroundMusic();
			}
		});
	}
	public void initGamePanel() {
		Container contentPane= getContentPane();
		contentPane.removeAll();
		GamePanel gamePanel = new GamePanel();
		contentPane.add(gamePanel, BorderLayout.CENTER);
		
		txtrWelcomToPlay= new JTextArea();
		txtrWelcomToPlay.setEnabled(false);
		txtrWelcomToPlay.setLineWrap(true);
		txtrWelcomToPlay.setText("Welcom to play running dinosaur!!!!\r\n");
		getContentPane().add(txtrWelcomToPlay, BorderLayout.SOUTH);
		contentPane.validate();
	}
}

2.2 分数界面

package lyrics.ui;

import java.awt.BorderLayout;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

import lyrics.service.ScoreService;
import javax.swing.UIManager;
import javax.swing.JLabel;
import java.awt.Font;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.Color;

/**
 * ScoreUI 
 * 
 * @author lyrics
 * @since 2020/07/08
 */
public class ScoreUI extends JDialog {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private final JPanel contentPanel = new JPanel();
	private JLabel lblFirst;
	/**
	 * Create the dialog.
	 */
	public ScoreUI() {
		setTitle("Score");
		setBounds(100, 100, 219, 300);
		setVisible(true);
		setModal(true);
		setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
		int scores[] = ScoreService.getScores();
		getContentPane().setLayout(new BorderLayout());
		contentPanel.setBackground(UIManager.getColor("window"));
		contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
		getContentPane().add(contentPanel, BorderLayout.CENTER);
		contentPanel.setLayout(null);

		JLabel lblThird = new JLabel("The Third: ");
		lblThird.setBounds(28, 177, 60, 18);
		contentPanel.add(lblThird);

		JLabel lblRankingList = new JLabel("Ranking List");
		lblRankingList.setBounds(41, 28, 118, 29);
		lblRankingList.setForeground(new Color(255, 0, 0));
		lblRankingList.setFont(new Font("Dialog", Font.BOLD, 20));
		contentPanel.add(lblRankingList);	
		
		lblFirst = new JLabel("The First: ");
		lblFirst.setBounds(28, 85, 60, 18);
		contentPanel.add(lblFirst);
		
		JLabel lblSecond = new JLabel("The Second: ");
		lblSecond.setBounds(28, 131, 73, 18);
		contentPanel.add(lblSecond);
		
		JLabel lblScore1 = new JLabel(scores[2]+"scores");
		lblScore1.setBounds(116, 85, 73, 18);
		contentPanel.add(lblScore1);
		
		JLabel lblScore2 = new JLabel(scores[1]+"scores");
		lblScore2.setBounds(116, 131, 73, 18);
		contentPanel.add(lblScore2);
		
		JLabel lblScore3 = new JLabel(scores[0]+"scores");
		lblScore3.setBounds(116, 177, 73, 18);
		contentPanel.add(lblScore3);

		JPanel buttonPane = new JPanel();
		getContentPane().add(buttonPane, BorderLayout.SOUTH);
		buttonPane.setLayout(new BorderLayout(0, 0));
	
		JButton okButton = new JButton("restart game");
		okButton.setActionCommand("OK");
		okButton.addActionListener(event -> {
			  dispose();// 销毁对话框
		});
		
		buttonPane.add(okButton);
		getRootPane().setDefaultButton(okButton);
		WindowAdapter windowAdapter = new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				MainFrameUI.getInstance().initGamePanel();
			}
		}; 
		this.addWindowListener(windowAdapter);
	}
}

2.3 GamePanel

package lyrics.ui;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import javax.swing.JPanel;

import org.apache.log4j.Logger;

import lyrics.image.BackgroundImage;
import lyrics.modle.DinosaurModle;
import lyrics.modle.ObstacleModle;
import lyrics.service.FreshService;
import lyrics.service.ScoreService;
import lyrics.service.SoundSevice;
/**
 * GamePanel
 * 
 * @author lyrics
 * @since 2020/07/06
 */
public class GamePanel extends JPanel{
	private final static Logger log = Logger.getLogger(GamePanel.class);
	private static final int ADD_OBSTACLE_TIME = FreshService.FRESH_TIME*40;
	private static final long serialVersionUID = 1L;
	private BufferedImage image;// 主图片
	private BackgroundImage background;
	private Graphics2D g2;
	private ArrayList<ObstacleModle> obstacleList = new ArrayList<ObstacleModle>();
	private int addObstacleTimer = 0;
	private Thread freshService;
	private DinosaurModle dinosaurModle;
	private boolean finish = false;// 游戏结束标志
	
	private int scoreTimer = 0;
	private int score = 0;

    public GamePanel() {
    	this.setFocusable(true);
        // 主图片采用宽800高300的彩色图片
        image = new BufferedImage(800, 300, BufferedImage.TYPE_INT_BGR);
        g2 = image.createGraphics();// 获取主图片绘图对象
        background = new BackgroundImage();// 初始化滚动背景
        dinosaurModle = new DinosaurModle();
        obstacleList.add(new ObstacleModle());
        keyControl();
        SoundSevice.playBackGroundMusic();
		freshService = new FreshService(this);
		freshService.start();
    }

    /**
     * 绘制主图片
     */
    private void paintImage() {
        background.roll();// 背景图片开始滚动
        g2.drawImage(background.image, 0, 0, this);// 绘制滚动背景
        dinosaurModle.move();
        
        if(addObstacleTimer >= 4000-ADD_OBSTACLE_TIME) {
        	 obstacleList.add(new ObstacleModle());
        	 addObstacleTimer=0;
        }
        addObstacleTimer +=FreshService.FRESH_TIME;
        for(ObstacleModle ob: obstacleList) {
        	if(ob.isLive()) {
        	ob.move();
            g2.drawImage(ob.image, ob.x, ob.y, this);// 绘制障碍 
            if (ob.getBounds().intersects(dinosaurModle.getFootBounds())
                    || ob.getBounds().intersects(dinosaurModle.getHeadBounds())) {
                SoundSevice.playHitMusic();// 播放撞击声音
                gameOver();// 游戏结束
            }
        	}else {
        		obstacleList.remove(ob);
        	}
        }
        if (scoreTimer >= 500) {// 每过500毫秒
            score += 10;// 加十分
            scoreTimer = 0;// 重新计时
            log.info("score: "+score);
        }
        scoreTimer +=FreshService.FRESH_TIME;
        g2.drawImage(dinosaurModle.image, dinosaurModle.x, dinosaurModle.y, this);// 绘制恐龙
    }
    /**
     * 游戏是否结束
     * 
     * @return
     */
    public boolean isFinish() {
        return finish;
    }
    private void gameOver() {
    	ScoreService.addNewScore(score);
    	finish = true;
	}

	/**
     * 重写绘制组件方法
     */
    public void paint(Graphics g) {
    	super.paint(g);
        paintImage();// 绘制主图片内容
        g.drawImage(image, 0, 0, this);
    }
    
    public void keyControl() {
    	KeyAdapter keyAdapter = new KeyAdapter() {
    	    /**
    	     * 实现按下键盘按键方法
    	     */
    	    public void keyPressed(KeyEvent e) {
    	        int code = e.getKeyCode();// 获取按下的按键值
    	        if (code == KeyEvent.VK_SPACE) {// 如果是空格
    	        	log.info("user pressed space key!!");
    	        	dinosaurModle.jump();// 恐龙跳跃
    	        }
    	    }
    	};
    	this.addKeyListener(keyAdapter);
    }

}

3.服务类

3.1 刷新游戏界面 FreshService

package lyrics.service;

import org.apache.log4j.Logger;
import lyrics.ui.GamePanel;
import lyrics.ui.MainFrameUI;
import lyrics.ui.ScoreUI;

/**
 * FreshService
 * 
 * @author lyrics
 * @since 2020/07/06
 */
public class FreshService extends Thread{
	private final static Logger log = Logger.getLogger(FreshService.class);
	public static int FRESH_TIME= 25;
	private GamePanel gamePanel;
	public FreshService(GamePanel gamePanel) {
		this.gamePanel = gamePanel;
	}
	public void run() {
		while(!gamePanel.isFinish()){
			gamePanel.repaint();
			try {
				Thread.sleep(FRESH_TIME);
			} catch (InterruptedException e) {
				log.error(e.getMessage());
			}
		}
		log.info("Game over!");
		new ScoreUI().setLocationRelativeTo(MainFrameUI.getInstance());
		SoundSevice.stopBackGroundMusic();
	}
}

3.2 分数记录 ScoreService

package lyrics.service;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Arrays;

/**
 * ScoreService 
 * 
 * @author lyrics
 * @since 2020/07/08
 */
public class ScoreService {
    private static final String SCOREFILE = "data/soure";// 得分记录文件
    private static int scores[] = new int[3];// 当前得分最高前三名

    /**
     * 分数初始化
     */
    public static void init() {
        File f = new File(SCOREFILE);// 创建记录文件
        if (!f.exists()) {// 如果文件不存在
            try {
                f.createNewFile();// 创建新文件
            } catch (IOException e) {
                e.printStackTrace();
            }
            return;// 停止方法
        }
        FileInputStream fis = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        try {
            fis = new FileInputStream(f);// 文件字节输入流
            isr = new InputStreamReader(fis);// 字节流转字符流
            br = new BufferedReader(isr);// 缓冲字符流
            String value = br.readLine();// 读取一行
            if (!(value == null || "".equals(value))) {// 如果不为空值
                String vs[] = value.split(",");// 分割字符串
                if (vs.length < 3) {// 如果分割结果小于3
                    Arrays.fill(scores, 0);// 数组填充0
                } else {
                    for (int i = 0; i < 3; i++) {
                        // 将记录文件中的值赋给当前分数数组
                        scores[i] = Integer.parseInt(vs[i]);
                    }
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {// 依次关闭流
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                isr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    /**
     * 保存分数
     */
    public static void saveScore() {
        // 拼接得分数组
        String value = scores[0] + "," + scores[1] + "," + scores[2];
        FileOutputStream fos = null;
        OutputStreamWriter osw = null;
        BufferedWriter bw = null;
        try {
            fos = new FileOutputStream(SCOREFILE);// 文件字节输出流
            osw = new OutputStreamWriter(fos);// 字节流转字符流
            bw = new BufferedWriter(osw);// 缓冲字符流
            bw.write(value);// 写入拼接后的字符串
            bw.flush();// 字符流刷新
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {// 依次关闭流
            try {
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                osw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 添加分数。如果新添加的分数比排行榜分数高,则会将新分数记入排行榜。
     * 
     * @param score
     *            新分数
     */
    static public void addNewScore(int score) {
        // 在得分组数基础上创建一个长度为4的临时数组
        int tmp[] = Arrays.copyOf(scores, 4);
        tmp[3] = score;// 将新分数赋值给第四个元素
        Arrays.sort(tmp);// 临时数组降序排列
        scores = Arrays.copyOfRange(tmp, 1, 4);// 将后三个元素赋值给得分数组
    }

    /**
     * 获取分数
     * 
     * @return
     */
    static public int[] getScores() {
        return scores;
    }

}

3.3 游戏声音 SoundSevice

package lyrics.service;

import java.io.FileNotFoundException;

import org.apache.log4j.Logger;

import lyrics.util.MusicPlayerUtil;

/**
 * SoundSevice
 * 
 * @author lyrics
 * @since 2020/07/05
 */
public class SoundSevice {
	private final static Logger log = Logger.getLogger(SoundSevice.class);
	private static final SoundSevice instance = new SoundSevice();
	private static MusicPlayerUtil backGroundMusic;
	private static MusicPlayerUtil hitMusic;
	private static MusicPlayerUtil jumpMusic;
	private static boolean silent = false;
	
	public static boolean isSilent() {
		return silent;
	}
	public static void setSilent(boolean silent) {
		SoundSevice.silent = silent;
	}
	public static SoundSevice getInstance() {
		return instance;
	}
	private SoundSevice(){
		try {
			backGroundMusic = new MusicPlayerUtil("music/background.wav",true);
			hitMusic = new MusicPlayerUtil("music/hit.wav");
			jumpMusic = new MusicPlayerUtil("music/jump.wav");
		} catch (FileNotFoundException e) {
			log.error(e.getMessage());
		}
	}
	public static void playBackGroundMusic() {
		if(silent) {
			return ;
		}
		backGroundMusic.playMusic();
	}
	public static void stopBackGroundMusic() {
		if(silent) {
			return ;
		}
		backGroundMusic.stopMusic();
	}
	public static void playHitMusic() {		
		if(silent) {
			return ;
		}
		hitMusic.playMusic();
	}
	public static void stopHitMusic() {
		hitMusic.stopMusic();
	}
	public static void playJumpMusic() {
		jumpMusic.playMusic();
	}
	public static void stopJumpMusic() {
		jumpMusic.stopMusic();
	}
	
	public static void closeAllMusic() {
		if(backGroundMusic!=null) {
			stopBackGroundMusic();
		}
		if(hitMusic!=null) {
			stopHitMusic();
		}
		if(jumpMusic!=null) {
			stopJumpMusic();
		}
	}
	public static void playAllMusic() {
		playBackGroundMusic();
		playHitMusic();
		playJumpMusic();
	}
}

4. 模型

4.1 DinosaurModle 恐龙模型

package lyrics.modle;

import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

import org.apache.log4j.Logger;

import lyrics.service.FreshService;
import lyrics.service.SoundSevice;

/**
 * DinosaurModle 
 * 
 * @author lyrics
 * @since 2020/07/07
 */
public class DinosaurModle {
	private final static Logger log = Logger.getLogger(DinosaurModle.class);
	public int x, y;// 横纵坐标
    public BufferedImage image;
    private BufferedImage image1;// 恐龙1
    private BufferedImage image2;// 恐龙2
    private BufferedImage image3;// 恐龙2
    private int stepTimer = 0;
    private boolean jumpState = false;// 跳跃状态
    private final int JUMP_HIGHT = 100;// 跳起最大高度
    private final int LOWEST_Y = 120;// 落地最低坐标
    private int jumpValue = 0;// 跳跃的增变量
    
	public DinosaurModle(){
		try {
			image1 = ImageIO.read(new File("image/恐龙1.png"));
			image2 = ImageIO.read(new File("image/恐龙2.png"));
			image3 = ImageIO.read(new File("image/恐龙3.png"));
		} catch (IOException e) {
			log.error(e.getMessage());
		}
		
		// 恐龙的初始位置
		x=20;
		y=LOWEST_Y;
	}
	/**
     * 踏步
     */
    private void step() {
    	switch(stepTimer/250%3) {
    	case 1:
    		image = image1;
    		break;
    	case 2:
    		image = image2;
    		break;
    	default:
    		image = image3;
    	}
    	stepTimer += FreshService.FRESH_TIME;
    }
    /**
     * 跳跃
     */
    public void jump() {
        if (!jumpState) {// 如果没处于跳跃状态
            SoundSevice.playJumpMusic();// 播放跳跃音效
        }
        jumpState = true;// 处于跳跃状态
    }
    /**
	 * 移动
	 */
    public void move() {
    	step();
        if (jumpState) {// 如果正在跳跃
            if (y >= LOWEST_Y) {// 如果纵坐标大于等于最低点
                jumpValue = -4;// 增变量为负值
            }
            if (y <= LOWEST_Y - JUMP_HIGHT) {// 如果跳过最高点
                jumpValue = 4;// 增变量为正值
            }
            y += jumpValue;// 纵坐标发生变化
            if (y >= LOWEST_Y) {// 如果再次落地
                jumpState = false;// 停止跳跃
            }
        }
    }
    
    /**
     * 足部边界区域
     * 
     * @return
     */
    public Rectangle getFootBounds() {
        return new Rectangle(x + 30, y + 59, 29, 18);
    }

    /**
     * 头部边界区域
     * 
     * @return
     */
    public Rectangle getHeadBounds() {
        return new Rectangle(x + 66, y + 25, 32, 22);
    }
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}

4.2 障碍模型 ObstacleModle

package lyrics.modle;

import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;

import org.apache.log4j.Logger;

import lyrics.image.BackgroundImage;

/**
 * ObstacleModle 
 * 
 * @author lyrics
 * @since 2020/07/07
 */
public class ObstacleModle {
	private final static Logger log = Logger.getLogger(ObstacleModle.class);
	public BufferedImage image;
	private BufferedImage stone; // 石头
	private BufferedImage cacti; // 仙人掌
	private int speed;// 移动速度
	public int x, y;// 横纵坐标
	
	public ObstacleModle() {
		try {
			stone = ImageIO.read(new File("image/石头.png"));
			cacti = ImageIO.read(new File("image/仙人掌.png"));
		} catch (IOException e) {
			log.error(e.getMessage());
		}
		Random random = new Random();
		if(random.nextInt(2) == 0) {
			image = stone;
		}else {
			image = cacti;
		}
		// 障碍的初始位置
		x=800;
		y=200 - image.getHeight();
		speed=BackgroundImage.SPEED;
	}
	
	public void move() {
		x-=speed;
	}
	
    /**
     * 获取边界
     * 
     * @return
     */
    public Rectangle getBounds() {
        if (image == cacti) {// 如果使用仙人掌图片
            // 返回仙人掌的边界
            return new Rectangle(x + 7, y, 15, image.getHeight());
        }
        // 返回石头的边界
        return new Rectangle(x + 5, y + 4, 23, 21);
    }

    /**
     * 是否有效障碍
     * 
     * @return
     */
    public boolean isLive() {
        // 如果移出了游戏界面
        if (x <= -image.getWidth()) {
            return false;// 无效
        }
        return true;// 有效
    }
}

5. 图片

5.1 背景图片 BackgroundImage
package lyrics.image;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import org.apache.log4j.Logger;
/**
 * BackgroundImage
 * 
 * @author lyrics
 * @since 2020/07/06
 */
public class BackgroundImage {
	private final static Logger log = Logger.getLogger(BackgroundImage.class);
	public BufferedImage image;// 背景图片
	private BufferedImage image1, image2;// 滚动的两个图片
	private Graphics2D g;// 背景图片的绘图对象
	public int x1, x2;// 两个滚动图片的坐标
	public static final int SPEED = 4;// 滚动速度

	/**
	 * Create the panel.
	 */
	public BackgroundImage() {
		try {
            image1 = ImageIO.read(new File("image/背景.png"));
            image2 = ImageIO.read(new File("image/背景2.png"));
        } catch (IOException e) {
        	log.error(e.getMessage());
        }
        // 主图片采用宽800高300的彩色图片
        image = new BufferedImage(800, 300, BufferedImage.TYPE_INT_RGB);
        g = image.createGraphics();// 获取主图片绘图对象
        x1 = 0;// 第一幅图片初始坐标为0
        x2 = 800;// 第二幅图片初始横坐标为800
        g.drawImage(image1, x1, 0, null);
	}
    /**
     * 滚动
     */
    public void roll() {
        x1 -= SPEED;// 第一幅图片左移
        x2 -= SPEED;// 第二幅图片左移
        if (x1 <= -800) {// 如果第一幅图片移出屏幕
            x1 = 800;// 回到屏幕右侧
        }
        if (x2 <= -800) {// 如果第二幅图片移出屏幕
            x2 = 800;// 回到屏幕右侧
        }
        g.drawImage(image1, x1, 0, null); // 在主图片中绘制两幅图片
        g.drawImage(image2, x2, 0, null);
    }

}

6. util实现类

6.1 声音播放 MusicPlayerUtil
package lyrics.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

import org.apache.log4j.Logger;

/**
 * MusicPlayer
 * 
 * @author lyrics
 * @since 2020/07/05
 */
public class MusicPlayerUtil extends Thread{
	private final static Logger log = Logger.getLogger(MusicPlayerUtil.class);
	private File soundFile;
	private boolean circulePlay = false;
	private Thread thread;

    public MusicPlayerUtil(String filepath) throws FileNotFoundException {
    	this(filepath,false);
    }
    public MusicPlayerUtil(String filepath, boolean circulate)
            throws FileNotFoundException {
        this.circulePlay = circulate;
        soundFile = new File(filepath);
        if (!soundFile.exists()) {// 如果文件不存在
            throw new FileNotFoundException(filepath + "未找到");
        }
    }
    public void playMusic() {
    	thread = new Thread(this);
    	thread.start();// 开启线程
    }
	@SuppressWarnings("deprecation")
	public void stopMusic() {
    	thread.stop();
	}
	@Override
	public void run() {
		 byte[] auBuffer = new byte[1024 * 128];// 创建128k缓冲区
	        do {
	            AudioInputStream audioInputStream = null; // 创建音频输入流对象
	            SourceDataLine auline = null; // 混频器源数据行
	            try {
	                // 从音乐文件中获取音频输入流
	                audioInputStream = AudioSystem.getAudioInputStream(soundFile);
	                AudioFormat format = audioInputStream.getFormat(); // 获取音频格式
	                // 按照源数据行类型和指定音频格式创建数据行对象
	                DataLine.Info info = new DataLine.Info(SourceDataLine.class,
	                        format);
	                // 利用音频系统类获得与指定 Line.Info 对象中的描述匹配的行,并转换为源数据行对象
	                auline = (SourceDataLine) AudioSystem.getLine(info);
	                auline.open(format);// 按照指定格式打开源数据行
	                auline.start();// 源数据行开启读写活动
	                int byteCount = 0;// 记录音频输入流读出的字节数
	                while (byteCount != -1) {// 如果音频输入流中读取的字节数不为-1
	                    // 从音频数据流中读出128K的数据
	                    byteCount = audioInputStream.read(auBuffer, 0,
	                            auBuffer.length);
	                    if (byteCount >= 0) {// 如果读出有效数据
	                        auline.write(auBuffer, 0, byteCount);// 将有效数据写入数据行中
	                    }
	                }
	            } catch (IOException | LineUnavailableException | UnsupportedAudioFileException e) {
	            	log.error(e.getMessage());
	            } finally {
	                auline.drain();// 清空数据行
	                auline.close();// 关闭数据行
	            }
	        } while (circulePlay);// 根据循环标志判断是否循环播放
	} 
	public static void main(String[] args) {
		try {
			MusicPlayerUtil musicPlayer = new MusicPlayerUtil("music/hit.wav",true);
			musicPlayer.playMusic();
			Thread.sleep(3000);
			musicPlayer.stopMusic();
		} catch (FileNotFoundException | InterruptedException e) {
			log.info(e.getMessage());
		}
	}
}

7.日志

7.1 日志配置
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%%-d{yyyy-MM-dd HH:mm:ss}  [ %p ]  %m%n
 
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File = logInfo/logInfo.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss}  [ %p ]  %m%n

log4j.rootLogger=INFO,console,file

四、演示

Java小游戏:恐龙快跑(Running Dinosaur)_第5张图片
Java小游戏:恐龙快跑(Running Dinosaur)_第6张图片
Java小游戏:恐龙快跑(Running Dinosaur)_第7张图片
Java小游戏:恐龙快跑(Running Dinosaur)_第8张图片

五、最后

第一次写小游戏,代码有一些小瑕疵,勉强凑合着用,大家多多包涵。

你可能感兴趣的:(java,SWT/Swing/Awt,小游戏)