向没有 collider/rigidbody 的玩家投射光线

Raycasting to a player without collider/rigidbody

我需要的是一个 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 中,我尝试对播放器进行光线投射,但没有 collider/rigitbody 它显然不起作用。如果我附上 collider/rigitbody 它会检测到玩家,但我无法移动。

我做过一次类似的事情,我通过检查玩家的位置是否在代表 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)的玩家。所以你可以在你的网格中检查这三个位置并将它们与玩家的当前位置进行比较,如果匹配,则玩家在路径中。

现在除此之外,还可以使用刚体移动玩家(这样您就可以保持光线投射方法)。您可以使用刚体的速度使 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;