冒险岛游戏简介
游戏界面简介
技术选型
- 编程语言及技术: java GUI
- 框架:Frame
- 多线程控制
- 双缓冲
项目的目录结构
项目中所用到的技巧
- 根据java的集成特性由继承的方式来基于frame框架定制适合自身的框架
- 利用map来制作图片工具类,用来进行项目初始化时只加载需要的图片,提高效率。
- 使用枚举类型的数据来标识项目中实体的方向和行为
- 利用列表容器来装怪物和子弹
- 将图片转换为字节流的工具类
tips:画笔使用的时候需要先取出然后清洗再进行重新赋值颜色
public class GameUtil {
/**
* 根据图片路径进行转换且可以设置图片放大倍数
* @param imgpath 图片路径
* @param beishu 放大的倍数
*/
public static Image getImage(String imgpath,double beishu) {
InputStream imgInput = new GameUtil().getClass().getResourceAsStream(imgpath);
Image image = null;
try {
BufferedImage imgBuffered = ImageIO.read(imgInput);
int width = (int) (imgBuffered.getWidth()*beishu);
int height = (int) (imgBuffered.getHeight()*beishu);
image = imgBuffered.getScaledInstance(width, height, Image.SCALE_DEFAULT);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return image;
}
/**
* 根据图片路径进行转换
* @param imgpath 图片路径
*/
public static Image getImage(String imgpath) {
InputStream imgInput = new GameUtil().getClass().getResourceAsStream(imgpath);
Image image = null;
try {
BufferedImage imgBuffered = ImageIO.read(imgInput);
int width = imgBuffered.getWidth();
int height = imgBuffered.getHeight();
image = imgBuffered.getScaledInstance(width, height, Image.SCALE_DEFAULT);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return image;
}
/**
* 改变图片的一条边
* @param imgpath 图片路径
* @param bian 边的长度
* @param state (0|1)(不改变宽|不改变长)
*/
public static Image getImage(String imgpath,int bian,int state) {
InputStream imgInput = new GameUtil().getClass().getResourceAsStream(imgpath);
Image image = null;
try {
BufferedImage imgBuffered = ImageIO.read(imgInput);
int width = imgBuffered.getWidth();
int height = imgBuffered.getHeight();
if(state==0) {
height = (int) ((double) bian / width * height) ;
width = bian;
}else {
width = (int) ((double) bian / height * width) ;
height = bian;
}
image = imgBuffered.getScaledInstance(width, height, Image.SCALE_DEFAULT);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return image;
}
}
- 自定义的frame框架及使用
/**
* @ClassName FrameUtil
* @Description: 窗口初始化工具类
* @Author Xu Feng
* @Date 2020/3/17
* @Version V1.0
**/
public class FrameUtil extends Frame implements KeyListener, MouseListener, MouseMotionListener{
public void Init(){
//设置窗口的初始位置
this.setBounds(400,200,Constant.GAME_WIDTH,Constant.GAME_HEIGHT);
//设置窗口的标题
this.setTitle("冒险岛");
//设置窗口关闭的监听事件
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
//添加键盘监听映射
this.addKeyListener(this);
//添加鼠标监听映射
this.addMouseListener(this);
//设置可见性
this.setVisible(true);
//设置聚焦
this.setFocusable(true);
//启动线程
new MyThread().run();
}
// 解决图片闪烁的问题,用双缓冲方法解决闪烁问题
Image backImg = null;
// 重写update()方法,在窗口的里层添加一个虚拟的图片
@Override
public void update(Graphics g) {
if (backImg == null) {
// 如果虚拟图片不存在,创建一个和窗口一样大小的图片
backImg = createImage(Constant.GAME_WIDTH, Constant.GAME_HEIGHT);
}
// 获取到虚拟图片的画笔
Graphics backg = backImg.getGraphics();
Color c = backg.getColor();
backg.setColor(Color.white);
backg.fillRect(0, 0, Constant.GAME_WIDTH, Constant.GAME_HEIGHT);
backg.setColor(c);
// 调用虚拟图片的paint()方法,每50ms刷新一次
paint(backg);
g.drawImage(backImg, 0, 0, null);
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mouseDragged(MouseEvent e) {
}
@Override
public void mouseMoved(MouseEvent e) {
}
//启动线程重画画布
class MyThread extends Thread {
@Override
public void run() {
for (; ; ) {
repaint();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
- 单独进行一个线程来加载音乐
package com.feng.untils;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;
import java.io.BufferedInputStream;
import java.io.File;
/**
* @ClassName MusicUtil
* @Description: 加载声音
* @Author Xu Feng
* @Date 2020/3/20
* @Version V1.0
**/
public class MusicUtil extends Thread {
private Player player;
private File music;
private String musicPath;
private boolean loop;
public MusicUtil(String musicPath){
this.musicPath = musicPath;
}
public MusicUtil(String musicPath,boolean loop){
this.musicPath = musicPath;
this.loop = loop;
}
@Override
public void run() {
super.run();
try {
if (loop){
while (true){
play();
}
}else {
play();
}
}catch (JavaLayerException e){
e.printStackTrace();
}
}
public void play() throws JavaLayerException {
BufferedInputStream buff = new BufferedInputStream(MusicUtil.class.getClassLoader()
.getResourceAsStream(musicPath));
player = new Player(buff);
player.play();
}
public static void main(String[] args) {
MusicUtil musicUtil = new MusicUtil("music/Bruno Mars - Talking to the Moon (Acoustic Piano).mp3",true);
musicUtil.start();
}
}
- 英雄自由落体的跳跃算法
//英雄的跳算法
public static List<Integer> jump(int y){
double v0 = 30;
double vt = 0;
double g = 9.8;
double t = 0.5;
double d_h = 0;
List<Integer> jumps = new ArrayList();
boolean jump_up = true;
//竖直上抛运动
if (jump_up){
for (;;){
System.out.println(+y);
vt = v0 - g * t;
d_h = v0 * t;
v0 = vt;
y -= d_h;
jumps.add(y);
System.out.println("竖直上抛:"+y);
if (vt<=0){
v0 = 0;
vt = 0;
jump_up = false;
System.out.println("自由落体最终:"+y);
break;
}
}
}
//自由落体
if (!jump_up){
for (;;){
vt = v0 + g * t;
d_h = v0 * t;
v0 = vt;
y += d_h;
jumps.add(y);
if (y>=400){
y = 400;
v0 = 30;
vt = 0;
jump_up = true;
System.out.println("自由落体最终:"+y);
break;
}
}
}
if (jumps.get(jumps.size()-1)>= y){
Collections.replaceAll(jumps,jumps.get(jumps.size()-1),y);
}
return jumps;
}
static class jumpThread extends Thread{
@Override
public void run() {
for (int dy : jump(400)){
System.out.println(dy);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}