Как я могу переместить каждый GameObject одновременно? - PullRequest
1 голос
/ 10 ноября 2019

Я создаю ритмическую игру на основе сетки, вдохновленную Crypt of the Necrodancer . Для этого мне нужно переместить игрока, а также врагов (в моем случае кур) в то же время точно .

Я создал скрипт GameLogic, в котором таймеробратный отсчет до нуля:

public class GameLogic : MonoBehaviour
{
    public float maxTime = 0.5f;
    public float timeLeft;

    public bool move;

    void Start()
    {

        timeLeft = maxTime;
    }

    void LateUpdate()
    {
        //Universal Timer
        timeLeft -= Time.deltaTime;

        if(timeLeft <= 0)
        {
            move = true;
            UpdateTime();
        }


    }

    public void UpdateTime()
    {
        timeLeft = maxTime;
        move = false;

    }

Теперь я ссылаюсь на этот таймер в сценарии проигрывателя:

 GameLogic gameLogic;

    Vector3 up = Vector3.zero,
    right = new Vector3(0, 90, 0),
    down = new Vector3(0, 180, 0),
    left = new Vector3(0, 270, 0),
    currentDirection = Vector3.zero;

    Vector3 nextPos, destination, direction;

    float speed = 5;
    float rayLength = 1f;
    //float timeLeft;
    //public float maxTime = 1;



    bool canMove = true;
    //bool movedToNext;
    bool bouncedOff;


    void Start()
    {
        GameObject g = GameObject.Find("Game Logic");
        gameLogic = g.GetComponent<GameLogic>();

        currentDirection = up;
        nextPos = Vector3.forward;
        destination = transform.position;

    }

    // Update is called once per frame
    void Update()
    {

        BeatMovement();
        Move();

    }

    void BeatMovement()
    {
        //timeLeft -= Time.deltaTime;

        if (gameLogic.move)
        {
            canMove = true;
            bouncedOff = false;

            //gameLogic.move = false;

        }
        else { canMove = false; }
    }

    void Move()
    {
        transform.position = Vector3.MoveTowards(transform.position, destination, speed * Time.deltaTime);

        if(Input.GetKeyDown(KeyCode.W) || Input.GetKeyDown(KeyCode.UpArrow))
        {
            nextPos = Vector3.forward;
            currentDirection = up;
        }
        if (Input.GetKeyDown(KeyCode.S) || Input.GetKeyDown(KeyCode.DownArrow))
        {
            nextPos = Vector3.back;
            currentDirection = down;

        }
        if (Input.GetKeyDown(KeyCode.D) || Input.GetKeyDown(KeyCode.RightArrow))
        {
            nextPos = Vector3.right;
            currentDirection = right;

        }
        if (Input.GetKeyDown(KeyCode.A) || Input.GetKeyDown(KeyCode.LeftArrow))
        {
            nextPos = Vector3.left;
            currentDirection = left;

        }


        if (Vector3.Distance(destination, transform.position) <= 0.000001f)
        {
            transform.localEulerAngles = currentDirection;

            if(canMove)
            {
                if(Valid())
                {
                    destination = transform.position + nextPos;
                    direction = nextPos;

                }
                else
                {
                    if(currentDirection == up && bouncedOff == false)
                    {
                        nextPos = Vector3.back;
                        currentDirection = down;
                        bouncedOff = true;

                    }
                    if (currentDirection == down && bouncedOff == false)
                    {
                        nextPos = Vector3.forward;
                        currentDirection = up;
                        bouncedOff = true;
                    }

                    if (currentDirection == left && bouncedOff == false)
                    {
                        nextPos = Vector3.right;
                        currentDirection = right;
                        bouncedOff = true;
                    }

                    if (currentDirection == right && bouncedOff == false)
                    {
                        nextPos = Vector3.left;
                        currentDirection = left;
                        bouncedOff = true;
                    }
                }
            }
        }
    }

    //checks if there is an obstacle in the destinationPosition the Player wants to move
    bool Valid()
    {
        Ray myRay = new Ray(transform.position + new Vector3(0, 0.25f, 0), transform.forward);
        RaycastHit hit;

        Debug.DrawRay(myRay.origin, myRay.direction, Color.red);

        if(Physics.Raycast(myRay, out hit, rayLength))
        {
            if(hit.collider.tag == "Obstacle")
            {
                return false;
            }
        }

        //if the raycast doesnt hit anything the movement is valid (true) 
        return true;
    }
}

Кажется, это работает. Но как только другой GameObject использует этот таймер, все становится сложнее. Ни один из GameObjects не будет двигаться. Я думаю, это потому, что таймер больше не достигнет нуля и скоро обновится. Я попытался обновить время в плеере или ChickeScripts, но это привело к тому, что один из них не смог двигаться. Я вижу проблему, я просто не знаю, как ее исправить.

Вот код курицы, использующий скрипт PathFollower:

public class PathFollower : MonoBehaviour
{
    Node[] pathNode;
    public GameObject player;

    Vector3 CurrentPositionHolder;
    int CurrentNode;


    GameLogic gamelogic;

    void Start()
    {
        GameObject g = GameObject.Find("Game Logic");

        pathNode = GetComponentsInChildren<Node>();
        gamelogic = g.GetComponent<GameLogic>();

        CheckNode();

    }

    void CheckNode()
    {
        //tells me on which position the next Node is
        CurrentPositionHolder = pathNode[CurrentNode].transform.position;
    }

    void Update()
    {   
        if (gamelogic.move)
        {
            Movement();
        }
    }

    void Movement()
    {

        //moves player to the next position
        if (player.transform.position != CurrentPositionHolder)
        {
            player.transform.position = CurrentPositionHolder;
              Debug.Log("moves");

        }
        else
        //if player is on the position u want him to be then set the next node 
        {
            if (CurrentNode < pathNode.Length - 1)
            {
                CurrentNode++;
                CheckNode();

            }
        }

        if (CurrentNode == pathNode.Length -1)
        {
            CurrentNode = 0;
            CheckNode();

        }
    }
}

Я рад любым предложениям! Заранее спасибо:)

1 Ответ

0 голосов
/ 10 ноября 2019

То, что у вас здесь есть, это игра на основе поворота. Crypt of the Necrodancer похож на roguelike, и его поворот был одним из важных свойств игры Rogue.

Обычно игры делятся на «GameTicks», называемые юнитами. Игра «в реальном времени», просто имеет очень высокую скорость GameTicks (30-60 в секунду), которая не ждет пользовательского ввода, чтобы закончить ходы. Обычно речь идет об ограничении GameTicks верхней границей и обеспечении того, чтобы вы не замедляли рисование. Игровые подсказки всегда должны учитываться и обрабатываться в обновлении, а не в коде розыгрыша.

Теперь дело в том, что в настоящее время тики выполняют больше , чем просто подсчет ходов. Есть другие вещи, такие как анимация, которые им нужны. Или интерпретировать пользовательский ввод, не связанный с игрой (меню). Не зная об этом, я могу сказать, что Unity предоставит счетчик Game Tick. Либо в перегруженном обновлении в качестве параметра, либо в виде поля класса.

Таким образом, у вас есть два варианта:

  1. Используйте подсчет тиков для ходов игры. Но держите подальше обработку ввода. В основном, только часть движения Обновления находится под ограничением / подсчетом тиков
  2. Ограничьте подсчет тиков как обычно, но повороты должны быть отдельным счетчиком. Тот, который вы продвигаете как часть кода Обновления в разделе gameticks.
  3. В этом конкретном случае может быть поддержка Unity. Если это так, обычно используйте это.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...