线程游戏实战之像素肥鸟
基于被这款游戏的虐心经历后,决定把刚学的线程应用出来,模仿写出这一个游戏,基本游戏功能实现后打算写个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 之后,感觉添上一些未知陷阱会添加更多欢乐,接下来往这方面修改。
线程游戏实战之像素肥鸟相关推荐
- java线程游戏V4之飞机大战(一)
关于实现飞机大战线程游戏,需要几点,首先是战机类,然后我方与敌方战机分别作为子类继承它.然后是子弹类,也分为敌方子弹和我方子弹.接着是需要的线程. 首先创建一个界面,创建GameUI类继承JFrame ...
- 【微信小游戏实战】零基础制作《欢乐停车场》二、关卡设计
1.游戏立项 微信小游戏中有一款<欢乐停车场Plus>的小游戏,大家可以搜索玩下.这是一款益智类的小游戏,游戏中有红.黄.绿.蓝.紫5辆豪车6个停车位,玩家通过可行走路线移动小车,最终让各 ...
- Swift游戏实战-跑酷熊猫 01 创建工程导入素材
原文:Swift游戏实战-跑酷熊猫 01 创建工程导入素材 在这节里,我们将建立一个游戏工程,并导入一些必要的素材,例如序列帧动画文件,声音素材文件.动画文件我们使用atlas形式.在打包发布或者模拟 ...
- python 写游戏好简单啊,我用键盘可以随意控制角色了【python 游戏实战 04】
前言 本系列文章将会以通俗易懂的对话方式进行教学,对话中将涵盖了新手在学习中的一般问题.此系列将会持续更新,包括别的语言以及实战都将使用对话的方式进行教学,基础编程语言教学适用于零基础小白,之后实战课 ...
- 这是我第一次使用代码创建出一个窗口【python 游戏实战 01】
前言 本系列文章将会以通俗易懂的对话方式进行教学,对话中将涵盖了新手在学习中的一般问题.此系列将会持续更新,包括别的语言以及实战都将使用对话的方式进行教学,基础编程语言教学适用于零基础小白,之后实战课 ...
- 《看聊天记录都学不会Python到游戏实战?太菜了吧》(8)我们开始做一个数字小游戏吧
本系列文章将会以通俗易懂的对话方式进行教学,对话中将涵盖了新手在学习中的一般问题.此系列将会持续更新,包括别的语言以及实战都将使用对话的方式进行教学,基础编程语言教学适用于零基础小白,之后实战课程也将 ...
- 《看聊天记录都学不会Python到游戏实战?太菜了吧》(10)无底洞的循环
本系列文章将会以通俗易懂的对话方式进行教学,对话中将涵盖了新手在学习中的一般问题.此系列将会持续更新,包括别的语言以及实战都将使用对话的方式进行教学,基础编程语言教学适用于零基础小白,之后实战课程也将 ...
- 《看聊天记录都学不会Python到游戏实战?太菜了吧》(7)我用函数写了个特洛伊木马
本系列文章将会以通俗易懂的对话方式进行教学,对话中将涵盖了新手在学习中的一般问题.此系列将会持续更新,包括别的语言以及实战都将使用对话的方式进行教学,基础编程语言教学适用于零基础小白,之后实战课程也将 ...
- 【Java线程】“打工人”初识线程池及自定义线程池实战
目录 理论 原理 线程池创建 工作流程图 拒绝策略 参数设置 四种线程池 实战 理论 聊一下为什么要使用线程池? 程序的运行本质,就是通过使用系统资源(CPU.内存.网络.磁盘等等)来完成信息的处理, ...
最新文章
- python ftp文件夹文件递归上传推送
- 1002: A+B for Input-Output Practice (II)
- iOS从零开始学习直播之音频2.后台播放和在线播放
- android常见面试问题
- 第一百零一期:如何处理ASP .NET Core中的cookie?
- butterknife 不能绑定错误
- 逻辑表达式是否合法_Linux shell 逻辑运算符、逻辑表达式详解
- phoenix timestamp字段查询
- 最简单的c 语言打开串口程序,一个简单的串口程序
- 实对称矩阵的特征值求法_旋转之三 - 旋转矩阵
- 【历史上的今天】7 月 3 日:人体工程学标准法案;消费电子领域先驱诞生;育碧发布 Uplay
- Cocos2d-x手机游戏开发视频教程
- 以太网结构框架的学习
- 2022树莓派安装甜糖 步骤分享
- springboot+mybatis打包时,单元测试类报错
- Python学习笔记_获取猫耳广播剧
- JVM参数-XXMatespaceSize的含义
- Python 二分法求多项式单根
- 开发微信小程序都需要哪些资质?
- 鸿蒙系统运行内存为啥只有8g,为什么手机运存是8G的,但是可用却只有5G?
热门文章
- 【示波器专题】数字示波器的主要指标——采样率
- python读conf配置文件_python读写配置文件操作示例
- STM32标准外设库
- 【谦川解读】特斯拉事件:安全,智能汽车的达摩克利斯之剑
- 【实验】流量控制之分为流量抑制和风暴控制
- 数字图像处理matlab实践
- 2018 中国大陆网速排名世界 141 位;Linux 4.18 内核发布
- MASM32连接程序时error A2006: undefined symbol : u
- 记武汉疫情期间的一次数据库和翻译记忆库的数据恢复 (一)
- mysql select符合查询_mysql学习-select查询,子查询,联接查询,union,intersect,except联合...