Player, player movement, camera control
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a42d4a8b13177294587a103a75e3eef0
|
||||
folderAsset: yes
|
||||
timeCreated: 1507244931
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 091be7fd48275134aa2e7bbbb7579ba9
|
||||
folderAsset: yes
|
||||
timeCreated: 1507248146
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 10d8a9820a4bc8641b664104d8ab9b0b
|
||||
timeCreated: 1506988233
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a0121041686b2045a832bb37b8cb164
|
||||
timeCreated: 1517762935
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 25800000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,78 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18d9b5cfbe4e1f9459f9d9c422562181
|
||||
timeCreated: 1517762935
|
||||
licenseType: Store
|
||||
TextureImporter:
|
||||
fileIDToRecycleName:
|
||||
8900000: generatedCubemap
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 1
|
||||
seamlessCubemap: 1
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 2
|
||||
aniso: 0
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 2
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 100
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e84db11925c17d24a8f1469567009d4a
|
||||
folderAsset: yes
|
||||
timeCreated: 1507244924
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a949d0a73985bf46b0f3682d1ca7dc1
|
||||
folderAsset: yes
|
||||
timeCreated: 1507245639
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,245 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using KinematicCharacterController;
|
||||
using System;
|
||||
|
||||
namespace KinematicCharacterController.Walkthrough.SimpleJumping
|
||||
{
|
||||
public struct PlayerCharacterInputs
|
||||
{
|
||||
public float MoveAxisForward;
|
||||
public float MoveAxisRight;
|
||||
public Quaternion CameraRotation;
|
||||
public bool JumpDown;
|
||||
}
|
||||
|
||||
public class MyCharacterController : MonoBehaviour, ICharacterController
|
||||
{
|
||||
public KinematicCharacterMotor Motor;
|
||||
|
||||
[Header("Stable Movement")]
|
||||
public float MaxStableMoveSpeed = 10f;
|
||||
public float StableMovementSharpness = 15;
|
||||
public float OrientationSharpness = 10;
|
||||
|
||||
[Header("Air Movement")]
|
||||
public float MaxAirMoveSpeed = 10f;
|
||||
public float AirAccelerationSpeed = 5f;
|
||||
public float Drag = 0.1f;
|
||||
|
||||
[Header("Jumping")]
|
||||
public bool AllowJumpingWhenSliding = 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 Vector3 _moveInputVector;
|
||||
private Vector3 _lookInputVector;
|
||||
private bool _jumpRequested = false;
|
||||
private bool _jumpConsumed = false;
|
||||
private bool _jumpedThisFrame = false;
|
||||
private float _timeSinceJumpRequested = Mathf.Infinity;
|
||||
private float _timeSinceLastAbleToJump = 0f;
|
||||
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Assign to motor
|
||||
Motor.CharacterController = this;
|
||||
}
|
||||
|
||||
/// <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
|
||||
Vector3 moveInputVector = Vector3.ClampMagnitude(new Vector3(inputs.MoveAxisRight, 0f, inputs.MoveAxisForward), 1f);
|
||||
|
||||
// Calculate camera direction and rotation on the character plane
|
||||
Vector3 cameraPlanarDirection = Vector3.ProjectOnPlane(inputs.CameraRotation * Vector3.forward, Motor.CharacterUp).normalized;
|
||||
if (cameraPlanarDirection.sqrMagnitude == 0f)
|
||||
{
|
||||
cameraPlanarDirection = Vector3.ProjectOnPlane(inputs.CameraRotation * Vector3.up, Motor.CharacterUp).normalized;
|
||||
}
|
||||
Quaternion cameraPlanarRotation = Quaternion.LookRotation(cameraPlanarDirection, Motor.CharacterUp);
|
||||
|
||||
// Move and look inputs
|
||||
_moveInputVector = cameraPlanarRotation * moveInputVector;
|
||||
_lookInputVector = cameraPlanarDirection;
|
||||
|
||||
// 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 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 void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
|
||||
{
|
||||
if (_lookInputVector != Vector3.zero && OrientationSharpness > 0f)
|
||||
{
|
||||
// Smoothly interpolate from current to target look direction
|
||||
Vector3 smoothedLookInputDirection = Vector3.Slerp(Motor.CharacterForward, _lookInputVector, 1 - Mathf.Exp(-OrientationSharpness * deltaTime)).normalized;
|
||||
|
||||
// Set the current rotation (which will be used by the KinematicCharacterMotor)
|
||||
currentRotation = Quaternion.LookRotation(smoothedLookInputDirection, Motor.CharacterUp);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 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(_moveInputVector, Motor.CharacterUp);
|
||||
Vector3 reorientedInput = Vector3.Cross(Motor.GroundingStatus.GroundNormal, inputRight).normalized * _moveInputVector.magnitude;
|
||||
targetMovementVelocity = reorientedInput * MaxStableMoveSpeed;
|
||||
|
||||
// Smooth movement Velocity
|
||||
currentVelocity = Vector3.Lerp(currentVelocity, targetMovementVelocity, 1 - Mathf.Exp(-StableMovementSharpness * deltaTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add move input
|
||||
if (_moveInputVector.sqrMagnitude > 0f)
|
||||
{
|
||||
targetMovementVelocity = _moveInputVector * 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)
|
||||
{
|
||||
// See if we actually are allowed to jump
|
||||
if (!_jumpConsumed && ((AllowJumpingWhenSliding ? Motor.GroundingStatus.FoundAnyGround : Motor.GroundingStatus.IsStableOnGround) || _timeSinceLastAbleToJump <= JumpPostGroundingGraceTime))
|
||||
{
|
||||
// Calculate jump direction before ungrounding
|
||||
Vector3 jumpDirection = Motor.CharacterUp;
|
||||
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(0.1f);
|
||||
|
||||
// Add to the return velocity and reset jump state
|
||||
currentVelocity += (jumpDirection * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp);
|
||||
_jumpRequested = false;
|
||||
_jumpConsumed = true;
|
||||
_jumpedThisFrame = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (Called by KinematicCharacterMotor during its update cycle)
|
||||
/// This is called after the character has finished its movement update
|
||||
/// </summary>
|
||||
public void AfterCharacterUpdate(float deltaTime)
|
||||
{
|
||||
// Handle jump-related values
|
||||
{
|
||||
// Handle jumping pre-ground grace period
|
||||
if (_jumpRequested && _timeSinceJumpRequested > JumpPreGroundingGraceTime)
|
||||
{
|
||||
_jumpRequested = false;
|
||||
}
|
||||
|
||||
// Handle jumping while sliding
|
||||
if (AllowJumpingWhenSliding ? Motor.GroundingStatus.FoundAnyGround : Motor.GroundingStatus.IsStableOnGround)
|
||||
{
|
||||
// If we're on a ground surface, reset jumping values
|
||||
if (!_jumpedThisFrame)
|
||||
{
|
||||
_jumpConsumed = false;
|
||||
}
|
||||
_timeSinceLastAbleToJump = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep track of time since we were last able to jump (for grace period)
|
||||
_timeSinceLastAbleToJump += deltaTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsColliderValidForCollisions(Collider coll)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
|
||||
{
|
||||
}
|
||||
|
||||
public void PostGroundingUpdate(float deltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
public void AddVelocity(Vector3 velocity)
|
||||
{
|
||||
}
|
||||
|
||||
public void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnDiscreteCollisionDetected(Collider hitCollider)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f052f48e80bba64c8fd341e19240cd1
|
||||
timeCreated: 1507245673
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,92 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using KinematicCharacterController;
|
||||
using KinematicCharacterController.Examples;
|
||||
using System.Linq;
|
||||
|
||||
namespace KinematicCharacterController.Walkthrough.SimpleJumping
|
||||
{
|
||||
public class MyPlayer : MonoBehaviour
|
||||
{
|
||||
public ExampleCharacterCamera OrbitCamera;
|
||||
public Transform CameraFollowPoint;
|
||||
public MyCharacterController Character;
|
||||
|
||||
private const string MouseXInput = "Mouse X";
|
||||
private const string MouseYInput = "Mouse Y";
|
||||
private const string MouseScrollInput = "Mouse ScrollWheel";
|
||||
private const string HorizontalInput = "Horizontal";
|
||||
private const string VerticalInput = "Vertical";
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Cursor.lockState = CursorLockMode.Locked;
|
||||
|
||||
// Tell camera to follow transform
|
||||
OrbitCamera.SetFollowTransform(CameraFollowPoint);
|
||||
|
||||
// Ignore the character's collider(s) for camera obstruction checks
|
||||
OrbitCamera.IgnoredColliders.Clear();
|
||||
OrbitCamera.IgnoredColliders.AddRange(Character.GetComponentsInChildren<Collider>());
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (Input.GetMouseButtonDown(0))
|
||||
{
|
||||
Cursor.lockState = CursorLockMode.Locked;
|
||||
}
|
||||
|
||||
HandleCharacterInput();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
HandleCameraInput();
|
||||
}
|
||||
|
||||
private void HandleCameraInput()
|
||||
{
|
||||
// Create the look input vector for the camera
|
||||
float mouseLookAxisUp = Input.GetAxisRaw(MouseYInput);
|
||||
float mouseLookAxisRight = Input.GetAxisRaw(MouseXInput);
|
||||
Vector3 lookInputVector = new Vector3(mouseLookAxisRight, mouseLookAxisUp, 0f);
|
||||
|
||||
// Prevent moving the camera while the cursor isn't locked
|
||||
if (Cursor.lockState != CursorLockMode.Locked)
|
||||
{
|
||||
lookInputVector = Vector3.zero;
|
||||
}
|
||||
|
||||
// Input for zooming the camera (disabled in WebGL because it can cause problems)
|
||||
float scrollInput = -Input.GetAxis(MouseScrollInput);
|
||||
#if UNITY_WEBGL
|
||||
scrollInput = 0f;
|
||||
#endif
|
||||
|
||||
// Apply inputs to the camera
|
||||
OrbitCamera.UpdateWithInput(Time.deltaTime, scrollInput, lookInputVector);
|
||||
|
||||
// Handle toggling zoom level
|
||||
if (Input.GetMouseButtonDown(1))
|
||||
{
|
||||
OrbitCamera.TargetDistance = (OrbitCamera.TargetDistance == 0f) ? OrbitCamera.DefaultDistance : 0f;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCharacterInput()
|
||||
{
|
||||
PlayerCharacterInputs characterInputs = new PlayerCharacterInputs();
|
||||
|
||||
// Build the CharacterInputs struct
|
||||
characterInputs.MoveAxisForward = Input.GetAxisRaw(VerticalInput);
|
||||
characterInputs.MoveAxisRight = Input.GetAxisRaw(HorizontalInput);
|
||||
characterInputs.CameraRotation = OrbitCamera.Transform.rotation;
|
||||
characterInputs.JumpDown = Input.GetKeyDown(KeyCode.Space);
|
||||
|
||||
// Apply inputs to character
|
||||
Character.SetInputs(ref characterInputs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2f934d74d9c62e409691089041cc749
|
||||
timeCreated: 1507245673
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a745148b60f27df4196c3428d25cafe2
|
||||
folderAsset: yes
|
||||
timeCreated: 1507245639
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,261 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using KinematicCharacterController;
|
||||
using System;
|
||||
|
||||
namespace KinematicCharacterController.Walkthrough.DoubleJumping
|
||||
{
|
||||
public struct PlayerCharacterInputs
|
||||
{
|
||||
public float MoveAxisForward;
|
||||
public float MoveAxisRight;
|
||||
public Quaternion CameraRotation;
|
||||
public bool JumpDown;
|
||||
}
|
||||
|
||||
public class MyCharacterController : MonoBehaviour, ICharacterController
|
||||
{
|
||||
public KinematicCharacterMotor Motor;
|
||||
|
||||
[Header("Stable Movement")]
|
||||
public float MaxStableMoveSpeed = 10f;
|
||||
public float StableMovementSharpness = 15;
|
||||
public float OrientationSharpness = 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 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 Vector3 _moveInputVector;
|
||||
private Vector3 _lookInputVector;
|
||||
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 void Start()
|
||||
{
|
||||
// Assign to motor
|
||||
Motor.CharacterController = this;
|
||||
}
|
||||
|
||||
/// <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
|
||||
Vector3 moveInputVector = Vector3.ClampMagnitude(new Vector3(inputs.MoveAxisRight, 0f, inputs.MoveAxisForward), 1f);
|
||||
|
||||
// Calculate camera direction and rotation on the character plane
|
||||
Vector3 cameraPlanarDirection = Vector3.ProjectOnPlane(inputs.CameraRotation * Vector3.forward, Motor.CharacterUp).normalized;
|
||||
if (cameraPlanarDirection.sqrMagnitude == 0f)
|
||||
{
|
||||
cameraPlanarDirection = Vector3.ProjectOnPlane(inputs.CameraRotation * Vector3.up, Motor.CharacterUp).normalized;
|
||||
}
|
||||
Quaternion cameraPlanarRotation = Quaternion.LookRotation(cameraPlanarDirection, Motor.CharacterUp);
|
||||
|
||||
// Move and look inputs
|
||||
_moveInputVector = cameraPlanarRotation * moveInputVector;
|
||||
_lookInputVector = cameraPlanarDirection;
|
||||
|
||||
// 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 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 void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
|
||||
{
|
||||
if (_lookInputVector != Vector3.zero && OrientationSharpness > 0f)
|
||||
{
|
||||
// Smoothly interpolate from current to target look direction
|
||||
Vector3 smoothedLookInputDirection = Vector3.Slerp(Motor.CharacterForward, _lookInputVector, 1 - Mathf.Exp(-OrientationSharpness * deltaTime)).normalized;
|
||||
|
||||
// Set the current rotation (which will be used by the KinematicCharacterMotor)
|
||||
currentRotation = Quaternion.LookRotation(smoothedLookInputDirection, Motor.CharacterUp);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 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(_moveInputVector, Motor.CharacterUp);
|
||||
Vector3 reorientedInput = Vector3.Cross(Motor.GroundingStatus.GroundNormal, inputRight).normalized * _moveInputVector.magnitude;
|
||||
targetMovementVelocity = reorientedInput * MaxStableMoveSpeed;
|
||||
|
||||
// Smooth movement Velocity
|
||||
currentVelocity = Vector3.Lerp(currentVelocity, targetMovementVelocity, 1 - Mathf.Exp(-StableMovementSharpness * deltaTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add move input
|
||||
if (_moveInputVector.sqrMagnitude > 0f)
|
||||
{
|
||||
targetMovementVelocity = _moveInputVector * 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(0.1f);
|
||||
|
||||
// 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 (!_jumpConsumed && ((AllowJumpingWhenSliding ? Motor.GroundingStatus.FoundAnyGround : Motor.GroundingStatus.IsStableOnGround) || _timeSinceLastAbleToJump <= JumpPostGroundingGraceTime))
|
||||
{
|
||||
// Calculate jump direction before ungrounding
|
||||
Vector3 jumpDirection = Motor.CharacterUp;
|
||||
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(0.1f);
|
||||
|
||||
// Add to the return velocity and reset jump state
|
||||
currentVelocity += (jumpDirection * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp);
|
||||
_jumpRequested = false;
|
||||
_jumpConsumed = true;
|
||||
_jumpedThisFrame = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (Called by KinematicCharacterMotor during its update cycle)
|
||||
/// This is called after the character has finished its movement update
|
||||
/// </summary>
|
||||
public 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 bool IsColliderValidForCollisions(Collider coll)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
|
||||
{
|
||||
}
|
||||
|
||||
public void PostGroundingUpdate(float deltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
public void AddVelocity(Vector3 velocity)
|
||||
{
|
||||
}
|
||||
|
||||
public void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnDiscreteCollisionDetected(Collider hitCollider)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d04975d64d6f73489b29b0d953c1701
|
||||
timeCreated: 1507245715
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,91 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using KinematicCharacterController;
|
||||
using KinematicCharacterController.Examples;
|
||||
|
||||
namespace KinematicCharacterController.Walkthrough.DoubleJumping
|
||||
{
|
||||
public class MyPlayer : MonoBehaviour
|
||||
{
|
||||
public ExampleCharacterCamera OrbitCamera;
|
||||
public Transform CameraFollowPoint;
|
||||
public MyCharacterController Character;
|
||||
|
||||
private const string MouseXInput = "Mouse X";
|
||||
private const string MouseYInput = "Mouse Y";
|
||||
private const string MouseScrollInput = "Mouse ScrollWheel";
|
||||
private const string HorizontalInput = "Horizontal";
|
||||
private const string VerticalInput = "Vertical";
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Cursor.lockState = CursorLockMode.Locked;
|
||||
|
||||
// Tell camera to follow transform
|
||||
OrbitCamera.SetFollowTransform(CameraFollowPoint);
|
||||
|
||||
// Ignore the character's collider(s) for camera obstruction checks
|
||||
OrbitCamera.IgnoredColliders.Clear();
|
||||
OrbitCamera.IgnoredColliders.AddRange(Character.GetComponentsInChildren<Collider>());
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (Input.GetMouseButtonDown(0))
|
||||
{
|
||||
Cursor.lockState = CursorLockMode.Locked;
|
||||
}
|
||||
|
||||
HandleCharacterInput();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
HandleCameraInput();
|
||||
}
|
||||
|
||||
private void HandleCameraInput()
|
||||
{
|
||||
// Create the look input vector for the camera
|
||||
float mouseLookAxisUp = Input.GetAxisRaw(MouseYInput);
|
||||
float mouseLookAxisRight = Input.GetAxisRaw(MouseXInput);
|
||||
Vector3 lookInputVector = new Vector3(mouseLookAxisRight, mouseLookAxisUp, 0f);
|
||||
|
||||
// Prevent moving the camera while the cursor isn't locked
|
||||
if (Cursor.lockState != CursorLockMode.Locked)
|
||||
{
|
||||
lookInputVector = Vector3.zero;
|
||||
}
|
||||
|
||||
// Input for zooming the camera (disabled in WebGL because it can cause problems)
|
||||
float scrollInput = -Input.GetAxis(MouseScrollInput);
|
||||
#if UNITY_WEBGL
|
||||
scrollInput = 0f;
|
||||
#endif
|
||||
|
||||
// Apply inputs to the camera
|
||||
OrbitCamera.UpdateWithInput(Time.deltaTime, scrollInput, lookInputVector);
|
||||
|
||||
// Handle toggling zoom level
|
||||
if (Input.GetMouseButtonDown(1))
|
||||
{
|
||||
OrbitCamera.TargetDistance = (OrbitCamera.TargetDistance == 0f) ? OrbitCamera.DefaultDistance : 0f;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCharacterInput()
|
||||
{
|
||||
PlayerCharacterInputs characterInputs = new PlayerCharacterInputs();
|
||||
|
||||
// Build the CharacterInputs struct
|
||||
characterInputs.MoveAxisForward = Input.GetAxisRaw(VerticalInput);
|
||||
characterInputs.MoveAxisRight = Input.GetAxisRaw(HorizontalInput);
|
||||
characterInputs.CameraRotation = OrbitCamera.Transform.rotation;
|
||||
characterInputs.JumpDown = Input.GetKeyDown(KeyCode.Space);
|
||||
|
||||
// Apply inputs to character
|
||||
Character.SetInputs(ref characterInputs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1d3de52431e52141b1432cc9c5a1a80
|
||||
timeCreated: 1507245715
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 402b3ab8c3fb82f4e8f07cd42854f159
|
||||
folderAsset: yes
|
||||
timeCreated: 1507245639
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,280 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using KinematicCharacterController;
|
||||
using System;
|
||||
|
||||
namespace KinematicCharacterController.Walkthrough.WallJumping
|
||||
{
|
||||
public struct PlayerCharacterInputs
|
||||
{
|
||||
public float MoveAxisForward;
|
||||
public float MoveAxisRight;
|
||||
public Quaternion CameraRotation;
|
||||
public bool JumpDown;
|
||||
}
|
||||
|
||||
public class MyCharacterController : MonoBehaviour, ICharacterController
|
||||
{
|
||||
public KinematicCharacterMotor Motor;
|
||||
|
||||
[Header("Stable Movement")]
|
||||
public float MaxStableMoveSpeed = 10f;
|
||||
public float StableMovementSharpness = 15;
|
||||
public float OrientationSharpness = 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 Vector3 _moveInputVector;
|
||||
private Vector3 _lookInputVector;
|
||||
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;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Assign to motor
|
||||
Motor.CharacterController = this;
|
||||
}
|
||||
|
||||
/// <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
|
||||
Vector3 moveInputVector = Vector3.ClampMagnitude(new Vector3(inputs.MoveAxisRight, 0f, inputs.MoveAxisForward), 1f);
|
||||
|
||||
// Calculate camera direction and rotation on the character plane
|
||||
Vector3 cameraPlanarDirection = Vector3.ProjectOnPlane(inputs.CameraRotation * Vector3.forward, Motor.CharacterUp).normalized;
|
||||
if (cameraPlanarDirection.sqrMagnitude == 0f)
|
||||
{
|
||||
cameraPlanarDirection = Vector3.ProjectOnPlane(inputs.CameraRotation * Vector3.up, Motor.CharacterUp).normalized;
|
||||
}
|
||||
Quaternion cameraPlanarRotation = Quaternion.LookRotation(cameraPlanarDirection, Motor.CharacterUp);
|
||||
|
||||
// Move and look inputs
|
||||
_moveInputVector = cameraPlanarRotation * moveInputVector;
|
||||
_lookInputVector = cameraPlanarDirection;
|
||||
|
||||
// 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 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 void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
|
||||
{
|
||||
if (_lookInputVector != Vector3.zero && OrientationSharpness > 0f)
|
||||
{
|
||||
// Smoothly interpolate from current to target look direction
|
||||
Vector3 smoothedLookInputDirection = Vector3.Slerp(Motor.CharacterForward, _lookInputVector, 1 - Mathf.Exp(-OrientationSharpness * deltaTime)).normalized;
|
||||
|
||||
// Set the current rotation (which will be used by the KinematicCharacterMotor)
|
||||
currentRotation = Quaternion.LookRotation(smoothedLookInputDirection, Motor.CharacterUp);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 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(_moveInputVector, Motor.CharacterUp);
|
||||
Vector3 reorientedInput = Vector3.Cross(Motor.GroundingStatus.GroundNormal, inputRight).normalized * _moveInputVector.magnitude;
|
||||
targetMovementVelocity = reorientedInput * MaxStableMoveSpeed;
|
||||
|
||||
// Smooth movement Velocity
|
||||
currentVelocity = Vector3.Lerp(currentVelocity, targetMovementVelocity, 1 - Mathf.Exp(-StableMovementSharpness * deltaTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add move input
|
||||
if (_moveInputVector.sqrMagnitude > 0f)
|
||||
{
|
||||
targetMovementVelocity = _moveInputVector * 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(0.1f);
|
||||
|
||||
// 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(0.1f);
|
||||
|
||||
// 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 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 bool IsColliderValidForCollisions(Collider coll)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
|
||||
{
|
||||
}
|
||||
|
||||
public 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 void PostGroundingUpdate(float deltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
public void AddVelocity(Vector3 velocity)
|
||||
{
|
||||
}
|
||||
|
||||
public void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnDiscreteCollisionDetected(Collider hitCollider)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2fd76c082aede85429438d24ce95942c
|
||||
timeCreated: 1507245754
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,91 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using KinematicCharacterController;
|
||||
using KinematicCharacterController.Examples;
|
||||
|
||||
namespace KinematicCharacterController.Walkthrough.WallJumping
|
||||
{
|
||||
public class MyPlayer : MonoBehaviour
|
||||
{
|
||||
public ExampleCharacterCamera OrbitCamera;
|
||||
public Transform CameraFollowPoint;
|
||||
public MyCharacterController Character;
|
||||
|
||||
private const string MouseXInput = "Mouse X";
|
||||
private const string MouseYInput = "Mouse Y";
|
||||
private const string MouseScrollInput = "Mouse ScrollWheel";
|
||||
private const string HorizontalInput = "Horizontal";
|
||||
private const string VerticalInput = "Vertical";
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Cursor.lockState = CursorLockMode.Locked;
|
||||
|
||||
// Tell camera to follow transform
|
||||
OrbitCamera.SetFollowTransform(CameraFollowPoint);
|
||||
|
||||
// Ignore the character's collider(s) for camera obstruction checks
|
||||
OrbitCamera.IgnoredColliders.Clear();
|
||||
OrbitCamera.IgnoredColliders.AddRange(Character.GetComponentsInChildren<Collider>());
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (Input.GetMouseButtonDown(0))
|
||||
{
|
||||
Cursor.lockState = CursorLockMode.Locked;
|
||||
}
|
||||
|
||||
HandleCharacterInput();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
HandleCameraInput();
|
||||
}
|
||||
|
||||
private void HandleCameraInput()
|
||||
{
|
||||
// Create the look input vector for the camera
|
||||
float mouseLookAxisUp = Input.GetAxisRaw(MouseYInput);
|
||||
float mouseLookAxisRight = Input.GetAxisRaw(MouseXInput);
|
||||
Vector3 lookInputVector = new Vector3(mouseLookAxisRight, mouseLookAxisUp, 0f);
|
||||
|
||||
// Prevent moving the camera while the cursor isn't locked
|
||||
if (Cursor.lockState != CursorLockMode.Locked)
|
||||
{
|
||||
lookInputVector = Vector3.zero;
|
||||
}
|
||||
|
||||
// Input for zooming the camera (disabled in WebGL because it can cause problems)
|
||||
float scrollInput = -Input.GetAxis(MouseScrollInput);
|
||||
#if UNITY_WEBGL
|
||||
scrollInput = 0f;
|
||||
#endif
|
||||
|
||||
// Apply inputs to the camera
|
||||
OrbitCamera.UpdateWithInput(Time.deltaTime, scrollInput, lookInputVector);
|
||||
|
||||
// Handle toggling zoom level
|
||||
if (Input.GetMouseButtonDown(1))
|
||||
{
|
||||
OrbitCamera.TargetDistance = (OrbitCamera.TargetDistance == 0f) ? OrbitCamera.DefaultDistance : 0f;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCharacterInput()
|
||||
{
|
||||
PlayerCharacterInputs characterInputs = new PlayerCharacterInputs();
|
||||
|
||||
// Build the CharacterInputs struct
|
||||
characterInputs.MoveAxisForward = Input.GetAxisRaw(VerticalInput);
|
||||
characterInputs.MoveAxisRight = Input.GetAxisRaw(HorizontalInput);
|
||||
characterInputs.CameraRotation = OrbitCamera.Transform.rotation;
|
||||
characterInputs.JumpDown = Input.GetKeyDown(KeyCode.Space);
|
||||
|
||||
// Apply inputs to character
|
||||
Character.SetInputs(ref characterInputs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ab774effe3d22149bec95ad5454a24c
|
||||
timeCreated: 1507245754
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user