Rotate 3D Character Super Mario Style

Hi!

I’m trying to rotate my character style 2d platform games like Super Mario, and I’m having several problems, I tried with the function transform.Rotate (,) and do not get the result you want. And I need lights to see how to do so following the rotating each direction.

Sorry for my bad english as well!

Thank you!

Hi,
I did not understand your issue… Can you explain it in another way or with a screenshot ?

c u

how do u want to rotate it? if is 2d i supose you want to see the character rotating slow in his Y axis when it changes its direction.
If this is your target, i think i can help you because i have made a game with a character doing this rotation.

It’s like Afisicos said, this is exactly what I want, when you rotate it changes direction relative to the y axis rather, about 180 degrees, as in Limbo, and several 2D platform games.

Then Afisicos, how can you help me???

Thanks!

yes. im in the work. when i arrive home i will help you if i remember :stuck_out_tongue:

This had me confused for a while as well… try using transform.EulerAngles.y instead, that will change the object’s rotation on the world’s axis. I think transform.rotation is used for calculation rather than actually changing positions.

Ok Afisicos!

My time zone is different for your, so, i dont see when you online, but i´m waiting. I program software, see it in the university, and myself too, but the template library and the use of scripts in unity are something that still need to study hard.

Thanks!

Hi,
if I understand well, you have to manipulate the transfom component (doc) of your player.

You can use the Transform.Rotate function to apply a rotation around any axis, so Y axis in your case (supposed you use Y+ for top).

Just an example :

void Update()
    {
        transform.Rotate(Vector3.up, Time.deltaTime * rotationSpeed);
    }

This is what I tried, but no results. If you saw the video, then realized what I do. I’ll leave the code as is, it might be easier to analyze.

var velocidadeAndar : float;
private var controlo : CharacterController;
var velocidadeRotacao : float = 10.0;
var velocidadeSalto : float = 7.0;
private var speed : float = 0;
var gravidade : float = 20.0;
private var direcaoMovimento : Vector3 = Vector3.zero;
private var isGrounded : boolean = true;

function Start ()
{
	// Inicialização
	controlo = GetComponent(CharacterController);

	// Coloca todas as animações para o loop
	animation.wrapMode = WrapMode.Loop;
	
	// Excepto "jump"
	animation["jump"].wrapMode = WrapMode.Once;
	
	// Colocá-lo noutro layer superior (por padrão é zero)
	animation["jump"].layer = 1;
	
	// Para todas as animações
	animation.Stop();
	
}

function Update () 
{
	// Reprodução de caminhada ou marcha lenta, a depender
	// Se o jogador está a ir para frente
	
	if (Mathf.Abs(Input.GetAxis("Horizontal")) > 0.2)
	{
	// Andar
	animation.CrossFade("walk");
	
	// Será que estamos a caminhar para a frente ou para trás?
	// Defina a velocidade de reprodução da animação
	
		// Expressão abaixo equivalente
		//animation["walk"].speed = (Input.GetAxis("Horizontal") < -0.2) ? -1 : 1;
		if (Input.GetAxis("Horizontal") < -0.2)
		{
			animation["walk"].speed = -1;
			
		}
		else
		{
			animation["walk"].speed = 1;
			
		}
	
	// Definir a velocidade de raiz do personagem
	speed = Mathf.Abs(Input.GetAxis("Horizontal")) * velocidadeAndar;
	
	}
    
	else
	{
     	animation.CrossFade("idle");
     	speed = 0;
	}
	
	if (Input.GetKeyDown(KeyCode.W)  isGrounded)
	{
		animation.CrossFade("jump");
	}
	
	
	// Input.GetAxis ("Horizontal") retorna um número positivo se nós estamos pressionando a seta para o lado direito, e
	// Um número negativo se estamos pressionando a seta para o lado esquerdo.  Portanto, a nossa direcaoMovimento ou será
	// (0,0,0) para inativo ou (0,0 ,+/-) para andar no caráter do sistema de coordenadas raiz.
	
	direcaoMovimento = new Vector3(0,0,Input.GetAxis("Horizontal"));
	
	// Precisamos multiplicar a direção em que estamos nos movendo pelo transformar do personagem de modo que
	// Nos movemos corretamente no espaço do mundo.
	
	direcaoMovimento = transform.TransformDirection(direcaoMovimento);
	
	// Finalmente, mova o controlador.  Time.deltaTime nos dá o tempo decorrido desde o
    // Update da última chamada.  Multiplicando Time.deltaTime com velocidade nos dará
    // A distância que o personagem deveria ter viajado desde o último quadro.  Nós
    // Escalamosa direcaoMovimento por essa distância.
    // Aplicamos gravidade 
    
    direcaoMovimento.y -= gravidade * Time.deltaTime;
    controlo.Move(direcaoMovimento * (Time.deltaTime * speed));
	
	

}

Thanks!

So, is it working just for going left/right and jump (without rotation) ?
I am bit surprised your player seems to have Z+ axis as forward direction…
Anyway, here is a proposal (code not tested) :

private float targetAngle = 0;

function Update () 
{
    // Reprodução de caminhada ou marcha lenta, a depender
    // Se o jogador está a ir para frente

    if (Mathf.Abs(Input.GetAxis("Horizontal")) > 0.2)
    {
            // Andar
            animation.CrossFade("walk");

            // Será que estamos a caminhar para a frente ou para trás?

            // Defina a velocidade de reprodução da animação

        // Expressão abaixo equivalente
        //animation["walk"].speed = (Input.GetAxis("Horizontal") < -0.2) ? -1 : 1;

        float oldSpeed = animation["walk"].speed;
        if (Input.GetAxis("Horizontal") < -0.2)
        {
            animation["walk"].speed = -1;
        }
        else
        {
            animation["walk"].speed = 1;
        }
        
        if(oldSpeed != animation["walk"].speed)
        {
                targetAngle = oldSpeed == 1 ? -180.0f : 180.0f;
        }

            // Definir a velocidade de raiz do personagem

            speed = Mathf.Abs(Input.GetAxis("Horizontal")) * velocidadeAndar;
    }

        ....
        ....

        if( Mathf.Abs(transform.Rotation.eulerAngles.y - targetAngle) > epsilon)          // you have to tweak epsilon value. Perhaps 1° or 2°
        {
                transform.Rotate(0, rotateSpeed * Time.deltaTime, 0);        // rotateSpeed has to be high to perform a quick rotation
        }
        else
        {
                transform.rotation.eulerAngles = new Vector3(0, targetAngle, 0);
        }
}

You will have to tweak a bit (or a lot) for your case.

Hope it helps.

I was seeing the changes that you made in the script, and i did not understand the comment in the line of the variable epsilon and their function." What value it should have?

I see at home with more attention and thank you Nems!

The use of epsilon is due to imprecision depending on rotation.
If your Y angle is 0° and your target angle is 180°, then the player will rotate each frame a little bit. So, it will be :
frame 0 = 0° ; frame 1 = 0° + 1.234° ; frame 2 = 0° + 1.234° + 0.987 °… till frame n ~= 180°.
You need to stop the “transform.Rotate” when you reach target angle, so when player’s Y angle is close to 180°. But since it will never be exactly 180.0000°, you have to accept a little gap.

Let’s Y angle as Y° ; epsilon as e ; target angle as t ;
If Y° is close to t, then : |Y - target| is small.
Let’s e = 1° and t = 180°, so the algo stop to rotate when Y° is between : t +/- e = 179° or 181°.

About rotateSpeed, just look at mario or Limbo… When they turn back it have to be quick (less than 1 second). So you have to try different values and adjust to your needs.

ps : On line 32, change :
targetAngle = oldSpeed == 1 ? -180.0f : 180.0f;
to
targetAngle = oldSpeed == 1 ? 180.0f : 0.0f;