线程游戏实战之像素肥鸟

基于被这款游戏的虐心经历后,决定把刚学的线程应用出来,模仿写出这一个游戏,基本游戏功能实现后打算写个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 之后,感觉添上一些未知陷阱会添加更多欢乐,接下来往这方面修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值