如何阻止Ursina 2D迷宫游戏玩家穿过墙体?
Ursina 2D迷宫玩家穿墙问题解决
我正在使用Ursina引擎开发一款2D迷宫游戏,但无法实现玩家不能穿过墙体的效果。我尝试添加了collider但没有作用,因为需要检测碰撞后执行对应逻辑;添加raycast后也未解决该问题,恳请提供帮助。
用户原代码:
from ursina import * from ursina import physics class top_down_controller(Entity): def __init__(self, model, color, scale = 1, texture = None, collider = 'box', ignore=[], position=[0,0]): super().__init__( model = model, color = color, scale = scale, texture = texture, collider = collider, ignore = ignore, vleft = -0.1, vright = 0.1, vup = 0.1, vdown = -0.1, position= position ) def update(self): self.x += held_keys['a'] * self.vleft self.x += held_keys["d"] * self.vright self.y += held_keys['w'] * self.vup self.y += held_keys['s'] * self.vdown above = raycast(self.world_position, self.up, 0.51, ignore=[self], debug = True) above_left = raycast(self.world_position+Vec3(-0.5,0,0), self.up, 0.51, ignore = [self], debug = True) above_right = raycast(self.world_position+Vec3(0.5,0,0), self.up, 0.51, ignore = [self], debug = True) below = raycast(self.world_position, self.down, 0.51, ignore = [self], debug = True) below_left = raycast(self.world_position+Vec3(-0.5,0,0), self.down, 0.51, ignore = [self], debug = True) below_right = raycast(self.world_position+Vec3(0.5,0,0), self.down, 0.51, ignore = [self], debug = True) left = raycast(self.world_position, self.left, 0.51, ignore = [self], debug = True) left_above = raycast(self.world_position+Vec3(0,0.5,0), self.left, 0.51, ignore = [self], debug = True) left_down = raycast(self.world_position+Vec3(0,-0.5,0), self.left, 0.51, ignore = [self], debug = True) right = raycast(self.world_position, self.right, 0.51, ignore = [self], debug=True) right_above = raycast(self.world_position+Vec3(0,0.5,0), self.right, 0.51, ignore = [self], debug = True) right_down = raycast(self.world_position+Vec3(0,-0.5,0), self.right, 0.51, ignore = [self], debug = True) if any((above.hit, above_left.hit, above_right.hit)): self.vup = 0 elif any((left.hit, left_above.hit, left_down.hit)): self.vleft = 0 elif any((right.hit, right_above.hit, right_down.hit)): self.vright = 0 elif any((below_right.hit, below.hit, below_left.hit)): self.vdown = 0 app = Ursina() e1 = Entity(model = 'quad', color = color.green, collider = 'box') e = top_down_controller(model = 'quad', color = color.blue, position = [2,2], ignore = [e1]) app.run()
问题分析与修复方案
核心问题点
elif逻辑冲突:四个方向的碰撞判断用elif串联,导致仅第一个满足条件的方向生效,其他方向碰撞被忽略(比如同时碰左墙和上墙时,仅左墙限制生效)。- 速度未恢复:碰撞时把对应方向速度设为0,但没有在碰撞消失后恢复,导致玩家碰到墙后永久失去该方向移动能力。
- ignore参数未传递:自定义控制器的
ignore列表没有传入raycast,导致raycast可能误检测自身或其他对象。 - 移动顺序错误:先移动玩家再检测碰撞,导致玩家已经穿墙后才触发限制。
修复后的Raycast版本代码
from ursina import * class top_down_controller(Entity): def __init__(self, model, color, scale=1, texture=None, collider='box', ignore=[], position=[0,0]): super().__init__( model=model, color=color, scale=scale, texture=texture, collider=collider, position=position ) # 单独定义基础速度,方便碰撞后恢复 self.base_speed = 0.1 self.vleft = -self.base_speed self.vright = self.base_speed self.vup = self.base_speed self.vdown = -self.base_speed # 合并忽略列表,包含自身和指定对象 self.ignore_list = ignore + [self] def update(self): # 每次更新先恢复基础速度,解决碰撞后无法移动的问题 self.vleft = -self.base_speed self.vright = self.base_speed self.vup = self.base_speed self.vdown = -self.base_speed # 各方向碰撞检测 above = raycast(self.world_position, self.up, 0.51, ignore=self.ignore_list) above_left = raycast(self.world_position + Vec3(-0.5, 0, 0), self.up, 0.51, ignore=self.ignore_list) above_right = raycast(self.world_position + Vec3(0.5, 0, 0), self.up, 0.51, ignore=self.ignore_list) below = raycast(self.world_position, self.down, 0.51, ignore=self.ignore_list) below_left = raycast(self.world_position + Vec3(-0.5, 0, 0), self.down, 0.51, ignore=self.ignore_list) below_right = raycast(self.world_position + Vec3(0.5, 0, 0), self.down, 0.51, ignore=self.ignore_list) left = raycast(self.world_position, self.left, 0.51, ignore=self.ignore_list) left_above = raycast(self.world_position + Vec3(0, 0.5, 0), self.left, 0.51, ignore=self.ignore_list) left_down = raycast(self.world_position + Vec3(0, -0.5, 0), self.left, 0.51, ignore=self.ignore_list) right = raycast(self.world_position, self.right, 0.51, ignore=self.ignore_list) right_above = raycast(self.world_position + Vec3(0, 0.5, 0), self.right, 0.51, ignore=self.ignore_list) right_down = raycast(self.world_position + Vec3(0, -0.5, 0), self.right, 0.51, ignore=self.ignore_list) # 用独立if判断每个方向,避免相互干扰 if any((above.hit, above_left.hit, above_right.hit)): self.vup = 0 if any((left.hit, left_above.hit, left_down.hit)): self.vleft = 0 if any((right.hit, right_above.hit, right_down.hit)): self.vright = 0 if any((below_right.hit, below.hit, below_left.hit)): self.vdown = 0 # 最后执行移动 self.x += held_keys['a'] * self.vleft self.x += held_keys["d"] * self.vright self.y += held_keys['w'] * self.vup self.y += held_keys['s'] * self.vdown app = Ursina() # 给墙体设置合适大小,避免默认尺寸导致初始碰撞 e1 = Entity(model='quad', color=color.green, collider='box', scale=(2,2)) e = top_down_controller(model='quad', color=color.blue, position=[2,2], ignore=[e1]) app.run()
更简洁的2D物理系统方案
直接使用Ursina内置的Physics2dComponent,无需手动编写raycast,自动处理碰撞限制:
from ursina import * from ursina.physics_2d import Physics2dComponent class top_down_controller(Entity): def __init__(self, model, color, scale=1, texture=None, collider='box', ignore=[], position=[0,0]): super().__init__( model=model, color=color, scale=scale, texture=texture, collider=collider, position=position ) # 关闭重力,适配俯视视角2D游戏 self.physics = Physics2dComponent(self, gravity=0) self.base_speed = 10 def update(self): # 计算移动方向并归一化 direction = Vec2( held_keys['d'] - held_keys['a'], held_keys['w'] - held_keys['s'] ).normalized() # 设置物理速度 self.physics.velocity = direction * self.base_speed app = Ursina() e1 = Entity(model='quad', color=color.green, collider='box', scale=(2,2)) e = top_down_controller(model='quad', color=color.blue, position=[2,2]) app.run()
内容的提问来源于stack exchange,提问作者Phước Thắng Đinh
相关产品推荐
相关产品推荐

