飞翔的小鸟代码详解

游戏开始界面

游戏运行界面

游戏得分界面

游戏结束界面

开发准备

1、eclipse开发工具

2、java语言

3、jdk1.5以上

一、案例分析

写任何代码都是先分析代码需求再干活,千万不要盲目的去干,盲目的去干就算干完了也是错的。

飞翔的小鸟算是一个比较基础的入门案例,代码相对简单。设计这款游戏需要先分析出需要使用到哪些对象:

1、背景对象:游戏的背景图

2、地面对象:游戏启动地面移动相对的实现小鸟飞翔

3、游戏开始和结束的状态:大致可以分为3种状态即准备0、运行1、结束2。状态是图片表示所以不用创建对象,根据游戏状态切换图片即可。

4、小鸟对象:小鸟的飞行效果由8张小鸟图片轮播实现。

5、柱子对象:柱子在状态0时不会出现在界面中,在状态1时不断前移。

6、swing组件:需要使用Jframe底层窗口容器,在Jpanel中制作操作面板

7、鼠标权限:获取鼠标点击松开事件用来操作小鸟等

8、IO流:读取图片

9、线程:控制游戏速度

10、异常处理机制:和IO配合使用,捕获可能会发生的异常

以上就是全部需要使用的知识点,这里大概上分为5个类

二、创建游戏窗口

Mains类作为主类,在mian方法下定义一个m1()方法,设置窗口。

//定义一个初始化的游戏窗口方法 
	public static void m1() {
		//获取底层窗口界面的工具类
		JFrame jf =new JFrame();//创建了窗口对象
		jf.setSize(432, 644);//设置窗口大小
		jf.setTitle("出击吧小鸟");//设置窗口标题
		jf.setLocationRelativeTo(null);//默认坐标居中
		jf.setVisible(true);//设置窗口可见
		jf.setResizable(false);//设置窗口大小不可以调整 
		//设置窗口监听,关闭窗口时,程序结束运行
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
	}

此时可以在main方法中调用m1方法,点击运行,效果如下

三、背景对象

将图片资源都放在src下面,在BackGround类中,使用IO流读取背景图片,获取图片宽度高度等。


public class BackGround {//背景类
	//在这个类中描述背景图片的属性

	public int width;//图片的宽度属性
	public int height;//图片的高度属性
	//使用处理图片的工具类
	public BufferedImage  img=null;
	
	public BackGround() {
		//在构造器中初始化背景类的宽度、高度属性
		// 读取  ,写入 
		/*
		 * 异常处理机制、异常捕获机制
		 * try抛出异常 ,catch捕获异常
		 * 处理程序运行时出现的异常
		 * try{} 可能出现问题的代码
		 * catch{} 出现问题之后,跳过try中剩余的代码
		 * 执行catch{}中的代码
		 * catch( 准备捕获的异常类型 )
		 */
		try {
			img = ImageIO.read(getClass().getResource("/bg.png"));
			//图片资源 储存了背景图片的所有信息
			width = img.getWidth();//获取图片资源的宽度给类中的属性赋值
			height=img.getHeight();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
	}
}

四、操作面板

面板类这里直接在Mians类下定义一个单独的类,上面用于实现背景,小鸟等对象。

面板类继承Jpanel类,重新paint方法,绘制背景对象。

//游戏的操作面板类
//继承面板工具类 JPanel
class Panel extends JPanel {
    BackGround  bg =null;	// 创建背景类的对象 
    
    public Panel() {//构造器
		bg =new BackGround();//加载背景类的实例
    } 
//绘制图片的方法  Jpanel工具类中的 paint()
	@Override
	public void paint(Graphics g) {
		//在绘制图片的方法中 ,绘制背景图片,小鸟。柱子等等
		//Graphics类  制图工具类   使用制图功能绘制图片,或者文字
		g.drawImage(bg.img,0,0,null);
		//参数1: 要绘制的图片
		//参数2:图片的x坐标
		//参数3: 图片的y坐标
		//参数4: 默认出现的位置.
    }
}

 然后在设置游戏窗口的m1方法中,将制作的游戏面板添加到窗口中。在设置窗口可见这行代码的下边添加即可。

	Panel p =new Panel();//创建面板对象
		jf.add(p);//在窗口中添加面板

然后点击运行,窗口中就有背景图了。

五、地面对象

在窗口的左上角默认坐标点是x=0.y=0

地面图片的y坐标 = 背景图片的高度 - 地面图片的高度。

地面是根据背景的基础上实现移动的,在地面类中需要添加一个单独的移动方法。

public class Ground {//地面类
	BufferedImage img =null;
	public int width;//图片的宽度属性
	public int height;//图片的高度属性
	public int x,y;//地面的x坐标 y坐标
	//获取背景类对象的高度属性
	BackGround bg=null;
	public Ground() {
		try {
			bg=new BackGround();
			img = ImageIO.read(getClass().getResource("/ground.png"));
			//图片资源 储存了背景图片的所有信息
			width = img.getWidth();//获取图片资源的宽度给类中的属性赋值
			height=img.getHeight();
			x=0;
			y=bg.height-height;
			//背景图片高度,减去地面图片高度,就是地面的初始y坐标
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	//让地面移动的方法
	public void move(BackGround bg) {
		// 横向前移  x 
		x--;
		//设计一个循环 ,能够一直移动
		if(x==bg.width+10-width) {//修正值
			x=0;//x坐标归零
		}
	}

}

 然后在面板类Panel中创建地面类的对象,将地面对象在paint方法中绘制出来

class Panel extends JPanel{
	
	BackGround  bg =null;	// 创建背景类的对象 
	Ground ground=null;//创建地面类对象
	public Panel() {
		bg =new BackGround();//加载背景类的实例 
		ground =new Ground();//加载地面类实例
	}
	
	//绘制图片的方法  Jpanel工具类中的 paint()
		@Override
		public void paint(Graphics g) {
			//在绘制图片的方法中 ,绘制背景图片,小鸟。柱子等等
			//Graphics类  制图工具类   使用制图功能绘制图片,或者文字
			g.drawImage(bg.img,0,0,null);
			//参数1: 要绘制的图片
			//参数2:图片的x坐标
			//参数3: 图片的y坐标
			//参数4: 默认出现的位置.
			g.drawImage(ground.img,ground.x,ground.y,null);
		}
}

 现在点击运行,看起来和没绘制地面之前没有什么不同,因为地面图片与背景中的地面位置完美重合了,接下来要调用地面移动的方法。在面板类中定义一个方法action作为所有运行状态的启动开关,地面一直在移动,所以用一个死循环来实现,加上线程休眠时间,来控制游戏运行的速度。

//调用游戏中动态效果的方法
	public void action() {//执行这个方法,游戏开始运行
//地面移动  一直在移动  是一个死循环
		while(true) {
			ground.move(bg);
	//设置线程休眠 每隔一段时间,线程休眠一次,相当于清空内存重新执行
			try {
				Thread.sleep(1000/40);//控制速度的
				this.repaint();//重新绘制
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}//每隔这么长时间重新执行
        }
}

 写完之后在Mains类中的m1方法最后一行调用,点击运行,地面开始移动起来。

p.action();//开始运行

 六、加入游戏状态图片

游戏开始前,加入start图片,游戏结束,加入gameover图片。由于状态不需要单独创建对象,图片资源直接在面板类中设计。通过鼠标点击来切换状态,所以这里需要加载鼠标点击松开事件。JPanle面板工具类中有定义好的鼠标工具对象,使用this来调用即可。

//继承面板工具类 JPanel
class Panel extends JPanel {
//在 这里添加游戏状态属性  0 1 2 
	public int state=0;//初始状态是0  准备开始 
	BufferedImage imgStart=null;//0 准备开始的图片
	BufferedImage gameover=null;//2 游戏结束的图片

    BackGround  bg =null;	// 创建背景类的对象 
	Ground ground=null;//创建地面类对象
    public Panel() {//构造器
		bg =new BackGround();//加载背景类的实例 
		ground =new Ground();//加载地面类实例
    try {//加载图片资源
			imgStart = ImageIO.read(getClass().getResource("/start.png"));
			gameover = ImageIO.read(getClass().getResource("/gameover.png"));
		} catch (IOException e) {
			// TODO: handle exception
		}
    }

//绘制图片的方法  Jpanel工具类中的 paint()
	@Override
	public void paint(Graphics g) {
		//在绘制图片的方法中 ,绘制背景图片,小鸟。柱子等等
		//Graphics类  制图工具类   使用制图功能绘制图片,或者文字
		g.drawImage(bg.img,0,0,null);
		//参数1: 要绘制的图片
		//参数2:图片的x坐标
		//参数3: 图片的y坐标
		//参数4: 默认出现的位置.
		if(state==0) {
			g.drawImage(imgStart,0,0,null);
		}else if(state==1) {
	
		}else if(state==2) {
			g.drawImage(gameover,0,0,null);
		}
		g.drawImage(ground.img,ground.x,ground.y,null);
	}
//调用游戏中动态效果的方法
	public void action() {//执行这个方法,游戏开始运行
		//通过鼠标点击,切换游戏状态
		//获取鼠标权限 
		this.addMouseListener(new MouseAdapter() {
			//点击鼠标释放后的事件
			@Override
			public void mouseReleased(MouseEvent e) {
				//super.mouseReleased(e);
				// 0准备   1开始    2 结束 
				switch (state) {
				case 0:	
					state=1;
					break;
				case 1:
					state=2;
					break;
				case 2:
					state=0;
					break;
				default:
					break;
				}
			}
		});
		
		
		//地面移动  一直在移动  是一个死循环
		while(true) {
			ground.move(bg);
		//设置线程休眠 每隔一段时间,线程休眠一次,相当于清空内存重新执行
			try {
				Thread.sleep(1000/40);//控制速度的
				this.repaint();//重新绘制
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}//每隔这么长时间重新执行
		}
	}
	

}

 现在点击运行,在界面中点击鼠标可以切换状态了。

七、小鸟对象

小鸟一共有8张图片,所以这里使用图片工具类数组来储存,然后添加一个方法,由切换图片实现小鸟煽动翅膀的飞行动作。

首先是游戏状态0时,在start图片中间有一处留白的位置准备放一个会动的小鸟,这里先创建小鸟类,然后在状态0时绘制,切换到状态1时,小鸟位置切换。


public class Bird {//小鸟类
	// x:190 y:220
	public int width;//图片的宽度属性
	public int height;//图片的高度属性
	public int x,y;//地面的x坐标 y坐标
	public BufferedImage[] imgs=new BufferedImage[8];
	BufferedImage img=null;//准备一个图片,用来属性赋值
	//这是一个图片数组,数组中储存8张图片
	int index=0; //下标属性
	
	
	
	public Bird() {
		try {
			for (int i = 0; i < imgs.length; i++) {//i 0-7
				imgs[i]=ImageIO.read(getClass().
						getResource("/"+i+".png"));
			}
			img=imgs[0];
			height=img.getHeight();
			width=img.getWidth();
			x=190;
			y=220;
			
		} catch (Exception e) {
		
		}
	}
	
	// 添加小鸟煽动翅膀飞行的动作
	public void fly() {
		//定义一个数组的下标 根据下标切换数组中的图片,实现轮播效果
		index++;
		img = imgs[index%8];//index自增得出下标  振动频率/6 
		if(index==200) {//修正值,到100之后归0
			index=0;
		}
	}
}

在面板类中绘制小鸟,在action方法中执行小鸟飞行动作

	    if(state==0) {
			g.drawImage(imgStart,0,0,null);
			g.drawImage(bird.img,bird.x,bird.y,null);
		}else if(state==1) {
			//准备绘制小鸟和柱子 以及分数等
			g.drawImage(bird.img,bird.x-80,bird.y,null);
		}else if(state==2) {
			g.drawImage(gameover,0,0,null);
		}
    while(true) {
			ground.move(bg);
			bird.fly();//小鸟一直在飞行
    }

 下一步,小鸟在状态1时,通过鼠标点击向上飞行,不点就按照重力加速度规则自动掉落,这里在小鸟类中添加一些速度变量,定义两个方法控制上升和掉落

    //关于重力加速度的变量
	double g=9.8;
	double v=0;//初始下降速度
	double t=0.18;//小鸟自动下降的时长
	double h;//小鸟下降的距离 
	double up=25;//小鸟上升的速度	


	//小鸟向上飞行的动作
	public void up() {
		v = up;
	}
	
	//如果不点鼠标小鸟会根据重力自动向下掉
	public void down() {
		v=v-g*t;
		h=v*t-g*t*t/2;
		y=y-(int)h;
		//根据物理公式,得出小鸟下降的距离,给y坐标重新赋值
	}

掉落的方法是一直都在执行的,所以写在死循环中,当状态是1时,小鸟自行掉落。

while(true) {
			ground.move(bg);
			bird.fly();//小鸟一直在飞行
			if(state==0) {
				
			}else if(state==1) {
				bird.down();//如果是开始状态,小鸟会自动下降
			}

 上升的方法是点击鼠标的时候执行的,所以要写在点击鼠标事件的状态1中

this.addMouseListener(new MouseAdapter() {
			//点击鼠标释放后的事件
			@Override
			public void mouseReleased(MouseEvent e) {
				//super.mouseReleased(e);
				// 0准备   1开始    2 结束 
				switch (state) {
				case 0:	
					state=1;
					break;
				case 1:
					bird.up();//状态是运行时,点击鼠标小鸟向上飞
					break;
				case 2:
					state=0;
					break;
				default:
					break;
				}
			}
		});
		

现在点击运行,小鸟会飞了。

八、柱子对象

直接上代码


public class Column {//柱子类
	public int width;//图片的宽度属性
	public int height;//图片的高度属性
	public int x,y;//x坐标 y坐标
	BufferedImage img =null;
	

/*
 * 小鸟闯关的柱子,每隔244间距,就要再产生一根新柱子
 * 柱子的高度通过随机数产生,所以要先计算出柱子的高度
 * 柱子的最大高度:柱子的图片高度-柱子通道距离144,然后除2 
 * 柱子的最小高度:柱子的最大高度 - 背景高度 -地面高度 -通道距离
 * 柱子的y坐标: 最大柱子高度和最小高度之间的随机数
 */
	Random ran =new Random();//获取随机数权限
	int max=0 , min=0;
public Column(BackGround bg,Ground ground) {
	// 柱子的x坐标需要参考背景和地面的x坐标
	try {
		img = ImageIO.read(getClass().getResource("/column.png"));
		width=img.getWidth();
		height=img.getHeight();
		x=bg.width;
		// 柱子高度的最大值和最小值 
		max= (height -144)/2;
		min =(height -144)/2 - (bg.height-144 -ground.height);
		
		y= -(ran.nextInt(max-min)+ min);
		
	} catch (Exception e) {
		// TODO: handle exception
	}
}	
	
//柱子不断向前移动的动作
public void move (BackGround bg) {
	x--;
	if(x== - width) {
		x=bg.width;
		y=-(ran.nextInt(max-min)+ min);
		//如果柱子移动出界,将x 坐标和y坐标 初始化
	}
}
	
}

在面板类中创建两根柱子对象,然后在paint方法中绘制。在action方法中调用柱子移动的方法。

    Column c1=null;
	Column c2=null;//创建两根柱子对象 
	public Panel() {
		bg =new BackGround();//加载背景类的实例 
		ground =new Ground();//加载地面类实例
		bird=new Bird();//加载小鸟类实例
		c1=new Column(bg, ground);
		c2=new Column(bg, ground);//加载柱子类实例 
		c2.x = bg.width+244;//两根柱子的间距
    }

    if(state==0) {
			g.drawImage(imgStart,0,0,null);
			g.drawImage(bird.img,bird.x,bird.y,null);
		}else if(state==1) {
			//准备绘制小鸟和柱子 以及分数等
			g.drawImage(bird.img,bird.x-80,bird.y,null);
			g.drawImage(c1.img,c1.x,c1.y,null);
			g.drawImage(c2.img,c2.x,c2.y,null);
		}else if(state==2) {
			g.drawImage(gameover,0,0,null);
		}

现在点击运行,柱子也出现了。现在需要定义小鸟与柱子、天空、地面等对象碰撞死亡,和穿过柱子计分的方法。

//给小鸟添加死亡方法 
	//碰撞地面 死亡
	public boolean  hitGround(BackGround bg ,Ground ground) {
		if(y+height >= (bg.height-ground.height)) {
			//小鸟当前y坐标+小鸟自身的高度 》>= 背景高度-地面高度 
			return true; //说明碰撞到了地面
		}else {
			return false;//说明没有碰到 
		}
	}
	//碰撞天空 死亡
	public boolean hitSky() {
		if(y<=0) {//小鸟当前的y坐标<=0 说明碰到了天空边缘
			return true;//是,死亡
		}
			return false;
		
	}
	//碰到柱子 死亡
	public boolean hitColumn(Column c) {
		// 检测x 坐标 和 y坐标
		if( x-width>= c.x  && x<= (c.x+c.width)) {
			//如果碰撞了当前柱子的x坐标
			if(y<= c.y+(c.height-144)/2 || y>= c.y+(c.height+144)/2-height) {
				//如果碰撞到上半部柱子或者下半部柱子
				return true;//死亡
			}
		}
			
		return false;
		
	}
	
	//如果没有碰到柱子得分的方法 
	public boolean addScore(Column c) {
		if(x==c.x+c.width) {
			return true;
		}
		return false;
	}
	
	

然后在面板类中,根据游戏状态的不同进行调用。这里需要先定义一个分数变量score,穿过柱子时+1分

//绘制图片的方法  Jpanel工具类中的 paint()
	@Override
	public void paint(Graphics g) {
		//在绘制图片的方法中 ,绘制背景图片,小鸟。柱子等等
		//Graphics类  制图工具类   使用制图功能绘制图片,或者文字
		g.drawImage(bg.img,0,0,null);
		//参数1: 要绘制的图片
		//参数2:图片的x坐标
		//参数3: 图片的y坐标
		//参数4: 默认出现的位置.
		Font f =new Font(Font.SANS_SERIF,Font.ITALIC,20);
		g.setFont(f);
		g.setColor(Color.ORANGE);//设置橙色字体
		g.drawString("得分:"+score, 20, 40);
		if(state==0) {
			g.drawImage(imgStart,0,0,null);
			g.drawImage(bird.img,bird.x,bird.y,null);
		}else if(state==1) {
			//准备绘制小鸟和柱子 以及分数等
			g.drawImage(bird.img,bird.x-80,bird.y,null);
			g.drawImage(c1.img,c1.x,c1.y,null);
			g.drawImage(c2.img,c2.x,c2.y,null);
		}else if(state==2) {
			g.drawImage(gameover,0,0,null);
		}
			
		g.drawImage(ground.img,ground.x,ground.y,null);
	}
	
	//调用游戏中动态效果的方法
	public void action() {//执行这个方法,游戏开始运行
		//通过鼠标点击,切换游戏状态
		//获取鼠标权限 
		this.addMouseListener(new MouseAdapter() {
			//点击鼠标释放后的事件
			@Override
			public void mouseReleased(MouseEvent e) {
				//super.mouseReleased(e);
				// 0准备   1开始    2 结束 
				switch (state) {
				case 0:	
					state=1;
					bird.x=110;
					break;
				case 1:
					bird.up();//状态是运行时,点击鼠标小鸟向上飞
					break;
				case 2:
					state=0;
					score=0;
					bird.x=190;
					bird.y=220;
					bird.v=0;
					c1.x=bg.width;
					c2.x=bg.width+244;
					break;
				default:
					break;
				}
			}
		});
		
		

		//地面移动  一直在移动  是一个死循环
		while(true) {
			ground.move(bg);
			bird.fly();//小鸟一直在飞行
			if(state==0) {
				
			}else if(state==1) {
				bird.down();//如果是开始状态,小鸟会自动下降
				c1.move(bg);
				c2.move(bg);
				if(bird.hitColumn(c1)||bird.hitColumn(c2)||
						bird.hitSky()||bird.hitGround(bg, ground)) {
					//如果小鸟飞行的过程中碰到了柱子1,2 或者天空,地面,切换到游戏结束状态
					state=2;
				}else {
					// 没碰到时调用是否穿过通道
					if(bird.addScore(c1)||bird.addScore(c2)) {
						score++;//分数自增
						System.out.println("恭喜你的小鸟穿过了通道加一分");
					}
				}
			}
			
			//设置线程休眠 每隔一段时间,线程休眠一次,相当于清空内存重新执行
			try {
				Thread.sleep(1000/40);//控制速度的
				this.repaint();//重新绘制
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}//每隔这么长时间重新执行
		}
	}
	
	
}

现在点击运行,基本上就可以玩了。还可以自行研究一下背景音乐,键盘点击操作等等。

项目所需的图片放在下方,需要的童鞋可以自行下载。谢谢

https://pan.baidu.com/s/15etinrxLZYa_WuZkVWMKWg

链接提取码:qw12

  

  • 17
    点赞
  • 125
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值