Diff
checker
文本
文本
图像
文档
Excel
文件夹
Legal
Enterprise
桌面版
定价
登录
下载 Diffchecker 桌面版
比较文本
查找两个文本文件之间的差异
工具
历史
实时编辑器
折叠未更改行
关闭换行
视图
拆分
统一
比对精度
智能
单词
字符
语法高亮
选择语法
忽略
文本转换
转到第一个差异
编辑输入
Diffchecker Desktop
运行Diffchecker最安全的方式。获取Diffchecker桌面应用:您的差异永远不会离开您的电脑!
获取桌面版
Untitled diff
创建于
7年前
差异永不过期
清除
导出
分享
解释
17 删除
行
总计
删除
字符
总计
删除
要继续使用此功能,请升级到
Diff
checker
Pro
查看价格
280 行
全部复制
12 添加
行
总计
添加
字符
总计
添加
要继续使用此功能,请升级到
Diff
checker
Pro
查看价格
275 行
全部复制
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine;
using KinematicCharacterController;
using KinematicCharacterController;
using System;
using System;
复制
已复制
复制
已复制
namespace
Kinematic
CharacterController
.Walkthrough.WallJumping
namespace
Lez
CharacterController
{
{
public struct PlayerCharacterInputs
public struct PlayerCharacterInputs
{
{
public float horizontal;
public float horizontal;
public bool JumpDown;
public bool JumpDown;
}
}
复制
已复制
复制
已复制
public class
MyCharacterController
: BaseCharacterController
public class
KinematicCharacter
: BaseCharacterController
{
{
复制
已复制
复制
已复制
[Header("
Stable
Movement")]
[Header("
Movement")]
public float MaxStableMoveSpeed = 10f;
public float MaxStableMoveSpeed = 10f;
public float StableMovementSharpness = 15;
public float StableMovementSharpness = 15;
public float rotateSpeed = 10;
public float rotateSpeed = 10;
[Header("Air Movement")]
[Header("Air Movement")]
public float MaxAirMoveSpeed = 10f;
public float MaxAirMoveSpeed = 10f;
public float AirAccelerationSpeed = 5f;
public float AirAccelerationSpeed = 5f;
public float Drag = 0.1f;
public float Drag = 0.1f;
[Header("Jumping")]
[Header("Jumping")]
public bool AllowJumpingWhenSliding = false;
public bool AllowJumpingWhenSliding = false;
public bool AllowDoubleJump = false;
public bool AllowDoubleJump = false;
public bool AllowWallJump = false;
public bool AllowWallJump = false;
public float JumpSpeed = 10f;
public float JumpSpeed = 10f;
public float JumpPreGroundingGraceTime = 0f;
public float JumpPreGroundingGraceTime = 0f;
public float JumpPostGroundingGraceTime = 0f;
public float JumpPostGroundingGraceTime = 0f;
[Header("Misc")]
[Header("Misc")]
复制
已复制
复制
已复制
public bool RotationObstruction;
public Vector3 Gravity = new Vector3(0, -30f, 0);
public Vector3 Gravity = new Vector3(0, -30f, 0);
public Transform MeshRoot;
public Transform MeshRoot;
复制
已复制
复制
已复制
private Vector3 moveDirection;
private float Angle;
private float inputAmount;
private bool _jumpRequested = false;
private bool _jumpRequested = false;
private bool _jumpConsumed = false;
private bool _jumpConsumed = false;
private bool _jumpedThisFrame = false;
private bool _jumpedThisFrame = false;
private float _timeSinceJumpRequested = Mathf.Infinity;
private float _timeSinceJumpRequested = Mathf.Infinity;
private float _timeSinceLastAbleToJump = 0f;
private float _timeSinceLastAbleToJump = 0f;
private bool _doubleJumpConsumed = false;
private bool _doubleJumpConsumed = false;
private bool _canWallJump = false;
private bool _canWallJump = false;
private Vector3 _wallJumpNormal;
private Vector3 _wallJumpNormal;
复制
已复制
复制
已复制
float inputAmount, Angle;
public
Transform DirectionReference;
Vector3 moveDirection;
Transform DirectionReference;
private void Start()
private void Start()
{
{
DirectionReference = new GameObject("Player's Direction Reference").transform;
DirectionReference = new GameObject("Player's Direction Reference").transform;
}
}
/// <summary>
/// <summary>
/// This is called every frame by MyPlayer in order to tell the character what its inputs are
/// This is called every frame by MyPlayer in order to tell the character what its inputs are
/// </summary>
/// </summary>
public void SetInputs(ref PlayerCharacterInputs inputs)
public void SetInputs(ref PlayerCharacterInputs inputs)
{
{
// Clamp input
// Clamp input
float inputMagnitude = Mathf.Abs(inputs.horizontal);
float inputMagnitude = Mathf.Abs(inputs.horizontal);
inputAmount = Mathf.Clamp01(inputMagnitude);
inputAmount = Mathf.Clamp01(inputMagnitude);
// base movement on direction reference
// base movement on direction reference
Vector3 correctedHorizontal = inputs.horizontal * DirectionReference.transform.right;
Vector3 correctedHorizontal = inputs.horizontal * DirectionReference.transform.right;
moveDirection = new Vector3((correctedHorizontal).normalized.x, 0, (correctedHorizontal).normalized.z);
moveDirection = new Vector3((correctedHorizontal).normalized.x, 0, (correctedHorizontal).normalized.z);
// Jumping input
// Jumping input
if (inputs.JumpDown)
if (inputs.JumpDown)
{
{
_timeSinceJumpRequested = 0f;
_timeSinceJumpRequested = 0f;
_jumpRequested = true;
_jumpRequested = true;
}
}
}
}
复制
已复制
复制
已复制
/// <summary>
/// (Called by KinematicCharacterMotor during its update cycle)
/// This is called before the character begins its movement update
/// </summary>
public override void BeforeCharacterUpdate(float deltaTime)
public override void BeforeCharacterUpdate(float deltaTime)
{
{
}
}
/// <summary>
/// <summary>
/// (Called by KinematicCharacterMotor during its update cycle)
/// (Called by KinematicCharacterMotor during its update cycle)
/// This is where you tell your character what its rotation should be right now.
/// This is where you tell your character what its rotation should be right now.
/// This is the ONLY place where you should set the character's rotation
/// This is the ONLY place where you should set the character's rotation
/// </summary>
/// </summary>
public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
{
{
// rotate player to movement direction
// rotate player to movement direction
if (moveDirection != Vector3.zero)
if (moveDirection != Vector3.zero)
{
{
Angle = Vector3.Angle(transform.forward, DirectionReference.right);
Angle = Vector3.Angle(transform.forward, DirectionReference.right);
Quaternion rot = Quaternion.LookRotation(moveDirection);
Quaternion rot = Quaternion.LookRotation(moveDirection);
Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * inputAmount * rotateSpeed);
Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * inputAmount * rotateSpeed);
currentRotation = targetRotation;
currentRotation = targetRotation;
}
}
else
else
{
{
if (Angle < 90)
if (Angle < 90)
{
{
Quaternion rot = Quaternion.LookRotation(DirectionReference.right);
Quaternion rot = Quaternion.LookRotation(DirectionReference.right);
Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * rotateSpeed);
Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * rotateSpeed);
currentRotation = targetRotation;
currentRotation = targetRotation;
}
}
else
else
{
{
Quaternion rot = Quaternion.LookRotation(-DirectionReference.right);
Quaternion rot = Quaternion.LookRotation(-DirectionReference.right);
Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * rotateSpeed);
Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * rotateSpeed);
currentRotation = targetRotation;
currentRotation = targetRotation;
}
}
}
}
}
}
/// <summary>
/// <summary>
/// (Called by KinematicCharacterMotor during its update cycle)
/// (Called by KinematicCharacterMotor during its update cycle)
/// This is where you tell your character what its velocity should be right now.
/// This is where you tell your character what its velocity should be right now.
/// This is the ONLY place where you can set the character's velocity
/// This is the ONLY place where you can set the character's velocity
/// </summary>
/// </summary>
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
{
{
Vector3 targetMovementVelocity = Vector3.zero;
Vector3 targetMovementVelocity = Vector3.zero;
if (Motor.GroundingStatus.IsStableOnGround)
if (Motor.GroundingStatus.IsStableOnGround)
{
{
// Reorient velocity on slope
// Reorient velocity on slope
currentVelocity = Motor.GetDirectionTangentToSurface(currentVelocity, Motor.GroundingStatus.GroundNormal) * currentVelocity.magnitude;
currentVelocity = Motor.GetDirectionTangentToSurface(currentVelocity, Motor.GroundingStatus.GroundNormal) * currentVelocity.magnitude;
// Calculate target velocity
// Calculate target velocity
Vector3 inputRight = Vector3.Cross(moveDirection, Motor.CharacterUp);
Vector3 inputRight = Vector3.Cross(moveDirection, Motor.CharacterUp);
Vector3 reorientedInput = Vector3.Cross(Motor.GroundingStatus.GroundNormal, inputRight).normalized * moveDirection.magnitude;
Vector3 reorientedInput = Vector3.Cross(Motor.GroundingStatus.GroundNormal, inputRight).normalized * moveDirection.magnitude;
targetMovementVelocity = reorientedInput * MaxStableMoveSpeed;
targetMovementVelocity = reorientedInput * MaxStableMoveSpeed;
// Smooth movement Velocity
// Smooth movement Velocity
currentVelocity = Vector3.Lerp(currentVelocity, targetMovementVelocity, 1 - Mathf.Exp(-StableMovementSharpness * deltaTime));
currentVelocity = Vector3.Lerp(currentVelocity, targetMovementVelocity, 1 - Mathf.Exp(-StableMovementSharpness * deltaTime));
}
}
else
else
{
{
// Add move input
// Add move input
if (moveDirection.sqrMagnitude > 0f)
if (moveDirection.sqrMagnitude > 0f)
{
{
targetMovementVelocity = moveDirection * MaxAirMoveSpeed;
targetMovementVelocity = moveDirection * MaxAirMoveSpeed;
// Prevent climbing on un-stable slopes with air movement
// Prevent climbing on un-stable slopes with air movement
if (Motor.GroundingStatus.FoundAnyGround)
if (Motor.GroundingStatus.FoundAnyGround)
{
{
Vector3 perpenticularObstructionNormal = Vector3.Cross(Vector3.Cross(Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), Motor.CharacterUp).normalized;
Vector3 perpenticularObstructionNormal = Vector3.Cross(Vector3.Cross(Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), Motor.CharacterUp).normalized;
targetMovementVelocity = Vector3.ProjectOnPlane(targetMovementVelocity, perpenticularObstructionNormal);
targetMovementVelocity = Vector3.ProjectOnPlane(targetMovementVelocity, perpenticularObstructionNormal);
}
}
Vector3 velocityDiff = Vector3.ProjectOnPlane(targetMovementVelocity - currentVelocity, Gravity);
Vector3 velocityDiff = Vector3.ProjectOnPlane(targetMovementVelocity - currentVelocity, Gravity);
currentVelocity += velocityDiff * AirAccelerationSpeed * deltaTime;
currentVelocity += velocityDiff * AirAccelerationSpeed * deltaTime;
}
}
// Gravity
// Gravity
currentVelocity += Gravity * deltaTime;
currentVelocity += Gravity * deltaTime;
// Drag
// Drag
currentVelocity *= (1f / (1f + (Drag * deltaTime)));
currentVelocity *= (1f / (1f + (Drag * deltaTime)));
}
}
// Handle jumping
// Handle jumping
{
{
_jumpedThisFrame = false;
_jumpedThisFrame = false;
_timeSinceJumpRequested += deltaTime;
_timeSinceJumpRequested += deltaTime;
if (_jumpRequested)
if (_jumpRequested)
{
{
// Handle double jump
// Handle double jump
if (AllowDoubleJump)
if (AllowDoubleJump)
{
{
if (_jumpConsumed && !_doubleJumpConsumed && (AllowJumpingWhenSliding ? !Motor.GroundingStatus.FoundAnyGround : !Motor.GroundingStatus.IsStableOnGround))
if (_jumpConsumed && !_doubleJumpConsumed && (AllowJumpingWhenSliding ? !Motor.GroundingStatus.FoundAnyGround : !Motor.GroundingStatus.IsStableOnGround))
{
{
Motor.ForceUnground();
Motor.ForceUnground();
// Add to the return velocity and reset jump state
// Add to the return velocity and reset jump state
currentVelocity += (Motor.CharacterUp * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp);
currentVelocity += (Motor.CharacterUp * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp);
_jumpRequested = false;
_jumpRequested = false;
_doubleJumpConsumed = true;
_doubleJumpConsumed = true;
_jumpedThisFrame = true;
_jumpedThisFrame = true;
}
}
}
}
// See if we actually are allowed to jump
// See if we actually are allowed to jump
if (_canWallJump ||
if (_canWallJump ||
(!_jumpConsumed && ((AllowJumpingWhenSliding ? Motor.GroundingStatus.FoundAnyGround : Motor.GroundingStatus.IsStableOnGround) || _timeSinceLastAbleToJump <= JumpPostGroundingGraceTime)))
(!_jumpConsumed && ((AllowJumpingWhenSliding ? Motor.GroundingStatus.FoundAnyGround : Motor.GroundingStatus.IsStableOnGround) || _timeSinceLastAbleToJump <= JumpPostGroundingGraceTime)))
{
{
// Calculate jump direction before ungrounding
// Calculate jump direction before ungrounding
Vector3 jumpDirection = Motor.CharacterUp;
Vector3 jumpDirection = Motor.CharacterUp;
if (_canWallJump)
if (_canWallJump)
{
{
jumpDirection = _wallJumpNormal;
jumpDirection = _wallJumpNormal;
}
}
else if (Motor.GroundingStatus.FoundAnyGround && !Motor.GroundingStatus.IsStableOnGround)
else if (Motor.GroundingStatus.FoundAnyGround && !Motor.GroundingStatus.IsStableOnGround)
{
{
jumpDirection = Motor.GroundingStatus.GroundNormal;
jumpDirection = Motor.GroundingStatus.GroundNormal;
}
}
// Makes the character skip ground probing/snapping on its next update.
// Makes the character skip ground probing/snapping on its next update.
// If this line weren't here, the character would remain snapped to the ground when trying to jump. Try commenting this line out and see.
// If this line weren't here, the character would remain snapped to the ground when trying to jump. Try commenting this line out and see.
Motor.ForceUnground();
Motor.ForceUnground();
// Add to the return velocity and reset jump state
// Add to the return velocity and reset jump state
currentVelocity += (jumpDirection * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp);
currentVelocity += (jumpDirection * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp);
_jumpRequested = false;
_jumpRequested = false;
_jumpConsumed = true;
_jumpConsumed = true;
_jumpedThisFrame = true;
_jumpedThisFrame = true;
}
}
}
}
// Reset wall jump
// Reset wall jump
_canWallJump = false;
_canWallJump = false;
}
}
}
}
/// <summary>
/// <summary>
/// (Called by KinematicCharacterMotor during its update cycle)
/// (Called by KinematicCharacterMotor during its update cycle)
/// This is called after the character has finished its movement update
/// This is called after the character has finished its movement update
/// </summary>
/// </summary>
public override void AfterCharacterUpdate(float deltaTime)
public override void AfterCharacterUpdate(float deltaTime)
{
{
// Handle jump-related values
// Handle jump-related values
{
{
// Handle jumping pre-ground grace period
// Handle jumping pre-ground grace period
if (_jumpRequested && _timeSinceJumpRequested > JumpPreGroundingGraceTime)
if (_jumpRequested && _timeSinceJumpRequested > JumpPreGroundingGraceTime)
{
{
_jumpRequested = false;
_jumpRequested = false;
}
}
if (AllowJumpingWhenSliding ? Motor.GroundingStatus.FoundAnyGround : Motor.GroundingStatus.IsStableOnGround)
if (AllowJumpingWhenSliding ? Motor.GroundingStatus.FoundAnyGround : Motor.GroundingStatus.IsStableOnGround)
{
{
// If we're on a ground surface, reset jumping values
// If we're on a ground surface, reset jumping values
if (!_jumpedThisFrame)
if (!_jumpedThisFrame)
{
{
_doubleJumpConsumed = false;
_doubleJumpConsumed = false;
_jumpConsumed = false;
_jumpConsumed = false;
}
}
_timeSinceLastAbleToJump = 0f;
_timeSinceLastAbleToJump = 0f;
}
}
else
else
{
{
// Keep track of time since we were last able to jump (for grace period)
// Keep track of time since we were last able to jump (for grace period)
_timeSinceLastAbleToJump += deltaTime;
_timeSinceLastAbleToJump += deltaTime;
}
}
}
}
}
}
public override bool IsColliderValidForCollisions(Collider coll)
public override bool IsColliderValidForCollisions(Collider coll)
{
{
return true;
return true;
}
}
public override void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
public override void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
{
{
}
}
public override void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
public override void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
{
{
// We can wall jump only if we are not stable on ground and are moving against an obstruction
// We can wall jump only if we are not stable on ground and are moving against an obstruction
if (AllowWallJump && !Motor.GroundingStatus.IsStableOnGround && !hitStabilityReport.IsStable)
if (AllowWallJump && !Motor.GroundingStatus.IsStableOnGround && !hitStabilityReport.IsStable)
{
{
_canWallJump = true;
_canWallJump = true;
_wallJumpNormal = hitNormal;
_wallJumpNormal = hitNormal;
}
}
}
}
复制
已复制
复制
已复制
public override void
PostGroundingUpdate(float deltaTime)
public override void
ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport)
{
}
public void AddVelocity(Vector3 velocity)
{
{
}
}
复制
已复制
复制
已复制
public override void
ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport)
public override void
PostGroundingUpdate(float deltaTime)
{
{
}
}
}
}
}
}
复制
已复制
复制
已复制
已保存差异
原始文本
打开文件
using System.Collections; using System.Collections.Generic; using UnityEngine; using KinematicCharacterController; using System; namespace KinematicCharacterController.Walkthrough.WallJumping { public struct PlayerCharacterInputs { public float horizontal; public bool JumpDown; } public class MyCharacterController : BaseCharacterController { [Header("Stable Movement")] public float MaxStableMoveSpeed = 10f; public float StableMovementSharpness = 15; public float rotateSpeed = 10; [Header("Air Movement")] public float MaxAirMoveSpeed = 10f; public float AirAccelerationSpeed = 5f; public float Drag = 0.1f; [Header("Jumping")] public bool AllowJumpingWhenSliding = false; public bool AllowDoubleJump = false; public bool AllowWallJump = false; public float JumpSpeed = 10f; public float JumpPreGroundingGraceTime = 0f; public float JumpPostGroundingGraceTime = 0f; [Header("Misc")] public Vector3 Gravity = new Vector3(0, -30f, 0); public Transform MeshRoot; private bool _jumpRequested = false; private bool _jumpConsumed = false; private bool _jumpedThisFrame = false; private float _timeSinceJumpRequested = Mathf.Infinity; private float _timeSinceLastAbleToJump = 0f; private bool _doubleJumpConsumed = false; private bool _canWallJump = false; private Vector3 _wallJumpNormal; float inputAmount, Angle; Vector3 moveDirection; Transform DirectionReference; private void Start() { DirectionReference = new GameObject("Player's Direction Reference").transform; } /// <summary> /// This is called every frame by MyPlayer in order to tell the character what its inputs are /// </summary> public void SetInputs(ref PlayerCharacterInputs inputs) { // Clamp input float inputMagnitude = Mathf.Abs(inputs.horizontal); inputAmount = Mathf.Clamp01(inputMagnitude); // base movement on direction reference Vector3 correctedHorizontal = inputs.horizontal * DirectionReference.transform.right; moveDirection = new Vector3((correctedHorizontal).normalized.x, 0, (correctedHorizontal).normalized.z); // Jumping input if (inputs.JumpDown) { _timeSinceJumpRequested = 0f; _jumpRequested = true; } } /// <summary> /// (Called by KinematicCharacterMotor during its update cycle) /// This is called before the character begins its movement update /// </summary> public override void BeforeCharacterUpdate(float deltaTime) { } /// <summary> /// (Called by KinematicCharacterMotor during its update cycle) /// This is where you tell your character what its rotation should be right now. /// This is the ONLY place where you should set the character's rotation /// </summary> public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime) { // rotate player to movement direction if (moveDirection != Vector3.zero) { Angle = Vector3.Angle(transform.forward, DirectionReference.right); Quaternion rot = Quaternion.LookRotation(moveDirection); Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * inputAmount * rotateSpeed); currentRotation = targetRotation; } else { if (Angle < 90) { Quaternion rot = Quaternion.LookRotation(DirectionReference.right); Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * rotateSpeed); currentRotation = targetRotation; } else { Quaternion rot = Quaternion.LookRotation(-DirectionReference.right); Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * rotateSpeed); currentRotation = targetRotation; } } } /// <summary> /// (Called by KinematicCharacterMotor during its update cycle) /// This is where you tell your character what its velocity should be right now. /// This is the ONLY place where you can set the character's velocity /// </summary> public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime) { Vector3 targetMovementVelocity = Vector3.zero; if (Motor.GroundingStatus.IsStableOnGround) { // Reorient velocity on slope currentVelocity = Motor.GetDirectionTangentToSurface(currentVelocity, Motor.GroundingStatus.GroundNormal) * currentVelocity.magnitude; // Calculate target velocity Vector3 inputRight = Vector3.Cross(moveDirection, Motor.CharacterUp); Vector3 reorientedInput = Vector3.Cross(Motor.GroundingStatus.GroundNormal, inputRight).normalized * moveDirection.magnitude; targetMovementVelocity = reorientedInput * MaxStableMoveSpeed; // Smooth movement Velocity currentVelocity = Vector3.Lerp(currentVelocity, targetMovementVelocity, 1 - Mathf.Exp(-StableMovementSharpness * deltaTime)); } else { // Add move input if (moveDirection.sqrMagnitude > 0f) { targetMovementVelocity = moveDirection * MaxAirMoveSpeed; // Prevent climbing on un-stable slopes with air movement if (Motor.GroundingStatus.FoundAnyGround) { Vector3 perpenticularObstructionNormal = Vector3.Cross(Vector3.Cross(Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), Motor.CharacterUp).normalized; targetMovementVelocity = Vector3.ProjectOnPlane(targetMovementVelocity, perpenticularObstructionNormal); } Vector3 velocityDiff = Vector3.ProjectOnPlane(targetMovementVelocity - currentVelocity, Gravity); currentVelocity += velocityDiff * AirAccelerationSpeed * deltaTime; } // Gravity currentVelocity += Gravity * deltaTime; // Drag currentVelocity *= (1f / (1f + (Drag * deltaTime))); } // Handle jumping { _jumpedThisFrame = false; _timeSinceJumpRequested += deltaTime; if (_jumpRequested) { // Handle double jump if (AllowDoubleJump) { if (_jumpConsumed && !_doubleJumpConsumed && (AllowJumpingWhenSliding ? !Motor.GroundingStatus.FoundAnyGround : !Motor.GroundingStatus.IsStableOnGround)) { Motor.ForceUnground(); // Add to the return velocity and reset jump state currentVelocity += (Motor.CharacterUp * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp); _jumpRequested = false; _doubleJumpConsumed = true; _jumpedThisFrame = true; } } // See if we actually are allowed to jump if (_canWallJump || (!_jumpConsumed && ((AllowJumpingWhenSliding ? Motor.GroundingStatus.FoundAnyGround : Motor.GroundingStatus.IsStableOnGround) || _timeSinceLastAbleToJump <= JumpPostGroundingGraceTime))) { // Calculate jump direction before ungrounding Vector3 jumpDirection = Motor.CharacterUp; if (_canWallJump) { jumpDirection = _wallJumpNormal; } else if (Motor.GroundingStatus.FoundAnyGround && !Motor.GroundingStatus.IsStableOnGround) { jumpDirection = Motor.GroundingStatus.GroundNormal; } // Makes the character skip ground probing/snapping on its next update. // If this line weren't here, the character would remain snapped to the ground when trying to jump. Try commenting this line out and see. Motor.ForceUnground(); // Add to the return velocity and reset jump state currentVelocity += (jumpDirection * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp); _jumpRequested = false; _jumpConsumed = true; _jumpedThisFrame = true; } } // Reset wall jump _canWallJump = false; } } /// <summary> /// (Called by KinematicCharacterMotor during its update cycle) /// This is called after the character has finished its movement update /// </summary> public override void AfterCharacterUpdate(float deltaTime) { // Handle jump-related values { // Handle jumping pre-ground grace period if (_jumpRequested && _timeSinceJumpRequested > JumpPreGroundingGraceTime) { _jumpRequested = false; } if (AllowJumpingWhenSliding ? Motor.GroundingStatus.FoundAnyGround : Motor.GroundingStatus.IsStableOnGround) { // If we're on a ground surface, reset jumping values if (!_jumpedThisFrame) { _doubleJumpConsumed = false; _jumpConsumed = false; } _timeSinceLastAbleToJump = 0f; } else { // Keep track of time since we were last able to jump (for grace period) _timeSinceLastAbleToJump += deltaTime; } } } public override bool IsColliderValidForCollisions(Collider coll) { return true; } public override void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) { } public override void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) { // We can wall jump only if we are not stable on ground and are moving against an obstruction if (AllowWallJump && !Motor.GroundingStatus.IsStableOnGround && !hitStabilityReport.IsStable) { _canWallJump = true; _wallJumpNormal = hitNormal; } } public override void PostGroundingUpdate(float deltaTime) { } public void AddVelocity(Vector3 velocity) { } public override void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport) { } } }
更改后文本
打开文件
using System.Collections; using System.Collections.Generic; using UnityEngine; using KinematicCharacterController; using System; namespace LezCharacterController { public struct PlayerCharacterInputs { public float horizontal; public bool JumpDown; } public class KinematicCharacter : BaseCharacterController { [Header("Movement")] public float MaxStableMoveSpeed = 10f; public float StableMovementSharpness = 15; public float rotateSpeed = 10; [Header("Air Movement")] public float MaxAirMoveSpeed = 10f; public float AirAccelerationSpeed = 5f; public float Drag = 0.1f; [Header("Jumping")] public bool AllowJumpingWhenSliding = false; public bool AllowDoubleJump = false; public bool AllowWallJump = false; public float JumpSpeed = 10f; public float JumpPreGroundingGraceTime = 0f; public float JumpPostGroundingGraceTime = 0f; [Header("Misc")] public bool RotationObstruction; public Vector3 Gravity = new Vector3(0, -30f, 0); public Transform MeshRoot; private Vector3 moveDirection; private float Angle; private float inputAmount; private bool _jumpRequested = false; private bool _jumpConsumed = false; private bool _jumpedThisFrame = false; private float _timeSinceJumpRequested = Mathf.Infinity; private float _timeSinceLastAbleToJump = 0f; private bool _doubleJumpConsumed = false; private bool _canWallJump = false; private Vector3 _wallJumpNormal; public Transform DirectionReference; private void Start() { DirectionReference = new GameObject("Player's Direction Reference").transform; } /// <summary> /// This is called every frame by MyPlayer in order to tell the character what its inputs are /// </summary> public void SetInputs(ref PlayerCharacterInputs inputs) { // Clamp input float inputMagnitude = Mathf.Abs(inputs.horizontal); inputAmount = Mathf.Clamp01(inputMagnitude); // base movement on direction reference Vector3 correctedHorizontal = inputs.horizontal * DirectionReference.transform.right; moveDirection = new Vector3((correctedHorizontal).normalized.x, 0, (correctedHorizontal).normalized.z); // Jumping input if (inputs.JumpDown) { _timeSinceJumpRequested = 0f; _jumpRequested = true; } } public override void BeforeCharacterUpdate(float deltaTime) { } /// <summary> /// (Called by KinematicCharacterMotor during its update cycle) /// This is where you tell your character what its rotation should be right now. /// This is the ONLY place where you should set the character's rotation /// </summary> public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime) { // rotate player to movement direction if (moveDirection != Vector3.zero) { Angle = Vector3.Angle(transform.forward, DirectionReference.right); Quaternion rot = Quaternion.LookRotation(moveDirection); Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * inputAmount * rotateSpeed); currentRotation = targetRotation; } else { if (Angle < 90) { Quaternion rot = Quaternion.LookRotation(DirectionReference.right); Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * rotateSpeed); currentRotation = targetRotation; } else { Quaternion rot = Quaternion.LookRotation(-DirectionReference.right); Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * rotateSpeed); currentRotation = targetRotation; } } } /// <summary> /// (Called by KinematicCharacterMotor during its update cycle) /// This is where you tell your character what its velocity should be right now. /// This is the ONLY place where you can set the character's velocity /// </summary> public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime) { Vector3 targetMovementVelocity = Vector3.zero; if (Motor.GroundingStatus.IsStableOnGround) { // Reorient velocity on slope currentVelocity = Motor.GetDirectionTangentToSurface(currentVelocity, Motor.GroundingStatus.GroundNormal) * currentVelocity.magnitude; // Calculate target velocity Vector3 inputRight = Vector3.Cross(moveDirection, Motor.CharacterUp); Vector3 reorientedInput = Vector3.Cross(Motor.GroundingStatus.GroundNormal, inputRight).normalized * moveDirection.magnitude; targetMovementVelocity = reorientedInput * MaxStableMoveSpeed; // Smooth movement Velocity currentVelocity = Vector3.Lerp(currentVelocity, targetMovementVelocity, 1 - Mathf.Exp(-StableMovementSharpness * deltaTime)); } else { // Add move input if (moveDirection.sqrMagnitude > 0f) { targetMovementVelocity = moveDirection * MaxAirMoveSpeed; // Prevent climbing on un-stable slopes with air movement if (Motor.GroundingStatus.FoundAnyGround) { Vector3 perpenticularObstructionNormal = Vector3.Cross(Vector3.Cross(Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), Motor.CharacterUp).normalized; targetMovementVelocity = Vector3.ProjectOnPlane(targetMovementVelocity, perpenticularObstructionNormal); } Vector3 velocityDiff = Vector3.ProjectOnPlane(targetMovementVelocity - currentVelocity, Gravity); currentVelocity += velocityDiff * AirAccelerationSpeed * deltaTime; } // Gravity currentVelocity += Gravity * deltaTime; // Drag currentVelocity *= (1f / (1f + (Drag * deltaTime))); } // Handle jumping { _jumpedThisFrame = false; _timeSinceJumpRequested += deltaTime; if (_jumpRequested) { // Handle double jump if (AllowDoubleJump) { if (_jumpConsumed && !_doubleJumpConsumed && (AllowJumpingWhenSliding ? !Motor.GroundingStatus.FoundAnyGround : !Motor.GroundingStatus.IsStableOnGround)) { Motor.ForceUnground(); // Add to the return velocity and reset jump state currentVelocity += (Motor.CharacterUp * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp); _jumpRequested = false; _doubleJumpConsumed = true; _jumpedThisFrame = true; } } // See if we actually are allowed to jump if (_canWallJump || (!_jumpConsumed && ((AllowJumpingWhenSliding ? Motor.GroundingStatus.FoundAnyGround : Motor.GroundingStatus.IsStableOnGround) || _timeSinceLastAbleToJump <= JumpPostGroundingGraceTime))) { // Calculate jump direction before ungrounding Vector3 jumpDirection = Motor.CharacterUp; if (_canWallJump) { jumpDirection = _wallJumpNormal; } else if (Motor.GroundingStatus.FoundAnyGround && !Motor.GroundingStatus.IsStableOnGround) { jumpDirection = Motor.GroundingStatus.GroundNormal; } // Makes the character skip ground probing/snapping on its next update. // If this line weren't here, the character would remain snapped to the ground when trying to jump. Try commenting this line out and see. Motor.ForceUnground(); // Add to the return velocity and reset jump state currentVelocity += (jumpDirection * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp); _jumpRequested = false; _jumpConsumed = true; _jumpedThisFrame = true; } } // Reset wall jump _canWallJump = false; } } /// <summary> /// (Called by KinematicCharacterMotor during its update cycle) /// This is called after the character has finished its movement update /// </summary> public override void AfterCharacterUpdate(float deltaTime) { // Handle jump-related values { // Handle jumping pre-ground grace period if (_jumpRequested && _timeSinceJumpRequested > JumpPreGroundingGraceTime) { _jumpRequested = false; } if (AllowJumpingWhenSliding ? Motor.GroundingStatus.FoundAnyGround : Motor.GroundingStatus.IsStableOnGround) { // If we're on a ground surface, reset jumping values if (!_jumpedThisFrame) { _doubleJumpConsumed = false; _jumpConsumed = false; } _timeSinceLastAbleToJump = 0f; } else { // Keep track of time since we were last able to jump (for grace period) _timeSinceLastAbleToJump += deltaTime; } } } public override bool IsColliderValidForCollisions(Collider coll) { return true; } public override void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) { } public override void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) { // We can wall jump only if we are not stable on ground and are moving against an obstruction if (AllowWallJump && !Motor.GroundingStatus.IsStableOnGround && !hitStabilityReport.IsStable) { _canWallJump = true; _wallJumpNormal = hitNormal; } } public override void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport) { } public override void PostGroundingUpdate(float deltaTime) { } } }
查找差异