You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Godot开发俄罗斯方块:旋转后节点位置偏移致碰撞误判求助

解决Godot俄罗斯方块旋转后角度与位置偏移问题

核心问题分析

  1. 角度非整数问题:直接对rotation_degrees加减90,会因浮点数精度累积产生微小误差(比如90.0000001或89.9999999),导致碰撞检测误判。
  2. 子方块位置偏移:父节点旋转时,子节点相对坐标经浮点计算后会产生非整数偏移,而俄罗斯方块的方块需严格对齐网格,微小偏移会导致落地位置偏差。

具体解决方案

1. 锁定父节点旋转为精确90度倍数

放弃直接加减角度的方式,用状态变量记录当前旋转阶段(0-3对应0°、90°、180°、270°),直接设置精确角度,从根源避免浮点误差:

# 在类定义中添加状态变量
var current_rot_stage = 0  # 0:0°, 1:90°, 2:180°, 3:270°

func rotate_piece(boundary, playedblocks):
    if not movable:
        return
    color_blocks(Color.RED)
    
    # 计算目标旋转状态与角度
    var target_stage = (current_rot_stage + 1) % 4
    var target_deg = target_stage * 90
    
    # 先应用目标旋转
    self.rotation_degrees = target_deg
    
    # 修正子方块:保持直立+坐标取整
    for block in blocks:
        block.rotation_degrees = 0  # 强制子方块不旋转,保持直立
        # 将坐标取整,对齐网格
        block.position = Vector2(round(block.position.x), round(block.position.y))
    
    # 检测边界与碰撞
    var is_enclosed = boundary.encloses(get_boundary())
    var does_intersect = IntersectsPlayedPieces(playedblocks)
    
    if not is_enclosed or does_intersect:
        # 旋转失败,恢复原状态
        self.rotation_degrees = current_rot_stage * 90
        for block in blocks:
            block.rotation_degrees = 0
            block.position = Vector2(round(block.position.x), round(block.position.y))
    else:
        # 旋转成功,更新状态
        current_rot_stage = target_stage

2. 移除子方块的帧内旋转修正

之前在_process中每帧修正旋转的方式不仅低效,还可能引入额外误差。改为在父节点旋转完成后一次性处理子方块状态,可完全去掉子方块的_process旋转逻辑:

# 子方块脚本中移除旋转修正代码,保留坐标显示即可(可选)
func _process(delta):  
    var text = str("x: ", self.position.x, "\ny: ", self.position.y)
    label.text = text

3. 优化碰撞检测(可选)

改用网格坐标进行碰撞检测,彻底避免浮点Rect相交的误判问题:

  • 给每个方块添加grid_x、grid_y属性,记录其在网格中的整数位置
  • 碰撞检测时直接比较网格坐标是否重叠:
func IntersectsPlayedPieces(playedblocks) -> bool:
    var intersects = false
    for setblock in playedblocks:       
        if not setblock.is_deleted():
            var set_grid = Vector2(setblock.grid_x, setblock.grid_y)
            for currblock in blocks:
                var curr_grid = Vector2(currblock.grid_x, currblock.grid_y)
                if curr_grid == set_grid:
                    intersects = true
                    break
            if intersects:
                break
    return intersects

关键原理

  • 用状态变量控制旋转,直接设置0/90/180/270这些精确整数角度,彻底消除浮点精度误差
  • 子方块坐标取整确保严格对齐网格,解决旋转后的偏移问题
  • 网格坐标碰撞检测比浮点Rect相交更准确高效,适合俄罗斯方块这类网格对齐的游戏

内容的提问来源于stack exchange,提问作者Bulsatar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 13:22:08