【Android游戏】Android平台飞机大战游戏APP设计与实现

  • 前言
  • 一、界面设计与功能实现
  • 二、数据库设计与实现
    • 2.1 Room数据库的好处
    • 2.2 Room的配置
    • 2.3 表的设计
    • 2.4 Room的管理与应用
  • 三、服务器设计与实现
    • 3.1 绑定端口
    • 3.2 动作数据与提示信息同步
  • 四、其他功能实现
    • 4.1 飞机碰撞的原理与实现
    • 4.2 摇杆功能的实现
    • 4.3 音乐服务的实现
    • 4.4 recycleview 适配器的实现

前言

本系统是基于以上主流开发工具之一的 Android Studio 软件进行客户端的开发, 利用 Eclipse2017 软件实现服务器端开发,所用语言皆为 Java 语言。通过上述软件开发一款童年经典的小游戏: 飞机大战小游戏。


一、界面设计与功能实现

【Android游戏开发详细过程1】Android平台飞机大战游戏APP设计与实现

二、数据库设计与实现

2.1 Room数据库的好处

Room 因其良好的开发经验大大降低了 SQLite 的门槛。与 sqliteopenhelper 等传统方法相比,使用 room 驱动 SQLite 具有以下好处:
(1) API 设计友好, 使人容易理解。
(2) 编译期的 SQL 语法检查。
(3) 开发效率高,避免了大量的模板代码。
(4) 可以和 RxJava、 LiveData 等进行桥接。

2.2 Room的配置

在 Gradle scripts 下的第二个 build.gradle 下添加依赖如下。

implementation "androidx.room:room-runtime:2.4.2"
annotationProcessor"androidx.room:room-compiler:2.4.2"

在项目中创建一个新目录 room,在里面添加表,数据库,和数据库访问者。

2.3 表的设计

(1) 项目要用到的表有用户表 User,里面的属性如表 3.2 所示;飞机商店表ShopPlane,里面的属性如表格 3.3所示;用户飞机表 MyPlane,里面的属性如表格 3.4 所示。
(2) 多对多关系中, 主表中的一条数据映射着从表中的零个或多个, 反之一样。每个 User 中可以有很多的商店飞机(ShopPlane),每个商店的飞机可以归属于不同的用户(User), 因此, User 和 ShopPlane 之间时多对多的关系。
定义两个表的联合表 MyPlane 关键代码如下:

@Entity(primaryKeys = {"planeId","userId"},
foreignKeys ={@ForeignKey(entity = User.class,parentColumns = "userId",child Columns = "userId"),
@ForeignKey(entity = ShopPlane.class,parentColumns = "planeId",childColum ns = "planeId")} )//在定义类名的前面书写这些代码。

多键对多键关系中, User表之间与 ShopPlane表之间并不是一个确定的外键的约束连接关系, 必须先建立起一种交叉的连接关系表: MyPlane 表, 然后再依次分别为 User 表之间与 ShopPlane 表之间产生一个有约束连接的外键。 User表与 ShopPlane 表之间的笛卡尔积分是数据交叉与连接的一个结果,即是二表数据的联合。

2.4 Room的管理与应用

(1) 它主要包括三个组件如下表 3.5 所示:

(2) 三个组件的关系图如图 3.15 所示。
(3) 数据库(Database)是我们对底层数据库的访问, 创建 UserDatabase 关键代码如下:

@Database(entities ={User.class,MP.class,ShopPlane.class},version = 1,exportS chema = false)//在类名前定义, 异步开启数据库:
INSTANCE = Room.databaseBuilder
(context.getApplicationContext(),UserDatabase.class,"user_database")
.build();

( 4) 实体表示数据库中的表。我们使用@entity 来定义一个实体类,类中的属性对应于表中的列;所有属性必须是公共的,或者具有 get 或 set 方法;属性中至少有一个主键。使用@primarykey 表示一个主键,或定义多个主键,如下所示:当主键值为空时, autogenerate 能够使得在@primarykey( autogenerate=true)下自动生成键值。
( 5) DAO( Data Access Object) 提供了访问数据库的接口, DAO 的方法使用需要在当前线程进行, 因此要免于在 UI 线程直接使用。通过@Dao 定义 DAO 类,使用@Insert、 @Query 、 @Delete 注释增删改。 自定义UserDao, MyPlaneDao 和 ShoPlaneDao 接口用他们来定义要实现的语句。
( 6)定义一个 DBEngine 用来管理数据库,详细实现数据库的增删改查,用户不用在 Activity 类中调用 DAO 的接口,只需要在调用 DBEngine 书写的方法即可,减少Activity 类代码的冗余性。

三、服务器设计与实现

3.1 绑定端口

端口的实现和使用过程如下:
( 1) 创建服务器线程 ServerThread,在里面通过 new ServerSocket(9999)开放9999 号端口,同时开启动作捕捉线程 ActionThread。
( 2) 监听服务器端口。一旦数据被发送,它将被封装到一个套接字对象中。如果没有发送数据,它将处于线程阻塞状态,不会继续向下执行。 核心代码是 socket sc=ss. accept();
( 3) 一旦有数据发来,就执行动态代理线程ServerAgentThread, 负责和客户端交流数据。
( 4) 客户端为手机模拟器和服务端为真实手机,他们两个需要连在同一局域网下, 所以需要真实手机连接电脑的 WIFI。
( 5) 两个用户成功连接后,服务器端运行如图 3.16 所示

3.2 动作数据与提示信息同步

通过对动作数据的同步来更新队友屏幕上的动作,实现过程如下:
(1) 为套接字初始化输入输出流 new DataInputStream()和 new DataOutputStream()
(2) 在通过输入流 readUTF()接受数据时,服务器通过 startsWith(“<#CONNECT#>”)函数来检查是否带有连接字样开头的数据。
(3) 如果有则将客户端用户添加到 List 集合中,并返回个客户端连接成功字样即 writeUTF(“<#OK#>”),最多能连接两个客户,第一个为红飞机连接,第二个为黄飞机连接,两个飞机连接成功后提示客户端可以开始游戏的字样。 如果还有客户端想要继续连接则返回该客户端用户已经满的字样。
(4) 当两个飞机连接成功后,客户端将带有 KEY 字样的数据连同用飞机的偏移量一同发给服务器端,服务器代理器接收到带有 KEY 开头字样的数据以后将他通过 substring()和 split()进行分割,分别得到飞机的偏移量 X 和
Y 并存储到动作队列中。
(5) ActionThread 将新产生的红飞机或者黄飞机的 X 和 Y 得值从队列中获取出来并将动作移除队列,数据再在动作类 Action 中进行计算和范围限制,最后通过服务器代理的 broadcastState()方法发送给所有的客户端, 数据加上了 GAME_DATA 的前缀
(6) 客户端接收到数据后用 subString()和 Split()函数对数据进行拆分,并将飞机的 x 和 y 数据进行赋值,别通过绘制线程 DrawThread 进行实时更新。
(7) 注意在绘制飞机坐标数据时要加锁this.activity.gamedate.lock 防止服务器新来的游戏数据将之前的替换掉。还要注意关闭输入输出流和套接字。
核心代码:

synchronized(this.activity.gamedate.lock)
{this.activity. gamedate.rx=trx;
this.activity. gamedate.ry=try;
this.activity. gamedate.gx=tgx;
this.activity. gamedate.gy=tgy;
}

四、其他功能实现

本应用中还有几个重要的技术需要深刻讨论,他们的实现也占据了项目开发的大部分时间,主要思考为数学逻辑和流程逻辑。

4.1 飞机碰撞的原理与实现

在解释碰撞原理之前我们要知道, event.getX()和 event.getRawX()的异样, event.getX()是触碰点相对于它所在组件坐标系的坐标; event.getRawX()是触碰点相对于屏幕默认坐标系的坐标。 横屏时, X 的值随着手机左侧到右侧逐渐变大, Y 的值随着手机从上到小变大,如图 3.25 所示
碰撞的双方为两个长方形图片,假设为 Rect1,中心点为(x1, y1),宽为w1,高为 h1 和 Rect2, 中心点为(x2, y2),宽为 w2,高为 h2,则如果同时满足如下四步则判断为碰撞:
x1+w1 >= x2, x2+w2 >= x1,y1+h1 >= y2,y2+h2 >= y1, 飞机碰撞关键代码如下:

(myPlaneBullet.getBullet_x()+myPlaneBullet.getBulletImgWidth()>=
enemyPlane.getPlane_x())
&&(enemyPlane.getPlane_x()+enemyPlane.getPlaneImgWidth()>=my
PlaneBullet.getBullet_x())
&&myPlaneBullet.getBullet_y()+myPlaneBullet.getBulletImgHeight()
>=enemyPlane.getPlane_y())
&&(enemyPlane.getPlane_y()+enemyPlane.getPlaneImgHeight()>=m
yPlaneBullet.getBullet_y()//子弹和飞机碰撞代码类似只是参数不同

原理图如图 3.17 所示。

4.2 摇杆功能的实现

(1) 先找两个圆形摇杆图片一个大圆和一个小圆, 根据横屏时 x, y 坐标系设置摇杆图片的初始位置,小圆和大圆的圆心在同一位置,再设置动态圆的半径。 游戏中摇杆的形式主要有两种方式:固定式和跟随式。
本项目开发的摇杆为固定式,即内环圆心在外环圆内移动;外环位置固定不能移动。 更改方法为判断触碰点 P 是否在外环圆内, 若是则直接让内环到 P点, 若不是则计算新旧位置之间的向量[9]。
(2) 方向控制包括四个方向和八个方向。有一种常用的计算方法:计算内外环中心的角度,然后根据角度定义为四个方向: 上、下、左、右,以及八个方向:左上、左下、右上和右下。
角度用三角函数计算,过程如下:

  1. 得到两点 x 的距离。
  2. 得到两点 y 的距离。
  3. 算出斜边长度。
  4. 得到这个角度的余弦值。
  5. 通过反余弦函数得到弧度。
  6. 四方向和八方向判断。
    关键代码如下所示:
    //获取水平夹角弧度。
float lenA=x2-x1;
float lenB=y2-y1;
float lenC=(float) Math.sqrt(lenA*lenA+lenB*lenB);
float angle=(float)Math.acos(lenA/lenC);
angle=angle*(y2<y1?-1:1);
//获取长度
int result=(int)Math.sqrt(Math.pow(x-centerX, 2)+Math.pow(y-centerY, 2));

(3) 最后根据方向和飞机的移动速度, 修改飞机的坐标。

4.3 音乐服务的实现

(1) 游戏大厅背景音乐实现:选择非绑定式界面,让背景音乐在设置界面、我的飞机和商店界面仍能继续播放, 但是当进入游戏时将背景音乐关掉。播放游戏相关的音乐。 实现过程如下:

  1. 在服务中引用要播放的音乐,他们存放在 raw 文件夹下,用 int 型数组引用即可。
  2. 创建广播接收器 new MyReciver(),以便设置界面能够进行音乐的相关设置。
  3. 创建播放器 new MediPlayer(),通过音乐 ID 来播放音乐,关键代码如下:
mPlayer=MediaPlayer.create(this,music);//将音乐加入播放器
mPlayer.start();//播放音乐
mPlayer.setLooping(true);//允许循环播放
  1. 创建 IntentFilter 过滤器,使音乐服务器端的接收器只能接受客户端发来的 CTL_ACTION 消息,注册带有此筛选器的接收器。关键代码如下:
IntentFilter filter = new IntentFilter();
filter.addAction(Set_UpActivity.CTL_ACTION);
registerReceiver(serviceReceiver, filter);
  1. 为音乐播放器绑定监听器,监听是那首音乐和音乐的播放状态,并将它们通过广播发送个设置界面以便来查看音乐播放的状态。 关键代码如下:
Intent sendIntent = new Intent(Set_UpActivity.UPDATE_ACTION);
sendIntent.putExtra("update", status);
sendIntent.putExtra("current", current);
sendBroadcast(sendIntent);
  1. 通过服务中的线程来刷新设置界面中音乐的进度条。
    (2) 游戏音乐实现: 创建 MusicUtil 将要播放的音乐信息通过键值对的方式存放在 HashMap 中。 在游戏运行的线程 GameRunThread 中播放背景音乐,并且每当方式我方机和敌机,我方子弹和敌机碰撞时播放音乐特效。 核心代码如下:
MusicUtil.soundPool.play(MusicUtil.sounds.get(1),1,1,2,-1,1);

MusicUtil.sounds.get(1)为播放的音乐 ID 号,两个 1 为左右声道, 2 为优先级, -1为循环播放,最后一个 1 为正常倍速。

4.4 recycleview 适配器的实现

(1) recycleview 控件和适配器 Adapter 联合使用,能够将图片和文本大量的调入,使显示的方法更加容易。
(2) 导入 recycleview 依赖,如下:implementation ‘androidx.recyclerview:recyclerview:1.1.0’
(3) 相关适配器继承 RecyclerView.Adapter<MyPlaneAdapter.MyPlaneViewHolder>并重写它的方法:

  1. onCreateViewHolder()在这里面添加要显示的控件布局
  2. onBindViewHolder()在这里面这只每一个控件的详细内容
  3. getItemCount()获取控件数据的数量
    (4) 在适配器中书写内部类 MyPlaneViewHolder 继承 RecyclerView.ViewHolder 用来初始化控价,并为控件增加点击监听事件。
    (5) 在界面中调用适配器遵循四部原则:初始化适配器,初始化界面布局,设置界面布局和界面添加适配器。(顺序不可颠倒),关键代码如下:
Adapter adapter = new Adapter(相关参数);
GridLayoutManager gridLayoutManager = new GridLayoutManager(相关参数);
控件区域.setLayoutManager(gridLayoutManager)
控件区域.setAdapter(adapter);

(6) 当然数据需要通过 List 集合进行添加,先初始化 List:
List<对象> data = new ArrayList<>(); 再将每个对象的相关属性进行添加,最后通过 data.add(对象名)将每个对象添加到集合中去。

【Android游戏开发详细过程2】Android平台飞机大战游戏APP设计与实现相关推荐

  1. C++游戏编程教程(七)——改进飞机大战游戏

    注:在本篇博客中,对上一篇博客的飞机大战游戏进行了完善,但有很多细微的修改,由于篇幅原因,没有把所有代码列出来,大家需要仔细阅读,否则可能漏掉一些地方,导致编译错误或产生bug. PS:如果大家有什么 ...

  2. 体感游戏 | 手势识别玩飞机大战游戏(三) 使用OpenCV实现手势识别玩飞机大战游戏

    后面将分四篇文章来介绍实现手势识别控制飞机大战游戏的功能,它们分别是: 使用Pygame实现简易飞机大战小游戏 使用Python+OpenCV实现简单手势识别 使用OpenCV实现手势识别玩飞机大战游 ...

  3. 华为云IOT Android应用开发详细教程

    华为云IOT Android应用开发详细教程 (Android Studio开发) 第〇章    简介       大家好,上一期发布的教程叫大家如何利用华为云物联网平台提供的官方Java Demo去 ...

  4. 鸿蒙开发实例 | ArkUI JS飞机大战游戏开发

    本篇介绍使用ArkUI JS框架开发一款基于鸿蒙操作系统的飞机大战游戏.这款飞机大战游戏是在普通单机游戏的基础上添加了鸿蒙操作系统分布式支持,使游戏可以同时使用多台鸿蒙操作系统设备,为游戏玩家提供分布 ...

  5. 基于Java的飞机大战游戏的设计与实现论文

    源码下载 http://www.byamd.xyz/hui-zong-1/ 摘 要 现如今,随着智能手机的兴起与普及,加上4G(the 4th Generation mobile communicat ...

  6. 基于Java的飞机大战游戏的设计与实现(含源文件)

    欢迎添加微信互相交流学习哦! 项目源码:https://gitee.com/oklongmm/biye 基于Java的飞机大战游戏的设计与实现 摘   要 现如今,随着智能手机的兴起与普及,加上4G( ...

  7. 基于Java的飞机大战游戏的设计与实现(论文+源码)

    毕业设计(论文)任务书 第1页 毕业设计(论文)题目:基于Java的飞机大战游戏的设计与实现毕业设计(论文)要求及原始数据(资料):1.综述基于Java的飞机大战游戏的现状:2.深入了解Java的设计 ...

  8. 【java毕业设计】基于java+Eclipse的飞机大战游戏设计与实现(毕业论文+程序源码)——飞机大战游戏

    基于java+Eclipse的飞机大战游戏设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于java+Eclipse的飞机大战游戏设计与实现,文章末尾附有本毕业设计的论文和源码下载地址哦. ...

  9. 基于pygame实现的飞机大战游戏

    目录 1.引言 1.1 背景 1.2 意义 1.3 功能 2.系统结构 2.1 整体框架 2.2 精灵与精灵组 2.3 功能介绍 2.3.1 玩家飞机 2.3.2 敌机类型和关卡设定 2.3.3 敌机 ...

  10. 飞机大战游戏python_基于Python的飞机大战游戏

    基于 Python 的飞机大战游戏 杨铠 [期刊名称] <电脑迷> [年 ( 卷 ), 期] 2017(000)021 [摘要] 我们每天都享受到科技带来的好处 , 了解计算机编程对每个人 ...

最新文章

  1. caffe anaconda3 Python.h: 没有那个文件或目录
  2. JDBC+Servlet+JSP整合开发之22.JSP简介
  3. WWW 2022 | 弯道超车:基于纯MLP架构的序列推荐模型
  4. 03 | AOF 日志:宕机了, Redis 如何避免数据丢失?
  5. 前端面试之Vue相关总结
  6. 王道 —— 进程互斥的软件实现方法
  7. python求众数程序_求众数(python实现)
  8. router-LInk传参与接受参数(记录)
  9. pandas中dataframe的索引问题
  10. 中国·哈尔滨国际友好城市冰雪汽车挑战赛开赛
  11. vivado版本升级导致的IP锁定的更新解决办法
  12. python 使用PIL工具包中的pytesseract函数识别英文字符
  13. 自我鉴定计算机专业大学,大学生计算机专业的自我鉴定书
  14. 第三代USRP 产品对比
  15. DoIP节点连接状态管理
  16. 理解ES6中的TDZ(暂时性死区)
  17. WINUSB设备的inf文档的编写
  18. linux注销系统有几种方法,怎么注销Linux子系统
  19. Ubuntu18.04美化主题(mac主题)
  20. spleeter音乐人声分离、5种架子鼓钢琴声音分离的高质量模型运行超详细教程windows+ubuntu18.04

热门文章

  1. Qt学习之路八——利用qt对数据库进行操作
  2. 涉密计算机检查问题,针对RG涉密信息自检查工具1.0Beta检查出来的电脑泄密问题的应对措施?...
  3. 喜马拉雅音频批量下载
  4. STM32入门(一)Keil5软件安装以及使用
  5. OpenGL学习(八)phong光照模型
  6. Mathtype公式编辑器常用快捷键
  7. Java8 实战系列-02-lambda 表达式简介
  8. PMP考试重点总结二——启动过程组
  9. readelf命令使用
  10. 挑战程序设计竞赛——抽签Ⅱ