Raycasting к игроку без коллайдера / твердого тела - PullRequest
0 голосов
/ 27 мая 2018

Что мне нужно, так это то, что NPC, который движется по пути по сценарию, останавливается перед игроком, если игрок стоит на пути.Это 2D игра сверху вниз с движением сетки.NPC все время перемещает 4 клетки вниз, 2 клетки влево, 4 клетки вверх и 2 клетки вправо.Мне нужно, чтобы, если игрок мешал, он останавливался впереди и продолжал, когда игрок покидает сетку.Я не хочу использовать коллайдер на плеере, потому что тогда мне нужен rigitbody2d, и с этим мой скрипт движения не работает.

Вот TileMovementController.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class TileMovementController : MonoBehaviour {

    public enum Direction { Left, Right, Up, Down }; // Direction of movement

    protected Vector3 newPosition; // For movement

    protected virtual Vector3 move(Direction dir, int steps) {
        if (dir == Direction.Left && transform.position == newPosition)
            newPosition += new Vector3(steps * (-1), 0, 0);
        else if (dir == Direction.Right && transform.position == newPosition)
            newPosition += new Vector3(steps, 0, 0);
        else if (dir == Direction.Up && transform.position == newPosition)
            newPosition += new Vector3(0, steps, 0);
        else if (dir == Direction.Down && transform.position == newPosition)
            newPosition += new Vector3(0, steps * (-1), 0);

        return newPosition;
    }
}

PlayerMovementController.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovementController : TileMovementController {

    public float moveSpeed = 2.0f;

    void Start () {
        newPosition = transform.position; // Take the initial position
    }

    private void FixedUpdate() {
        // RayCasts for collisions, ignoring layer 2 (Ignore Raycast)

        if (Input.GetKey(KeyCode.A) && Physics2D.Raycast(transform.position, Vector2.left, 1, ~(1 << 2)).collider == null) { // Left
            newPosition = move(Direction.Left, 1);
        }

        if (Input.GetKey(KeyCode.D) && Physics2D.Raycast(transform.position, Vector2.right, 1, ~(1 << 2)).collider == null) { // Right
            newPosition = move(Direction.Right, 1);
        }

        if (Input.GetKey(KeyCode.W) && Physics2D.Raycast(transform.position, Vector2.up, 1, ~(1 << 2)).collider == null) { // Up
            newPosition = move(Direction.Up, 1);
        }

        if (Input.GetKey(KeyCode.S) && Physics2D.Raycast(transform.position, Vector2.down, 1, ~(1 << 2)).collider == null) { // Down
            newPosition = move(Direction.Down, 1);
        }

        transform.position = Vector3.MoveTowards(transform.position, newPosition, Time.deltaTime * moveSpeed); // Move there
    }
}

И NpcMovementController.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NpcMovementController : TileMovementController {

    // Defines the direction and number of steps in that direction has to move
    [System.Serializable]
    public struct MoveStep {
        public Direction direction;
        public int steps; // Each step is a grid square. 1 step = 1 unit in the grid position

        public MoveStep(Direction direction, int steps) {
            this.direction = direction;
            this.steps = steps;
        }
    }

    public List<MoveStep> path = new List<MoveStep>();
    public float moveSpeed = 2.0f;

    private int nextStepIndex = 0;
    private bool waiting = false;


    void Start () {
        newPosition = transform.position; // Take the initial position
    }

    private void FixedUpdate() {
        if (path.Count > 0) {
            if (Vector3.Distance(transform.position, newPosition) < 0.05f && !waiting) {
                transform.position = newPosition; // Adjust the position to be exactly what it should be

                waiting = true;
                StartCoroutine("wait", 2f);
            } else {
                if (Vector3.Distance(transform.position, newPosition) > 0.05f)
                    transform.position = Vector3.MoveTowards(transform.position, newPosition, Time.deltaTime * moveSpeed);
            }
        }
    }

    IEnumerator wait(float seconds) {
        yield return new WaitForSecondsRealtime(seconds);

        newPosition = move(path[nextStepIndex].direction, path[nextStepIndex].steps);

        if (nextStepIndex == path.Count - 1)
            nextStepIndex = 0;
        else
            nextStepIndex++;

        waiting = false;
    }
}

В NPCMovementController я пытался сделать raycast для игрока, но без коллайдера / ригтела это делаетне работает, очевидно.Если я присоединяю коллайдер / ригтело, он обнаруживает игрока, но я не могу двигаться.

1 Ответ

0 голосов
/ 27 мая 2018

Я однажды сделал нечто подобное и решил, проверив, находится ли положение игрока внутри квадратов сетки, которые представляют путь NPC.Например.

Давайте представим, что NPC движется так:

(0,0) -> (0,1) -> (0,2) -> (0,3)-> (1,3) -> (2,3) -> (2,2) -> (2,1) -> (2,0) -> (1,0) -> (0,0)

Так что, насколько я понимаю, если NPC находится в (0,0), он обнаружит игрока в (0,1), (0,2) и (0,3).Таким образом, вы можете проверить эти три позиции в вашей сетке и сравнить их с текущей позицией игрока, если есть совпадение, игрок находится на пути.

Теперь, кроме этого, можно перемещать своиигрок, использующий твердое тело (так что вы можете придерживаться подхода raycast).Вы можете использовать скорость твердого тела для перемещения NPC в одном или другом направлении.

//moveHorizontal and moveVertical can have +1 or -1 values depending on the inputs of the player:
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rigidbody.velocity = movement * speed;
...