Годо: Как ограничить движение игрока только определенными плитками?

Я пытаюсь создать клон "каменного века". И я пытаюсь придумать способ ограничить движение моего игрока определенными плитками. Это означает, что игрок может перемещаться только по определенным плиткам.

На данный момент я сделал две карты TileMaps: одну для «пола, пригодного для ходьбы», а другую - для «пола, пригодного для ходьбы». Я кладу их на разные слои столкновения, и мой игрок сталкивается только с «непроходимым полом». Таким образом, игрок не может войти в него: Здесь (https://i.imgur.com/sPGCS0V.png): пол, по которому можно пройти, - это коричневая плитка, а по непроходимому - та, что написано «ЭТАЖ».

Этот метод является проблемой, потому что у меня есть платформы, на которые я хочу переместить своего игрока. (Плитки со стрелками на них) Но если весь фон недоступен, мой игрок столкнется с ним, когда будет на платформе, поэтому он не сможет использовать платформы для перемещения ...

Есть лучший способ сделать это?


person PragmaticSystematic    schedule 18.09.2019    source источник


Ответы (1)


Я нашел решение в этом руководстве и немного изменил его. Вкратце решение состоит в использовании ray-cast по направлению движения и посмотрим, есть ли столкновение.

Что я сделал, так это создал карту тайлов и назвал все тайлы, которые позволяют игроку передвигаться, «walkable_ [something]». В скрипте плеера, где я обнаруживаю столкновение из луча, я проверяю имя тайла, с которым столкнулся raycast. Если название начинается с «можно ходить», я разрешаю движение, а во всех остальных случаях - нет.

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 (), она получает строковое имя тайла, с которым столкнулся луч. Поскольку коллизия raycast возвращает всю карту тайлов, нам нужно знать, с каким именно тайлом мы столкнулись. Поэтому я использовал положение игрока + направление вектора луча, чтобы определить правильный тайл. Сначала я добавил половину плитки шириной и высотой размера плитки, потому что позиция игрока считается верхним левым углом узла игрока. Например, если игрок представляет собой квадрат размером 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)

Для завершения здесь находится вставка полного скрипта проигрывателя.

person PragmaticSystematic    schedule 19.09.2019