当前位置: 首页 > news >正文

《碰撞检测》基于屏幕大小及敌人的宽高,生成抽象网格,根据网格让敌人在网格中随机生成

让我彻底重写关于"将屏幕划分为蝙蝠大小的网格"这一部分的解释,并逐行详细说明整个碰撞处理逻辑:

碰撞后蝙蝠重定位的完整解析

if (slimeBounds.Intersects(batBounds))
{// 1. 计算屏幕网格划分int totalColumns = GraphicsDevice.PresentationParameters.BackBufferWidth / (int)_bat.Width;int totalRows = GraphicsDevice.PresentationParameters.BackBufferHeight / (int)_bat.Height;// 2. 随机选择网格位置int column = Random.Shared.Next(0, totalColumns);int row = Random.Shared.Next(0, totalRows);// 3. 计算新位置_batPosition = new Vector2(column * _bat.Width, row * _bat.Height);// 4. 重置移动方向AssignRandomBatVelocity();
}

1. 为什么要划分网格?深层原因

  • 设计目的:创建离散的、安全的重生点系统
  • 问题解决:避免随机位置产生的三大问题:
    • 位置重叠(蝙蝠重生在史莱姆身上再次碰撞)
    • 位置无效(部分出现在屏幕外)
    • 分布不均(聚集在特定区域)
  • 数学原理:通过整数除法创建网格坐标系
    屏幕宽度 = 1280px, 蝙蝠宽度 = 64px
    总列数 = 1280 / 64 = 20列屏幕高度 = 720px, 蝙蝠高度 = 64px
    总行数 = 720 / 64 = 11.25 → 取整为11行(舍去小数)
    

2. 逐行深度解析

int totalColumns = GraphicsDevice.PresentationParameters.BackBufferWidth / (int)_bat.Width;
  • BackBufferWidth:当前屏幕宽度(如1280)
  • _bat.Width:蝙蝠精灵的实际宽度(考虑缩放后)
  • 强制转换(int):舍弃小数部分,确保列数为整数
  • 物理意义:计算屏幕横向能容纳多少个完整蝙蝠
int totalRows = GraphicsDevice.PresentationParameters.BackBufferHeight / (int)_bat.Height;
  • 取整处理:向下取整(Floor),保证蝙蝠不会部分出现在屏幕外
  • 示例计算
    720px高度 / 64px蝙蝠高度 = 11.25 → 取整为11
    最大Y坐标 = 11 * 64 = 704px (确保蝙蝠完全在720px内)
    
int column = Random.Shared.Next(0, totalColumns);
  • Random.Shared:.NET 6+的线程安全随机数生成器
  • 参数含义
    • 最小值0:包含第一列
    • 最大值totalColumns:不包含(生成0到totalColumns-1)
  • 示例:如果totalColumns=20,生成0-19的随机整数
int row = Random.Shared.Next(0, totalRows);
  • 行索引:确保蝙蝠不会出现在屏幕底部之外
  • 数学保证:row_max * bat.Height ≤ 屏幕高度
_batPosition = new Vector2(column * _bat.Width, row * _bat.Height);
  • 网格坐标→像素坐标
    • X = 列索引 × 蝙蝠宽度 → 保证水平对齐
    • Y = 行索引 × 蝙蝠高度 → 保证垂直对齐
  • 位置安全性
    • 左边界:column=0 → X=0
    • 右边界:column=max → X = max×width ≤ 屏幕宽度
    • 上边界:row=0 → Y=0
    • 下边界:row=max → Y = max×height ≤ 屏幕高度
AssignRandomBatVelocity();
  • 重置方向:避免蝙蝠"卡在"边缘反复碰撞
  • 游戏性设计:增加每次碰撞后的不确定性

为什么这样设计比完全随机更好?

方法 优点 缺点 本方案解决
完全随机坐标 实现简单 1. 可能出现在屏幕外
2. 可能与玩家重叠
3. 分布不均匀
✅ 网格约束确保位置有效
固定重生点 位置可控 1. 模式可预测
2. 需要手动设置点
✅ 随机选择避免模式化
区域排除法 避开玩家 1. 计算复杂
2. 可能无有效位置
⚠️ 本方案不直接解决但风险低

实际执行示例

假设:

  • 屏幕:1280×720
  • 蝙蝠尺寸:64×64
  • 随机生成:column=5, row=3

计算过程:

X = 5 * 64 = 320px
Y = 3 * 64 = 192px蝙蝠边界:
左:320px
右:320+64=384px (<1280)
上:192px
下:192+64=256px (<720)

潜在问题及优化建议

  1. 尺寸整除问题

    // 更好的做法:考虑余数空间
    int totalColumns = (int)Math.Floor(screenWidth / batWidth);
    int totalRows = (int)Math.Floor(screenHeight / batHeight);
    
  2. 位置重叠预防

    // 增加距离检查
    Vector2 newPos;
    int attempts = 0;
    do {column = Random.Shared.Next(0, totalColumns);row = Random.Shared.Next(0, totalRows);newPos = new Vector2(column * _bat.Width, row * _bat.Height);
    } while(Vector2.Distance(newPos, _slimePosition) < 200 && attempts++ < 10);
    
  3. 边界处理增强

    // 确保不贴边
    column = Random.Shared.Next(1, totalColumns - 1);
    row = Random.Shared.Next(1, totalRows - 1);
    

总结设计思想

  1. 空间离散化:将连续屏幕空间转换为离散网格单元
  2. 单元标准化:每个网格单元=1蝙蝠尺寸
  3. 随机采样:在有效网格中均匀随机选择
  4. 坐标转换:网格索引→像素坐标
  5. 行为重置:清除碰撞后的运动状态

这种设计保证了:

  • 100%位置有效性(完全在屏幕内)
  • 位置分布均匀性
  • 计算高效(O(1)复杂度)
  • 避免连续碰撞
  • 代码简洁易维护

说明了网格划分的原理、实现细节和设计考量。这种方法是游戏开发中处理敌人重生的经典模式,在《吃豆人》等游戏中广泛使用。


// 1. 计算屏幕网格划分
int totalColumns = GraphicsDevice.PresentationParameters.BackBufferWidth / (int)_bat.Width;
int totalRows = GraphicsDevice.PresentationParameters.BackBufferHeight / (int)_bat.Height;

这也是为了判断 这个蝙蝠这个屏幕空间内宽高多少为一格网格吗?

您理解得非常准确!这两行代码的核心目的确实是:计算屏幕可以被划分为多少个以蝙蝠尺寸为单位的网格单元。让我详细解释为什么需要这样计算以及它的具体作用:

核心目的:创建基于蝙蝠尺寸的网格坐标系

int totalColumns = GraphicsDevice.PresentationParameters.BackBufferWidth / (int)_bat.Width;
int totalRows = GraphicsDevice.PresentationParameters.BackBufferHeight / (int)_bat.Height;

为什么需要这样的网格?

  1. 精确位置控制

    • 确保蝙蝠总是完整显示在屏幕内
    • 避免蝙蝠部分出现在屏幕外或与UI重叠
  2. 碰撞后安全重生

    • 防止重生后立即再次与玩家碰撞
    • 保证重生位置有效(不会出现在不可达区域)
  3. 均匀分布

    • 使蝙蝠可能出现在屏幕任何区域
    • 避免重生点聚集在特定位置

具体计算过程详解

1. 计算列数(水平方向网格数)

int totalColumns = 屏幕宽度 / 蝙蝠宽度;
  • 示例

    • 屏幕宽度 = 1280像素
    • 蝙蝠宽度 = 64像素
    • 计算结果:1280 / 64 = 20列
  • 物理意义

    • 屏幕被划分为20个垂直条带
    • 每个条带宽度 = 64像素(正好容纳一只蝙蝠)
    • 最大有效列索引:0到19(共20列)
  • 可视化

    列索引:0   1   2   ...  19┌───┬───┬───┬───┐
    像素位置:0   64 128 ... 1216└───┴───┴───┴───┘↑蝙蝠位置 = 列索引 × 64
    

2. 计算行数(垂直方向网格数)

int totalRows = 屏幕高度 / 蝙蝠高度;
  • 示例

    • 屏幕高度 = 720像素
    • 蝙蝠高度 = 64像素
    • 计算结果:720 / 64 = 11.25 → 取整为11行(因为是整数除法)
  • 关键细节

    • 整数除法会自动截断小数部分(11.25 → 11)
    • 这样确保最后一行蝙蝠不会超出屏幕底部:
      最大Y坐标 = 11 × 64 = 704像素
      蝙蝠底部 = 704 + 64 = 768像素 < 720? // 错误!
      

重要修正:安全的行数计算

原始代码存在边界问题,正确做法应该是:

// 安全计算行数(防止底部溢出)
int totalRows = (屏幕高度 - 蝙蝠高度) / 蝙蝠高度 + 1;

修正后计算:

int totalRows = (720 - 64) / 64 + 1= 656 / 64 + 1= 10.25 → 10 + 1 = 11行
  • 验证底部边界
    最后一行Y坐标 = 10 × 64 = 640像素
    蝙蝠底部 = 640 + 64 = 704像素 < 720 (安全!)
    

网格系统的实际应用

当代码执行:

int column = Random.Shared.Next(0, totalColumns); // 0-19
int row = Random.Shared.Next(0, totalRows);       // 0-10_batPosition = new Vector2(column * _bat.Width,  // X坐标 = 列索引 × 蝙蝠宽row * _bat.Height     // Y坐标 = 行索引 × 蝙蝠高
);

位置有效性保证:

边界 计算 保证
左边界 列索引=0 → X=0 蝙蝠左侧贴屏幕左边缘
右边界 列索引=max → X=(totalColumns-1)×宽 蝙蝠右侧≤屏幕宽度
上边界 行索引=0 → Y=0 蝙蝠顶部贴屏幕上边缘
下边界 行索引=max → Y=(totalRows-1)×高 蝙蝠底部≤屏幕高度

为什么不用随机像素坐标?

方法 问题 网格方案解决
完全随机坐标 可能部分出现在屏幕外 ✅ 确保完整显示
可能与玩家位置重叠 ✅ 网格隔离降低概率
位置分布不均匀 ✅ 均匀覆盖全屏
需要额外边界检查 ✅ 内置边界保护

实际游戏示例

假设:

  • 蝙蝠尺寸:64×64像素
  • 屏幕尺寸:1280×720像素
  • 随机生成:列=3, 行=5

重生位置计算:

X = 3 × 64 = 192
Y = 5 × 64 = 320蝙蝠边界框:
Left: 192
Right: 192+64=256
Top: 320
Bottom: 320+64=384

完全位于屏幕内部且不会与边缘重叠

总结

这两行网格划分代码的本质是创建一个基于敌人尺寸的离散坐标系,它:

  1. 将连续屏幕空间量化为网格单元
  2. 每个单元尺寸 = 敌人尺寸
  3. 通过整数索引系统确保位置有效性
  4. 为随机重生提供结构化位置池

这种方法是游戏开发中处理敌人重生、道具生成等需求的经典模式,在《炸弹人》、《吃豆人》等网格化游戏中应用广泛,即使在全自由移动的游戏中也常用于保证位置有效性。

http://www.vanclimg.com/news/1706.html

相关文章:

  • 技术文章
  • 请勿在DNS MX记录中直接使用IP地址 - 邮件服务器配置指南
  • 激活函数
  • 用回溯算法实现全排列
  • 如何在Consumption类型的容器应用环境中缓存Docker镜像
  • [AlpaGasus] AlpaGasus: Training A Better Alpaca with Fewer Data | ICLR 2024
  • DNS 记录类型详解
  • 使用Docker部署前端应用
  • python基础篇(1)
  • P1956 Sum 题解
  • 洛谷P8742 [蓝桥杯 2021 省 AB] 砝码称重 题解
  • 拼接文件路径
  • 踩坑:Mybatis Plus 逻辑删除 @TableLogic
  • UE简单激活教程V24.00.0.72
  • msf生成Windows木马
  • 深入浅出控制反转与依赖注入:从理论到实践 - 详解
  • java入门:安装开发环境
  • 背包DP(基础篇) - L
  • 3、行列转换(列转行)
  • 洛谷P1510 精卫填海 题解
  • 30
  • 25.7.29ds专题测试总结
  • 软工7.29
  • 在线卷积全解-从cdq分治到多叉与自迭代结构
  • ​iTrustSSL证书夏季大促,最高直降92.5%!
  • Ekoparty CTF 2024 赛题详解:从取证分析到密码破解的实战记录
  • 亚马逊机器人如何用多模态识别技术取代条形码
  • js获取多个div元素的方法。如果这些div有父子关系,如何进行区分?如何由子获得父?
  • django+Vue的项目使用docker打包
  • PyTorch 构建轻量级验证码识别模型