现有的这样的小游戏,一定要去github上看看有没有现成的。
经过一番搜索,我找到了最合适且写得干净的C#版本[bubble-shooter-unity3d]。 碰撞使用unity的Collider和rigidbody。 我是一个固执的人,但即使项目进度极其紧张,我仍然拒绝使用现有的物理系统。 幸运的是,我把头发烧了一周之后,基本的计算就完成了。 接下来就是一堆业务逻辑和工作量。 玩法分析
基本框架和找到的项目都已经写得很漂亮了,剩下的就是一些二维计算和几个算法的实现了。 我们先来分析一下一些比较耗时的点:
地图生成、地图数据结构移动(上下移动) 【算法】寻找邻居 【算法】消除小球 【算法】小球掉落 【计算】小球发射时会击中的小球【计算】小球应该落在哪个格子上【计算】墙壁碰撞视线的动态长度。 【拓展】特殊球的实现:炸弹、雷电球、石头、饰品的练习
接下来我们就根据分析来一一分解难点。
地图生成和数据结构首先是地图的生成,即地图网格。 我使用二维矩阵来维护网格数据和模板生成。
2.地图移动(上下)
地图的移动。 地图的表现是一个偏移坐标矩阵。 当地图超过预期行数时,需要上下移动。 移动时需要考虑奇数行在左边还是奇数行在右边。 我维护一个变量isBaselineAlignedLeft来记录第一行是否向左,并在移动基行时修改这个变量。
3.【算法】寻找邻居
在二维矩阵中寻找邻居时,可以分析矩阵中的坐标行是向左还是向右,然后对矩阵的行数和列数进行加减来寻找邻居。 一开始我考虑了一个又一个条件,写了差不多200行if else来分析情况。 后来了解了正六边形网格的研究,利用配套表一下子就搞定了。 搭配表简直就是神器! 我们只需要列出奇数行和偶数行中所有相邻网格的偏移坐标,就可以一次性找到它们。
local NeighborsMap =
{
-- 左、 右、 左上、 右上、 左下、右下
[1] = {{0,-1},{0,1},{-1,-1},{-1,0},{1,-1},{1,0}}, -- 奇数
[2] = {{0,-1},{0,1},{-1, 0},{-1,1},{1, 0},{1,1}}, -- 偶数
}
4.【算法】小球消除
小球的消除算法,找邻居算法完成后,一切就那么顺理成章了,找邻居算法+递归就可以解决了
5.【算法】球掉落
落球算法也是寻邻算法+递归。 不同之处在于,对邻居的搜索是从顶行开始的。 最上面一排称为支点,从支点连接的任何东西都不会脱落;
首先,我们遍历所有的球音乐,将状态设置为关闭状态,然后遍历最上面一排球unity onmousedown,逐一进行邻居查找算法+递归,找到邻居时将其设置为连接状态。 记得维护访问过的列表,否则重复步骤太多。 子逻辑unity onmousedown,甚至无限循环。 最后一次遍历完所有球后,仍处于脱落状态的球就是我们要寻找的球。
6.【计算】小球发射时会击中的球
有很多方法可以计算球发射时将击中的球。 我用的是计算点到线的距离。 它遍历所有的小球,计算从球中心到发射线段的距离,找到距离小于球直径的球。 这是所有可能沿发射方向击中的球。
下一步是找到实际碰撞的球:我计算了球中心到线段的距离+垂直脚到发射点的距离。 虽然我无法解释任何科学原因3D交通工具,但表现是正确的。
7.【计算】小球应该落在哪个格子上?
计算出球的碰撞坐标后,接下来要做的就是找到球应该落地的网格。 当我编写地图生成时,我提供了 CellForPosition 和 PositionForCell 来转换 localPosition 和网格坐标。
8.【计算】墙壁碰撞
计算完6,计算出没有东西被撞到之后,就该判断是否撞到了墙。
① 首先判断发射点的延长线与顶线段是否相交。 如果它们相交,请停止
②判断是否与左右边界相交。 如果相交,则进行反射【递归】
9、瞄准线动态长度
我使用LineRender来实现动态长度,然后使用物理系统的碰撞器来实现碰撞并找到端点。 Unity LineRenderer 绘制连续的反射光线
【扩展】特殊球的实现:炸弹、闪电球、石头、珠宝
我最初为这个过程写了一堆垃圾代码。 后来整理了一下,用表格解决了。 桌配对的方法是世界上最好的。 工厂方法解决了一切。 参考:
正六方晶格的研究
文章来源:https://blog.csdn.net/weixin_39983427/article/details/111119898