问题产生分析:
现象:只有重力为0时,才跳的起来
原因:只有不修改isTouched时才跳的起来,一旦修改则不跳
猜测:可能两个脚本间有延迟
现象2:降落时会在地面上空停顿一下,重力会变一次60
现象3:60面能飞,20面不能飞只能跳/修改顺序后两面都能按住W飞,重力为0
推测:只有离开地面且istouched为true时能飞
问题出在这段代码:有一个细节,键盘操作时,gettop会到顶归零,鼠标操作时,gettop立刻归零,导致一上来就有了60的重力,并且y速度被归零
//到达顶点速度方向改变,重力归零
if (deltaPosition.y < 0 && getTop == false && isTouched == false)
{
gravity = 60;
velocity.y = 0;
getTop = true;
}
解决办法:为方便调用,我们新建一个脚本,将两个脚本Snowfield01和BaseControllerMouseMove合在一起
将重力方法写进move中,传入的参数改为键盘输入,在move中将重力加到参数上
Vector2 deltaPosition = deltaPos + new Vector2(0, gravity * gravity * Time.deltaTime * -0.001f) ;
这样我们就可以对速度进行更细致的检测
鼠标的移动单独做,我们把鼠标移动产生的速度分量判断放在最后,重力归零代码中
在重力归零代码中,加入判断条件
if ((jumpDirect * velocityMouse + deltaPosition).y < 0 && getTop == false && isTouched == false)
{
gravity = 60;
jumpDirect.y = 0;
velocity.y = 0;
getTop = true;
}
并且不要忘记将jumpDirect.y也归零,不然会再次发生二段跳
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Collider2D))]
public class SnowField02 : MonoBehaviour
{
private const float MIN_MOVE_DISTANCE = 0.001f;
private new Collider2D collider2D;
private new Rigidbody2D rigidbody2D;
private ContactFilter2D contactFilter2D;
private readonly List<RaycastHit2D> raycastHit2DList = new List<RaycastHit2D>();
private readonly List<RaycastHit2D> tangentRaycastHit2DList = new List<RaycastHit2D>();
public LayerMask layerMask;
//[HideInInspector]
public Vector2 velocity = Vector2.zero;
public float velocityMouse;
public Vector2 tangentDirection;
//BaseControllerMouseMove
public Vector3 mouseLocation;
public Vector2 jumpDirect;
public int inAir = 0;
//数值参数
public float gravity = 60;
//状态参数
public bool isTouched = false;//常态为1,表示在地面或接触到碰撞体
public bool getTop = false;
private Vector3 theScale = new Vector3(0.5f, 0.5f, 1);
//调试参数
public int test;
void Start()
{
collider2D = GetComponent<Collider2D>();
rigidbody2D = GetComponent<Rigidbody2D>();
if (rigidbody2D == null)
rigidbody2D = gameObject.AddComponent<Rigidbody2D>();
rigidbody2D.hideFlags = HideFlags.NotEditable;
//rigidbody2D.bodyType = RigidbodyType2D.Kinematic;
rigidbody2D.simulated = true;
rigidbody2D.useFullKinematicContacts = false;
rigidbody2D.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
rigidbody2D.sleepMode = RigidbodySleepMode2D.NeverSleep;
rigidbody2D.interpolation = RigidbodyInterpolation2D.Interpolate;
rigidbody2D.constraints = RigidbodyConstraints2D.FreezeRotation;
rigidbody2D.gravityScale = 0;
contactFilter2D = new ContactFilter2D
{
useLayerMask = true,
useTriggers = false,
layerMask = layerMask
};
}
private void OnValidate()
{
contactFilter2D.layerMask = layerMask;
}
private void Update()
{
if (isTouched == true)//腾空时保留速度
{
velocity = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
}
}
private void FixedUpdate()
{
//rigidbody2D.position += jumpDirect * velocityMouse;
//重力速度加在Input.GetAxisRaw获得的速度上,一起传入Move
Movement(velocity * Time.deltaTime * 5f);
MouseController();
if (isTouched == false && inAir == 1)
{
inAir = 2;
}
if (isTouched == true && inAir == 2)
{
inAir = 0;
velocityMouse = 0f;
mouseLocation = Input.mousePosition;
}
rigidbody2D.position += jumpDirect * velocityMouse;
}
private void Movement(Vector2 deltaPos)
{
Vector2 deltaPosition = deltaPos + new Vector2(0, gravity * gravity * Time.deltaTime * -0.001f) ;
Vector2 updateDeltaPosition = Vector2.zero;
float distance = deltaPosition.magnitude;
Vector2 direction = deltaPosition.normalized;
if (distance <= MIN_MOVE_DISTANCE)
distance = MIN_MOVE_DISTANCE;
if (rigidbody2D.Cast(direction, contactFilter2D, raycastHit2DList, distance) == 0)
{
isTouched = false;
}
else
{
isTouched = true;
}
Vector2 finalDirection = direction;
float finalDistance = distance;
//理解:hit取自raycastHit2DList//遍历处理碰撞
foreach (var hit in raycastHit2DList)
{
float moveDistance = hit.distance;
Debug.DrawLine(hit.point, hit.point + hit.normal, Color.white);
Debug.DrawLine(hit.point, hit.point + direction, Color.yellow);
float projection = Vector2.Dot(hit.normal, direction);
if (projection >= 0)
{
moveDistance = distance;
}
else
{
tangentDirection = new Vector2(hit.normal.y, -hit.normal.x);
float tangentDot = Vector2.Dot(tangentDirection, direction);
if (tangentDot < 0)
{
tangentDirection = -tangentDirection;
tangentDot = -tangentDot;
}
float tangentDistance = tangentDot * distance;
if (tangentDot != 0)
{
rigidbody2D.Cast(tangentDirection, contactFilter2D, tangentRaycastHit2DList, tangentDistance);
foreach (var tangentHit in tangentRaycastHit2DList)
{
Debug.DrawLine(tangentHit.point, tangentHit.point + tangentDirection, Color.magenta);
if (Vector2.Dot(tangentHit.normal, tangentDirection) >= 0)
continue;
if (tangentHit.distance < tangentDistance)
tangentDistance = tangentHit.distance;
}
updateDeltaPosition += tangentDirection * tangentDistance;
}
}
if (moveDistance < finalDistance)
{
finalDistance = moveDistance;
}
}
updateDeltaPosition += finalDirection * finalDistance;
rigidbody2D.position += updateDeltaPosition;
//重力
if (isTouched == false)
{
gravity += 5f;
}
else
{
gravity = 60;
getTop = false;
if (Input.GetAxisRaw("Horizontal") == 0 || Input.GetAxisRaw("Vertical") != 0)
{
gravity = 0;
}
if (Input.GetAxisRaw("Horizontal") != 0 && tangentDirection.y > 0)
{
gravity = 20;
}
}
if ((jumpDirect * velocityMouse + deltaPosition).y < 0 && getTop == false && isTouched == false)
{
gravity = 60;
jumpDirect.y = 0;
velocity.y = 0;
getTop = true;
}
}
void MouseController()
{
if (!Input.GetMouseButton(0))
{
mouseLocation = Input.mousePosition;
}
if (Input.GetMouseButton(0) && (mouseLocation - Input.mousePosition).magnitude >= 20)
{
if (isTouched == true)
{
jumpDirect = (Input.mousePosition - mouseLocation).normalized;
if (jumpDirect.y > 0 && inAir == 0)
{
//jumpShortOrLong = 2;
velocityMouse = 0.3f;
inAir = 1;
isTouched = false;
}
}
}
}
}