如图,游戏角色在地形的边缘,且沿移动方向(蓝色Z轴方向)继续移动将要掉落地形时,控制角色沿着地形边缘滑行移动,而不是让角色直接停在原地(这样处理游戏体验极差)。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
private Rigidbody roleRigidbody;
private int groundLayerMask;
private float speed = 300;
private void Start()
{
groundLayerMask = LayerMask.GetMask("Ground");
roleRigidbody = GetComponent<Rigidbody>();
}
Vector3 moveVelocity;
private void Update()
{
moveVelocity = Vector3.zero;
if(Input.GetKey(KeyCode.A))
{
if(Input.GetKey(KeyCode.W))
{
moveVelocity.x = -1;
moveVelocity.z = 1;
}
else if(Input.GetKey(KeyCode.S))
{
moveVelocity.x = -1;
moveVelocity.z = -1;
}
else
{
moveVelocity.x = -1;
moveVelocity.z = 0;
}
}
else if(Input.GetKey(KeyCode.D))
{
if(Input.GetKey(KeyCode.W))
{
moveVelocity.x = 1;
moveVelocity.z = 1;
}
else if(Input.GetKey(KeyCode.S))
{
moveVelocity.x = 1;
moveVelocity.z = -1;
}
else
{
moveVelocity.x = 1;
moveVelocity.z = 0;
}
}
else if(Input.GetKey(KeyCode.W))
{
moveVelocity.x = 0;
moveVelocity.z = 1;
}
else if(Input.GetKey(KeyCode.S))
{
moveVelocity.x = 0;
moveVelocity.z = -1;
}
if(moveVelocity != Vector3.zero)
{
moveVelocity = moveVelocity.normalized * speed * Time.deltaTime;
if(IsPlayerCanMove(moveVelocity))
Move(moveVelocity);
else
SidewipeMove(moveVelocity);
}
}
public void Move(Vector3 velocity)
{
roleRigidbody.velocity = velocity;
if(velocity != Vector3.zero)
transform.forward = Vector3.Lerp(transform.forward,velocity.normalized,0.5f).normalized;
}
public void Move(Vector3 velocity,Vector3 forwardDir)
{
roleRigidbody.velocity = velocity;
transform.forward = Vector3.Lerp(transform.forward,forwardDir.normalized,0.5f).normalized;
}
public void StopMove()
{
roleRigidbody.velocity = Vector3.zero;
}
public bool IsPlayerCanMove(Vector3 moveVelocity)
{
//根据移动速度计算下一帧移动位移*安全系数
moveVelocity = moveVelocity * Time.fixedDeltaTime * 1.2f;
//最小预判距离为1
if(moveVelocity.sqrMagnitude < 1)
moveVelocity.Normalize();
//预算下一帧移动后的位置
moveVelocity += transform.position;
//检测点向上偏移2单位
moveVelocity.y += 2;
//检测下一帧位置是否在可移动范围内
if(Physics.Raycast(moveVelocity,Vector3.down,5,groundLayerMask))
return true;
Debug.DrawLine(moveVelocity + Vector3.up * 5,moveVelocity,Color.red);
return false;
}
//角色遇到障碍物/地图边缘,在可行走区域内贴边滑行
const int predictAngle = 80;
int offsetAngle, leftAngle, rightAngle;
Vector3 tempVelocity, targetVelocity;
public void SidewipeMove(Vector3 velocity)
{
if(velocity == Vector3.zero)
{
StopMove();
return;
}
//当前移动方向往右偏移80度
offsetAngle = predictAngle;
tempVelocity = Quaternion.AngleAxis(offsetAngle,Vector3.up) * velocity;
if(IsPlayerCanMove(tempVelocity))
{
//可往右侧滑行
leftAngle = 0;
rightAngle = offsetAngle;
}
else
{
offsetAngle *= -1;
tempVelocity = Quaternion.AngleAxis(offsetAngle,Vector3.up) * velocity;
if(IsPlayerCanMove(tempVelocity))
{
//可往左侧滑行
leftAngle = offsetAngle;
rightAngle = 0;
}
else
{
//不可滑行,转向、停止移动
//transform.forward = velocity.normalized;
transform.forward = Vector3.Lerp(transform.forward,velocity.normalized,0.05f);
StopMove();
return;
}
}
int count = 0;
//二分法判断可滑行方向
targetVelocity = tempVelocity;
while(rightAngle - leftAngle > 10)
{
offsetAngle = (leftAngle + rightAngle) / 2;
tempVelocity = Quaternion.AngleAxis(offsetAngle,Vector3.up) * velocity;
if(IsPlayerCanMove(tempVelocity))
{
if(offsetAngle > 0)
rightAngle = offsetAngle;
else
leftAngle = offsetAngle;
targetVelocity = tempVelocity;
}
else
{
if(offsetAngle > 0)
leftAngle = offsetAngle;
else
rightAngle = offsetAngle;
}
count++;
}
//减慢速度
targetVelocity *= 0.75f;
//滑行时方向保持摇杆方向,与移动方向不同向
Move(targetVelocity,velocity);
}
}
本文来自博客园,作者:萧然CS,转载请注明原文链接:https://www.cnblogs.com/z-c-s/p/15112847.html