简体   繁体   English

向没有对撞机/刚体的玩家进行光线投射

[英]Raycasting to a player without collider/rigidbody

What I need is that an NPC that is moving in a path by script, stops in front of the player if the player is in the way. 我需要的是,按脚本在路径中移动的NPC,如果播放器在路上,则停在播放器前面。 It's a top-down 2d game rpg with grid movement. 这是一款具有网格运动的自上而下的2D游戏角色扮演。 The NPC is moving 4 cells down, 2 cells left, 4 cells up and 2 cells right all the time. NPC一直在向下移动4个单元格,向左移动2个单元格,向上移动4个单元格,向右移动2个单元格。 I need that if the player is in the way, it stops in front and continue when the player leaves the grid. 我需要,如果玩家在路上,它会停在前面,并在玩家离开网格时继续。 I don't want to use a collider on the player because then I need a rigitbody2d and with that, my movement script is not working. 我不想在播放器上使用对撞机,因为那时我需要使用rigitbody2d,因此我的运动脚本无法正常工作。

Here is the TileMovementController.cs: 这是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;
    }
}

The PlayerMovementController.cs: 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
    }
}

And the NpcMovementController.cs: 和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;
    }
}

In the NPCMovementController I tried to do a raycast to player, but without the collider/rigitbody it does not work obviously. 在NPCMovementController中,我尝试对播放器进行光线投射,但是如果没有对撞机/刚体,则显然无法正常工作。 If I attach the collider/rigitbody it detects the player but I cannot move. 如果我安装对撞机/刚体,它将检测到玩家,但我无法移动。

I did once something similar and I solved by checking if the position of the player is inside the grid squares which represent the path of the npc. 我做了一次类似的事情,然后通过检查播放器的位置是否在代表npc路径的网格正方形内来解决。 For example. 例如。

Let's imagine that the npc moves like this: 假设npc像这样移动:

(0,0) -> (0,1) -> (0,2) -> (0,3) -> (1,3) -> (2,3) -> (2,2) -> (2,1) -> (2,0) -> (1,0) -> (0,0) loop (0,0)->(0,1)->(0,2)->(0,3)->(1,3)->(2,3)->(2,2)->( 2,1)->(2,0)->(1,0)->(0,0)循环

So for my understanding, if the npc is in (0,0), it will detect the player in (0,1), (0,2) and (0,3). 因此,据我了解,如果npc在(0,0)中,它将检测(0,1),(0,2)和(0,3)中的玩家。 So you can check this three positions in your grid and compare them with the current position of the player, if there is a match, the player is in the path. 因此,您可以检查网格中的这三个位置,并将它们与玩家的当前位置进行比较,如果存在匹配,则玩家在路径中。

Now besides that, it is possible to move your player using the rigidbody (so you can keep with your raycast approach). 现在除此之外,还可以使用刚体移动播放器(这样您就可以使用射线投射方法了)。 You can use the velocity of the rigidbody to move the npc in one direction or another. 您可以使用刚体的速度沿一个方向或另一个方向移动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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM