移除ECM2
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e410a670998601e4c86e40c34747c170
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4ae63dacfed40dd8a3675e13b58068c
|
||||
timeCreated: 1702783925
|
||||
@@ -1,46 +0,0 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECM2.Editor
|
||||
{
|
||||
public static class CharacterFactoryEditor
|
||||
{
|
||||
private const string PATH = "GameObject/ECM2/";
|
||||
private const int PRIORITY = 1;
|
||||
|
||||
private static void InitPhysicsBody(GameObject go)
|
||||
{
|
||||
Rigidbody rb = go.GetComponent<Rigidbody>();
|
||||
|
||||
rb.linearDamping = 0.0f;
|
||||
rb.angularDamping = 0.0f;
|
||||
rb.useGravity = false;
|
||||
rb.isKinematic = true;
|
||||
rb.interpolation = RigidbodyInterpolation.Interpolate;
|
||||
|
||||
CapsuleCollider capsuleCollider = go.GetComponent<CapsuleCollider>();
|
||||
|
||||
capsuleCollider.center = new Vector3(0f, 1f, 0f);
|
||||
capsuleCollider.radius = 0.5f;
|
||||
capsuleCollider.height = 2.0f;
|
||||
}
|
||||
|
||||
[MenuItem(PATH + "Character", false, PRIORITY)]
|
||||
public static void CreateCharacter()
|
||||
{
|
||||
// Create an initialize a new Character GameObject
|
||||
|
||||
GameObject go = new GameObject("Character", typeof(Rigidbody), typeof(CapsuleCollider),
|
||||
typeof(CharacterMovement), typeof(Character));
|
||||
|
||||
InitPhysicsBody(go);
|
||||
|
||||
// Focus the newly created character
|
||||
|
||||
Undo.RegisterCreatedObjectUndo(go, "Create " + go.name);
|
||||
|
||||
Selection.activeGameObject = go;
|
||||
SceneView.FrameLastActiveSceneView();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 229efc90fc94436ca2b1a73d23c044c6
|
||||
timeCreated: 1702783950
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9f3fcc8c4084496b897827d8e50634a
|
||||
timeCreated: 1700450016
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 475ff761b0b75d14db323dd54effdaac
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c24b37cf05649248a32b248a93eb05d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 902a39e6598617c4596fd0bbc3ff7667
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57066912f8758f14b9bf7d2ece477e69
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 112000000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -1,117 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac5ca879376bdb94e9f4867550fde697
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
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
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 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}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 2
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 100
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2fe07f4fb0c44cf9a8cb190a16e0c4e8
|
||||
timeCreated: 1700523469
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ecf6744d31b373840925fd4dbd4cbf18
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82dc065f9f6f4cb4953fe304639ea0ea
|
||||
timeCreated: 1700707754
|
||||
@@ -1,47 +0,0 @@
|
||||
using ECM2.Examples.FirstPerson;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECM2.Examples.FirstPersonFly
|
||||
{
|
||||
/// <summary>
|
||||
/// Regular First Person Character Input. Shows how to handle movement while flying.
|
||||
/// In this case, we allow to fly towards our view direction, allowing to freely move through the air.
|
||||
/// </summary>
|
||||
|
||||
public class FirstPersonFlyInput : FirstPersonInput
|
||||
{
|
||||
protected override void HandleInput()
|
||||
{
|
||||
// Call base method implementation
|
||||
|
||||
base.HandleInput();
|
||||
|
||||
if (character.IsFlying())
|
||||
{
|
||||
// Movement when Flying
|
||||
|
||||
Vector2 movementInput = GetMovementInput();
|
||||
Vector3 movementDirection = Vector3.zero;
|
||||
|
||||
// Strafe
|
||||
|
||||
movementDirection += character.GetRightVector() * movementInput.x;
|
||||
|
||||
// Forward, along camera view direction (if any) or along character's forward if camera not found
|
||||
|
||||
Vector3 forward = character.camera
|
||||
? character.cameraTransform.forward
|
||||
: character.GetForwardVector();
|
||||
|
||||
movementDirection += forward * movementInput.y;
|
||||
|
||||
// Vertical movement
|
||||
|
||||
if (character.jumpInputPressed)
|
||||
movementDirection += Vector3.up;
|
||||
|
||||
character.SetMovementDirection(movementDirection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbbf3b9b979aa9d46901c3742b3c1230
|
||||
@@ -1,85 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECM2.Examples.FirstPersonFly
|
||||
{
|
||||
/// <summary>
|
||||
/// This example shows how to extend a Character (through composition) and use
|
||||
/// its Flying movement mode to implement a fly ability.
|
||||
///
|
||||
/// Flying movement mode needs to be manually enabled / disabled as needed.
|
||||
/// </summary>
|
||||
|
||||
public class FlyAbility : MonoBehaviour
|
||||
{
|
||||
public bool canEverFly = true;
|
||||
|
||||
private Character _character;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the Character is able to fly in its current state.
|
||||
/// </summary>
|
||||
|
||||
private bool IsFlyAllowed()
|
||||
{
|
||||
return canEverFly && _character.IsFalling();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the character should enter flying movement mode.
|
||||
/// </summary>
|
||||
|
||||
protected virtual bool CanFly()
|
||||
{
|
||||
bool isFlyAllowed = IsFlyAllowed();
|
||||
|
||||
if (isFlyAllowed)
|
||||
{
|
||||
// If Fly is allowed, determine if is falling down otherwise its a jump!
|
||||
|
||||
Vector3 worldUp = -_character.GetGravityDirection();
|
||||
float verticalSpeed = Vector3.Dot(_character.GetVelocity(), worldUp);
|
||||
|
||||
isFlyAllowed = verticalSpeed < 0.0f;
|
||||
}
|
||||
|
||||
return isFlyAllowed;
|
||||
}
|
||||
|
||||
private void OnCollided(ref CollisionResult collisionResult)
|
||||
{
|
||||
// If flying and collided with walkable ground, exit flying state.
|
||||
// I.e: Change to Falling movement mode as this is managed based on grounding status.
|
||||
|
||||
if (_character.IsFlying() && collisionResult.isWalkable)
|
||||
_character.SetMovementMode(Character.MovementMode.Falling);
|
||||
}
|
||||
|
||||
private void OnBeforeSimulationUpdated(float deltaTime)
|
||||
{
|
||||
// Attempts to enter Flying movement mode
|
||||
|
||||
bool isFlying = _character.IsFlying();
|
||||
bool wantsToFly = _character.jumpInputPressed;
|
||||
|
||||
if (!isFlying && wantsToFly && CanFly())
|
||||
_character.SetMovementMode(Character.MovementMode.Flying);
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_character = GetComponent<Character>();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_character.Collided += OnCollided;
|
||||
_character.BeforeSimulationUpdated += OnBeforeSimulationUpdated;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_character.Collided -= OnCollided;
|
||||
_character.BeforeSimulationUpdated -= OnBeforeSimulationUpdated;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bda31f3d5180a634f93709c79f028bce
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 815661453b364202904d788f5432336a
|
||||
timeCreated: 1700523481
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f6e4d053a8307d4c820c4452d96fc36
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66684442958e47e4bcf3c569fe375813
|
||||
timeCreated: 1700707789
|
||||
@@ -1,62 +0,0 @@
|
||||
using ECM2.Examples.FirstPerson;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECM2.Examples.FirstPersonSwim
|
||||
{
|
||||
/// <summary>
|
||||
/// This example shows how to handle movement while swimming.
|
||||
/// Here, we allow to swim towards our view direction, allowing to freely move through the water.
|
||||
///
|
||||
/// Swimming is automatically enabled / disabled when Water Physics Volume is used,
|
||||
/// otherwise it must be enabled / disabled as needed.
|
||||
/// </summary>
|
||||
|
||||
public class FirstPersonSwimInput : FirstPersonInput
|
||||
{
|
||||
protected override void HandleInput()
|
||||
{
|
||||
// Call base method implementation
|
||||
|
||||
base.HandleInput();
|
||||
|
||||
if (character.IsSwimming())
|
||||
{
|
||||
// Handle movement when swimming
|
||||
|
||||
// Strafe
|
||||
|
||||
Vector2 movementInput = GetMovementInput();
|
||||
Vector3 movementDirection = Vector3.zero;
|
||||
movementDirection += character.GetRightVector() * movementInput.x;
|
||||
|
||||
// Forward, along camera view direction (if any) or along character's forward if camera not found
|
||||
|
||||
Vector3 forward =
|
||||
character.camera ? character.cameraTransform.forward : character.GetForwardVector();
|
||||
|
||||
movementDirection += forward * movementInput.y;
|
||||
|
||||
// Vertical movement
|
||||
|
||||
if (character.jumpInputPressed)
|
||||
{
|
||||
// Use immersion depth to check if we are at top of water line,
|
||||
// if yes, jump of water
|
||||
|
||||
float depth = character.CalcImmersionDepth();
|
||||
if (depth > 0.65f)
|
||||
movementDirection += character.GetUpVector();
|
||||
else
|
||||
{
|
||||
// Jump out of water
|
||||
|
||||
character.SetMovementMode(Character.MovementMode.Falling);
|
||||
character.LaunchCharacter(character.GetUpVector() * 9.0f, true);
|
||||
}
|
||||
}
|
||||
|
||||
character.SetMovementDirection(movementDirection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 492ff1da6c6e3884bbc194a74442b56b
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6f0ddb4d2c11864ebefcdf23c9f5b1e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ba11ada392fd66943aa0802367e37654
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 800cd5310655eb943a19e700021158a6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,72 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECM2.Examples.FirstPerson
|
||||
{
|
||||
/// <summary>
|
||||
/// This example extends a Character (through inheritance), implementing a First Person control.
|
||||
/// </summary>
|
||||
|
||||
public class FirstPersonCharacter : Character
|
||||
{
|
||||
[Tooltip("The first person camera parent.")]
|
||||
public GameObject cameraParent;
|
||||
|
||||
private float _cameraPitch;
|
||||
|
||||
/// <summary>
|
||||
/// Add input (affecting Yaw).
|
||||
/// This is applied to the Character's rotation.
|
||||
/// </summary>
|
||||
|
||||
public virtual void AddControlYawInput(float value)
|
||||
{
|
||||
if (value != 0.0f)
|
||||
AddYawInput(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add input (affecting Pitch).
|
||||
/// This is applied to the cameraParent's local rotation.
|
||||
/// </summary>
|
||||
|
||||
public virtual void AddControlPitchInput(float value, float minPitch = -80.0f, float maxPitch = 80.0f)
|
||||
{
|
||||
if (value != 0.0f)
|
||||
_cameraPitch = MathLib.ClampAngle(_cameraPitch + value, minPitch, maxPitch);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update cameraParent local rotation applying current _cameraPitch value.
|
||||
/// </summary>
|
||||
|
||||
protected virtual void UpdateCameraParentRotation()
|
||||
{
|
||||
cameraParent.transform.localRotation = Quaternion.Euler(_cameraPitch, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If overriden, base method MUST be called.
|
||||
/// </summary>
|
||||
|
||||
protected virtual void LateUpdate()
|
||||
{
|
||||
UpdateCameraParentRotation();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If overriden, base method MUST be called.
|
||||
/// </summary>
|
||||
|
||||
protected override void Reset()
|
||||
{
|
||||
// Call base method implementation
|
||||
|
||||
base.Reset();
|
||||
|
||||
// Disable character's rotation,
|
||||
// it is handled by the AddControlYawInput method
|
||||
|
||||
SetRotationMode(RotationMode.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 713b3a549961cf64d88d9131fdc9be1a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,114 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace ECM2.Examples.FirstPerson
|
||||
{
|
||||
/// <summary>
|
||||
/// First person character input.
|
||||
/// Extends the default CharacterInput component adding support for typical first person controls.
|
||||
/// </summary>
|
||||
|
||||
public class FirstPersonInput : CharacterInput
|
||||
{
|
||||
[Space(15.0f)]
|
||||
public bool invertLook = true;
|
||||
[Tooltip("Look sensitivity")]
|
||||
public Vector2 sensitivity = new Vector2(0.05f, 0.05f);
|
||||
|
||||
[Space(15.0f)]
|
||||
[Tooltip("How far in degrees can you move the camera down.")]
|
||||
public float minPitch = -80.0f;
|
||||
[Tooltip("How far in degrees can you move the camera up.")]
|
||||
public float maxPitch = 80.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Cached FirstPersonCharacter.
|
||||
/// </summary>
|
||||
|
||||
public FirstPersonCharacter firstPersonCharacter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Movement InputAction.
|
||||
/// </summary>
|
||||
|
||||
public InputAction lookInputAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Polls look InputAction (if any).
|
||||
/// Return its current value or zero if no valid InputAction found.
|
||||
/// </summary>
|
||||
|
||||
public Vector2 GetLookInput()
|
||||
{
|
||||
return lookInputAction?.ReadValue<Vector2>() ?? Vector2.zero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize player InputActions (if any).
|
||||
/// E.g. Subscribe to input action events and enable input actions here.
|
||||
/// </summary>
|
||||
|
||||
protected override void InitPlayerInput()
|
||||
{
|
||||
base.InitPlayerInput();
|
||||
|
||||
// Look input action (no handler, this is polled, e.g. GetLookInput())
|
||||
|
||||
lookInputAction = inputActionsAsset.FindAction("Look");
|
||||
lookInputAction?.Enable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribe from input action events and disable input actions.
|
||||
/// </summary>
|
||||
|
||||
protected override void DeinitPlayerInput()
|
||||
{
|
||||
base.DeinitPlayerInput();
|
||||
|
||||
// Unsubscribe from input action events and disable input actions
|
||||
|
||||
if (lookInputAction != null)
|
||||
{
|
||||
lookInputAction.Disable();
|
||||
lookInputAction = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
firstPersonCharacter = character as FirstPersonCharacter;
|
||||
}
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
Cursor.lockState = CursorLockMode.Locked;
|
||||
}
|
||||
|
||||
protected override void HandleInput()
|
||||
{
|
||||
// Move
|
||||
|
||||
Vector2 movementInput = GetMovementInput();
|
||||
|
||||
Vector3 movementDirection = Vector3.zero;
|
||||
|
||||
movementDirection += Vector3.forward * movementInput.y;
|
||||
movementDirection += Vector3.right * movementInput.x;
|
||||
|
||||
movementDirection =
|
||||
movementDirection.relativeTo(firstPersonCharacter.cameraTransform, firstPersonCharacter.GetUpVector());
|
||||
|
||||
firstPersonCharacter.SetMovementDirection(movementDirection);
|
||||
|
||||
// Look
|
||||
|
||||
Vector2 lookInput = GetLookInput() * sensitivity;
|
||||
|
||||
firstPersonCharacter.AddControlYawInput(lookInput.x);
|
||||
firstPersonCharacter.AddControlPitchInput(invertLook ? -lookInput.y : lookInput.y, minPitch, maxPitch);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ba598d44e33b26849a4d3d6005e49fd1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43bf17ba2afdabe47a7815ab3d6c2cd6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e74b0d624806d3a44945b1bbb4524553
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 137e5ade8532c7b4bbcc84ad8d35487d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,115 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECM2.Examples.Glide
|
||||
{
|
||||
/// <summary>
|
||||
/// This example shows how to extend a Character (through composition) implementing a Glide mechanic.
|
||||
/// </summary>
|
||||
|
||||
public class GlideAbility : MonoBehaviour
|
||||
{
|
||||
public bool canEverGlide = true;
|
||||
public float maxFallSpeedGliding = 1.0f;
|
||||
|
||||
private Character _character;
|
||||
|
||||
protected bool _glideInputPressed;
|
||||
protected bool _isGliding;
|
||||
|
||||
public bool glideInputPressed => _glideInputPressed;
|
||||
|
||||
/// <summary>
|
||||
/// Is the Character gliding?
|
||||
/// </summary>
|
||||
|
||||
public virtual bool IsGliding()
|
||||
{
|
||||
return _isGliding;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to start a glide.
|
||||
/// </summary>
|
||||
|
||||
public virtual void Glide()
|
||||
{
|
||||
_glideInputPressed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request to stop gliding.
|
||||
/// </summary>
|
||||
|
||||
public virtual void StopGliding()
|
||||
{
|
||||
_glideInputPressed = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the character is able to perform a glide in its current state.
|
||||
/// </summary>
|
||||
|
||||
protected virtual bool IsGlideAllowed()
|
||||
{
|
||||
return canEverGlide && _character.IsFalling();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the character can perform a requested glide.
|
||||
/// </summary>
|
||||
|
||||
protected virtual bool CanGlide()
|
||||
{
|
||||
bool isGlideAllowed = IsGlideAllowed();
|
||||
|
||||
if (isGlideAllowed)
|
||||
{
|
||||
Vector3 worldUp = -_character.GetGravityDirection();
|
||||
float verticalSpeed = Vector3.Dot(_character.GetVelocity(), worldUp);
|
||||
|
||||
isGlideAllowed = verticalSpeed < 0.0f;
|
||||
}
|
||||
|
||||
return isGlideAllowed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start / Stop a requested glide.
|
||||
/// </summary>
|
||||
|
||||
protected virtual void CheckGlideInput()
|
||||
{
|
||||
if (!_isGliding && _glideInputPressed && CanGlide())
|
||||
{
|
||||
_isGliding = true;
|
||||
_character.maxFallSpeed = maxFallSpeedGliding;
|
||||
|
||||
}
|
||||
else if (_isGliding && (!_glideInputPressed || !CanGlide()))
|
||||
{
|
||||
_isGliding = false;
|
||||
_character.maxFallSpeed = 40.0f;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBeforeCharacterSimulationUpdated(float deltaTime)
|
||||
{
|
||||
CheckGlideInput();
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_character = GetComponent<Character>();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_character.BeforeSimulationUpdated += OnBeforeCharacterSimulationUpdated;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_character.BeforeSimulationUpdated -= OnBeforeCharacterSimulationUpdated;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d97f3b8906b7417e88698c51eb7e04c8
|
||||
timeCreated: 1700291875
|
||||
@@ -1,38 +0,0 @@
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace ECM2.Examples.Glide
|
||||
{
|
||||
/// <summary>
|
||||
/// Extends default Character Input to handle GlideAbility Input.
|
||||
/// </summary>
|
||||
|
||||
public class GlideInput : CharacterInput
|
||||
{
|
||||
private GlideAbility _glideAbility;
|
||||
|
||||
/// <summary>
|
||||
/// Extend OnJump handler to add GlideAbility input support.
|
||||
/// </summary>
|
||||
|
||||
public override void OnJump(InputAction.CallbackContext context)
|
||||
{
|
||||
// Call base method implementation (handle jump)
|
||||
|
||||
base.OnJump(context);
|
||||
|
||||
if (context.started)
|
||||
_glideAbility.Glide();
|
||||
else if (context.canceled)
|
||||
_glideAbility.StopGliding();
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
// Cache Glide Ability
|
||||
|
||||
_glideAbility = GetComponent<GlideAbility>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49ae0493228344b5b3bdfc1bf5545e57
|
||||
timeCreated: 1700292768
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa1a2b686f299e74e923e08fcae397f6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f75d14915da71e7428ad9168e63a1789
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5be7a2664b8bb6b4c9d56b86dc8964c0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,413 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECM2.Examples.Jump
|
||||
{
|
||||
/// <summary>
|
||||
/// This example shows how to extend a Character (through composition) implementing a jump ability.
|
||||
/// This is the exact jump available in the Character class before v1.4.
|
||||
/// </summary>
|
||||
|
||||
public class JumpAbility : MonoBehaviour
|
||||
{
|
||||
[Space(15f)]
|
||||
[Tooltip("Is the character able to jump ?")]
|
||||
[SerializeField]
|
||||
private bool _canEverJump;
|
||||
|
||||
[Tooltip("Can jump while crouching ?")]
|
||||
[SerializeField]
|
||||
private bool _jumpWhileCrouching;
|
||||
|
||||
[Tooltip("The max number of jumps the Character can perform.")]
|
||||
[SerializeField]
|
||||
private int _jumpMaxCount;
|
||||
|
||||
[Tooltip("Initial velocity (instantaneous vertical velocity) when jumping.")]
|
||||
[SerializeField]
|
||||
private float _jumpImpulse;
|
||||
|
||||
[Tooltip("The maximum time (in seconds) to hold the jump. eg: Variable height jump.")]
|
||||
[SerializeField]
|
||||
private float _jumpMaxHoldTime;
|
||||
|
||||
[Tooltip("How early before hitting the ground you can trigger a jump (in seconds).")]
|
||||
[SerializeField]
|
||||
private float _jumpPreGroundedTime;
|
||||
|
||||
[Tooltip("How long after leaving the ground you can trigger a jump (in seconds).")]
|
||||
[SerializeField]
|
||||
private float _jumpPostGroundedTime;
|
||||
|
||||
private Character _character;
|
||||
|
||||
protected bool _jumpButtonPressed;
|
||||
protected float _jumpButtonHeldDownTime;
|
||||
protected float _jumpHoldTime;
|
||||
protected int _jumpCount;
|
||||
protected bool _isJumping;
|
||||
|
||||
/// <summary>
|
||||
/// Is the character able to jump ?
|
||||
/// </summary>
|
||||
|
||||
public bool canEverJump
|
||||
{
|
||||
get => _canEverJump;
|
||||
set => _canEverJump = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can jump while crouching ?
|
||||
/// </summary>
|
||||
|
||||
public bool jumpWhileCrouching
|
||||
{
|
||||
get => _jumpWhileCrouching;
|
||||
set => _jumpWhileCrouching = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The max number of jumps the Character can perform.
|
||||
/// </summary>
|
||||
|
||||
public int jumpMaxCount
|
||||
{
|
||||
get => _jumpMaxCount;
|
||||
set => _jumpMaxCount = Mathf.Max(1, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initial velocity (instantaneous vertical velocity) when jumping.
|
||||
/// </summary>
|
||||
|
||||
public float jumpImpulse
|
||||
{
|
||||
get => _jumpImpulse;
|
||||
set => _jumpImpulse = Mathf.Max(0.0f, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The maximum time (in seconds) to hold the jump. eg: Variable height jump.
|
||||
/// </summary>
|
||||
|
||||
public float jumpMaxHoldTime
|
||||
{
|
||||
get => _jumpMaxHoldTime;
|
||||
set => _jumpMaxHoldTime = Mathf.Max(0.0f, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// How early before hitting the ground you can trigger a jump (in seconds).
|
||||
/// </summary>
|
||||
|
||||
public float jumpPreGroundedTime
|
||||
{
|
||||
get => _jumpPreGroundedTime;
|
||||
set => _jumpPreGroundedTime = Mathf.Max(0.0f, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// How long after leaving the ground you can trigger a jump (in seconds).
|
||||
/// </summary>
|
||||
|
||||
public float jumpPostGroundedTime
|
||||
{
|
||||
get => _jumpPostGroundedTime;
|
||||
set => _jumpPostGroundedTime = Mathf.Max(0.0f, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True is _jumpButtonPressed is true, false otherwise.
|
||||
/// </summary>
|
||||
|
||||
public bool jumpButtonPressed => _jumpButtonPressed;
|
||||
|
||||
/// <summary>
|
||||
/// This is the time (in seconds) that the player has held the jump button.
|
||||
/// </summary>
|
||||
|
||||
public float jumpButtonHeldDownTime => _jumpButtonHeldDownTime;
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the current number of jumps performed.
|
||||
/// </summary>
|
||||
|
||||
public int jumpCount => _jumpCount;
|
||||
|
||||
/// <summary>
|
||||
/// This is the time (in seconds) that the player has been holding the jump.
|
||||
/// Eg: Variable height jump.
|
||||
/// </summary>
|
||||
|
||||
public float jumpHoldTime => _jumpHoldTime;
|
||||
|
||||
/// <summary>
|
||||
/// Is the Character jumping ?
|
||||
/// </summary>
|
||||
|
||||
public virtual bool IsJumping()
|
||||
{
|
||||
return _isJumping;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a jump.
|
||||
/// Call this from an input event (such as a button 'down' event).
|
||||
/// </summary>
|
||||
|
||||
public void Jump()
|
||||
{
|
||||
_jumpButtonPressed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop the Character from jumping.
|
||||
/// Call this from an input event (such as a button 'up' event).
|
||||
/// </summary>
|
||||
|
||||
public void StopJumping()
|
||||
{
|
||||
// Input state
|
||||
|
||||
_jumpButtonPressed = false;
|
||||
_jumpButtonHeldDownTime = 0.0f;
|
||||
|
||||
// Jump holding state
|
||||
|
||||
_isJumping = false;
|
||||
_jumpHoldTime = 0.0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current jump count.
|
||||
/// </summary>
|
||||
|
||||
public virtual int GetJumpCount()
|
||||
{
|
||||
return _jumpCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the Character is able to perform the requested jump.
|
||||
/// </summary>
|
||||
|
||||
public virtual bool CanJump()
|
||||
{
|
||||
// Is character even able to jump ?
|
||||
|
||||
if (!canEverJump)
|
||||
return false;
|
||||
|
||||
// Can jump while crouching ?
|
||||
|
||||
if (_character.IsCrouched() && !jumpWhileCrouching)
|
||||
return false;
|
||||
|
||||
// Cant jump if no jumps available
|
||||
|
||||
if (jumpMaxCount == 0 || _jumpCount >= jumpMaxCount)
|
||||
return false;
|
||||
|
||||
// Is fist jump ?
|
||||
|
||||
if (_jumpCount == 0)
|
||||
{
|
||||
// On first jump,
|
||||
// can jump if is walking or is falling BUT withing post grounded time
|
||||
|
||||
bool canJump = _character.IsWalking() ||
|
||||
_character.IsFalling() && jumpPostGroundedTime > 0.0f && _character.fallingTime < jumpPostGroundedTime;
|
||||
|
||||
// Missed post grounded time ?
|
||||
|
||||
if (_character.IsFalling() && !canJump)
|
||||
{
|
||||
// Missed post grounded time,
|
||||
// can jump if have any 'in-air' jumps but the first jump counts as the in-air jump
|
||||
|
||||
canJump = jumpMaxCount > 1;
|
||||
if (canJump)
|
||||
_jumpCount++;
|
||||
}
|
||||
|
||||
return canJump;
|
||||
}
|
||||
|
||||
// In air jump conditions...
|
||||
|
||||
return _character.IsFalling();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the jump impulse vector.
|
||||
/// </summary>
|
||||
|
||||
protected virtual Vector3 CalcJumpImpulse()
|
||||
{
|
||||
Vector3 worldUp = -_character.GetGravityDirection();
|
||||
|
||||
float verticalSpeed = Vector3.Dot(_character.GetVelocity(), worldUp);
|
||||
float actualJumpImpulse = Mathf.Max(verticalSpeed, jumpImpulse);
|
||||
|
||||
return worldUp * actualJumpImpulse;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to perform a requested jump.
|
||||
/// </summary>
|
||||
|
||||
protected virtual void DoJump(float deltaTime)
|
||||
{
|
||||
// Update held down timer
|
||||
|
||||
if (_jumpButtonPressed)
|
||||
_jumpButtonHeldDownTime += deltaTime;
|
||||
|
||||
// Wants to jump and not already jumping..
|
||||
|
||||
if (_jumpButtonPressed && !IsJumping())
|
||||
{
|
||||
// If jumpPreGroundedTime is enabled,
|
||||
// allow to jump only if held down time is less than tolerance
|
||||
|
||||
if (jumpPreGroundedTime > 0.0f)
|
||||
{
|
||||
bool canJump = _jumpButtonHeldDownTime <= jumpPreGroundedTime;
|
||||
if (!canJump)
|
||||
return;
|
||||
}
|
||||
|
||||
// Can perform the requested jump ?
|
||||
|
||||
if (CanJump())
|
||||
{
|
||||
// Jump!
|
||||
|
||||
_character.SetMovementMode(Character.MovementMode.Falling);
|
||||
|
||||
_character.PauseGroundConstraint();
|
||||
_character.LaunchCharacter(CalcJumpImpulse(), true);
|
||||
|
||||
_jumpCount++;
|
||||
_isJumping = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle jumping state.
|
||||
/// Eg: check input, perform jump hold (jumpMaxHoldTime > 0), etc.
|
||||
/// </summary>
|
||||
|
||||
protected virtual void Jumping(float deltaTime)
|
||||
{
|
||||
// Is character allowed to jump ?
|
||||
|
||||
if (!canEverJump)
|
||||
{
|
||||
// If not allowed but was jumping, stop jump
|
||||
|
||||
if (IsJumping())
|
||||
StopJumping();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check jump input state and attempts to do the requested jump
|
||||
|
||||
DoJump(deltaTime);
|
||||
|
||||
// Perform jump hold, applies an opposite gravity force proportional to _jumpHoldTime.
|
||||
|
||||
if (IsJumping() && _jumpButtonPressed && jumpMaxHoldTime > 0.0f && _jumpHoldTime < jumpMaxHoldTime)
|
||||
{
|
||||
Vector3 actualGravity = _character.GetGravityVector();
|
||||
|
||||
float actualGravityMagnitude = actualGravity.magnitude;
|
||||
Vector3 actualGravityDirection = actualGravityMagnitude > 0.0f
|
||||
? actualGravity / actualGravityMagnitude
|
||||
: Vector3.zero;
|
||||
|
||||
float jumpProgress = Mathf.InverseLerp(0.0f, jumpMaxHoldTime, _jumpHoldTime);
|
||||
float proportionalForce = Mathf.LerpUnclamped(actualGravityMagnitude, 0.0f, jumpProgress);
|
||||
|
||||
Vector3 proportionalJumpForce = -actualGravityDirection * proportionalForce;
|
||||
_character.AddForce(proportionalJumpForce);
|
||||
|
||||
_jumpHoldTime += deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnMovementModeChanged(Character.MovementMode prevMovementMode, int prevCustomMode)
|
||||
{
|
||||
if (_character.IsWalking())
|
||||
_jumpCount = 0;
|
||||
else if (_character.IsFlying() || _character.IsSwimming())
|
||||
StopJumping();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If overriden, base method MUST be called.
|
||||
/// </summary>
|
||||
|
||||
protected virtual void Reset()
|
||||
{
|
||||
_canEverJump = true;
|
||||
_jumpWhileCrouching = true;
|
||||
_jumpMaxCount = 1;
|
||||
_jumpImpulse = 5.0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If overriden, base method MUST be called.
|
||||
/// </summary>
|
||||
protected virtual void OnValidate()
|
||||
{
|
||||
jumpMaxCount = _jumpMaxCount;
|
||||
jumpImpulse = _jumpImpulse;
|
||||
jumpMaxHoldTime = _jumpMaxHoldTime;
|
||||
jumpPreGroundedTime = _jumpPreGroundedTime;
|
||||
jumpPostGroundedTime = _jumpPostGroundedTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If overriden, base method MUST be called.
|
||||
/// </summary>
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
_character = GetComponent<Character>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If overriden, base method MUST be called.
|
||||
/// </summary>
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
_character.MovementModeChanged += OnMovementModeChanged;
|
||||
_character.BeforeSimulationUpdated += Jumping;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If overriden, base method MUST be called.
|
||||
/// </summary>
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
_character.BeforeSimulationUpdated -= Jumping;
|
||||
_character.MovementModeChanged -= OnMovementModeChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If overriden, base method MUST be called.
|
||||
/// </summary>
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
// Disable Character built-in jump
|
||||
|
||||
_character.canEverJump = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 06597227e58abd64eb2b11f0a43d4219
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,36 +0,0 @@
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace ECM2.Examples.Jump
|
||||
{
|
||||
/// <summary>
|
||||
/// Extends default Character Input to handle JumpAbility Input.
|
||||
/// </summary>
|
||||
|
||||
public class JumpInput : CharacterInput
|
||||
{
|
||||
// The jump ability
|
||||
|
||||
private JumpAbility _jumpAbility;
|
||||
|
||||
/// <summary>
|
||||
/// Extend OnJump handler to manage JumpAbility input.
|
||||
/// </summary>
|
||||
|
||||
public override void OnJump(InputAction.CallbackContext context)
|
||||
{
|
||||
if (context.started)
|
||||
_jumpAbility.Jump();
|
||||
else if (context.canceled)
|
||||
_jumpAbility.StopJumping();
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
// Cache JumpAbility
|
||||
|
||||
_jumpAbility = GetComponent<JumpAbility>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b75fe96fbf5426a80316e1303c9fa5c
|
||||
timeCreated: 1700900486
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4769c4722c8844c49d187dbe2b9c7bad
|
||||
timeCreated: 1700523532
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2251171a89ad034d9cdb694d2cc700f
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 593d3397361c48ab9f2a4688ec660199
|
||||
timeCreated: 1700524424
|
||||
@@ -1,76 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECM2.Examples.Ladders
|
||||
{
|
||||
public sealed class Ladder : MonoBehaviour
|
||||
{
|
||||
#region EDITOR EXPOSED FIELDS
|
||||
|
||||
[Header("Ladder Path")]
|
||||
public float PathLength = 10.0f;
|
||||
public Vector3 PathOffset = new Vector3(0f, 0f, -0.5f);
|
||||
|
||||
[Header("Anchor Points")]
|
||||
public Transform TopPoint;
|
||||
public Transform BottomPoint;
|
||||
|
||||
#endregion
|
||||
|
||||
#region PROPERTIES
|
||||
|
||||
public Vector3 bottomAnchorPoint => transform.position + transform.TransformVector(PathOffset);
|
||||
|
||||
public Vector3 topAnchorPoint => bottomAnchorPoint + transform.up * PathLength;
|
||||
|
||||
#endregion
|
||||
|
||||
#region METHODS
|
||||
|
||||
public Vector3 ClosestPointOnPath(Vector3 position, out float pathPosition)
|
||||
{
|
||||
Vector3 path = topAnchorPoint - bottomAnchorPoint;
|
||||
Vector3 pathToPoint = position - bottomAnchorPoint;
|
||||
|
||||
float height = Vector3.Dot(pathToPoint, path.normalized);
|
||||
|
||||
if (height > 0.0f)
|
||||
{
|
||||
// If we are below top point
|
||||
|
||||
if (height <= path.magnitude)
|
||||
{
|
||||
pathPosition = 0;
|
||||
return bottomAnchorPoint + path.normalized * height;
|
||||
}
|
||||
|
||||
// If we are higher than top point
|
||||
|
||||
pathPosition = height - path.magnitude;
|
||||
return topAnchorPoint;
|
||||
}
|
||||
|
||||
// Below bottom point
|
||||
|
||||
pathPosition = height;
|
||||
return bottomAnchorPoint;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MONOBEHAVIOUR
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawLine(bottomAnchorPoint, topAnchorPoint);
|
||||
|
||||
if (BottomPoint == null || TopPoint == null)
|
||||
return;
|
||||
|
||||
Gizmos.DrawWireCube(BottomPoint.position, Vector3.one * 0.25f);
|
||||
Gizmos.DrawWireCube(TopPoint.position, Vector3.one * 0.25f);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eaeb4b7f9b0647b4ba93dc7f142b09f6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,287 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECM2.Examples.Ladders
|
||||
{
|
||||
/// <summary>
|
||||
/// This example shows how to extend a Character (through composition) adding a custom movement mode.
|
||||
/// Here we implement a ladder climbing ability using a Climbing custom movement mode.
|
||||
/// </summary>
|
||||
|
||||
public class LadderClimbAbility : MonoBehaviour
|
||||
{
|
||||
public enum CustomMovementMode
|
||||
{
|
||||
Climbing = 1
|
||||
}
|
||||
|
||||
public enum ClimbingState
|
||||
{
|
||||
None,
|
||||
Grabbing,
|
||||
Grabbed,
|
||||
Releasing
|
||||
}
|
||||
|
||||
public float climbingSpeed = 5.0f;
|
||||
public float grabbingTime = 0.25f;
|
||||
|
||||
public LayerMask ladderMask;
|
||||
|
||||
private Character _character;
|
||||
|
||||
private Ladder _activeLadder;
|
||||
private float _ladderPathPosition;
|
||||
|
||||
private Vector3 _ladderStartPosition;
|
||||
private Vector3 _ladderTargetPosition;
|
||||
|
||||
private Quaternion _ladderStartRotation;
|
||||
private Quaternion _ladderTargetRotation;
|
||||
|
||||
private float _ladderTime;
|
||||
|
||||
private ClimbingState _climbingState;
|
||||
|
||||
private Character.RotationMode _previousRotationMode;
|
||||
|
||||
/// <summary>
|
||||
/// True if the Character is in Climbing custom movement mode, false otherwise.
|
||||
/// </summary>
|
||||
|
||||
public bool IsClimbing()
|
||||
{
|
||||
bool isClimbing = _character.movementMode == Character.MovementMode.Custom &&
|
||||
_character.customMovementMode == (int)CustomMovementMode.Climbing;
|
||||
|
||||
return isClimbing;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the Character is able to climb.
|
||||
/// </summary>
|
||||
|
||||
private bool CanClimb()
|
||||
{
|
||||
// Do not allow to climb if crouching
|
||||
|
||||
if (_character.IsCrouched())
|
||||
return false;
|
||||
|
||||
// Attempt to find a ladder
|
||||
|
||||
CharacterMovement characterMovement = _character.characterMovement;
|
||||
var overlappedColliders =
|
||||
characterMovement.OverlapTest(ladderMask, QueryTriggerInteraction.Collide, out int overlapCount);
|
||||
|
||||
if (overlapCount == 0)
|
||||
return false;
|
||||
|
||||
// Is a ladder ?
|
||||
|
||||
if (!overlappedColliders[0].TryGetComponent(out Ladder ladder))
|
||||
return false;
|
||||
|
||||
// Found a ladder, make it active ladder and return
|
||||
|
||||
_activeLadder = ladder;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a climb.
|
||||
/// Call this from an input event (such as a button 'down' event).
|
||||
/// </summary>
|
||||
|
||||
public void Climb()
|
||||
{
|
||||
if (IsClimbing() || !CanClimb())
|
||||
return;
|
||||
|
||||
_character.SetMovementMode(Character.MovementMode.Custom, (int) CustomMovementMode.Climbing);
|
||||
|
||||
_ladderStartPosition = _character.GetPosition();
|
||||
_ladderTargetPosition = _activeLadder.ClosestPointOnPath(_ladderStartPosition, out _ladderPathPosition);
|
||||
|
||||
_ladderStartRotation = _character.GetRotation();
|
||||
_ladderTargetRotation = _activeLadder.transform.rotation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop the Character from climbing.
|
||||
/// Call this from an input event (such as a button 'up' event).
|
||||
/// </summary>
|
||||
|
||||
public void StopClimbing()
|
||||
{
|
||||
if (!IsClimbing() || _climbingState != ClimbingState.Grabbed)
|
||||
return;
|
||||
|
||||
_climbingState = ClimbingState.Releasing;
|
||||
|
||||
_ladderStartPosition = _character.GetPosition();
|
||||
_ladderStartRotation = _character.GetRotation();
|
||||
|
||||
_ladderTargetPosition = _ladderStartPosition;
|
||||
_ladderTargetRotation = _activeLadder.BottomPoint.rotation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform climbing movement.
|
||||
/// </summary>
|
||||
|
||||
private void ClimbingMovementMode(float deltaTime)
|
||||
{
|
||||
Vector3 velocity = Vector3.zero;
|
||||
|
||||
switch (_climbingState)
|
||||
{
|
||||
case ClimbingState.Grabbing:
|
||||
case ClimbingState.Releasing:
|
||||
{
|
||||
_ladderTime += deltaTime;
|
||||
|
||||
if (_ladderTime <= grabbingTime)
|
||||
{
|
||||
Vector3 interpolatedPosition = Vector3.Lerp(_ladderStartPosition, _ladderTargetPosition, _ladderTime / grabbingTime);
|
||||
|
||||
velocity = (interpolatedPosition - transform.position) / deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If target has been reached, change ladder phase
|
||||
|
||||
_ladderTime = 0.0f;
|
||||
|
||||
if (_climbingState == ClimbingState.Grabbing )
|
||||
{
|
||||
// Switch to ladder climb phase
|
||||
|
||||
_climbingState = ClimbingState.Grabbed;
|
||||
}
|
||||
else if (_climbingState == ClimbingState.Releasing)
|
||||
{
|
||||
// Exit climbing state (change to falling movement mode)
|
||||
|
||||
_character.SetMovementMode(Character.MovementMode.Falling);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ClimbingState.Grabbed:
|
||||
{
|
||||
// Get the path position from character's current position
|
||||
|
||||
_activeLadder.ClosestPointOnPath(_character.GetPosition(), out _ladderPathPosition);
|
||||
|
||||
if (Mathf.Abs(_ladderPathPosition) < 0.05f)
|
||||
{
|
||||
// Move the character along the ladder path
|
||||
|
||||
Vector3 movementInput = _character.GetMovementDirection();
|
||||
|
||||
velocity = _activeLadder.transform.up * (movementInput.z * climbingSpeed);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If reached on of the ladder path extremes, change to releasing phase
|
||||
|
||||
_climbingState = ClimbingState.Releasing;
|
||||
|
||||
_ladderStartPosition = _character.GetPosition();
|
||||
_ladderStartRotation = _character.GetRotation();
|
||||
|
||||
if (_ladderPathPosition > 0.0f)
|
||||
{
|
||||
// Above ladder path top point
|
||||
|
||||
_ladderTargetPosition = _activeLadder.TopPoint.position;
|
||||
_ladderTargetRotation = _activeLadder.TopPoint.rotation;
|
||||
}
|
||||
else if (_ladderPathPosition < 0.0f)
|
||||
{
|
||||
// Below ladder path bottom point
|
||||
|
||||
_ladderTargetPosition = _activeLadder.BottomPoint.position;
|
||||
_ladderTargetRotation = _activeLadder.BottomPoint.rotation;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Update character's velocity
|
||||
|
||||
_character.SetVelocity(velocity);
|
||||
}
|
||||
|
||||
private void OnMovementModeChanged(Character.MovementMode prevMovementMode, int prevCustomMovementMode)
|
||||
{
|
||||
// Enter Climbing movement mode
|
||||
|
||||
if (IsClimbing())
|
||||
{
|
||||
_climbingState = ClimbingState.Grabbing;
|
||||
|
||||
_character.StopJumping();
|
||||
|
||||
_character.EnableGroundConstraint(false);
|
||||
|
||||
_previousRotationMode = _character.rotationMode;
|
||||
_character.SetRotationMode(Character.RotationMode.Custom);
|
||||
}
|
||||
|
||||
// Exit Climbing movement mode
|
||||
|
||||
bool wasClimbing = prevMovementMode == Character.MovementMode.Custom &&
|
||||
prevCustomMovementMode == (int)CustomMovementMode.Climbing;
|
||||
|
||||
if (wasClimbing)
|
||||
{
|
||||
_climbingState = ClimbingState.None;
|
||||
|
||||
_character.EnableGroundConstraint(true);
|
||||
_character.SetRotationMode(_previousRotationMode);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCustomMovementModeUpdated(float deltaTime)
|
||||
{
|
||||
if (IsClimbing())
|
||||
ClimbingMovementMode(deltaTime);
|
||||
}
|
||||
|
||||
private void OnCustomRotationModeUpdated(float deltaTime)
|
||||
{
|
||||
if (IsClimbing() && (_climbingState == ClimbingState.Grabbing || _climbingState == ClimbingState.Releasing))
|
||||
{
|
||||
Quaternion rotation =
|
||||
Quaternion.Slerp(_ladderStartRotation, _ladderTargetRotation, _ladderTime / grabbingTime);
|
||||
|
||||
_character.SetRotation(rotation);
|
||||
}
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_character = GetComponent<Character>();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_character.MovementModeChanged += OnMovementModeChanged;
|
||||
_character.CustomMovementModeUpdated += OnCustomMovementModeUpdated;
|
||||
_character.CustomRotationModeUpdated += OnCustomRotationModeUpdated;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_character.MovementModeChanged -= OnMovementModeChanged;
|
||||
_character.CustomMovementModeUpdated -= OnCustomMovementModeUpdated;
|
||||
_character.CustomRotationModeUpdated -= OnCustomRotationModeUpdated;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ef7d6f6890f479fac1591d410e31408
|
||||
timeCreated: 1700524463
|
||||
@@ -1,74 +0,0 @@
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace ECM2.Examples.Ladders
|
||||
{
|
||||
/// <summary>
|
||||
/// Extends default Character Input to handle LadderClimbInput Input.
|
||||
/// </summary>
|
||||
|
||||
public class LadderClimbInput : CharacterInput
|
||||
{
|
||||
private LadderClimbAbility _ladderClimbAbility;
|
||||
|
||||
/// <summary>
|
||||
/// Interact InputAction.
|
||||
/// </summary>
|
||||
|
||||
public InputAction interactInputAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Jump InputAction handler.
|
||||
/// </summary>
|
||||
|
||||
public virtual void OnInteract(InputAction.CallbackContext context)
|
||||
{
|
||||
if (context.started)
|
||||
_ladderClimbAbility.Climb();
|
||||
else if (context.canceled)
|
||||
_ladderClimbAbility.StopClimbing();
|
||||
}
|
||||
|
||||
protected override void InitPlayerInput()
|
||||
{
|
||||
// Call base method implementation
|
||||
|
||||
base.InitPlayerInput();
|
||||
|
||||
// Setup Interact input action handlers
|
||||
|
||||
interactInputAction = inputActionsAsset.FindAction("Interact");
|
||||
if (interactInputAction != null)
|
||||
{
|
||||
interactInputAction.started += OnInteract;
|
||||
interactInputAction.canceled += OnInteract;
|
||||
|
||||
interactInputAction.Enable();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void DeinitPlayerInput()
|
||||
{
|
||||
base.DeinitPlayerInput();
|
||||
|
||||
// Unsubscribe from input action events and disable input actions
|
||||
|
||||
if (interactInputAction != null)
|
||||
{
|
||||
interactInputAction.started -= OnInteract;
|
||||
interactInputAction.canceled -= OnInteract;
|
||||
|
||||
interactInputAction.Disable();
|
||||
interactInputAction = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
// Cache Ladder Climb Ability
|
||||
|
||||
_ladderClimbAbility = GetComponent<LadderClimbAbility>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57e07038965948caa8713a162db0f2be
|
||||
timeCreated: 1700530516
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8dc639f37a2842f4797f45420d642695
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d9c687e966e32d43a70620826011878
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 491c3a228ce9f5240bba52a7a7803b4c
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da38947f7e566784b87c8bd65d208713
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 632c6e9af7bb79949a32cabf0120ff1d
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f4c17cba879bdb4c9259964863b47be
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c375cc69af33f7445ba348c9296d1651
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 078686a70f118ab45aef26d1a863eb79
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2bff2fd571e446343a27d8456cf58553
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e226eaad11f756648b790d950a5c1d66
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6503c5dd5b759f4682c6790728822ff
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 702cd3842e1f48b78516f11a721bb0bb
|
||||
timeCreated: 1700621484
|
||||
@@ -1,127 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECM2.Examples.OrientToGround
|
||||
{
|
||||
/// <summary>
|
||||
/// This example extends a Character (through composition) to adjust a Character's rotation
|
||||
/// to follow a 'terrain' contour.
|
||||
/// </summary>
|
||||
|
||||
public class CharacterOrientToGround : MonoBehaviour, IColliderFilter
|
||||
{
|
||||
public float maxSlopeAngle = 30.0f;
|
||||
public float alignRate = 10.0f;
|
||||
public float rayOffset = 0.1f;
|
||||
|
||||
public LayerMask groundMask = 1;
|
||||
|
||||
[Space(15f)]
|
||||
public bool drawRays = true;
|
||||
|
||||
private readonly RaycastHit[] _hits = new RaycastHit[8];
|
||||
|
||||
private Character _character;
|
||||
|
||||
// Implement IColliderFilter.
|
||||
// Ignore character's capsule collider.
|
||||
|
||||
public bool Filter(Collider otherCollider)
|
||||
{
|
||||
CharacterMovement characterMovement = _character.GetCharacterMovement();
|
||||
if (otherCollider == characterMovement.collider)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the average normal sampling a 3x3 area, each ray is a rayOffset distance of other.
|
||||
/// </summary>
|
||||
|
||||
private Vector3 ComputeAverageNormal()
|
||||
{
|
||||
CharacterMovement characterMovement = _character.GetCharacterMovement();
|
||||
|
||||
Vector3 worldUp = Vector3.up;
|
||||
Vector3 castOrigin = _character.GetPosition() + worldUp * (characterMovement.height * 0.5f);
|
||||
|
||||
Vector3 castDirection = -worldUp;
|
||||
float castDistance = characterMovement.height;
|
||||
LayerMask castLayerMask = groundMask;
|
||||
|
||||
Vector3 avgNormal = Vector3.zero;
|
||||
|
||||
float x = -rayOffset;
|
||||
float z = -rayOffset;
|
||||
|
||||
int hitCount = 0;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
z = -rayOffset;
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
bool hit = CollisionDetection.Raycast(castOrigin + new Vector3(x, 0.0f, z), castDirection,
|
||||
castDistance, castLayerMask, QueryTriggerInteraction.Ignore, out RaycastHit hitResult, _hits, this) > 0;
|
||||
|
||||
if (hit)
|
||||
{
|
||||
float angle = Vector3.Angle(hitResult.normal, worldUp);
|
||||
if (angle < maxSlopeAngle)
|
||||
{
|
||||
avgNormal += hitResult.normal;
|
||||
|
||||
if (drawRays)
|
||||
Debug.DrawRay(hitResult.point, hitResult.normal, Color.yellow);
|
||||
|
||||
hitCount ++;
|
||||
}
|
||||
}
|
||||
|
||||
z += rayOffset;
|
||||
}
|
||||
|
||||
x += rayOffset;
|
||||
}
|
||||
|
||||
if (hitCount > 0)
|
||||
avgNormal /= hitCount;
|
||||
else
|
||||
avgNormal = worldUp;
|
||||
|
||||
if (drawRays)
|
||||
Debug.DrawRay(_character.GetPosition(), avgNormal * 2f, Color.green);
|
||||
|
||||
return avgNormal;
|
||||
}
|
||||
|
||||
private void OnAfterSimulationUpdated(float deltaTime)
|
||||
{
|
||||
Vector3 avgNormal = _character.IsWalking() ? ComputeAverageNormal() : Vector3.up;
|
||||
|
||||
Quaternion characterRotation = _character.GetRotation();
|
||||
Vector3 characterUp = characterRotation * Vector3.up;
|
||||
|
||||
Quaternion slopeRotation = Quaternion.FromToRotation(characterUp, avgNormal);
|
||||
characterRotation = Quaternion.Slerp(characterRotation, slopeRotation * characterRotation, alignRate * deltaTime);
|
||||
|
||||
_character.SetRotation(characterRotation);
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_character = GetComponent<Character>();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_character.AfterSimulationUpdated += OnAfterSimulationUpdated;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_character.AfterSimulationUpdated -= OnAfterSimulationUpdated;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ddceac5c369948b4b1f56559e4d41796
|
||||
timeCreated: 1700621503
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3938dc9601b64b80aad092fdd3b438bf
|
||||
timeCreated: 1700523966
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a053c6add13e16f4fb8b91a32c583756
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5baa8109e4051dd4980b7e59de338ef3
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b200f749d8db4954d8599e6772165940
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 112000000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -1,117 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 23407264829349547ae7a870aa3ebae8
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
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
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 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}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 2
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 100
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f02f1530dd241694b817ab613b519138
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,60 +0,0 @@
|
||||
using ECM2.Examples.ThirdPerson;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECM2.Examples.PlanetWalk
|
||||
{
|
||||
/// <summary>
|
||||
/// This example extends a Character (through inheritance) adjusting its gravity and orientation
|
||||
/// to follow a planet curvature similar to the Mario Galaxy game.
|
||||
/// </summary>
|
||||
|
||||
public class PlayerCharacter : ThirdPersonCharacter
|
||||
{
|
||||
[Space(15f)]
|
||||
public Transform planetTransform;
|
||||
|
||||
// Current camera forward, perpendicular to target's up vector.
|
||||
|
||||
private Vector3 _cameraForward = Vector3.forward;
|
||||
|
||||
public override void AddControlYawInput(float value)
|
||||
{
|
||||
// Rotate our forward along follow target's up axis
|
||||
|
||||
Vector3 targetUp = followTarget.transform.up;
|
||||
_cameraForward = Quaternion.Euler(targetUp * value) * _cameraForward;
|
||||
}
|
||||
|
||||
protected override void UpdateCameraRotation()
|
||||
{
|
||||
// Make sure camera forward vector is perpendicular to Character's current up vector
|
||||
|
||||
Vector3 targetUp = followTarget.transform.up;
|
||||
Vector3.OrthoNormalize(ref targetUp, ref _cameraForward);
|
||||
|
||||
// Computes final Camera rotation from yaw and pitch
|
||||
|
||||
cameraTransform.rotation =
|
||||
Quaternion.LookRotation(_cameraForward, targetUp) * Quaternion.Euler(_cameraPitch, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
protected override void UpdateRotation(float deltaTime)
|
||||
{
|
||||
// Call base method (i.e: rotate towards movement direction)
|
||||
|
||||
base.UpdateRotation(deltaTime);
|
||||
|
||||
// Adjust gravity direction (ie: a vector pointing from character position to planet's center)
|
||||
|
||||
Vector3 toPlanet = planetTransform.position - GetPosition();
|
||||
SetGravityVector(toPlanet.normalized * GetGravityMagnitude());
|
||||
|
||||
// Adjust Character's rotation following the new world-up (defined by gravity direction)
|
||||
|
||||
Vector3 worldUp = GetGravityDirection() * -1.0f;
|
||||
Quaternion newRotation = Quaternion.FromToRotation(GetUpVector(), worldUp) * GetRotation();
|
||||
|
||||
SetRotation(newRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8e22f557fff8be48a9230f99a4a6f52
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 148600c99f8ab8849975d72f538c9b3c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af237fa0d4164de3b8bbb1640d85f70b
|
||||
timeCreated: 1700798056
|
||||
@@ -1,35 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECM2.Examples.SideScrolling
|
||||
{
|
||||
/// <summary>
|
||||
/// This example shows how to implement a typical side-scrolling movement with side to side rotation snap.
|
||||
/// </summary>
|
||||
|
||||
public class SideScrollingInput : CharacterInput
|
||||
{
|
||||
protected override void Awake()
|
||||
{
|
||||
// Call base method implementation
|
||||
|
||||
base.Awake();
|
||||
|
||||
// Disable Character rotation, well handle it here (snap move direction)
|
||||
|
||||
character.SetRotationMode(Character.RotationMode.None);
|
||||
}
|
||||
|
||||
protected override void HandleInput()
|
||||
{
|
||||
// Add horizontal movement (in world space)
|
||||
|
||||
Vector2 movementInput = GetMovementInput();
|
||||
character.SetMovementDirection(Vector3.right * movementInput.x);
|
||||
|
||||
// Snap side to side rotation
|
||||
|
||||
if (movementInput.x != 0)
|
||||
character.SetYaw(movementInput.x * 90.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f138cba3d2dc7146817f32230b4f5b5
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d6613720d4108f4fa955b37a378bbdc
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a4fe6b8eae2cde41a0bbf010cfe55d2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a7cb1b2a4b6ebc4bbc670e46e857527
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,216 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECM2.Examples.Slide
|
||||
{
|
||||
/// <summary>
|
||||
/// This example extends a Character (through inheritance) implementing a slide mechanic.
|
||||
/// </summary>
|
||||
|
||||
public class PlayerCharacter : Character
|
||||
{
|
||||
[Space(15.0f)]
|
||||
public float slideImpulse = 20.0f;
|
||||
public float slideDownAcceleration = 20.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Our custom movement mode(s) id(s).
|
||||
/// </summary>
|
||||
|
||||
enum ECustomMovementMode
|
||||
{
|
||||
Sliding = 1
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If sliding, return max walk speed as our speed limit.
|
||||
/// </summary>
|
||||
|
||||
public override float GetMaxSpeed()
|
||||
{
|
||||
return IsSliding() ? maxWalkSpeed : base.GetMaxSpeed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If sliding, limit acceleration.
|
||||
/// </summary>
|
||||
|
||||
public override float GetMaxAcceleration()
|
||||
{
|
||||
return IsSliding() ? maxAcceleration * 0.1f : base.GetMaxAcceleration();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override IsWalking (aka: grounded movement mode) to add Sliding movement mode support,
|
||||
/// otherwise crouch, jump will fail while sliding due its conditions checking if IsWalking.
|
||||
/// </summary>
|
||||
|
||||
public override bool IsWalking()
|
||||
{
|
||||
return IsSliding() || base.IsWalking();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the Character sliding?
|
||||
/// </summary>
|
||||
|
||||
public bool IsSliding()
|
||||
{
|
||||
return movementMode == MovementMode.Custom && customMovementMode == (int)ECustomMovementMode.Sliding;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the character can slide in its current state.
|
||||
/// </summary>
|
||||
|
||||
protected virtual bool CanSlide()
|
||||
{
|
||||
// Slide is tied to crouch, if not crouching cant slide!
|
||||
|
||||
if (!IsGrounded())
|
||||
return false;
|
||||
|
||||
// Check allowed slide speed threshold
|
||||
|
||||
float sqrSpeed = velocity.sqrMagnitude;
|
||||
float slideSpeedThreshold = maxWalkSpeedCrouched * maxWalkSpeedCrouched;
|
||||
|
||||
return sqrSpeed >= slideSpeedThreshold * 1.02f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate sliding direction vector.
|
||||
/// </summary>
|
||||
|
||||
protected virtual Vector3 CalcSlideDirection()
|
||||
{
|
||||
Vector3 slideDirection = GetMovementDirection();
|
||||
if (slideDirection.isZero())
|
||||
slideDirection = GetVelocity();
|
||||
else if (slideDirection.isZero())
|
||||
slideDirection = GetForwardVector();
|
||||
|
||||
slideDirection = ConstrainInputVector(slideDirection);
|
||||
|
||||
return slideDirection.normalized;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to perform a requested slide or
|
||||
/// stop it if requested or cant continue sliding.
|
||||
/// </summary>
|
||||
|
||||
protected virtual void CheckSlideInput()
|
||||
{
|
||||
bool isSliding = IsSliding();
|
||||
bool wantsToSlide = crouchInputPressed;
|
||||
|
||||
if (!isSliding && wantsToSlide && CanSlide())
|
||||
{
|
||||
SetMovementMode(MovementMode.Custom, (int)ECustomMovementMode.Sliding);
|
||||
}
|
||||
else if (isSliding && (!wantsToSlide || !CanSlide()))
|
||||
{
|
||||
SetMovementMode(MovementMode.Walking);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle Sliding enter / exit.
|
||||
/// </summary>
|
||||
|
||||
protected override void OnMovementModeChanged(MovementMode prevMovementMode, int prevCustomMode)
|
||||
{
|
||||
// Call base method implementation
|
||||
|
||||
base.OnMovementModeChanged(prevMovementMode, prevCustomMode);
|
||||
|
||||
// Enter sliding movement mode...
|
||||
|
||||
if (IsSliding())
|
||||
{
|
||||
// Apply initial slide impulse
|
||||
|
||||
Vector3 slideDirection = CalcSlideDirection();
|
||||
characterMovement.velocity += slideDirection * slideImpulse;
|
||||
|
||||
// Disable Character rotation
|
||||
|
||||
SetRotationMode(RotationMode.None);
|
||||
}
|
||||
|
||||
// Exit sliding movement mode...
|
||||
|
||||
bool wasSliding = prevMovementMode == MovementMode.Custom &&
|
||||
prevCustomMode == (int)ECustomMovementMode.Sliding;
|
||||
|
||||
if (wasSliding)
|
||||
{
|
||||
// Re-enable Character rotation
|
||||
|
||||
SetRotationMode(RotationMode.OrientRotationToMovement);
|
||||
|
||||
// If falling, make sure its velocity do not exceed maxWalkSpeed
|
||||
|
||||
if (IsFalling())
|
||||
{
|
||||
Vector3 worldUp = -GetGravityDirection();
|
||||
Vector3 verticalVelocity = Vector3.Project(velocity, worldUp);
|
||||
Vector3 lateralVelocity = Vector3.ClampMagnitude(velocity - verticalVelocity, maxWalkSpeed);
|
||||
|
||||
characterMovement.velocity = lateralVelocity + verticalVelocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnBeforeSimulationUpdate(float deltaTime)
|
||||
{
|
||||
// Call base method implementation
|
||||
|
||||
base.OnBeforeSimulationUpdate(deltaTime);
|
||||
|
||||
// Attempts to do a requested slide
|
||||
|
||||
CheckSlideInput();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update Character's velocity while SLIDING on walkable surfaces.
|
||||
/// </summary>
|
||||
|
||||
protected virtual void SlidingMovementMode(float deltaTime)
|
||||
{
|
||||
// Limit input to lateral movement only (strafing)
|
||||
|
||||
Vector3 desiredVelocity = Vector3.Project(GetDesiredVelocity(), GetRightVector());
|
||||
|
||||
// Calculate new velocity
|
||||
|
||||
characterMovement.velocity =
|
||||
CalcVelocity(characterMovement.velocity, desiredVelocity, groundFriction * 0.2f, false, deltaTime);
|
||||
|
||||
// Apply slide down acceleration
|
||||
|
||||
Vector3 slideDownDirection =
|
||||
Vector3.ProjectOnPlane(GetGravityDirection(), characterMovement.groundNormal).normalized;
|
||||
|
||||
characterMovement.velocity += slideDownAcceleration * deltaTime * slideDownDirection;
|
||||
|
||||
// Apply downwards force
|
||||
|
||||
if (applyStandingDownwardForce)
|
||||
ApplyDownwardsForce();
|
||||
}
|
||||
|
||||
protected override void CustomMovementMode(float deltaTime)
|
||||
{
|
||||
// Call base method implementation
|
||||
|
||||
base.CustomMovementMode(deltaTime);
|
||||
|
||||
// Sliding custom movement mode
|
||||
|
||||
if (customMovementMode == (int)ECustomMovementMode.Sliding)
|
||||
SlidingMovementMode(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user