1
votes

I am trying to get my Player prefabs leg and shoe to move "Forward" world space wise without my shoe on each leg rotating. I just want it pointing forward.

I have a player prefab. On the prefab I have a script, two gameobjects with a cylinder in each one acting as a "leg", and another two gameobject with a shoe model I made in each gameobject. the shoe gameobject is inside the leg gameobject. so for example it goes:

Player prefab
-> Right Leg Gameobject
-> Left Leg Gameobject
-> RightShoe Gameobject
-> Left Shoe Gameobject
and under each gameopbject is the respective models for the leg or shoe.

I have written code so that my player's legs "move"/"change rotation" to make it look like it's walking (I don't know any animation so this is the only way I know how). There is also code so that moving player is with AWSD and looking or rotating player is with the mouse, just like any typical FPS game, except my game in 3rd person.

My player's leg does move "forward" relative to world space so that is not an issue but hen I use the mouse to rotate or look in another direction (left or right), the players shoes also rotate left or right in place. At first I thought something was wrong with the shoes but I did not write any code to the shoes, I only wrote code for the legs. Since my legs were cylindrical, I did not notice the leg rotates too. I only found this out once I set my cylindrical legs to be more oblong or more egg shaped like.

is there a way I can make my shoes do the same "animation" as my leg but not make it rotate in place?

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
    //https://stackguides.com/questions/53784897/unity-moving-player-leg-multiplayer
    [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;
        }
    }
}

I have included the entire script for my player controller, all you need to focus on is the CMDWALK or RPC WALK, they are both the same piece of code.

if anyone needs more info on the leg movement world space, take a look at this link, it is another question I asked Unity Moving Player Leg Multiplayer

1
You shouldn't use .rotation.x to get the x value. Don't mix Euler values with Quaternions. You could try transform.localEulerAngles instead. - derHugo
So like this? PlayerRightLeg.transform.localeulerangles= Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x + (60 * (WalkingTime - .8f)), transform.TransformVector(1, 0, 0)); - HumanlyRespectable
@derHugo I have taken a screen shot video of what happens, am I able to upload this anywhere on this site? The file is about 6MB - HumanlyRespectable
In your case actually I would rather use transform.Rotate(60*WalkingTime, 0, 0, Space.Self); and for a reset simply transform.localRotation = Quaternion.Identity; - derHugo
Haha no problem ;) Glad to help once more! - derHugo

1 Answers

1
votes

The problem is you are mixing Euler angles with Quaternion values. This is never a good idea. While an Euler angles can be uniquely represent in Quaternion space, the other way round one Quaternion has multiple representations in Euler space. Therefore your direct access of rotation.x is not reliable (at least not for using it than in AngleAxis.

Additionally you are dealing with global rotation here. You should use local rotations instead to avoid the problems with nested rotated objects.


However in your case you should as already said simply use

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

and for a reset simply

transform.localRotation = Quaternion.Identity; 

Btw as I mentioned in my answer(the "Update" section) to your previous question don't forget to skip the ClientRpc if you are the server or the client who originally invoked the call to avoid duplicate movements. And don't call both, Cmd and Rpc at the same place this could lead to strange behaviours since the Rpc can only be called by the server. Call one method walk and from there go on with the Cmd which than Invokes the Rpc.