Raycaster实体Sprite屏幕瞬移问题求助(CMU CS Academy简化Python)
修复Raycaster中相机旋转时Sprite瞬移的问题
我在CMU CS Academy的编程课上用简化Python开发类Doom/Wolfenstein的Raycaster,已经实现了主射线投射功能,但添加实体Sprite时,相机旋转时Sprite会在屏幕上瞬移,无法正确对应3D空间位置。程序显示坐标系范围为x/y 0-400,怀疑问题出在vx和vy的旋转计算上。
问题代码:
def drawEntity(entity): dir = plr.rotateAngle # camera directoin x = (entity.centerX - plr.centerX) # entity's relative position to player y = (entity.centerY - plr.centerY) # not used # # dis = m.sqrt((plr.centerX - entity.centerX)**2 + (plr.centerY - entity.centerY)**2) vx = x * m.cos(dir) - y * m.sin(dir) # is supposed to rotate the location of the sprite vy = x * m.sin(dir) + y * m.cos(dir) # but doesnt seem to work if vy > 0: sprite = Image(entities.animations[m.floor(entity.animation)], 200, 200) height = 30 * app.maxDistance / vy # where app.maxDistance = 200 / m.tan(45) sprite.width, sprite.height = abs(320 * height * 0.01), abs(320 * height * 0.01) # 320 is the image's width / height sprite.centerX, sprite.centerY = vx * (app.maxDistance / vy)+200, 200 # x-pos is messed up some how sprites.add(sprite) # draws sprite
问题根源
核心错误是旋转矩阵方向搞反了:我们需要把世界空间中实体相对于玩家的坐标,转换到玩家的局部坐标系(相机空间),这需要对向量进行逆旋转——玩家旋转了θ角,相当于世界相对于玩家反向旋转了θ角,而原代码用的是正向旋转矩阵,导致坐标转换完全错误,引发瞬移。
修复方案
替换vx和vy的计算逻辑,使用逆旋转矩阵;同时确保屏幕坐标计算逻辑一致:
def drawEntity(entity): dir = plr.rotateAngle # 相机方向(确保是弧度值,若为角度需用m.radians()转换) # 计算实体相对于玩家的世界空间坐标 rel_x = entity.centerX - plr.centerX rel_y = entity.centerY - plr.centerY # 逆旋转:将世界空间相对坐标转换到玩家局部空间 # 等价于把世界绕玩家旋转 -dir 角,让玩家朝向为局部空间正Y轴 vx = rel_x * m.cos(dir) + rel_y * m.sin(dir) vy = -rel_x * m.sin(dir) + rel_y * m.cos(dir) if vy > 0: # 仅绘制玩家前方的实体 sprite = Image(entities.animations[m.floor(entity.animation)], 200, 200) app.maxDistance = 200 / m.tan(m.radians(45)) # 确保用弧度计算视场角 height = 30 * app.maxDistance / vy scale = abs(height * 0.01) sprite.width = 320 * scale sprite.height = 320 * scale # 正确转换局部X坐标到屏幕X坐标 screen_x = (vx / vy) * app.maxDistance + 200 sprite.centerX = screen_x sprite.centerY = 200 # 可根据需求调整,比如改为200 + sprite.height/2让精灵底部对齐屏幕下方 sprites.add(sprite)
关键说明
- 逆旋转矩阵:逆旋转的核心是将sin项取反,这样才能让实体在玩家旋转时,始终保持在3D空间的正确相对位置,不会出现瞬移。
- 角度单位:确认
plr.rotateAngle是弧度值,如果CMU CS Academy返回的是角度,必须用m.radians(dir)转换后再传入m.cos()和m.sin()。 - 屏幕坐标计算:
(vx / vy) * app.maxDistance是将局部空间的X坐标,按照透视投影规则转换为屏幕偏移量,加上屏幕中心(200)后得到最终屏幕X位置。
内容的提问来源于stack exchange,提问作者VPexMC
相关产品推荐
相关产品推荐

