我在this 指南上找到了解决方案并稍作修改。简而言之,解决办法就是在运动的方向上使用ray-cast,看看有没有碰撞。
我所做的是创建一个瓦片地图并将所有允许玩家移动的瓦片称为“可行走_[某物]”。在我检测到来自光线投射的碰撞的播放器脚本中,我检查了光线投射与之碰撞的图块的名称。如果名称以“walkable”开头,我允许移动,而在所有其他情况下,我不允许。
onready var ray = $RayCast2D
var speed = 256 # big number because it's multiplied by delta
var tile_size = 64 # size in pixels of tiles on the grid
var last_position = Vector2() # last idle position
var target_position = Vector2() # desired position to move towards
var movedir = Vector2() # move direction
func _process(delta):
# MOVEMENT
if ray.is_colliding():
var collision = ray.get_collider()
if collision is TileMap:
var tile_name = get_tile(collision)
if !(tile_name.begins_with("Walkable")):
position = last_position
target_position = last_position
else:
position += speed * movedir * delta
if position.distance_to(last_position) >= tile_size - speed * delta: # if we've moved further than one space
position = target_position # snap the player to the intended position
else:
position += speed * movedir * delta
if position.distance_to(last_position) >= tile_size - speed * delta: # if we've moved further than one space
position = target_position # snap the player to the intended position
这是 get_tile() 函数,它获取射线投射碰撞的瓦片的字符串名称。因为光线投射碰撞返回整个瓦片地图,我们需要知道我们与哪个特定瓦片发生碰撞。所以我用玩家的位置+光线投射矢量的方向来找出正确的瓷砖。首先,我添加了一个 tile 大小的宽度和高度的半个 tile,因为玩家位置被认为是玩家节点的左上角。例如,如果玩家是一个大小为 2x2 的正方形,并且他位于 (0,0) 上。这意味着它的左上角在 0,0 上。这意味着 1,1 是正方形的中心。
func get_tile(tile_map):
if tile_map is TileMap:
var v = Vector2(tile_size / 2 , tile_size /2)
var tile_pos = tile_map.world_to_map(position + v + ray.cast_to)
var tile_id = tile_map.get_cellv(tile_pos)
if (tile_id == -1):
return "None"
else:
return tile_map.tile_set.tile_get_name(tile_id)
为了完成,here 是完整播放器脚本的 pastebin。