简单小游戏flappybird制作(八)

这次也是最后一次我们来说一说world类,world类继承了JPanel实现了Runnable接口
数据成员如下
private static boolean flag;
 private Thread th;
 private boolean diepoint;
 private static final int gamestart=0;
 private static final int gamerecord=4;
 private static final int gameready=1;
 private static final int gameplaying=2;
 private static final int gameover=3;
 private static int gamestate;
 public static final int gameW=448,gameH=685;
    private int score;
    private BufferedImage background;
 private BufferedImage readyImg;
 private BufferedImage gameoverImg;
 private Num num;
 private Start start;
 private Bird bird;
 private Ground ground;
 private Pipe pipe1;
 private Pipe pipe2;
 private AudioPlay wing;
 private AudioPlay point;
 private AudioPlay die;
 private AudioPlay hit;
 private int rateindex=1;
 private int sleeptime=15;

flag是线程运行的标志,当我们需要关闭线程的时候只要将flag置为false就行了。
gamestate是当前游戏状态标志,值有gamestart,gamerecord,gameready,gameplaying和gameover几类。

gameW和gameH是窗口宽高,score分数,background背景图片,readyImg准备界面图片,gameoverImg是gameover界面图片。diepoint是用来指示是否在gameover界面播放过die音效的指示器,rateindex是游戏难度级别默认为1,sleeptime是线程休眠时间,用来控制画面刷新速度。
public World() throws IOException {
		wing=new AudioPlay("wav/wing.wav");
		point=new AudioPlay("wav/point.wav");
		die=new AudioPlay("wav/die.wav");
		hit=new AudioPlay("wav/hit.wav");
		readyImg = ImageIO.read(new File("img/readyImg.png"));
		background = ImageIO.read(new File("img/bg.png"));
		gameoverImg = ImageIO.read(new File("img/gameover.png"));
		gamestate=gamestart;
		start();
	}
构造方法如上,没什么好说的。
private void start() throws IOException {
	score=0;
	diepoint=false;
        flag=true;
        num=new Num();
        start=new Start();
        bird=new Bird();
        ground=new Ground();
        pipe1=new Pipe(1);
        pipe2=new Pipe(2);
	}
start方法是游戏由gameover重新开始的入口,执行的也是一些初始化操作。

private void doInit() throws IOException {
        addMouseListener(new MouseAdapter() {
        	public void mousePressed(MouseEvent e) {
        		switch(gamestate) {
        		case gamestart:
        			if(e.getX()>40&&e.getX()<195&&e.getY()>470&&e.getY()<560) {
        				gamestate=gameready;
        			}else if(e.getX()>240&&e.getX()<390&&e.getY()>470&&e.getY()<560) {
        				gamestate=gamerecord;
        			}else if(e.getX()>170&&e.getX()<260&&e.getY()>350&&e.getY()<410) {
        				if(rateindex==3) {
        					rateindex=0;
        				}
        				rateindex++;
        				bird.setrate(rateindex);
        				setrate(rateindex);
        			}
        			break;
        		case gamerecord:
        			gamestate=gamestart;
        			break;
        		case gameready:
        			gamestate=gameplaying;
        			break;
        		case gameplaying:
        			bird.up();
					wing.play();
        			break;
        		case gameover:
        			if(e.getX()>130&&e.getX()<285&&e.getY()>330&&e.getY()<410) {
        				flag=false;
        				gamestate=gameready;
        				try {
        					start();
        				} catch (IOException e1) {
        					e1.printStackTrace();
        				}
        				bird.setrate(rateindex);
        				setrate(rateindex);
        			}
        		}
        	}
        });
        th=new Thread(this);
        th.start();
	}
doInit是第一次进入游戏的入口,用来添加鼠标监听并在鼠标监听里添加游戏流程控制代码,也是不用按钮实现一部分按钮功能的窍门所在。
游戏的流程全靠gamestate控制。

当gamestate==gamestart时也就是在开始界面,在rate图案范围内点击鼠标调用bird类和本类的setrate方法设置难度gamestate不变。在start图案范围内点击鼠标设置gamestate为gameready,也就是进入准备状态。在record图案范围内点击鼠标设置gamestate为gamerecord,也就是进入显示最高记录的状态。

当gamestate==gamerecord时也就是在record界面点击任意位置,置gamestate为gamestart,也就是恢复游戏的开始状态。

当gamestate==gameready时也就是在准备界面点击任意位置使gamestate=gameplaying表示游戏正在进行。
在游戏进行界面任意位置点击鼠标就是控制小鸟向上飞了。此外还会条用play方法播放小鸟挥动翅膀的音效。

当gamestate==gameover时,点击restart图案所在位置就会设gamestate=gameready重新回到准备界面。此外还要调用两个setrate方法使游戏难度保持一致。


doInit方法末尾是启动游戏的线程。

public void run() {
		while(flag) {
			long starttime = System.currentTimeMillis();
			if(gamestate==gamestart) start.refresh();
			if(gamestate==gameplaying) {
				bird.step();
				pipe1.step();
				pipe2.step();
				if(bird.pass(pipe1,pipe2)) {
					point.play();
					score++;
				}
				if(bird.hit(pipe1,pipe2,ground)) {
						hit.play();
					gamestate=gameover;
				}
			}		
			if(gamestate!=gameover&&gamestate!=gamestart&&gamestate!=gamerecord) bird.fly();
			if(gamestate==gameover) {
				BufferedReader fin=null;
				try {
					fin = new BufferedReader(new InputStreamReader(new FileInputStream("rec/record.txt")));
				} catch (FileNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				String recordline=null;
				try {
					recordline = fin.readLine();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				int record=Integer.valueOf(recordline);
				if(score>record) {
					BufferedWriter fout=null;
					try {
						fout = new BufferedWriter(new FileWriter("rec/record.txt"));
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					String scoreline=String.valueOf(score);
					try {
						fout.write(scoreline);
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					try {
						fout.flush();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					try {
						fout.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
run方法里starttime、endtime和sleeptime是用来控制图案刷新速率的。代码的大部分是先判断当前的游戏状态是否是bird、pipe等对象需要刷新的状态,如果是则刷新对象的位置,然后调用repaint方法重绘整个画面。其中调用的bird类的pass方法判断是否得分,调用hit方法判断是否碰撞,如果碰撞设gamestate为gameover并判断最高记录和得分的大小,如果得分更大,则以覆盖的方式写入record.txt文件。
public void setrate(int n) {
		if(n==1) {
			sleeptime=15;
		}else if(n==2) {
			sleeptime=9;
		}else if(n==3){
			sleeptime=5;
		}
	}
设置难度的方法。
public void paint(Graphics g) {
		if(gamestate!=gamestart) {
			g.drawImage(background,0,0,null);
		}
		if(gamestate!=gamestart&&gamestate!=gameready&&gamestate!=gamerecord) {
			pipe1.paint(g);
			pipe2.paint(g);
			if(score<=999) {
				num.paint(g, score,0);
			}else {
				num.paint(g, -1,0);
			}
		}
		if(gamestate!=gamestart) {
			ground.paint(g);
		}
		if(gamestate!=gamestart&&gamestate!=gamerecord) {
			bird.paint(g);
		}
		if(gamestate==gamestart) {
			start.paint(g);
			num.paint(g, rateindex, 2);
		}
		if(gamestate==gameready) {
			g.drawImage(readyImg, 0, 0, null);
		}
		if(gamestate==gamerecord) {
			BufferedReader fin=null;
			try {
				fin = new BufferedReader(new InputStreamReader(new FileInputStream("rec/record.txt")));
			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
			}
			String recordline=null;
			try {
				recordline = fin.readLine();
			} catch (IOException e) {
				e.printStackTrace();
			}
			int record=Integer.valueOf(recordline);
			if(record<=999) {
				num.paint(g, record, 1);
			}else {
				num.paint(g, -1, 1);
			}
			try {
				fin.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		if(gamestate==gameover) {
				if(!diepoint) {
					die.play();
					diepoint=true;
				}
			g.drawImage(gameoverImg, 0, 0, null);
		}
	}
paint方法跟run方法类似,也是先判断当前状态是否是对象需要重绘的状态,如果是则重绘图像。另外当gamestate==gamerecord的时候读取record.txt中的记录并绘制。
JFrame frame=new JFrame("Flappy Bird");
		World world=new World();
		frame.add(world);
		frame.setBounds(20, 40, gameW, gameH);
		frame.setResizable(false);
		frame.setVisible(true);
		frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                flag = false;
                frame.dispose();
                System.exit(0);
            }
            });
		world.doInit();
	}
最后main方法就是建立新的框架和面板设置相应参数,并进入游戏。
至此一个简单的flappybird游戏就编好了。
相关图片和音频资源链接如下:
点击打开链接




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值