待实现:在较小的斜坡上可以站住不动,在大的斜坡上会一直下滑,下滑时无法正常跑动
办法1:在2-4的基础上,加入坡度判断,用法线向量来表示
声明变量hitNormal
我们在重力代码中控制重力变化的部分加入条件
//条件1:不走&&坡度60||条件2:跳
if (Input.GetAxisRaw("Horizontal") == 0 && hitNormal.y > 0.5f || Input.GetAxisRaw("Vertical") != 0)
{
gravity = 0;
}
条件中的0.5是60度坡的cos,也就是坡度小于60度
实现下滑跑动禁止
首先在update中加条件
if (hitNormal.y < 0.5f)
{
velocity = new Vector2(0f, 0f);
}
再修改一下重力代码,使下滑时的重力大些
if (isTouched == false)
{
gravity += 5f;
}
else
{
gravity = 60;
getTop = false;
if (velocity.x == 0 && hitNormal.y > 0.5f || velocity.y != 0)//条件1:不走&&坡度60||条件2:跳
{
gravity = 0;
}
if (velocity.x != 0 && tangentDirection.y > 0)
{
gravity = 20;
}
if(hitNormal.y < 0.5f)
{
gravity = 100;
}
}
又发现一个问题:由于斜面坡度判断,同一片地上两个方向行走时重力不同,导致鼠标冲跳时的初速度不同
在鼠标冲跳代码中加入gravity = 0;
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)
{
gravity = 0;
//jumpShortOrLong = 2;
velocityMouse = 0.3f;
inAir = 1;
isTouched = false;
}
}
}
}
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 = 0f;
public Vector2 tangentDirection = Vector2.zero;
public Vector2 hitNormal = Vector2.zero;
//BaseControllerMouseMove
public Vector3 mouseLocation = Vector3.zero;
public Vector2 jumpDirect = Vector2.zero;
public int inAir = 0;
public float gravity = 60;
public bool isTouched = false;
public bool getTop = false;
private Vector3 theScale = new Vector3(0.5f, 0.5f, 1);
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"));
}
if (hitNormal.y < 0.5f)
{
velocity = new Vector2(0f, 0f);
}
}
private void FixedUpdate()
{
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;
foreach (var hit in raycastHit2DList)
{
float moveDistance = hit.distance;
hitNormal = hit.normal;
Debug.DrawLine(hit.point, hit.point + hitNormal, Color.white);
Debug.DrawLine(hit.point, hit.point + direction, Color.yellow);
//
float projection = Vector2.Dot(hitNormal, direction);
if (projection >= 0)
{
moveDistance = distance;
}
else
{
tangentDirection = new Vector2(hitNormal.y, -hitNormal.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 (velocity.x == 0 && hitNormal.y > 0.5f || velocity.y != 0)
{
gravity = 0;
}
if (velocity.x != 0 && tangentDirection.y > 0)
{
gravity = 20;
}
if(hitNormal.y < 0.5f)
{
gravity = 100;
}
}
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)
{
gravity = 0;
//jumpShortOrLong = 2;
velocityMouse = 0.3f;
inAir = 1;
isTouched = false;
}
}
}
}
}