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

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)

关键说明

  1. 逆旋转矩阵:逆旋转的核心是将sin项取反,这样才能让实体在玩家旋转时,始终保持在3D空间的正确相对位置,不会出现瞬移。
  2. 角度单位:确认plr.rotateAngle是弧度值,如果CMU CS Academy返回的是角度,必须用m.radians(dir)转换后再传入m.cos()和m.sin()。
  3. 屏幕坐标计算:(vx / vy) * app.maxDistance是将局部空间的X坐标,按照透视投影规则转换为屏幕偏移量,加上屏幕中心(200)后得到最终屏幕X位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 22:27:53