戈多特:如何将玩家的动作限制在某些区域?

时间:2019-09-18 19:29:47

标签: game-engine godot

我正在尝试克隆'Stone Age'。 而且我正在尝试找到一种方法来将玩家的运动限制在某些范围内。这意味着玩家只能在某些图块上移动。

到目前为止,我所做的是制作两个TileMap,一个用于“可行走的地板”,另一个用于“不可行走的地板”。我将它们放在不同的碰撞层上,我的播放器仅与“不可行走的地板”碰撞。因此,玩家无法进入: 这里(https://i.imgur.com/sPGCS0V.png):步行地板是棕色的瓷砖,不能步行的是说“地板”的瓷砖。

此方法有问题,因为我有要移动播放器的平台。 (上面有箭头的磁贴)但是,如果所有背景都无法移动,则我的玩家在平台上时会与它发生碰撞,因此他将无法使用平台移动...

有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

我在this指南中找到了一种解决方案,并对其进行了少许修改。简而言之,解决方案是在运动方向上使用ray-cast,看看是否有碰撞。

我所做的是创建一个tilemap,并将允许玩家移动的所有tile称为“ walkable_ [something]”。在播放器脚本中,我从射线投射中检测到碰撞,我检查了光线投射与之碰撞的瓦片的名称。如果名称以“ 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()函数,它获取与光线投射碰撞的图块的字符串名称。由于光线投射碰撞会返回整个贴图,因此我们需要知道与哪个特定的贴图发生碰撞。因此,我使用了播放器的位置+射线投射矢量的方向来找出正确的图块。首先,我将图块宽度和高度增加了一半,因为播放器位置被视为播放器节点的左上角。例如,如果玩家是一个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是完整播放器脚本的粘贴框。