基于被这款游戏的虐心经历后,决定把刚学的线程应用出来,模仿写出这一个游戏,基本游戏功能实现后打算写个2.0增加左右飞行方向,和别的物体互动,比如道具获得,怪物出现。 现已经基本实现原本游戏功能。
主要是有六个类来实现,游戏界面类,管子类,管子管理线程类,鸟管理线程类,鸟飞行鼠标监听器类,还有一个动画实现管理类。
首先是游戏界面类,用来创建游戏窗口和启动动画实现管理:
public class mainUI {
//程序入口
public static void main(String[] args) {
mainUI ui = new mainUI();
}
//构造函数,自动调用初始化方法和开始游戏方法
public mainUI() {
// TODO Auto-generated constructor stub
initUI();
}
//初始化游戏窗口
public void initUI(){
//判断是否开始游戏的标记
boolean startflag = false;
JFrame jf = new JFrame("Flappy Bird");
jf.setSize(600, 500);
jf.setLocationRelativeTo(null);
jf.setResizable(false);
jf.setDefaultCloseOperation(3);
jf.setVisible(true);
//创建游戏动画线程管理线程
Administration ad = new Administration(jf);
ad.start();
}
}
然后是动画实现管理类,在写这么一个类之前是纠结了好一段时间了,因为刚开始写的时候发现管子的线程,和鸟的线程,和背景的动画实现,没办法协调起来,分别独自画在窗体上会出现相互覆盖的情况,所以后来想出了这么个类,用来获取当前鸟的坐标,还有管子队列中各个管子坐标,然后和背景一起在这个类里面的BufferedImage()里面画出来,再一起显示,没有看过别人写的动画实现方法,就只能先想出这个办法了。
public class Administration extends Thread {
private JFrame jf;
private boolean die;
public Administration(JFrame jf){
this.jf = jf;
}
public void run(){
//创建柱子队列管理线程,管理柱子的生成
PipeManage pm = new PipeManage(jf);
pm.start();
//创建鸟管理线程,管理鸟的动态
BirdManage bm = new BirdManage(jf);
bm.start();
//创建图片图标
ImageIcon baitian = new ImageIcon("image/白天.png");
ImageIcon dimian = new ImageIcon("image/地.png");
ImageIcon zheng = new ImageIcon("image/正.png");
ImageIcon fan = new ImageIcon("image/反.png");
ImageIcon shang = new ImageIcon("image/上.png");
ImageIcon zhong = new ImageIcon("image/中.png");
ImageIcon xia = new ImageIcon("image/下.png");
//飞行状态
int fly = 3;
ImageIcon gameover = new ImageIcon("image/gameover.png");
//图片坐标
int x = 0;
//管子队列起画坐标
int xx = 0;
//创建图片缓冲区
BufferedImage buffer = new BufferedImage(jf.getWidth(), jf.getHeight(), BufferedImage.TYPE_INT_RGB);
//获取缓冲区画布
Graphics g = buffer.getGraphics();
//获取窗体画布
Graphics gg = jf.getGraphics();
while(true){
//延迟
delay(10);
//起画坐标移动
x--;
xx--;
if(x <= -baitian.getIconWidth())
x = 0;
//判断是否碰撞
iscrash(bm,pm,xx,zheng.getIconWidth(),zhong.getIconWidth(),zhong.getIconHeight(),dimian.getIconHeight());
if(die){
gg.drawImage(gameover.getImage(),(jf.getWidth()-gameover.getIconWidth())/2,(jf.getHeight()-gameover.getIconHeight())/2,null);
this.stop();
}
//清屏
g.setColor(jf.getBackground());
g.fillRect(0, 0, jf.getWidth(), jf.getHeight());
//----------画背景----------------------
g.drawImage(baitian.getImage(),x,0,null);
g.drawImage(baitian.getImage(),x+baitian.getIconWidth(),0,null);
g.drawImage(baitian.getImage(),x+2*baitian.getIconWidth(),0,null);
//---------画管子-------------
for(int i=1;i<=pm.getPipeNum();i++){
g.drawImage(fan.getImage(),xx+pm.getPipe(i).position,pm.getPipe(i).gap-fan.getIconHeight(),null);
g.drawImage(zheng.getImage(),xx+pm.getPipe(i).position,pm.getPipe(i).gap+130,null);
}
//---------画地面-------
g.drawImage(dimian.getImage(),x,jf.getHeight()-dimian.getIconHeight(),null);
g.drawImage(dimian.getImage(),x+dimian.getIconWidth(),jf.getHeight()-dimian.getIconHeight(),null);
g.drawImage(dimian.getImage(),x+2*dimian.getIconWidth(),jf.getHeight()-dimian.getIconHeight(),null);
//---------画鸟--------
if(fly==3){
g.drawImage(shang.getImage(),bm.getX(),bm.getY(),null);
fly--;
}else if(fly==2){
g.drawImage(zhong.getImage(),bm.getX(),bm.getY(),null);
fly--;
}else{
g.drawImage(xia.getImage(),bm.getX(),bm.getY(),null);
fly = 3;
}
//累计得分
g.setColor(Color.black);
g.drawString(CountScore(bm,pm, xx,zheng.getIconWidth()), 50, jf.getHeight()-dimian.getIconHeight()+50);
//显示出图片缓冲区的内容
gg.drawImage(buffer, 0, 0, null);
}
}
//累计得分
public String CountScore(BirdManage bm,PipeManage pm,int xx,int PipeWidth){
int score=0;
for(int i=1;i<=pm.getPipeNum();i++){
if(bm.getX()>=pm.getPipe(i).position+xx+PipeWidth)
score++;
}
System.out.println(score);
return Integer.toString(score);
}
//判断碰撞方法
public void iscrash(BirdManage bm,PipeManage pm,int xx,int PipeWidth,int birdWidth,int birdHeight,int dimian){
for(int i=1;i<=pm.getPipeNum();i++){
//判断上柱子(右碰)
if(bm.getX()+birdWidth >= pm.getPipe(i).position+xx && bm.getX()+birdWidth <= pm.getPipe(i).position+xx+PipeWidth && bm.getY() <= pm.getPipe(i).gap-5){
die = true;
return;
}
//判断上柱子(左碰)
if(bm.getX() >= pm.getPipe(i).position+xx && bm.getX() <= pm.getPipe(i).position+xx+PipeWidth && bm.getY() <= pm.getPipe(i).gap-5){
die = true;
return;
}
//判断下柱子(右碰)
if(bm.getX()+birdWidth >= pm.getPipe(i).position+xx && bm.getX()+birdWidth <= pm.getPipe(i).position+xx+PipeWidth && bm.getY()+birdHeight >= pm.getPipe(i).gap+145){
die = true;
return;
}
//判断下柱子(左碰)
if(bm.getX() >= pm.getPipe(i).position+xx && bm.getX() <= pm.getPipe(i).position+xx+PipeWidth && bm.getY()+birdHeight >= pm.getPipe(i).gap+145){
die = true;
return;
}
if(bm.getY()+birdHeight >= jf.getHeight()-dimian+12){
die = true;
return;
}
}
}
//延迟方法
public void delay(int t){
try {
sleep(t);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
然后是管子线程管理类,用来生成管子对象,并移动管子坐标,用来给动画实现管理类提供管子坐标,实现动画还有碰撞判断:
public class PipeManage extends Thread {
private static nodeQuene nq = new nodeQuene();;
private int position, Heigh;
private int gap;
private JFrame jf;
public PipeManage(JFrame jf) {
this.position = jf.getWidth();
this.Heigh = jf.getHeight();
}
public void run() {
Random rd = new Random();
while (true) {
// 延迟
try {
sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 移动管子坐标
position++;
// 管子队列
if (nq.size() == 0) {
// 产生管子随机缝隙纵坐标
gap = 70 + rd.nextInt(Heigh - 300);
pipe pp = new pipe(position, gap);
nq.add(pp);
} else {
// 产生管子随机缝隙纵坐标
gap = 70 + rd.nextInt(Heigh - 300);
// 如果前一个管子移动得足够远,生成管子,加入队列
if (nq.get(nq.size()).o.position <= position -180) {
pipe pp = new pipe(position, gap);
nq.add(pp);
}
}
}
}
public pipe getPipe(int i) {
return nq.get(i).o;
}
public int getPipeNum() {
return nq.size();
}
}
这个是管子类:
public class pipe {
public int position;
public int gap;
public pipe(int position,int gap){
this.gap = gap;
this.position = position;
}
}
然后就是鸟线程管理类,由于只有一直鸟,就没有再特地写一个鸟的类了,就直接放在这个类里面了:
public class BirdManage extends Thread{
private int X=150,Y=250;
static boolean flyingFlag;
static int dist = 25;
private JFrame jf;
public BirdManage(JFrame jf){
this.jf = jf;
}
public void run(){
//鼠标监听器
BirdListener bl = new BirdListener();
jf.addMouseListener(bl);
while(true){
//延迟
try {
sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//如果按下了起飞
if(flyingFlag){
if(dist<=0){
dist=25;
flyingFlag = false;
}
else{
Fly();
dist--;
}
continue;
}
//自动下落
DownBird();
}
}
public void Fly(){
Y-=3;
}
public void DownBird(){
Y+=2;
}
public int getX(){
return X;
}
public int getY(){
return Y;
}
}
还有就是点击事件,让鸟改变方向移动一段距离:
public class BirdListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
BirdManage.flyingFlag = true;
BirdManage.dist = 25;
}
}
还有就是一个队列类nodeQueue(),就不拿出来啦。。
最后感觉做出来的游戏,动画上还是和原作差不多,但是鸟的移动就感觉有点生硬,在考虑重力加速度而不是单纯地匀速移动之后应该会有更好的效果。然后看到最近挺火的超难游戏I Wanna 之后,感觉添上一些未知陷阱会添加更多欢乐,接下来往这方面修改。
分享到:
相关推荐
主要内容: 1.熟悉中控台的操作 2.熟悉在多线程下参数传递及子程序调用 3.副本功能的简单制作 4.特色功能的简单思路 幻想神域多线程实战视频 ...多线程实战之自动卖店(保留指定物品, 补充线程监控)
Java多线程编程实战指南(核心篇) 高清pdf带目录 随着现代处理器的生产工艺从提升处理器主频频率转向多核化,即在一块芯片上集成多个处理器内核(Core),多核处理器(Multicore Processor)离我们越来越近了――如今...
C++多线程 windows
c#多线程编程实战(原书第二版)源码
C#多线程编程实例实战.pdf
汪文君JAVA多线程编程实战(完整不加密)。 汪文君JAVA多线程编程实战(完整不加密),连接挂了留言, 我补 java 汪文君 多线程 视频教程 实战。
Java 高并发编程相关知识, 接下来将阅读该书, 并且进行比较详细的总结, 好记性不如烂笔头, 加油。 Java 多线程编程实战指南。
C#多线程编程实例实战.doc
P303.zip
详细的讲解了java多线程的原理,并配有代码进行实战,适合java初学者和想对多线程有进一步了解的人。
C#多线程编程实战.pdf
Java多线程并发实战,值得推荐
C++多线程编程实战 ,姜佑译(2018年PDF高清).rar C++多线程编程实战 ,姜佑译(2018年PDF高清).rar
C++多线程编程实战 姜佑译
在计算机处理器发展为包含越来越多的核心的时期,多线程是创建可伸缩性、高效的、高响应性应用程序的关键因素。如果你没有正确地使用多线程,它会导致难以捉摸的问题,需要你花费大量时间去解决。因此,现代应用程序...
讲解.NET多线程的书不是很多,至少在国内很少,这本书叫实战,算是名副其实吧,这本书讲解的理论不多,但是句句堪称经典。在讲解整个.NET的多线程体系时,讲解全面,从开始的创建线程,到最后的C#5.0引入的线程处理...
C#多线程编程实战原书第二版 完整实例源码,非常好的C#多线程编程学习资源,需要VS2015。
多线程在实际开发中有着举足轻重的作用,但在教科书中并没有学到,本文以mysql(支持任何数据库)插入数据和查询数据为例子,讲述了如何在几秒钟内疯狂插入几十万数据,在一个方法中如何同时运行多条SQL语句(效率比...
《C#多线程编程实战》.((美)Eugene Agafonov).[PDF]《C#多线程编程实战》.((美)Eugene Agafonov).[PDF]《C#多线程编程实战》.((美)Eugene Agafonov).[PDF]