Unity note-17-01-character controller with physics engine

Unity note-17-01-first person controller with physics engine

Realize basic functions such as walking, running and jumping

The first: with Character Controller component

Preconditions

First, create an empty object and add Character Controller, AudioSource and collider components to the empty object. If your model already has collider components, there is no need to add collider components to the empty object here

Script component

analysis

Move: to move on the physical engine, you can't use the relevant move method of Transform, which will lead to die piercing. Because the character controller component is added, the Move(x,y,z) method of this class should be used for the move here. This method is not constrained by gravity, that is, the effect of simulating gravity needs to be realized through script

In addition, the SimpleMove method cannot be used because it has its own gravity. If you use this method, you will not be able to jump

Jumping: in my test, if the Character Controller component is added and the rigid body component is added, it will lead to unknown wrong movement. Therefore, the jumping here needs to be realized by simulating gravity (if there is a big man, please leave a message to answer)

Script implementation

move

    float x = Input.GetAxis("Horizontal");
    float y = Input.GetAxis("Vertical");
    
characterController.Move((new Vector3(transform.forward.x, 0, transform.forward.z) * y + new Vector3(transform.right.x, 0, transformright.z) * x) * walkSpeed);

The reason why it is written here is that when the mouse controls the person to look up or down, the orientation of the object will be offset on the y axis

However, the movement is horizontal, so you need to eliminate the value of the y axis

walkSpeed is the walking speed. Because the running code is the same as the walking code, but the speed is different, so I won't repeat it here

jump

First, judge when to jump: 1. Press the space on the keyboard; 2. Not currently in the air

Therefore, a Bool variable isJump is set here to judge the condition. If the space is pressed and is not in the air, jumping is allowed, and isJump is set to true, indicating that jumping is currently in progress

Use an if statement structure to decompose the hierarchy:

At present, there are three situations of jumping: upward jumping process; Downward landing process; to ground

Here, a jumpTimeFlag of float type is added to indicate the current jump time and a jumpTime of float type to indicate the total specified jump time. If the jump time is less than the specified time, it is 1; Greater than 2; 3 additional judgment

1: In the rising process, the speed of the rising process should be decreasing;

Here, the bouncing forces jumpForce(float) and jumpSpeed(float) are introduced to represent the initial speed of bouncing and the speed at each time respectively, in which the bouncing force needs to be input in advance. The mathematical difference change is added to reduce the speed, which may still be unnatural and need debugging and physical calculation

2: Same as 1

3: After landing, set the jump speed every moment, decrease the speed every moment, set the current jump time to 0, and set isJump to false

Where: the object with character control component can use characterController.collisionFlags == CollisionFlags.Below code to judge whether it lands or not

    if (Input.GetKeyDown(KeyCode.Space) && !isJump)
    {
        isJump = true;
    }
    if (isJump)
    {
        if (jumpTimeFlag < jumpTime)
        {
            characterController.Move(Vector3.up * (jumpForce - jumpSpeed) * Time.deltaTime);
            if ((jumpForce - jumpSpeed) < 0.2F) jumpSpeed = jumpForce;
            else jumpSpeed = Mathf.Lerp(jumpSpeed, jumpForce, 0.3F);
            jumpTimeFlag += Time.deltaTime;
        }
        else if (jumpTimeFlag > jumpTime)
        {
            if ((gravity - gravitySpeed) < 0.2F) gravitySpeed = gravity;
            else gravitySpeed = Mathf.Lerp(gravitySpeed, gravity, 0.3F);
            characterController.Move(Vector3.up * -gravitySpeed * Time.deltaTime);

        }
        if (characterController.collisionFlags == CollisionFlags.Below)
        {
            jumpSpeed = 0;
            gravitySpeed = 0;
            jumpTimeFlag = 0;
            isJump = false;
        }
    }
    else
    {
        if (characterController.collisionFlags != CollisionFlags.Below)
            characterController.Move(transform.up * -gravity * Time.deltaTime);
    }

Second: with rigid body component

Preconditions

First, create an empty object and add rigid body, AudioSource and collider components to the empty object. If your model already has collider components, there is no need to add collider components to the empty object here

Script component

analysis

The relevant movement methods of Transform cannot be used, but the movement can be achieved through rigid body components, such as AddForce method to increase thrust;

Assign a value to the velocity of the rigid body, etc; RigidBody class also has other methods that can be implemented. Check the API documents by yourself

Script implementation

move

Here, the movement adopts the method of assigning value to the speed instead of using AddForce to increase the thrust; Because when the player is moving, he always presses the W forward button. If he uses AddForce, he will always increase reasoning, resulting in the consequences of accelerating speed. Of course, there must be a solution, but as a beginner, I don't know (I hope the boss can answer it)

float x = Input.GetAxis("Horizontal");
float y = Input.GetAxis("Vertical");

rigidbody.velocity = (new Vector3(transform.forward.x, 0, transform.forward.z) * y + new Vector3(transform.right.x, 0, transform.right.z) * x) * walkSpeed + Vector3.up * rigidbody.velocity.y;

It should be noted here that the speed is assigned, but the movement is horizontal, and the vertical speed cannot be changed to prevent conflict with jumping. Therefore, the original y-axis speed of the rigid body should be added at the end. The other points of attention are the same as the first one. In addition, the rigid body speed cannot be assigned to an axis alone, so it should be assigned as a whole

jump

First, judge the jumping conditions and press the space bar; Not in the air

Because the existence of rigid body is affected by gravity, jumping requires an instantaneous upward impact force, so it only needs to increase the force in the y-axis direction

        if (Input.GetKeyDown(KeyCode.Space) && IsOnLand())
        {
            rigidbody.AddForce(new Vector3(0, jumpForce, 0), ForceMode.Impulse);
        }

Judgment not in the air: the collider can be used to judge whether it is in contact with the ground; You can use the methods of Physics class to detect the collider;

Camera related scripts

Camera follow

Since it is the first person, you only need to assign the position and orientation of the object to the camera

        camera.transform.position = transform.position;
        camera.transform.forward = transform.forward;

Mouse control lens orientation

        float x = Input.GetAxis("Mouse X");
        float y = Input.GetAxis("Mouse Y");
        transform.eulerAngles += new Vector3(-y, x, 0) * mouseSpeed;

Of course, this is not enough. We need to add the angle restriction of raising and lowering our head. Here we need to pay attention to one thing:

The angle on the panel. When the angle value is negative, such as - 1, it is actually 359 degrees instead of - 1. Here, the panel will mislead the developer to write the wrong code

Therefore, it is necessary to judge whether the current angle is greater than 180. If the real angle is negative (Unity stipulates that negative value means head up and positive value means head down)

private float CheckEuler(float value)
    {
        float angle = value - 180;
        if (angle > 0)
        {
            return angle - 180;
        }
        if (value == 0) return 0;
        return value;
    }

In addition, use Mathf.Clamp(value,min,max) to limit the angle within the specified range

    private void mouseControl()
    {
        float x = Input.GetAxis("Mouse X");
        float y = Input.GetAxis("Mouse Y");
        transform.eulerAngles += new Vector3(-y, x, 0) * mouseSpeed;
        transform.eulerAngles = new Vector3(Mathf.Clamp(CheckEuler(transform.eulerAngles.x),-60,60), transform.eulerAngles.y, transform.eulerAngles.z) ;
    }

Tags: C# Unity

Posted on Thu, 14 Oct 2021 21:14:24 -0400 by pragma