Перемещение ноги игрока с помощью transform.rotation = Quaternion.AngleAxis - PullRequest
0 голосов
/ 20 декабря 2018

Я пытаюсь заставить свои сборные ноги и башмаки игрока перемещать «вперед» в мировом пространстве без вращения моей туфли на каждой ноге.Я просто хочу, чтобы он указывал вперед.

У меня есть сборный игрок.На префабе у меня есть сценарий, два игровых объекта с цилиндром в каждом, играющий роль «ноги», и еще два игровых объекта с моделью обуви, которую я сделал в каждом игровом объекте.игровой объект обуви находится внутри игрового объекта ноги.так, например, это идет:

Prefab игрока-> Правая нога Gameobject-> Левая нога Gameobject-> RightShoe Gameobject-> Левый башмак Gameobjectи под каждым игровым объектом есть соответствующие модели для ноги или ботинка.

Я написал код так, чтобы ноги моего игрока "двигались" / "меняли вращение", чтобы он выглядел так, как будто он идет (я не знаюлюбая анимация, так что это единственный способ, которым я умею).Существует также код, позволяющий перемещать игрока с AWSD, а смотреть или вращать игрока - с помощью мыши, как и в любую обычную игру FPS, за исключением моей игры от третьего лица.

Нога моего игрока движется относительно впередв мировом пространстве, так что это не проблема, но когда я использую мышь, чтобы вращать или смотреть в другом направлении (влево или вправо), ботинки игроков также вращаются влево или вправо на месте.Сначала я думал, что что-то не так с обувью, но я не написал код для обуви, я только написал код для ног.Поскольку мои ноги были цилиндрическими, я не заметил, что нога тоже вращается.Я узнал об этом только после того, как мои цилиндрические ножки стали более продолговатыми или более яйцевидными, как.

есть ли способ заставить мои туфли выполнять ту же «анимацию», что и моя нога, но не заставлять ее вращатьсяна месте?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class PlayerController : NetworkBehaviour
{

    public float speedH = 2.0f;
    private float yaw = 0.0f;

    public float WalkingTime;  //timer for walking animation
    public GameObject PlayerLeftLeg;
    public GameObject PlayerRightLeg;

    private float PlayerStatMenuTimer;
    public GameObject PlayerStatsMenu;

    public GameObject ThePlayer;


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

        if (!isLocalPlayer)
        {
            return;
        }

        //keep track of time for player stat menu
        //if not here than menua will show and hide like a thousand times when pressed once due to update reading code per frame
        PlayerStatMenuTimer = PlayerStatMenuTimer + 1 * Time.deltaTime;


        //moving player left right forward backward
        var x = Input.GetAxis("Horizontal") * Time.deltaTime * 50.0f;
        var z = Input.GetAxis("Vertical") * Time.deltaTime * 50.0f;
        transform.Translate(x, 0, z);


        //rotating player or "Looking"
        yaw += speedH * Input.GetAxis("Mouse X");
        transform.eulerAngles = new Vector3(0.0f, yaw, 0.0f);



        //if player is using WASD to move then do leg moving animation
        //if not moving then set legs to be still and reset in standing position
        //FYI:  "transform.TransformVector(1,0,0)" was used instead of "Vector3.forward" was because
        //   vector3.forward is local space, so when i rotate player the sense of "forward" also changes, thus i needed
        //  a code that uses the world space, thus i used "transform.TransformVector(1,0,0)"
        if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D))
        {
            CmdWalk();
            RpcWalk();
        }
        else
        {
            //if player not walking then reset
            PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
            PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
            WalkingTime = 0;
        }



        //get hidden mouse pointer back and unlock
        if (Input.GetKey(KeyCode.Escape))
        {
            Cursor.lockState = CursorLockMode.None;
        }



        //opens and closes stat menu
        if (Input.GetKey(KeyCode.Return) && (PlayerStatMenuTimer>=1) && (PlayerStatsMenu.activeSelf==false))
        {
            Cursor.lockState = CursorLockMode.None;
            PlayerStatsMenu.SetActive(true);
            PlayerStatMenuTimer = 0;

            //call the script "GetplayerStats" and call function "retrieceplayerstats"
            var GetStats = GetComponent<GetPlayerStats>();
            GetStats.RetrievePlayerStats();

        }
        else if (Input.GetKey(KeyCode.Return) && PlayerStatMenuTimer >= 1 && PlayerStatsMenu == true)
        {
            Cursor.lockState = CursorLockMode.Locked;
            PlayerStatsMenu.SetActive(false);
            PlayerStatMenuTimer = 0;
        }
    }



    private void Awake()
    {
        //this code locks mouse onto center of window
        //Screen.lockCursor = true;
        Cursor.lockState = CursorLockMode.Locked;
    }


    //initiaztes when started up
    void Start()
    {
        //calls script "SpawnItems" and function "RefreshItems" which will update the players items being shown
        ThePlayer.GetComponent<SpawnItems>().RefreshItems();
    }



    //so COMMAND is for server to client
    //it shows walking for local player
    [Command]
    void CmdWalk()
    {
        //timer
        WalkingTime += Time.deltaTime;

        //right leg stepping forward
        if (WalkingTime > 0 && WalkingTime < .4)
        {
            PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x - (60 * WalkingTime), transform.TransformVector(1, 0, 0));
            PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x + (60 * WalkingTime), transform.TransformVector(1, 0, 0));
        }

        //left leg stepping forward
        if (WalkingTime > .4 && WalkingTime < 1.2)
        {
            PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x + (60 * (WalkingTime - .8f)), transform.TransformVector(1, 0, 0));
            PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x - (60 * (WalkingTime - .8f)), transform.TransformVector(1, 0, 0));
        }

        //right leg stepping forward
        if (WalkingTime > 1.2 && WalkingTime < 1.59)
        {
            PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x - (60 * (WalkingTime - 1.6f)), transform.TransformVector(1, 0, 0));
            PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x + (60 * (WalkingTime - 1.6f)), transform.TransformVector(1, 0, 0));
        }

        //resetting
        if (WalkingTime > 1.6)
        {
            PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
            PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
            WalkingTime = 0;
        }
    }



    //so RPC is for Client to Server
    //it shows walking for other client players
    ///12227463/unity-moving-player-leg-multipleer
    [ClientRpc]
    void RpcWalk()
    {
        //timer
        WalkingTime += Time.deltaTime;

        //right leg stepping forward
        if (WalkingTime > 0 && WalkingTime < .4)
        {
            PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x - (60 * WalkingTime), transform.TransformVector(1, 0, 0));
            PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x + (60 * WalkingTime), transform.TransformVector(1, 0, 0));
        }

        //left leg stepping forward
        if (WalkingTime > .4 && WalkingTime < 1.2)
        {
            PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x + (60 * (WalkingTime - .8f)), transform.TransformVector(1, 0, 0));
            PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x - (60 * (WalkingTime - .8f)), transform.TransformVector(1, 0, 0));
        }

        //right leg stepping forward
        if (WalkingTime > 1.2 && WalkingTime < 1.59)
        {
            PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x - (60 * (WalkingTime - 1.6f)), transform.TransformVector(1, 0, 0));
            PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x + (60 * (WalkingTime - 1.6f)), transform.TransformVector(1, 0, 0));
        }

        //resetting
        if (WalkingTime > 1.6)
        {
            PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
            PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
            WalkingTime = 0;
        }
    }
}

Я включил весь сценарий для моего контроллера проигрывателя, все, на чем вам нужно сосредоточиться - это CMDWALK или RPC WALK, они оба представляют собой один и тот же кусок кода.

если кому-то нужна дополнительная информация о мировом пространстве движения ног, взгляните на эту ссылку, это еще один вопрос, который я задал Unity Moving Player Leg Multiplayer

1 Ответ

0 голосов
/ 21 декабря 2018

Проблема в том, что вы смешиваете углы Эйлера со значениями кватернионов.Это никогда не хорошая идея.В то время как углы Эйлера могут быть однозначно представлены в пространстве кватернионов, наоборот, один кватернион имеет несколько представлений в пространстве Эйлера.Поэтому ваш прямой доступ к rotation.x ненадежен (по крайней мере, не для его использования, чем в AngleAxis.

. Кроме того, здесь вы имеете дело с глобальным вращением. Вместо этого вы должны использовать локальные вращения, чтобы избежать проблем свложенные повернутые объекты.


Однако, как вы уже сказали, вы должны просто использовать

transform.Rotate(60 * WalkingTime, 0, 0, Space.Self); 

, а для сброса просто

transform.localRotation = Quaternion.Identity; 

Кстати, как я уже упоминал в мой ответ (раздел «Обновление») на свой предыдущий вопрос, не забудьте пропустить ClientRpc, если вы являетесь сервером или клиентом, который первоначально вызвал вызов, чтобы избежать дублированиядвижения и не вызывать оба, Cmd и Rpc в одном месте, это может привести к странному поведению, так как Rpc может быть вызван только сервером. Вызовите один метод walk и оттуда продолжайте с Cmd, которыйчем вызывает Rpc.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...