Unity使用代码控制2d游戏物体(一)

来源:互联网 发布:形容网络与生活的词语 编辑:程序博客网 时间:2024/06/05 18:25

博主Unity版本为5.4.4

这篇文章主要针对youtub上的一个专题系列的视频中的代码翻译和自己的一些理解,主要是是通过代码控制2d游戏物体的移动,碰撞,重力。视频地址:https://www.youtube.com/watch?v=MbWK8bCAU2w


首先简单的搭一下场景

这里写图片描述

新建几个quad,和材质,红色的为player,白色的为场景物体。

然后新建俩个C#脚本,分别为Player,Controller2D

第一部分:

using UnityEngine;using System.Collections;//自动给player添加Controller2D脚本组件[RequireComponent(typeof(Controller2D))]public class Player : MonoBehaviour {    public float moveSpeed = 6f;//移动速度    public float gravity;//重力加速度    private Vector3 velocity;//player的速度    private Controller2D controller;     void Start(){        controller =  GetComponent<Controller2D> ();    }    void Update(){        Vector2 input = new Vector2 (Input.GetAxisRaw("Horizontal"),Input.GetAxisRaw("Vertical"));//获取输入轴的值        velocity.x = input.x * moveSpeed;        velocity.y += gravity * Time.deltaTime;//通过代码控制重力        controller.Move (velocity*Time.deltaTime);//移动    }}

通过代码模拟重力,velocity*Time.deltaTime速度乘以时间得到每一帧的移动量

using UnityEngine;using System.Collections;//自动添加BoxCollider2D组件[RequireComponent(typeof(BoxCollider2D))]public class Controller2D : MonoBehaviour {    public LayerMask collisionMask;//射线碰撞检测层    public int horizontalRayCount = 4;//水平方向的射线数    public int verticalRayCount = 4;//竖直方向的射线数    private float horizontalRaySpacing;//水平方向的射线间距    private float verticalRaySpacing;//竖直方向的射线间距    private const float skillWidth = .015f;    private BoxCollider2D collider;    private RaycastOrigins raycastOrigins;//射线的源点    void Start(){        collider = GetComponent<BoxCollider2D> ();        CalculateRaySpacing ();    }    //Bounds在C#中是struct类型也就是值类型,所以每帧都要更新射线源点    private void UpdateRaycastOrigins(){        Bounds bounds = collider.bounds;//得到player的包围盒        bounds.Expand (skillWidth*-2);//将包围盒缩小,就像又包了一层        //得到射线源点        raycastOrigins.bottomLeft = new Vector2 (bounds.min.x,bounds.min.y);        raycastOrigins.bottomRight = new Vector2 (bounds.max.x,bounds.min.y);        raycastOrigins.topLeft = new Vector2 (bounds.min.x,bounds.max.y);        raycastOrigins.topRight = new Vector2 (bounds.max.x,bounds.max.y);    }    private void CalculateRaySpacing(){//计算水平和竖直的射线间距        Bounds bounds = collider.bounds;        bounds.Expand (skillWidth*-2);//缩小包围盒        horizontalRayCount = Mathf.Clamp (horizontalRayCount,2,int.MaxValue);//限定射线数量        verticalRayCount = Mathf.Clamp (verticalRayCount,2,int.MaxValue);        horizontalRaySpacing = bounds.size.y / (horizontalRayCount - 1);//计算间距        verticalRaySpacing = bounds.size.x / (verticalRayCount - 1);    }    private void VerticalCollisions(ref Vector3 velocity){//竖直方向的射线检测        float directionY = Mathf.Sign (velocity.y);//通过y来判断是跳跃还是下落        float rayLength = Mathf.Abs (velocity.y)+skillWidth;//射线的长度        for (int i = 0; i < verticalRayCount; i++) {            Vector2 rayOrigin = (directionY == -1) ? raycastOrigins.bottomLeft : raycastOrigins.topLeft;//通过方向来选择射线的起点            rayOrigin += Vector2.right * (verticalRaySpacing * i + velocity.x);//加上x方向的偏移            RaycastHit2D hit = Physics2D.Raycast (rayOrigin,Vector2.up*directionY,rayLength,collisionMask);//检测碰撞            Debug.DrawRay (rayOrigin,Vector2.up*directionY*rayLength,Color.red);            if (hit) {//如果发生碰撞                velocity.y = (hit.distance-skillWidth)*directionY;//移动距离变为碰撞点距物体的距离                rayLength = hit.distance;            }        }    }    private void HorizontalCollisions(ref Vector3 velocity){//水平方向检测碰撞        float directionX = Mathf.Sign (velocity.x);//通过x来判断是向左还是右        float rayLength = Mathf.Abs (velocity.x)+skillWidth;//射线的长度        for (int i = 0; i < horizontalRayCount; i++) {            Vector2 rayOrigin = (directionX == -1) ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight;//通过方向来选择射线的起点            rayOrigin += Vector2.up * (horizontalRaySpacing * i);//            RaycastHit2D hit = Physics2D.Raycast (rayOrigin,Vector2.right*directionX,rayLength,collisionMask);//检测碰撞            Debug.DrawRay (rayOrigin,Vector2.right*directionX*rayLength,Color.red);            if (hit) {//如果发生碰撞                    velocity.x = (hit.distance - skillWidth) * directionX;//移动距离变为碰撞点距物体的距离                    rayLength = hit.distance;            }        }    }    public void Move(Vector3 velocity){//移动        UpdateRaycastOrigins ();//更新射线源点        if(velocity.x!=0)            HorizontalCollisions(ref velocity);        if(velocity.y!=0)            VerticalCollisions (ref velocity);//竖直方向检测碰撞        transform.Translate (velocity);//移动    }    struct RaycastOrigins{//射线源点        public Vector2 topLeft,topRight;        public Vector2 bottomLeft,bottomRight;    }}

在这里我们使用射线检测的方式去处理碰撞,这段代码可能有点长,接下来画几个图帮助理解。

这里写图片描述
这里写图片描述

velocity.y是当前帧要移动的y方向的距离,加上skillWidth就是当前帧射线的探测长度,如果射线检测到了碰撞,则将velocity.y的值变为hit.distance-skillWidth,以保证不会穿透物体

这里写图片描述

这里水平方向跟竖直基本一样,这里需要注意一点,我们是在Move函数中先执行水平方向的检测再执行竖直方向的检测,因为竖直方向的射线源点带有x方向的偏移。如果先检测竖直方向的,那么x偏移量还没有被限制,此时加上skillWidth可能会大于与障碍物的距离,移动后,射线的位置会穿透到物体中,之后再检测竖直方向是就会误认为是地面而向上移动


第二部分: 加入跳跃和爬坡

using UnityEngine;using System.Collections;[RequireComponent(typeof(Controller2D))]public class Player : MonoBehaviour {    public float jumpHeight = 4f;//起跳高度    public float timeToJumpApex = .4f;//到达高度的时间    public float moveSpeed = 6f;    public float velocityXSmoothing;    public float accelerationTimeAirBorne = .2f;//在空中水平移动的缓冲时间    public float accelerationTimeGrounded = .1f;//在地面水平移动的缓冲时间    private float gravity;//重力加速度    private float jumpVelocity;//跳跃速度    private Vector3 velocity;    private Controller2D controller;     void Start(){        controller =  GetComponent<Controller2D> ();        gravity = -(2 * jumpHeight) / Mathf.Pow (timeToJumpApex,2);//s = V0t+(at)2/2        jumpVelocity = Mathf.Abs(gravity * timeToJumpApex);//VelocityFinal = Velocityinit+at    }    void Update(){        if (controller.collisions.above || controller.collisions.below) {            velocity.y = 0;        }        Vector2 input = new Vector2 (Input.GetAxisRaw("Horizontal"),Input.GetAxisRaw("Vertical"));        if (Input.GetKeyDown (KeyCode.Space) && controller.collisions.below) {//如果在地面则可以跳            velocity.y = jumpVelocity;        }        float targetVelocity =  velocity.x = input.x * moveSpeed;        //平滑移动,velocity.x:当前速度,targetVelocity:目标速度,velocityXSmoothing:中间量不用理会,(controller.collisions.below)?accelerationTimeGrounded:accelerationTimeAirBorne:缓冲时间,值越大越慢        velocity.x = Mathf.SmoothDamp (velocity.x,targetVelocity,ref velocityXSmoothing,(controller.collisions.below)?accelerationTimeGrounded:accelerationTimeAirBorne);        velocity.y += gravity * Time.deltaTime;        controller.Move (velocity*Time.deltaTime);    }}

这里我们重新修改了重力,通过跳跃高度和到达最大高度的时间来计算重力,其实就是高中物理上的公式,路程=初始速度x时间+加速度x时间的平方除以2,还有一个速度=初始速度+加速度x时间

using UnityEngine;using System.Collections;[RequireComponent(typeof(BoxCollider2D))]public class Controller2D : MonoBehaviour {    public LayerMask collisionMask;//射线碰撞检测层    public CollisionInfo collisions;//记录玩家处于什么位置    public int horizontalRayCount = 4;//水平方向的射线数    public int verticalRayCount = 4;//竖直方向的射线数    public float maxClimbAngle = 80f;//可以行走的斜坡最大倾斜度    public float maxDescendAngle = 75f;    private float horizontalRaySpacing;//水平方向的射线间距    private float verticalRaySpacing;//竖直方向的射线间距    private const float skillWidth = .015f;    private BoxCollider2D collider;    private RaycastOrigins raycastOrigins;    void Start(){        collider = GetComponent<BoxCollider2D> ();        CalculateRaySpacing ();    }    private void UpdateRaycastOrigins(){        Bounds bounds = collider.bounds;        bounds.Expand (skillWidth*-2);        raycastOrigins.bottomLeft = new Vector2 (bounds.min.x,bounds.min.y);        raycastOrigins.bottomRight = new Vector2 (bounds.max.x,bounds.min.y);        raycastOrigins.topLeft = new Vector2 (bounds.min.x,bounds.max.y);        raycastOrigins.topRight = new Vector2 (bounds.max.x,bounds.max.y);    }    private void CalculateRaySpacing(){//计算水平和竖直的射线间距        Bounds bounds = collider.bounds;        bounds.Expand (skillWidth*-2);//缩小包围盒        horizontalRayCount = Mathf.Clamp (horizontalRayCount,2,int.MaxValue);//限定射线数量        verticalRayCount = Mathf.Clamp (verticalRayCount,2,int.MaxValue);        horizontalRaySpacing = bounds.size.y / (horizontalRayCount - 1);//计算间距        verticalRaySpacing = bounds.size.x / (verticalRayCount - 1);    }    private void VerticalCollisions(ref Vector3 velocity){//竖直方向的射线检测        float directionY = Mathf.Sign (velocity.y);//通过y来判断是跳跃还是下落        float rayLength = Mathf.Abs (velocity.y)+skillWidth;//射线的长度        for (int i = 0; i < verticalRayCount; i++) {            Vector2 rayOrigin = (directionY == -1) ? raycastOrigins.bottomLeft : raycastOrigins.topLeft;//通过方向来选择射线的起点            rayOrigin += Vector2.right * (verticalRaySpacing * i + velocity.x);//加上x方向的偏移            RaycastHit2D hit = Physics2D.Raycast (rayOrigin,Vector2.up*directionY,rayLength,collisionMask);//检测碰撞            Debug.DrawRay (rayOrigin,Vector2.up*directionY*rayLength,Color.red);            if (hit) {//如果发生碰撞                velocity.y = (hit.distance-skillWidth)*directionY;//移动距离变为碰撞点距物体的距离                rayLength = hit.distance;                if (collisions.climbing) {                    velocity.x = velocity.y / Mathf.Tan (collisions.slopeAngle * Mathf.Deg2Rad) * Mathf.Sign (velocity.x);//当物体在斜坡上上方有障碍物时,限定x的分量                }                collisions.below = directionY == -1;                collisions.above = directionY == 1;            }        }    }    private void HorizontalCollisions(ref Vector3 velocity){//水平方向检测碰撞        float directionX = Mathf.Sign (velocity.x);//通过y来判断是跳跃还是下落        float rayLength = Mathf.Abs (velocity.x)+skillWidth;//射线的长度        for (int i = 0; i < horizontalRayCount; i++) {            Vector2 rayOrigin = (directionX == -1) ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight;//通过方向来选择射线的起点            rayOrigin += Vector2.up * (horizontalRaySpacing * i);//            RaycastHit2D hit = Physics2D.Raycast (rayOrigin,Vector2.right*directionX,rayLength,collisionMask);//检测碰撞            Debug.DrawRay (rayOrigin,Vector2.right*directionX*rayLength,Color.red);            if (hit) {//如果发生碰撞                float slopeAngle = Vector2.Angle(hit.normal,Vector2.up);//得到倾斜角                if (i == 0 && slopeAngle <= maxClimbAngle) {//只判断源点的射线,如果斜坡角度小于规定的值则处于爬坡                    float distanceToSlopeStart = 0;                    if (slopeAngle != collisions.slopeAngleOld) {//判断是否走的同一个坡                        distanceToSlopeStart = hit.distance - skillWidth;                        velocity.x -= distanceToSlopeStart * directionX;//变换不同斜面时把碰撞点到物体的距离的x分量先减去                    }                    ClimbSlope (ref velocity, slopeAngle);//爬坡                    velocity.x += distanceToSlopeStart * directionX;//处理完斜面分量在把之前的加上                }                if (!collisions.climbing || slopeAngle > maxClimbAngle) {                    velocity.x = (hit.distance - skillWidth) * directionX;//移动距离变为碰撞点距物体的距离                    rayLength = hit.distance;                    if (collisions.climbing) {                        velocity.y = Mathf.Tan (collisions.slopeAngle * Mathf.Deg2Rad) * Mathf.Abs (velocity.x);//如果物体在斜坡上水平方向遇到障碍物,则限定y分量                    }                    collisions.left = directionX == -1;                    collisions.right = directionX == 1;                }            }        }    }    //上斜坡检测    private void ClimbSlope(ref Vector3 velocity,float slopeAngle){        float moveDistance = Mathf.Abs (velocity.x);//得到移动距离        float climbVelocityY = Mathf.Sin (slopeAngle * Mathf.Deg2Rad) * moveDistance;//得到竖直方向的分量        if (velocity.y <= climbVelocityY) {//大于时处于跳跃中不做分量            velocity.y = climbVelocityY;            velocity.x = Mathf.Cos (slopeAngle * Mathf.Deg2Rad) * moveDistance*Mathf.Sign(velocity.x);//得到水平方向的分量            collisions.below = true;//走斜坡也是地面            collisions.climbing = true;//处于斜坡上            collisions.slopeAngle = slopeAngle;        }    }    public void Move(Vector3 velocity){//移动        UpdateRaycastOrigins ();//更新射线源点        collisions.ReSet();//重置碰撞位置信息        if(velocity.x!=0)            HorizontalCollisions(ref velocity);        if(velocity.y!=0)            VerticalCollisions (ref velocity);//竖直方向检测碰撞        transform.Translate (velocity);//移动    }    struct RaycastOrigins{//射线源点        public Vector2 topLeft,topRight;        public Vector2 bottomLeft,bottomRight;    }    public struct CollisionInfo{//碰撞位置变量        public bool above,below;        public bool left,right;        public bool climbing;        public float slopeAngle, slopeAngleOld;        public void ReSet(){            above = below = false;            left = right = false;            climbing = false;            slopeAngleOld = slopeAngle;            slopeAngle = 0;        }    }}

相比于第一部分又多了些代码,我们同样画几个图帮助理解

这里写图片描述
这里写图片描述

这里说一下,上坡认为是特殊的水平移动,只不过有了y方向的分量,所以velocity.x=s,之后velocity.x,velocity.y都根据角度得出

这里写图片描述

这里的问题是在爬坡时上方出现障碍物,如果不做处理,那么物体将照着途中的箭头循环移动。原因就是y方向受到了阻挡导致y的分量进行了限制,但是x分量正常,移动后x方向的射线进入到了斜坡内部此时被认为是水平方向的阻挡,所以会往相反方向退。代码中我们在竖直方向检测是加入了是否在爬坡,如果是在根据当前的y去限定x

这里写图片描述

有了上面的那个图,这个就好理解了。这个就是在爬坡时物体前面遇到障碍物,x为限制了,所以通过现在的x去计算y。斜坡在另一边是跟上面的一样就是方向变了,所以就不解释了。


第三部分:处理下坡,优化

这部分Player脚本没有变动

using UnityEngine;using System.Collections;[RequireComponent(typeof(BoxCollider2D))]public class Controller2D : MonoBehaviour {    public LayerMask collisionMask;//射线碰撞检测层    public CollisionInfo collisions;//记录玩家处于什么位置    public int horizontalRayCount = 4;//水平方向的射线数    public int verticalRayCount = 4;//竖直方向的射线数    public float maxClimbAngle = 80f;//可以行走的斜坡最大倾斜度    public float maxDescendAngle = 80f;//下坡最大角度    private float horizontalRaySpacing;//水平方向的射线间距    private float verticalRaySpacing;//竖直方向的射线间距    private const float skillWidth = .015f;    private BoxCollider2D collider;    private RaycastOrigins raycastOrigins;    void Start(){        collider = GetComponent<BoxCollider2D> ();        CalculateRaySpacing ();    }    private void UpdateRaycastOrigins(){        Bounds bounds = collider.bounds;        bounds.Expand (skillWidth*-2);        raycastOrigins.bottomLeft = new Vector2 (bounds.min.x,bounds.min.y);        raycastOrigins.bottomRight = new Vector2 (bounds.max.x,bounds.min.y);        raycastOrigins.topLeft = new Vector2 (bounds.min.x,bounds.max.y);        raycastOrigins.topRight = new Vector2 (bounds.max.x,bounds.max.y);    }    private void CalculateRaySpacing(){//计算水平和竖直的射线间距        Bounds bounds = collider.bounds;        bounds.Expand (skillWidth*-2);//缩小包围盒        horizontalRayCount = Mathf.Clamp (horizontalRayCount,2,int.MaxValue);//限定射线数量        verticalRayCount = Mathf.Clamp (verticalRayCount,2,int.MaxValue);        horizontalRaySpacing = bounds.size.y / (horizontalRayCount - 1);//计算间距        verticalRaySpacing = bounds.size.x / (verticalRayCount - 1);    }    private void VerticalCollisions(ref Vector3 velocity){//竖直方向的射线检测        float directionY = Mathf.Sign (velocity.y);//通过y来判断是跳跃还是下落        float rayLength = Mathf.Abs (velocity.y)+skillWidth;//射线的长度        for (int i = 0; i < verticalRayCount; i++) {            Vector2 rayOrigin = (directionY == -1) ? raycastOrigins.bottomLeft : raycastOrigins.topLeft;//通过方向来选择射线的起点            rayOrigin += Vector2.right * (verticalRaySpacing * i + velocity.x);//加上x方向的偏移            RaycastHit2D hit = Physics2D.Raycast (rayOrigin,Vector2.up*directionY,rayLength,collisionMask);//检测碰撞            Debug.DrawRay (rayOrigin,Vector2.up*directionY*rayLength,Color.red);            if (hit) {//如果发生碰撞                velocity.y = (hit.distance-skillWidth)*directionY;//移动距离变为碰撞点距物体的距离                rayLength = hit.distance;                if (collisions.climbing) {                    velocity.x = velocity.y / Mathf.Tan (collisions.slopeAngle * Mathf.Deg2Rad) * Mathf.Sign (velocity.x);//当物体在斜坡上上方有障碍物时,限定x的分量                }                collisions.below = directionY == -1;                collisions.above = directionY == 1;            }            if (collisions.climbing) {//平滑处理,防止移动太快而直接到另一个斜面上                float directionX = Mathf.Sign(velocity.x);                rayLength = Mathf.Abs (velocity.x)+skillWidth;                Vector2 rayOrigin1 = ((directionX==-1)?raycastOrigins.bottomLeft:raycastOrigins.bottomRight)+Vector2.up*velocity.y;                RaycastHit2D hit1 = Physics2D.Raycast (rayOrigin1,Vector2.right*directionX,rayLength,collisionMask);                if (hit1) {                    float slopeAngle = Vector2.Angle (hit1.normal,Vector2.up);                    if (slopeAngle != collisions.slopeAngle) {                        velocity.x = (hit1.distance - skillWidth) * directionX;                        collisions.slopeAngle = slopeAngle;                    }                }            }        }    }    private void HorizontalCollisions(ref Vector3 velocity){//水平方向检测碰撞        float directionX = Mathf.Sign (velocity.x);//通过y来判断是跳跃还是下落        float rayLength = Mathf.Abs (velocity.x)+skillWidth;//射线的长度        for (int i = 0; i < horizontalRayCount; i++) {            Vector2 rayOrigin = (directionX == -1) ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight;//通过方向来选择射线的起点            rayOrigin += Vector2.up * (horizontalRaySpacing * i);//            RaycastHit2D hit = Physics2D.Raycast (rayOrigin,Vector2.right*directionX,rayLength,collisionMask);//检测碰撞            Debug.DrawRay (rayOrigin,Vector2.right*directionX*rayLength,Color.red);            if (hit) {//如果发生碰撞                float slopeAngle = Vector2.Angle(hit.normal,Vector2.up);//得到倾斜角                if (i == 0 && slopeAngle <= maxClimbAngle) {                    if (collisions.descendingSlope) {                        collisions.descendingSlope = false;                        velocity = collisions.velocityOld;                    }                    float distanceToSlopeStart = 0;                    if (slopeAngle != collisions.slopeAngleOld) {                        distanceToSlopeStart = hit.distance - skillWidth;                        velocity.x -= distanceToSlopeStart * directionX;//变换不同斜面时把碰撞点到物体的距离的x分量先减去                    }                    ClimbSlope (ref velocity, slopeAngle);                    velocity.x += distanceToSlopeStart * directionX;//处理完斜面分量在把之前的加上                }                if (!collisions.climbing || slopeAngle > maxClimbAngle) {                    velocity.x = (hit.distance - skillWidth) * directionX;//移动距离变为碰撞点距物体的距离                    rayLength = hit.distance;                    if (collisions.climbing) {                        velocity.y = Mathf.Tan (collisions.slopeAngle * Mathf.Deg2Rad) * Mathf.Abs (velocity.x);//如果物体在斜坡上水平方向遇到障碍物,则限定y分量                    }                    collisions.left = directionX == -1;                    collisions.right = directionX == 1;                }            }        }    }    //上斜坡检测    private void ClimbSlope(ref Vector3 velocity,float slopeAngle){        float moveDistance = Mathf.Abs (velocity.x);//得到移动距离        float climbVelocityY = Mathf.Sin (slopeAngle * Mathf.Deg2Rad) * moveDistance;//得到竖直方向的分量        if (velocity.y <= climbVelocityY) {//大于时处于跳跃中不做分量            velocity.y = climbVelocityY;            velocity.x = Mathf.Cos (slopeAngle * Mathf.Deg2Rad) * moveDistance*Mathf.Sign(velocity.x);//得到水平方向的分量            collisions.below = true;//走斜坡也是地面            collisions.climbing = true;//处于斜坡上            collisions.slopeAngle = slopeAngle;        }    }    //下斜坡检测    private void DescendSlope(ref Vector3 velocity){        float directionX = Mathf.Sign (velocity.x);//x为正数则为1,反之为-1        Vector2 rayOrigin = (directionX == -1) ? raycastOrigins.bottomRight : raycastOrigins.bottomLeft;//射线源点根据x方向得出        RaycastHit2D hit = Physics2D.Raycast (rayOrigin,-Vector2.up,Mathf.Infinity,collisionMask);        if (hit) {            float slopeAngle = Vector2.Angle (hit.normal,Vector2.up);            if (slopeAngle != 0 && slopeAngle <= maxDescendAngle) {                if (Mathf.Sign (hit.normal.x) == directionX) {                    if (hit.distance - skillWidth <= Mathf.Tan (slopeAngle * Mathf.Deg2Rad) * Mathf.Abs (velocity.x)) {//判断物体不是在空中(跳跃中)                        float moveDistance = Mathf.Abs (velocity.x);                        float descendVelocityY = Mathf.Sin (slopeAngle * Mathf.Deg2Rad) * moveDistance;                        velocity.x = Mathf.Cos (slopeAngle*Mathf.Deg2Rad)*moveDistance*Mathf.Sign(velocity.x);                        velocity.y -= descendVelocityY;//注意这里为什么是减,因为你是要下坡                        collisions.slopeAngle = slopeAngle;                        collisions.descendingSlope = true;                        collisions.below = true;                    }                }            }        }    }    public void Move(Vector3 velocity){//移动        UpdateRaycastOrigins ();//更新射线源点        collisions.ReSet();//重置碰撞位置信息        collisions.velocityOld = velocity;//每次移动时把速度记下来        if(velocity.y<0)        DescendSlope(ref velocity);//下坡检测        if(velocity.x!=0)            HorizontalCollisions(ref velocity);        if(velocity.y!=0)            VerticalCollisions (ref velocity);//竖直方向检测碰撞        transform.Translate (velocity);//移动    }    struct RaycastOrigins{//射线源点        public Vector2 topLeft,topRight;        public Vector2 bottomLeft,bottomRight;    }    public struct CollisionInfo{//碰撞位置变量        public bool above,below;        public bool left,right;        public bool climbing;        public float slopeAngle, slopeAngleOld;        public bool descendingSlope;//处于下坡        public Vector3 velocityOld;        public void ReSet(){            above = below = false;            left = right = false;            climbing = false;            slopeAngleOld = slopeAngle;            slopeAngle = 0;            descendingSlope = false;        }    }}

同样,我们画几个图

这里写图片描述

下坡跟上坡很像,就是把当前x分解一下

这里写图片描述

加入平滑优化,原因就是物体可能移动太快而导致直接到了另一个斜坡上而不是从斜坡地开始,所以在检查完水平方向后,检查竖直方向是有多加了一个水平检查,但是是在y分量计算后才检测的,所以射线源点的位置加上了velocity.y

这里写图片描述

这种情况就是下坡完又上坡,每次移动前先用collisions.velocityOld把当前速度存下来,上坡时把没有处理过的速度传过去,不然传的就是下坡时的速度


到这里这一部分就完了,有理解不到位的,欢迎批评指正

原创粉丝点击