0
\$\begingroup\$

Brief Summary: I want to recreate Super Mario 64 turning movement into unity without the clunky movement I currently have. And I would also love how to implement the camera rotation system mentioned below.

Troubles: I get lost when thinking into movement algorithms for unity. Like my character won't respond to camera relative movement appropriately. I'll provide a link to a video I made comparing my current basic unity controls to Super Mario 64 if you wish to see the full comparison between the two. And in this video I also mention stuff I think I can do to replicate the things I want. Youtube Link to my comparison video

In-Depth Explanation of the problems with my current movement:

[TurnSpeed ~ My Character turn speed is actually decent. I can increase the value of it to mimic the instant snap turning Mario does when he has a input value of 0. Now when movement is being made, the characters simulate the smooth turning Mario does when given a value of 1 on horizontal input and 1 on vertical input (I usually clamp these values to make it more smooth for people on controllers). Mario: Also as a bonus, when Mario does make a instant snap turn; the camera slowly rotates itself behind the player again to give them the view of the direction they are heading. Estimate Solution: I would love to learn to how exactly make this but so far my guess is getting the direction the player is heading and use that information to rotate the camera using lerp to get it in the right position.]

My Code: I will provide my code for my progress so far in two different fashions: A clean basic movement version on here and a separate code link to see it all.

Full Code Links: CharacterController BasicMovement, and Basic Camera Controls

public Transform T_Player;
private CharacterController CC_PlayerCC;
public float F_CamTurnSpeed;
public float F_CamDistance;
public float F_CamTilt;
public float F_CamTiltLowest;
public float F_CamTiltHighest;
public float F_DirectionItsHeading;
public float F_PlayerHeight;

void start()
{
  CC_PlayersCC = GetComponent<CharacterController>();
}

void update()
{
    Input();
    CalculateCamera();
    CalculateGround();
    Move();
    Gravity();
    Jump();

    CC_PlayersCC.Move(V3_Velocity * Time.deltaTime);
}

void Input()
{
  V2_Input = new Vector2(Input.GetAxis("Horizontal_Keyboard"), Input.GetAxis("Vertical_Keyboard"));

  V2_Input = Vector2.ClampMagnitude(V2_Input, 1);
}

void CalculateCamera()
{
    V3_CamForwardDirection = T_CameraObj.forward;
    V3_CamRightDirection = T_CameraObj.right;
    V3_CamForwardDirection.y = 0;
    V3_CamRightDirection.y = 0;
    V3_CamForwardDirection = V3_CamForwardDirection.normalized;
    V3_CamRightDirection = V3_CamRightDirection.normalized;
}

void CalculateGround()
{
    if (CC_PlayersCC.isGrounded)
    {
        B_PlayerIsGrounded = true;
    }
    else
    {
        B_PlayerIsGrounded = false;
    }
}

void Move()
{
    V3_IntendedDirection = V3_CamForwardDirection * V2_Input.y + V3_CamRightDirection * V2_Input.x;
    F_CurrentTurnSpeed = V3_Velocity.magnitude / 5;
    F_PlayerTurnSpeed = Mathf.Lerp(F_PlayerHighestTurnSpeed, F_PlayerLowestTurnSpeed, F_CurrentTurnSpeed);
    if (V2_Input.magnitude > 0)
    {
        Q_PlayerRotation = Quaternion.LookRotation(V3_IntendedDirection);

        transform.rotation = Quaternion.Lerp(transform.rotation, Q_PlayerRotation, F_PlayerTurnSpeed * Time.deltaTime);
    }

    V3_VelocityXZ = V3_Velocity;
    V3_VelocityXZ.y = 0;
    V3_VelocityXZ = Vector3.Lerp(V3_VelocityXZ, transform.forward * V2_Input.magnitude * F_PlayerSpeed, F_Accerlation * Time.deltaTime);
    V3_Velocity = new Vector3(V3_VelocityXZ.x, V3_Velocity.y, V3_VelocityXZ.z);
}

void Gravity()
{
    if (B_PlayerIsGrounded)
    {
        V3_Velocity.y = F_OnGroundGravity; //OnGround Gravity
    }
    else
    {
        V3_Velocity.y -= F_PlayerGravity * Time.deltaTime;
        V3_Velocity.y = Mathf.Clamp(V3_Velocity.y, -10, 10);
    }
}

void Jump()
{
    if (B_PlayerIsGrounded == true)
    {
        if (Input.GetButtonDown("Jump"))
        {
            V3_Velocity.y = F_PlayerJumpHeight;
        }
    }
}

void OnControllerColliderHit(ControllerColliderHit hit)
{
    F_CurrentAngle = Vector3.Angle(Vector3.up, hit.normal);
}
\$\endgroup\$
  • \$\begingroup\$ Where did you get the level asset? Did you make it yourself? \$\endgroup\$ – user124517 Feb 26 at 16:24
  • \$\begingroup\$ @Vakore I got it from this website models-resource.com/nintendo_64/supermario64/model/8561 No, I did not make it but I can easily do that. I usually use blender and concept art to make my models. Now if it is a level then I usually make sections of that design into models; then I put it together. I can easily take the model apart and remake the level itself but what is the point if I can't even make the controls yet. \$\endgroup\$ – Downtionix Feb 26 at 16:31
  • \$\begingroup\$ Thanks for taking the time to improve the question. :) \$\endgroup\$ – DMGregory Feb 26 at 19:37
0
\$\begingroup\$

I'm working on a 3D platformer as well, and have studied SM64 a lot in the process of making, however, I'm not exactly replicating it, so I don't have the code on hand. However, I can tell you several things:

A: Mario moves forward based on the direction he is facing, and if you turn left on the movement stick while going forward, he will quickly, but noticeably, be in a rotation state, resulting in a curve to start fully moving left and not forward. You're going to use transform.forward a lot in this case, especially for diving and long jumps. A little something like this:

marioVelocity += transform.forward * acceleration;

Note that transform.forward and transform.right are both Vector3s, not floats. Another thing to note is that when when you slam the stick in the opposite direction you are moving, Mario will enter a short slide animation to change direction, and if the player presses 'A' as this happens, it does a side ward somersault. To make this happen, you should check if the absolute value of the rotation that needs to happen is greater than 160 degrees(give or take).

Also, when Mario is completely standing still and you start moving, he will instantly snap into the rotation you want to go in with no transition. A few if statements can help with that. Here is a little code on how to do that:

Vector3 rotateDirection = (camera.forward * Input.GetAxis("Vertical")) + (camera.right * Input.GetAxis("Horizontal"));
if (marioVelocity.magnitude == 0f) {
Quaternion newRotation = Quaternion.LookRotation(new Vector3(rotateDirection.x, 0f, rotateDirection.z));
transform.rotation = Quaternion.Slerp(transform.rotation, newRotation, rotationSpeed * Time.deltaTime);//You're going to make rotationSpeed super low, like 0.0001(not sure if 0 works) or super high. I forget which
}

When Mario is in the air he doesn't rotate, but rather faces the direction that he was on the ground last. You're going to want something like this at the begging of your code public Transform camera so that you can get the rotation of your camera(or what the camera is pivoting off of) so that you can use camera.right and camera.forward in the air, and for getting rotation reference on the ground.

For wall jumps however, that is a little more complex. I recommend this video for more reference.

Diving, long jumping, and triple jumps are pretty simple, as diving you jump test marioVelocity.magnitude to see if he is fast enough to perform a dive when the player presses 'B' otherwise kick or punch, long jumps if the player is crouching, has some velocity, and presses 'A', and triple jumps you just have a float that goes down, and when Mario lands again he has a short time to press 'A' to perforom a double or triple jump.

\$\endgroup\$
  • \$\begingroup\$ My Line Responses: [Response to lines (1-3)]Sweet to hear that you working on the same genre too. [Response to lines (4-9)] I didn't notice that, and I have done that before. But it was for more simplistic movement. Either way it seems that I can use this method of storing velocity values again. \$\endgroup\$ – Downtionix Feb 26 at 19:49
  • \$\begingroup\$ [Response to lines (10-14)] But isn't there programming involved with mario slightly carrying his speed after suddenly turning? Like acceleration would a easy way to modify that to be like sliding. [Response to lines (15-16)] Wow, I thought of that but I just didn't think it was how it was done. I thought it was part of the movement system itself instead of being a simple snap rotation. \$\endgroup\$ – Downtionix Feb 26 at 19:50
  • \$\begingroup\$ [Response to lines (17-20)] I didn't notice that either. but I have already done something like that before. I just didn't think to do it with this too much. [Response to line (21)] Thanks for the good source on wall jumps. [Response to lines (22-26)] I looked into that a while back when I was interested in learning how they created the triple jump. I usually forget that I manipulate information revolved around magnitude and velocity. velocity I usually only bother to look at for basic jumping but not much else. \$\endgroup\$ – Downtionix Feb 26 at 19:50
  • \$\begingroup\$ Could you help me find a good way to replicate the turning movement more? i haven't gotten home yet to practice and debug some concepts you helped me think of to get that to copy right. But the instant rotation snap is definitely useful information you provided. \$\endgroup\$ – Downtionix Feb 26 at 19:50
  • \$\begingroup\$ I have the instant rotation snap added to the code. \$\endgroup\$ – user124517 Feb 26 at 20:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.