用角色控制器控制移动和碰撞

Unity3d中CharacterController的移动和碰撞分析

这个地方值得记录一下.之前看教程的时候没注意,后来才发现这里涉及到很重要的角色移动方式和碰撞检测问题.可惜今天没时间了,等之后有时间了再来补上.

有必要仔细查看一下官方文档,养成习惯.


Character Controller API

官方注释:

A CharacterController allows you to easily do movement constrained by collisions without having to deal with a rigidbody.

也就是说,角色控制器自带的移动函数包含了碰撞体,不用再让我们自己设置刚体和碰撞体了.

这个组件有两个移动函数可以使用.

SimpleMove()

Moves the character with speed.
Velocity along the y-axis is ignored. Speed is in meters/s. Gravity is automatically applied. Returns if the character is grounded. It is recommended that you make only one call to Move or SimpleMove per frame.

最重要的一点就是,这个函数的Y轴速度是被限制了的.这个方法自带Gravity即重力属性,需要接地,所以物体不能腾空运动.这个方法接收一个速度向量.

下面是官方示例:

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(CharacterController))]
public class ExampleClass : MonoBehaviour {
    public float speed = 3.0F;
    public float rotateSpeed = 3.0F;
    void Update() {
        CharacterController controller = GetComponent<CharacterController>();
        transform.Rotate(0, Input.GetAxis("Horizontal") * rotateSpeed, 0);
        Vector3 forward = transform.TransformDirection(Vector3.forward);
        float curSpeed = speed * Input.GetAxis("Vertical");
        controller.SimpleMove(forward * curSpeed);
    }

Move()

官方注释:

A more complex move function taking absolute movement deltas.
Attempts to move the controller by motion, the motion will only be constrained by collisions. It will slide along colliders. CollisionFlags is the summary of collisions that occurred during the Move. This function does not apply any gravity.

与上面的方法相对,这个方法需要我们控制很多属性.首先它没有Gravity属性,如果不设置的话物体会飘起来;当然,这也意味着我们可以通过控制它来实现跳跃的方法(其实Gravity就是Y方向向量的加速度值).这个方法还带CollisionFlags属性,这个属性可以回应本方法的collision所接触到的所有coliders.可以利用这个属性做一些类似Mask的功能,无视某一类碰撞体.

官方示例:

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour {
    public float speed = 6.0F;
    public float jumpSpeed = 8.0F;
    public float gravity = 20.0F;
    private Vector3 moveDirection = Vector3.zero;
    void Update() {
        CharacterController controller = GetComponent<CharacterController>();
        if (controller.isGrounded) {
            moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
            moveDirection = transform.TransformDirection(moveDirection);
            moveDirection *= speed;
            if (Input.GetButton("Jump"))
                moveDirection.y = jumpSpeed;
            
        }
        moveDirection.y -= gravity * Time.deltaTime;
        controller.Move(moveDirection * Time.deltaTime);
    }
}

Move() 的 CollisionFlags 属性

CollisionFlags is a bitmask returned by CharacterController.Move.
It gives you a broad overview of where your character collided with any other objects.

四个属性分别是:
None, Sides(碰撞体边), Above(对应天花板), Below(对应地面)

示例:

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour
{
    void Update()
    {
        CharacterController controller = GetComponent<CharacterController>();
        if (controller.collisionFlags == CollisionFlags.None)
            print("Free floating!");

        if ((controller.collisionFlags & CollisionFlags.Sides) != 0)
            print("Touching sides!");

        if (controller.collisionFlags == CollisionFlags.Sides)
            print("Only touching sides, nothing else!");

        if ((controller.collisionFlags & CollisionFlags.Above) != 0)
            print("Touching sides!");

        if (controller.collisionFlags == CollisionFlags.Above)
            print("Only touching Ceiling, nothing else!");

        if ((controller.collisionFlags & CollisionFlags.Below) != 0)
            print("Touching ground!");

        if (controller.collisionFlags == CollisionFlags.Below)
            print("Only touching ground, nothing else!");
    }
}

OnControllerColliderHit(ControllerColliderHit)

OnControllerColliderHit is called when the controller hits a collider while performing a Move.
This can be used to push objects when they collide with the character.

官方将它归类于Message中,我不知道是不是消息函数的意思.由官方注释可知它可以用来实现碰撞体之间的推动.

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour {
    public float pushPower = 2.0F;
    void OnControllerColliderHit(ControllerColliderHit hit) {
        Rigidbody body = hit.collider.attachedRigidbody;
        if (body == null || body.isKinematic)   // 不存在或者设置
            return;                             // 为运动学特征
        
        if (hit.moveDirection.y < -0.3F)    // 可以理解为摩檫力过大吧
            return;
        
        Vector3 pushDir = new Vector3(hit.moveDirection.x, 0, hit.moveDirection.z);
        body.velocity = pushDir * pushPower;
    }
}

猜你喜欢

转载自www.cnblogs.com/ChanWunsam/p/10018309.html