Java Swing制作古老的打砖块游戏

2023-05-16

 最近研究了一下古老的Java Swing,研究之余,突发奇想开发了一个打砖块小游戏。
首先看一下效果图brick game
在这里插入图片描述

具体过程

  • 1.游戏框架搭建
    • 1.1步骤
  • 2.开发过程
    • 2.1各种游戏对象的绘制
    • 2.2游戏对象的运动
    • 2.3小球和砖块的碰撞检测
    • 2.4砖块被碰撞后的爆炸效果
  • 3.测试、完善。

1.游戏框架搭建

 整个游戏的画面的绘制渲染都位于JFrame上面,通过重写JFrame的paint(Graphics g)方法,完成所有游戏对象的绘制和各种效果的处理。注意不要调用super.paint(g)方法。
*[在这个过程中参考了一个大牛的Java 2D游戏系列文章,在此表示由衷的感谢。]*具体参考:https://blog.csdn.net/xcantloadx/category_7191132.html

1.1步骤

(1)这个过程主要是启动了一个游戏运行的窗口;
(2)为了让游戏中的对象动起来增加了一个渲染线程,按固定频率刷新;
(3)为与用户交互,控制挡板,窗口增加了键盘事件的监听和处理;
(4)当游戏中的对象动起来的时候出现闪烁现象,增加了双缓冲处理解决之;

2.开发过程

 为了方便和简单,在游戏开发过程中最终没有使用图片,也尝试了图片的小球、挡板、砖块,但是最终决定用最简单的几何图形绘制来表现各种游戏对象,在打砖块中只有简单的圆形和矩形,没有复杂的形状。

2.1各种游戏对象的绘制

(1)小球的绘制直接使用圆形,给定一个固定的半径,然后画圆,Swing的画圆是根据一个矩形,绘制矩形的内切圆,给出的坐标是矩形左上角的坐标,因此,如果需要获得圆心坐标,还需要在此基础只是各增加半径得到。
(2)挡板和砖块的绘制均为直接使用矩形,给出宽度、高度、坐标,然后画矩形。

2.2游戏对象的运动

(1)挡板的左右移动主要是靠键盘的左右方向键来控制,在挡板的左右移动中主要注意挡板到达边界的处理,不要移动到可视区域外面即可。
(2)按住方向键(up)游戏开始,小球开始运动。小球的运动范围位于整个窗口范围内,碰到墙后相应的改变方向,碰到挡板上面后继续弹起,如果落到挡板以下,则Game Over,碰到游戏内的砖块,显示一个爆炸效果并播放音效,砖块消失。

2.3小球和砖块的碰撞检测

 在实现小球和砖块碰撞效果的时候,自己直接使用逻辑判断来实现,然而常常没有考虑全面,出现了一些违反常理的现象,比如小球没有碰到砖块呢,可是砖块它消失了。而且觉得小球和砖块的碰撞情况也很复杂,没有想出全面的方法,小球碰到砖块的四个角是碰撞,碰到砖块的四个面那也是碰撞,感觉颇为棘手。于是借助了搜索引擎找到了一篇CSDN大牛的文章https://blog.csdn.net/yorhomwang/article/details/18195993,作者是在开发塔防游戏中涉及到此功能,给出了原理讲解和JavaScript的实现,于是借鉴之,改为Java实现,运行之后发现,这碰撞处理,简直完美!在此表示由衷的感谢。
 概括的说就是简化为圆形和矩形的碰撞,然后根据他们的坐标判断2者是否在平面直角坐标系的同一个象限内,只有2种情况,一种是矩形全部位于一个象限,另一种是矩形跨越了2个或2个以上的象限。

(1)矩形全部在一个象限内是圆形的圆心坐标和矩形的某个角的坐标之间距离计算处理。
矩形全部在一个象限内
这里示例了矩形全部在第一象限,任何一个象限都是这个原理,只要矩形全部在这个象限内。

这种情况比较好解决,首先,我们计算出矩形每个角的坐标,然后用勾股定理依次算出这个角到圆心的距离是否小于或者等于半径。设这个角与圆心横坐标之差为d1,纵坐标之差为d2,半径为r,公式表达如下
距离公式
如果有一个角满足要求则说明产生碰撞。
怎么判断矩形是不是在一个象限内呢?很简单,只要判断这个矩形左上角和右下角是否在同一个象限内就可以了。代码方法如下:

    /**
     * 判断矩形是不是在一个象限里面(参考CSDN某大牛的碰撞检测JS代码,作者牛批)
     *
     * @param center 圆形小球的圆心坐标
     * @param objA 矩形的左上角坐标
     * @param objB 矩形的右下角坐标
     * @return 圆形小球和矩形是否处于同一个直角坐标系象限
     */
    protected boolean isSameQuadrant(Point center, Point objA, Point objB) {
        int cX = center.x;
        int cY = center.y;
        int xoA = objA.x, yoA = objA.y, xoB = objB.x, yoB = objB.y;

        int deltaACX = xoA - cX;
        int deltaBCX = xoB - cX;
        int deltaACY = yoA - cY;
        int deltaBCY = yoB - cY;
        if (deltaACX > 0 && deltaBCX > 0) {
            if ((deltaACY > 0 && deltaBCY > 0) || (deltaACY < 0 && deltaBCY < 0)) {
                return true;
            }
            return false;
        } else if (deltaACX < 0 && deltaBCX < 0) {
            if ((deltaACY > 0 && deltaBCY > 0) || (deltaACY < 0 && deltaBCY < 0)) {
                return true;
            }
            return false;
        } else {
            return false;
        }
    }

(2)矩形跨越2个或2个以上象限,将圆形看做一个正方形,简化为2个矩形中心点坐标距离的计算和处理。
矩形跨越2个或更多象限
矩形碰撞算法如图:
矩形碰撞算法
 如果要横向判断碰撞的话,判断(x1-x2)的绝对值是否小于或者等于w1/2+w2/2,如果是则横向则有碰撞。纵向判断是一样的,判断(y1-y2)的绝对值是否小于或等于h1/2+h2/2即可。
代码片段如下

boolean is = isSameQuadrant(ball.getCenter(), getLeftTop(), getRightBottom());
if (is) {
	int r = ball.getRadius();
	Point lt = getLeftTop();
	Point lb = getLeftBottom();
	Point rt = getRightTop();
	Point rb = getRightBottom();
	Point c = ball.getCenter();
	int dx1 = Math.abs(c.x - lt.x), dy1 = Math.abs(c.y - lt.y);
	int dx2 = Math.abs(c.x - lb.x), dy2 = Math.abs(c.y - lb.y);
	int dx3 = Math.abs(c.x - rt.x), dy3 = Math.abs(c.y - rt.y);
	int dx4 = Math.abs(c.x - rb.x), dy4 = Math.abs(c.y - rb.y);

	if(((dx1*dx1) + (dy1*dy1) <= r*r)
	||((dx2*dx2) + (dy2*dy2) <= r*r)
	||((dx3*dx3) + (dy3*dy3) <= r*r)
	||((dx4*dx4) + (dy4*dy4) <= r*r)){
		System.out.println("发生了碰撞");
	}

} else {
	Point c = ball.getCenter();
	int squareW = ball.getRadius() * 2;
	int squareH = squareW;

	int brcx = x + getWidth() / 2;
	int brcy = y + getHeight() / 2;

	if((Math.abs(c.x - brcx) <= (squareW + getWidth())*0.5)
			&&(Math.abs(c.y - brcy) <= (squareH + getHeight())*0.5)
	){
		System.out.println("......发生碰撞");
	}

}

2.4砖块被碰撞后的爆炸效果

 爆炸效果的实现方法,爆炸现象一般是以一个点为中心呈辐射状向周围发散。基于此可以创建一堆粒子,每个粒子模拟一个碎片,粒子为圆形,半径在一个范围内随机给出,每一帧修改一次粒子圆心的x,y坐标,粒子向四周发散出去速度也在一个范围内随机给出,这样就会更加的像一个爆炸的效果,粒子运动固定的帧数后消失。
 爆炸的起始点为被撞砖块的中心点。
 粒子的颜色要和砖块的颜色相同。

	// 粒子的初始化
    public ExplodeObject(){
        for (int i = 0; i < DEFAULT_COUNT; i++) {
            Particle p = new Particle(x, y, random.nextInt(3) + 2);
            p.setSpeed(random.nextInt(3) + 2);
            p.setNewRate(0.1);
            list.add(p);
        }
    }

粒子坐标的变化

        for (int i = 0; i < list.size(); i++) {
            Particle p = list.get(i);
            double temp = DEFAULT_RADIUS * p.getNewRate();
            double angle = (2 * Math.PI / DEFAULT_COUNT)*i;
            p.x = x+getWidth()/2+(int) Math.round(temp*Math.sin(angle));
            p.y = y+getHeight()/2+(int) Math.round(temp * Math.cos(angle));
            //System.out.println(String.format("p.x:%d, p.y:%d, p.radius:%d", p.x,p.y,p.radius));
            p.setNewRate(p.getNewRate() + 0.05*p.getSpeed());
        }

3.测试、完善。

  窗口初始的宽高和实际游戏对象运动范围的宽高是不一样的,如果不注意小球可能会跑出去一点,到顶部甚至就看不到了。通过获取JFrame的Insets(外镶边)可以得到每个边界的值,相应处理即可。
  目前小球在碰到砖块的角的时候,还缺乏一个改变小球方向的功能,参考了2个流行的打砖块游戏发现,有一个打砖块游戏改变了小球的方向,另外一个也并没有处理方向问题,碰到砖块的角砖块消失,小球继续前进,目前也是采用了这一做法。
  在小球落到挡板下面,game over之后,需要鼠标点击重新开始重新进行游戏,目前这个鼠标落点是硬编码,有待改进。
  放一张代码的结构图
结构图
  项目已托管到github: https://github.com/ximen502/BrickGame,欢迎浏览和star。项目中有一个压缩包rar文件,下载解压后点击里面的runGame.bat即可愉快的开始游戏了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java Swing制作古老的打砖块游戏 的相关文章

  • ReactNative ViewPageAndroid组件详解

    源码传送门 在我们开发Android的时候 xff0c ViewPage这个控件的使用频率还是很高的 xff0c 最简单的就是制作引导页 xff0c 应用程序的主界面等 xff0c 在ReactNative开发中实现该功能的组件是ViewP
  • Android自定义数字键盘

    好久没有写Android的文章了 xff0c 有两三个月多了吧 xff0c 刚开始搞微信小程序 xff0c 后来又开搞ReactNative 现在又兴奋的开搞AI机器学习的东西 xff0c 感觉挺有意思的 xff0c 不过AI与其它的东西相
  • ConstraintLayout基础介绍

    自去年Google I O 大会发布ConstraintLayout至今 xff0c 已有一年多的时间 xff0c 但是并没有普及开来 xff0c 了解过ConstraintLayout布局的人知道 xff0c 它的性能的确提升了不少 在前
  • Gson转换报错com.google.gson.JsonSyntaxException

    转载请标明出处 xff1a http blog csdn net xiejinquan article details 52002196 Gson将jsonobject的字符转化为Bean类或者将jsonarray的字符串转化为List l
  • MTK6580调试IMX132流程分析

    MTK6580调试IMX132流程分析 一开始不了解 MTK 的点亮流程 怎么办呢 1 MTK 开机是 首先是 CameraService 先起来 然后就通过获取 HAL 中的 sensorList 中的信息 CameraManager与C
  • 双线性插值算法

    图像的缩放很好理解 就是图像的放大和缩小 传统的绘画工具中 有一种叫做 放大尺 的绘画工具 xff0c 画家常用它来放大图画 当然 xff0c 在计算机上 xff0c 我们不再需要用放大尺去放大或缩小图像了 xff0c 把这个工作交给程序来
  • JAVA字符串判空的方法

    1 记录自己工作中的问题 xff1a 针对某些字符串进行判空时 xff0c 出现的BUG StringUtils hasText StringUtils hasText null 61 false StringUtils hasText 3
  • 出现次数最多的小写字母

    出现次数最多的小写字母 题目描述 输入一个由小写字母组成的字符串 xff08 字符数量 lt 61 100 xff09 xff0c 输出出现次数最多的小写字母 注意 xff1a 如果有多个小写字母出现的次数一样多 xff0c 则输出ASCI
  • EFCore 从入门到精通-6(详谈查询)

    目录 1 初始准备1 1 工具准备1 2 程序准备1 3 准备数据 2 基础回顾以及探寻2 1 单个查询2 2 查询所有的数据 2 3 筛选和过滤查询2 4 探究原理 3 客户端评估和服务端评估3 1 IEnumerable And IQu
  • 【Android解决方案】在onResume里调用getIntent()得到的是上一次数据

    我有四个媒体分类 xff08 Record xff0c Music xff0c Video xff0c Picture xff09 xff0c 里面除了数据不同 xff0c 界面都是相似的 xff0c 所以我把它们用一个MediaActiv
  • pycharm运行停止快捷键

    运行 shift 43 f10 停止 ctrl 43 f2
  • RecyclerView预加载

    private boolean isLoadingMore 61 false 是否预加载 recyclerView addOnScrollListener new RecyclerView OnScrollListener 64 Overr
  • 自定义右侧弹出dialog并填充状态栏

    DialogUtil xff1a public class DialogUtil private Dialog dialog private View inflate public void showRightDialog Context
  • Android监听横竖屏切换

    偶然在项目中用到播放视频时 xff0c 需要横屏将视频全屏播放 xff0c 所以需要监听屏幕的横竖屏切换事件 ConfigChanges xff0c 用于捕获手机状态的改变 xff0c 当横竖屏切换 xff0c 屏幕尺寸变化 xff0c 弹
  • SVN利用 AS 进行代码对比的方法

    第 1 种 xff1a 如果我们是从 SVN 检出的项目 xff0c 并且想比较本地代码与从 SVN 检出时的代码相比都有那些区别 xff0c 可以按如下步骤操作 如上图所示 xff0c 在代码编辑区 xff0c 右键唤出功能菜单 xff0
  • ADB操作命令详解大全

    ADB 操作命令详解及用法大全 Lucas liu的博客 CSDN博客
  • Android Studio build下面找不见assembleDebug选项解决办法

    在开发Android的AAR库时 xff0c 习惯点击右侧gradle面板的Task任务进行编译 xff0c 如选择assembleDebug或assembleRelease进行编译 xff0c 如下 xff1a 说明 xff1a 其中as
  • android 注销到登陆界面实现

    code class java span class hljs keyword public span span class hljs class span class hljs keyword class span span class
  • 中兴2016校招软件在线笔试题

    面试经验可以参考我的另一篇文章 xff0c 是7月初参加openday面试的 xff0c 文章链接http blog csdn net dandelion1314 article details 47009585 招聘群里有人发的招聘时间安
  • 设置AndroidStudio左侧和右侧的字体

    1 File Settings Appearance amp Behavior Appearance xff0c 右边Override default fonts by not recommended 2 设置代码大小 xff1a File

随机推荐

  • Android下载网络资源文件

    直接上代码 xff1a lt uses permission android name 61 34 android permission WRITE EXTERNAL STORAGE 34 gt lt uses permission and
  • 出现:trying to draw too large(138078000bytes) bitmap:错误时

    这里就不翻译了 xff0c 意思就是说你将高分辨率图片放在了低分辨率文件夹下 例如 xff1a 图片的分辨率是属于xxhdpi的 xff0c 而你将这张图片放在了drawable xhdpi或者比这个还低的文件夹下 xff0c 就会报这个错
  • Android把图片压缩到一定大小并不失真

    本文转载只供参考 一 图片压缩方式 图片按比例大小压缩方法 64 param srcPath xff08 根据路径获取图片并压缩 xff09 64 return public static Bitmap getimage String sr
  • Android 动态设置TextView的位置

    RelativeLayout LayoutParams layoutParams 61 new RelativeLayout LayoutParams 40 40 宽高 layoutParams setMargins int dstX 20
  • 神经网络应用较多的算法,图卷积神经网络应用

    神经网络原理及应用 神经网络原理及应用1 什么是神经网络 xff1f 神经网络是一种模拟动物神经网络行为特征 xff0c 进行分布式并行信息处理的算法 这种网络依靠系统的复杂程度 xff0c 通过调整内部大量节点之间相互连接的关系 xff0
  • Java泛型学习

    纯属个人理解 xff0c 代码参考自视频 用途 xff1a 1 用于集合容器中 xff0c 可以使集合记住存储数据的类型 xff0c 防止频繁转换类型可能导致的ClassCastException 用于javac编译器的类型检查 xff0c
  • Java反射学习

    文字和代码来源于视频 反射 xff0c 通过它我们可以得到一个Java类的全部信息 xff0c 可以调用类的普通方法 xff0c 构造方法 xff0c 对类进行实例化 xff0c 操作类的属性 类中的所有内容 xff1a 属性 构造方法 普
  • 面试题之反转单向链表

    题目为 xff1a 将一个单向链表反转 xff0c 写出算法步骤或代码 懵批了 今学习如下 xff0c 文章代码参考https blog csdn net K346K346 article details 93371829 xff0c 感谢
  • 冒泡排序总结

    本文内容和代码均来自于 漫画算法 xff0c 小灰和大黄的对话 xff0c 非常有趣味的一本书 现理论结合实践 xff0c 做一下测试 span class token keyword private span span class tok
  • net6的Web MVC项目实现限流功能

    原理 xff1a 利用MemoryCache服务组件 xff0c 记录用户最后一次访问接口的时间 xff0c 如果本次访问距离最后一次访问不超过1秒 xff0c 提示用户访问过于频繁 xff0c 否则 xff0c 接口可以正常访问 然后利用
  • 快速排序总结

    文章内容和代码来自 漫画算法 和数据结构教材 现进行一下代码编写练习 1 双边循环法 span class token comment 双边循环法 xff0c 从左右两端分别向中间进行比较和交换数据 递归实现 span span class
  • 堆排序总结

    本文内容来源于 漫画算法 和数据结构教材 这里提到的堆是一个二叉堆 xff0c 本质上是一颗完全二叉树 堆排序只需要一个记录大小的辅助空间 1 java实现 span class token comment 下沉调整 64 param ar
  • 计数排序

    本文内容和代码来自 漫画算法 之前练习的冒泡排序 鸡尾酒排序 快速排序 堆排序都是基于元素比较和位置元素交换实现的 xff0c 有一些特殊的排序并不基于元素比较 xff0c 如计数排序 桶排序 基数排序 以计数排序来说 xff0c 这种排序
  • 桶排序

    本文内容和代码来源于 漫画算法 针对计数排序的局限性 xff0c 桶排序做出了弥补 xff0c 时间复杂度同样是线性级 类似于计数排序所创建的统计数组 xff0c 桶排序需要创建若干个桶来协助排序 那么桶排序中所谓的 桶 xff0c 又是什
  • 归并排序

    本文内容和代码来源于数据结构教材 归并排序 Merging Sort 是又一类不同的排序方法 34 归并 34 的含义是将2个或2个以上的有序表组合成1个新的有序表 无论是顺序存储还是链表存储结构 xff0c 都可在O m 43 n 的时间
  • 插入排序

    文章内容来源于数据结构教材 C语言版 教材讲解了4种插入排序算法 xff0c 分别为 1 直接插入排序 2 折半插入排序 3 2 路插入排序 4 表插入排序 还有一个希尔排序 属于插入排序分类 本文只将1 2 xff0c 两种算法进行了实践
  • 希尔排序

    本文内容来源于数据结构教材 C语言版 希尔排序 Shell s Sort xff0c 又称缩小增量排序 Diminishing Increment Sort xff0c 它也是一种属插入排序类的方法 xff0c 但在时间效率上较前几种插入排
  • Java swing绘制柱状图和饼图

    15 14编写程序 xff0c 使用条形图显示作业 平时测验 其中考试和期末考试占总成绩的百分比 假设作业占20 用红色显示 xff0c 平时测验占10 用蓝色显示 xff0c 其中考试占30 用绿色显示 xff0c 期末考试占40 用橙色
  • Java注解(Annotation)学习

    xff08 本文内容来源于疯狂Java讲义 xff0c 感谢 xff09 注解 Annotation Annotation是代码里的特殊标记 xff0c 这些标记可以在编译 类加载 运行时被读取 xff0c 并执行相应的处理 通过使用注解
  • Java Swing制作古老的打砖块游戏

    最近研究了一下古老的Java Swing xff0c 研究之余 xff0c 突发奇想开发了一个打砖块小游戏 首先看一下效果图 具体过程 1 游戏框架搭建1 1步骤 2 开发过程2 1各种游戏对象的绘制2 2游戏对象的运动2 3小球和砖块的碰