完善A星添加角色系统
This commit is contained in:
parent
3dcaf8b4de
commit
7070c9bf7d
@ -9490,7 +9490,7 @@ Transform:
|
|||||||
m_GameObject: {fileID: 285986652131527170}
|
m_GameObject: {fileID: 285986652131527170}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_LocalRotation: {x: 0.70710677, y: -0, z: -0, w: 0.7071068}
|
m_LocalRotation: {x: 0.70710677, y: -0, z: -0, w: 0.7071068}
|
||||||
m_LocalPosition: {x: 88.27699, y: 6.3215823, z: -0.047535613}
|
m_LocalPosition: {x: 85.52, y: 6.3215823, z: -0.047535613}
|
||||||
m_LocalScale: {x: 1.81862, y: 1.81862, z: 1.81862}
|
m_LocalScale: {x: 1.81862, y: 1.81862, z: 1.81862}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children:
|
m_Children:
|
||||||
@ -9565,7 +9565,7 @@ MonoBehaviour:
|
|||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
_isRunning: 0
|
_isRunning: 0
|
||||||
_shelfToolActionType: 0
|
_shelfToolActionType: 2
|
||||||
_currentBoxactor: {fileID: 0}
|
_currentBoxactor: {fileID: 0}
|
||||||
_treeOwner: {fileID: 0}
|
_treeOwner: {fileID: 0}
|
||||||
_targetPositionBox: {fileID: 0}
|
_targetPositionBox: {fileID: 0}
|
||||||
@ -84370,6 +84370,7 @@ GameObject:
|
|||||||
m_Component:
|
m_Component:
|
||||||
- component: {fileID: 4309968558015114303}
|
- component: {fileID: 4309968558015114303}
|
||||||
- component: {fileID: 8202619528938505423}
|
- component: {fileID: 8202619528938505423}
|
||||||
|
- component: {fileID: 3570133681296783813}
|
||||||
m_Layer: 0
|
m_Layer: 0
|
||||||
m_Name: actor_Warehouseshelf
|
m_Name: actor_Warehouseshelf
|
||||||
m_TagString: Untagged
|
m_TagString: Untagged
|
||||||
@ -84409,6 +84410,27 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
_targetBoxId: 0
|
_targetBoxId: 0
|
||||||
_tool: {fileID: 0}
|
_tool: {fileID: 0}
|
||||||
|
--- !u!65 &3570133681296783813
|
||||||
|
BoxCollider:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2895222871435310345}
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_LayerOverridePriority: 0
|
||||||
|
m_IsTrigger: 0
|
||||||
|
m_ProvidesContacts: 0
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_Size: {x: 165.03473, y: 52.36976, z: 13.39}
|
||||||
|
m_Center: {x: -1.0754242, y: 26.128292, z: 0}
|
||||||
--- !u!1 &2896999456890700578
|
--- !u!1 &2896999456890700578
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@ -232173,7 +232195,7 @@ Transform:
|
|||||||
m_GameObject: {fileID: 8386615510630291625}
|
m_GameObject: {fileID: 8386615510630291625}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
m_LocalPosition: {x: -0.24234578, y: 0.001337206, z: 2.2394881}
|
m_LocalPosition: {x: -0.24234578, y: 0.001337206, z: 2.796}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children:
|
m_Children:
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5ef555787d020214999b728e64154995
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,10 @@
|
|||||||
|
using TEngine;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace GameLogic
|
||||||
|
{
|
||||||
|
public class BaseCharacter : EntityLogic
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 44b5cd5e4befaa14fbb7642695a1c7f9
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c8ee8fd7dadbdaf48b7c3e25472f3aca
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,14 @@
|
|||||||
|
using TEngine;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace GameLogic
|
||||||
|
{
|
||||||
|
public class RobotAI : EnemyBase
|
||||||
|
{
|
||||||
|
protected override void OnInit(object userData)
|
||||||
|
{
|
||||||
|
base.OnInit(userData);
|
||||||
|
Log.Debug("初始化RobotAI");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f63f0d04665826e49bce7babd7c49fea
|
@ -0,0 +1,12 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace GameLogic
|
||||||
|
{
|
||||||
|
public class EnemyBase : BaseCharacter
|
||||||
|
{
|
||||||
|
protected override void OnInit(object userData)
|
||||||
|
{
|
||||||
|
base.OnInit(userData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e67158861e312b046824ebf7dd0bc104
|
@ -0,0 +1,9 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace GameLogic
|
||||||
|
{
|
||||||
|
public class PlayBase : BaseCharacter
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a794deeda4fe3fd4ca43b767021b59f7
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8b19fbd67cbcf4f429dd48ded3b0bb38
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,9 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace GameLogic
|
||||||
|
{
|
||||||
|
public class Player : PlayBase
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4496005bdb534ef43a55cd73750993dd
|
@ -12,33 +12,42 @@ namespace GameLogic
|
|||||||
[ShowInInspector]private Dictionary<int,BoxActor> _boxes = new Dictionary<int,BoxActor>();
|
[ShowInInspector]private Dictionary<int,BoxActor> _boxes = new Dictionary<int,BoxActor>();
|
||||||
protected override void OnLoad()
|
protected override void OnLoad()
|
||||||
{
|
{
|
||||||
//Init().Forget();
|
// //Init().Forget();
|
||||||
var array = transform.Find("BoxGroup").childCount;
|
// var array = transform.Find("BoxGroup").childCount;
|
||||||
for (int i = 0; i < array; i++)
|
// for (int i = 0; i < array; i++)
|
||||||
{
|
|
||||||
_boxes.Add(i,transform.Find("BoxGroup").GetChild(i).GetComponent<BoxActor>());
|
|
||||||
}
|
|
||||||
// foreach (var box in _boxes)
|
|
||||||
// {
|
// {
|
||||||
//
|
// _boxes.Add(i,transform.Find("BoxGroup").GetChild(i).GetComponent<BoxActor>());
|
||||||
// }
|
// }
|
||||||
|
// // foreach (var box in _boxes)
|
||||||
|
// // {
|
||||||
|
// //
|
||||||
|
// // }
|
||||||
|
|
||||||
base.OnLoad();
|
base.OnLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Start()
|
private async void Start()
|
||||||
{
|
{
|
||||||
// Init().Forget();
|
Init().Forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async UniTaskVoid Init()
|
private async UniTaskVoid Init()
|
||||||
{
|
{
|
||||||
// await GeneratorBox();
|
|
||||||
|
GameModuleExtension.Entity.AddEntityGroup("boxGroup",
|
||||||
|
-1,
|
||||||
|
30000,
|
||||||
|
99999999,
|
||||||
|
0);
|
||||||
|
|
||||||
|
|
||||||
|
await GeneratorBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private async UniTask GeneratorBox()
|
private async UniTask GeneratorBox()
|
||||||
{
|
{
|
||||||
|
IEntityGroup group = GameModuleExtension.Entity.GetEntityGroup("boxGroup");
|
||||||
var boxArray = GameObject.FindGameObjectsWithTag(TagSetting.Box);
|
var boxArray = GameObject.FindGameObjectsWithTag(TagSetting.Box);
|
||||||
GameObject boxGroup = new GameObject();
|
GameObject boxGroup = new GameObject();
|
||||||
boxGroup.name = "BoxGroup";
|
boxGroup.name = "BoxGroup";
|
||||||
@ -46,11 +55,12 @@ namespace GameLogic
|
|||||||
Material boxMat = GameModule.Resource.LoadAsset<Material>(LocationSetting.Mat_ActorBox);
|
Material boxMat = GameModule.Resource.LoadAsset<Material>(LocationSetting.Mat_ActorBox);
|
||||||
for (int i = 0; i < boxArray.Length; i++)
|
for (int i = 0; i < boxArray.Length; i++)
|
||||||
{
|
{
|
||||||
var boxActor = BoxFactory.CreatBox(i, boxArray[i].transform,boxGroup.transform);
|
var boxActor = BoxFactory.CreatBoxGameModule(i, boxArray[i].transform,boxGroup.transform,group);
|
||||||
//boxActor.SetMaterial(boxMat);
|
//boxActor.SetMaterial(boxMat);
|
||||||
_boxes.Add(i,boxActor);
|
_boxes.Add(i,boxActor);
|
||||||
Log.Info($"Box Generator (物流纸箱生成进度) :{i/(boxArray.Length*1.0f) * 100} %");
|
Log.Info($"Box Generator (物流纸箱生成进度) :{i/(boxArray.Length*1.0f) * 100} %");
|
||||||
}
|
}
|
||||||
|
Log.Info("实体数量"+group.EntityCount);
|
||||||
await UniTask.Yield();
|
await UniTask.Yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using TEngine;
|
using TEngine;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@ -8,7 +9,10 @@ namespace GameLogic
|
|||||||
public int index;
|
public int index;
|
||||||
|
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
OnInit(null);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetMaterial(Material material)
|
public void SetMaterial(Material material)
|
||||||
{
|
{
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
|
using TEngine;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace GameLogic
|
namespace GameLogic
|
||||||
{
|
{
|
||||||
public static class BoxFactory
|
public static class BoxFactory
|
||||||
{
|
{
|
||||||
public static BoxActor CreatBoxGameModule(int index,Transform origin,Transform parent)
|
public static BoxActor CreatBoxGameModule(int index,Transform origin,Transform parent,IEntityGroup group)
|
||||||
{
|
{
|
||||||
|
|
||||||
var boxGo = GameModule.Resource.LoadGameObject(LocationSetting.BoxActor);
|
var boxGo = GameModule.Resource.LoadGameObject(LocationSetting.BoxActor);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
boxGo.SetTransform(origin);
|
boxGo.SetTransform(origin);
|
||||||
boxGo.SetParent(parent);
|
boxGo.SetParent(parent);
|
||||||
|
|
||||||
var box = boxGo.GetComponent<BoxActor>();
|
var box = boxGo.GetComponent<BoxActor>();
|
||||||
box.index = index;
|
box.index = index;
|
||||||
return boxGo.GetComponent<BoxActor>();
|
return boxGo.GetComponent<BoxActor>();
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
using TEngine;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace GameLogic
|
||||||
|
{
|
||||||
|
public class GameModuleExtension
|
||||||
|
{
|
||||||
|
public static EntityModule Entity => GameObject.FindAnyObjectByType<EntityModule>();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3a0ec0e72ffc4da8a6bae9cd193d623a
|
||||||
|
timeCreated: 1745560001
|
@ -2,7 +2,7 @@
|
|||||||
using TEngine;
|
using TEngine;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
public class GameModule
|
public class GameModule
|
||||||
{
|
{
|
||||||
#region 框架模块
|
#region 框架模块
|
||||||
|
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 916c2cc0a94e68b47957485da44d162c
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: caa01241d67e9c147907e1d816ba28ed
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 88be720759cf79a4d9b14514fcf82a0d
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,144 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &2750169105938585654
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 3690873532784470854}
|
||||||
|
- component: {fileID: 5486110000465605157}
|
||||||
|
- component: {fileID: 2604934662711577773}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Blank Character
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &3690873532784470854
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2750169105938585654}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 2084248668550000093}
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &5486110000465605157
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2750169105938585654}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 78cff8dc757190641a7708af786fcf21, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
is2D: 0
|
||||||
|
bodyType: 1
|
||||||
|
bodySize: {x: 1, y: 2}
|
||||||
|
mass: 50
|
||||||
|
--- !u!114 &2604934662711577773
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2750169105938585654}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 4f199f35221ef584d909e881238cba74, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
tagsAndLayersProfile: {fileID: 0}
|
||||||
|
slopeLimit: 60
|
||||||
|
stepOffset: 0.5
|
||||||
|
stepUpSpeed: 0.5
|
||||||
|
stepDownDistance: 0.5
|
||||||
|
stepDownSpeed: 0.1
|
||||||
|
edgeCompensation: 0
|
||||||
|
alwaysNotGrounded: 0
|
||||||
|
verticalAlignmentSettings:
|
||||||
|
alignmentReference: {fileID: 0}
|
||||||
|
referenceMode: 1
|
||||||
|
alignmentDirection: {x: 0, y: 1, z: 0}
|
||||||
|
supportDynamicGround: 1
|
||||||
|
rotateForwardDirection: 1
|
||||||
|
applyWeightToGround: 1
|
||||||
|
weightGravity: 9.8
|
||||||
|
filterWeightRigidbodiesByTag: 1
|
||||||
|
addExternalVelocity: 1
|
||||||
|
ignoreStaticObstacles: 1
|
||||||
|
ignoreKinematicRigidbodies: 1
|
||||||
|
--- !u!1 &5532968350065946407
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 7399720800942972954}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Your animated character
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &7399720800942972954
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 5532968350065946407}
|
||||||
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 2084248668550000093}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &6415588977015373110
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 2084248668550000093}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Graphics
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &2084248668550000093
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6415588977015373110}
|
||||||
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 7399720800942972954}
|
||||||
|
m_Father: {fileID: 3690873532784470854}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2edb26b83da1f57409122f30d4205788
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,378 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &1218552866658402712
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 4842251681767870480}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Arrow
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &4842251681767870480
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1218552866658402712}
|
||||||
|
m_LocalRotation: {x: -0.49999714, y: -0.4999999, z: -0.5000029, w: -0.5000001}
|
||||||
|
m_LocalPosition: {x: 0, y: 2.288558, z: -0.20655823}
|
||||||
|
m_LocalScale: {x: 0.17285192, y: 0.17285194, z: 0.17285194}
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 2308672894763730565}
|
||||||
|
m_Father: {fileID: 2161635890232759230}
|
||||||
|
m_RootOrder: 1
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: -270, z: 90.00001}
|
||||||
|
--- !u!1 &1326713445091067784
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 2161635890232759230}
|
||||||
|
- component: {fileID: 8235324090581383526}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Capsule root
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &2161635890232759230
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1326713445091067784}
|
||||||
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 4172487410879816610}
|
||||||
|
- {fileID: 4842251681767870480}
|
||||||
|
m_Father: {fileID: 2084248668550000093}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &8235324090581383526
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1326713445091067784}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 5e93c8610dacb85428134b9b32dec22a, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
scaleHeightComponent: 1
|
||||||
|
--- !u!1 &1523431370174691967
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 2308672894763730565}
|
||||||
|
- component: {fileID: 2729997595277447576}
|
||||||
|
- component: {fileID: 4087739539510225864}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Mesh1
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &2308672894763730565
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1523431370174691967}
|
||||||
|
m_LocalRotation: {x: 0, y: -0, z: -0, w: 1}
|
||||||
|
m_LocalPosition: {x: -0.33, y: -0.85, z: -0}
|
||||||
|
m_LocalScale: {x: 1.7093, y: 1.7093, z: 1.7093}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 4842251681767870480}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!33 &2729997595277447576
|
||||||
|
MeshFilter:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1523431370174691967}
|
||||||
|
m_Mesh: {fileID: 4300000, guid: a21dd1b7fbbe2d744aa9bc81a1c7a04b, type: 3}
|
||||||
|
--- !u!23 &4087739539510225864
|
||||||
|
MeshRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1523431370174691967}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_CastShadows: 0
|
||||||
|
m_ReceiveShadows: 1
|
||||||
|
m_DynamicOccludee: 1
|
||||||
|
m_MotionVectors: 1
|
||||||
|
m_LightProbeUsage: 1
|
||||||
|
m_ReflectionProbeUsage: 1
|
||||||
|
m_RayTracingMode: 2
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_RendererPriority: 0
|
||||||
|
m_Materials:
|
||||||
|
- {fileID: 2100000, guid: 0278e8512b313d54ba7e4b2b109c2796, type: 2}
|
||||||
|
m_StaticBatchInfo:
|
||||||
|
firstSubMesh: 0
|
||||||
|
subMeshCount: 0
|
||||||
|
m_StaticBatchRoot: {fileID: 0}
|
||||||
|
m_ProbeAnchor: {fileID: 0}
|
||||||
|
m_LightProbeVolumeOverride: {fileID: 0}
|
||||||
|
m_ScaleInLightmap: 1
|
||||||
|
m_ReceiveGI: 1
|
||||||
|
m_PreserveUVs: 0
|
||||||
|
m_IgnoreNormalsForChartDetection: 0
|
||||||
|
m_ImportantGI: 0
|
||||||
|
m_StitchLightmapSeams: 1
|
||||||
|
m_SelectedEditorRenderState: 3
|
||||||
|
m_MinimumChartSize: 4
|
||||||
|
m_AutoUVMaxDistance: 0.5
|
||||||
|
m_AutoUVMaxAngle: 89
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingLayer: 0
|
||||||
|
m_SortingOrder: 0
|
||||||
|
--- !u!1 &2750169105938585654
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 3690873532784470854}
|
||||||
|
- component: {fileID: 5486110000465605157}
|
||||||
|
- component: {fileID: 2604934662711577773}
|
||||||
|
m_Layer: 8
|
||||||
|
m_Name: Capsule Blank Character
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &3690873532784470854
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2750169105938585654}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 2084248668550000093}
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &5486110000465605157
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2750169105938585654}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 78cff8dc757190641a7708af786fcf21, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
is2D: 0
|
||||||
|
bodySize: {x: 1, y: 2}
|
||||||
|
mass: 50
|
||||||
|
--- !u!114 &2604934662711577773
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2750169105938585654}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 4f199f35221ef584d909e881238cba74, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
interpolateActor: 1
|
||||||
|
useContinuousCollisionDetection: 1
|
||||||
|
UseRootMotion: 0
|
||||||
|
UpdateRootPosition: 1
|
||||||
|
rootMotionVelocityType: 0
|
||||||
|
UpdateRootRotation: 1
|
||||||
|
rootMotionRotationType: 1
|
||||||
|
oneWayPlatformsLayerMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
oneWayPlatformsValidArc: 175
|
||||||
|
useGroundTrigger: 0
|
||||||
|
alwaysNotGrounded: 0
|
||||||
|
forceGroundedAtStart: 1
|
||||||
|
stableLayerMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
slopeLimit: 60
|
||||||
|
useStableEdgeWhenLanding: 1
|
||||||
|
stepUpDistance: 0.6
|
||||||
|
stepDownDistance: 0.5
|
||||||
|
edgeCompensation: 0
|
||||||
|
detectGroundWhileAscending: 0
|
||||||
|
maxUnstableUpwardsVelocity: 7
|
||||||
|
preventBadSteps: 1
|
||||||
|
supportDynamicGround: 1
|
||||||
|
rotateForwardDirection: 1
|
||||||
|
maxGroundVelocityChange: 30
|
||||||
|
inheritedGroundPlanarVelocityThreshold: 2
|
||||||
|
inheritedGroundPlanarVelocityMultiplier: 1
|
||||||
|
inheritedGroundVerticalVelocityThreshold: 2
|
||||||
|
inheritedGroundVerticalVelocityMultiplier: 1
|
||||||
|
movementReference:
|
||||||
|
movementReferenceMode: 0
|
||||||
|
externalReference: {fileID: 0}
|
||||||
|
slideOnWalls: 1
|
||||||
|
stablePostSimulationVelocity: 2
|
||||||
|
unstablePostSimulationVelocity: 2
|
||||||
|
sizeReferenceType: 2
|
||||||
|
sizeLerpSpeed: 8
|
||||||
|
constraintRotation: 1
|
||||||
|
upDirectionReference: {fileID: 0}
|
||||||
|
upDirectionReferenceMode: 1
|
||||||
|
constraintUpDirection: {x: 0, y: 1, z: 0}
|
||||||
|
canPushDynamicRigidbodies: 1
|
||||||
|
pushableRigidbodyLayerMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
applyWeightToGround: 1
|
||||||
|
weightGravity: 9.8
|
||||||
|
--- !u!1 &6173809583089036531
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 4172487410879816610}
|
||||||
|
- component: {fileID: 4064914065884037380}
|
||||||
|
- component: {fileID: 6907179781620337088}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Capsule
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &4172487410879816610
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6173809583089036531}
|
||||||
|
m_LocalRotation: {x: -0, y: -0, z: -0.000000014901161, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 1, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 2161635890232759230}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!33 &4064914065884037380
|
||||||
|
MeshFilter:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6173809583089036531}
|
||||||
|
m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
--- !u!23 &6907179781620337088
|
||||||
|
MeshRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6173809583089036531}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_CastShadows: 1
|
||||||
|
m_ReceiveShadows: 1
|
||||||
|
m_DynamicOccludee: 1
|
||||||
|
m_MotionVectors: 1
|
||||||
|
m_LightProbeUsage: 1
|
||||||
|
m_ReflectionProbeUsage: 1
|
||||||
|
m_RayTracingMode: 2
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_RendererPriority: 0
|
||||||
|
m_Materials:
|
||||||
|
- {fileID: 2100000, guid: 0278e8512b313d54ba7e4b2b109c2796, type: 2}
|
||||||
|
m_StaticBatchInfo:
|
||||||
|
firstSubMesh: 0
|
||||||
|
subMeshCount: 0
|
||||||
|
m_StaticBatchRoot: {fileID: 0}
|
||||||
|
m_ProbeAnchor: {fileID: 0}
|
||||||
|
m_LightProbeVolumeOverride: {fileID: 0}
|
||||||
|
m_ScaleInLightmap: 1
|
||||||
|
m_ReceiveGI: 1
|
||||||
|
m_PreserveUVs: 0
|
||||||
|
m_IgnoreNormalsForChartDetection: 0
|
||||||
|
m_ImportantGI: 0
|
||||||
|
m_StitchLightmapSeams: 0
|
||||||
|
m_SelectedEditorRenderState: 3
|
||||||
|
m_MinimumChartSize: 4
|
||||||
|
m_AutoUVMaxDistance: 0.5
|
||||||
|
m_AutoUVMaxAngle: 89
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingLayer: 0
|
||||||
|
m_SortingOrder: 0
|
||||||
|
--- !u!1 &6415588977015373110
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 2084248668550000093}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Graphics
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &2084248668550000093
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6415588977015373110}
|
||||||
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 2161635890232759230}
|
||||||
|
m_Father: {fileID: 3690873532784470854}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 36306ba9866cb5b46b38bc07bf5f031f
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b7ee4dfaa2510534f8e447d3e92f889b
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
FactoryNumeric/Assets/Plugin/Character Controller Pro/Core/Resources/whiteArrowFilledIcon.png
(Stored with Git LFS)
Normal file
BIN
FactoryNumeric/Assets/Plugin/Character Controller Pro/Core/Resources/whiteArrowFilledIcon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,117 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e405849a2c57a92459447d4f1af4c839
|
||||||
|
TextureImporter:
|
||||||
|
internalIDToNameTable: []
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 13
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 0
|
||||||
|
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: 0
|
||||||
|
seamlessCubemap: 0
|
||||||
|
textureFormat: 1
|
||||||
|
maxTextureSize: 2048
|
||||||
|
textureSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
filterMode: 1
|
||||||
|
aniso: 1
|
||||||
|
mipBias: 0
|
||||||
|
wrapU: 1
|
||||||
|
wrapV: 1
|
||||||
|
wrapW: 1
|
||||||
|
nPOTScale: 0
|
||||||
|
lightmap: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 1
|
||||||
|
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: 1
|
||||||
|
spriteTessellationDetail: -1
|
||||||
|
textureType: 8
|
||||||
|
textureShape: 1
|
||||||
|
singleChannelComponent: 0
|
||||||
|
flipbookRows: 1
|
||||||
|
flipbookColumns: 1
|
||||||
|
maxTextureSizeSet: 0
|
||||||
|
compressionQualitySet: 0
|
||||||
|
textureFormatSet: 0
|
||||||
|
ignorePngGamma: 0
|
||||||
|
applyGammaDecoding: 1
|
||||||
|
swizzle: 50462976
|
||||||
|
cookieLightType: 1
|
||||||
|
platformSettings:
|
||||||
|
- serializedVersion: 4
|
||||||
|
buildTarget: DefaultTexturePlatform
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 1
|
||||||
|
- 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: 1
|
||||||
|
spriteSheet:
|
||||||
|
serializedVersion: 2
|
||||||
|
sprites: []
|
||||||
|
outline: []
|
||||||
|
customData:
|
||||||
|
physicsShape: []
|
||||||
|
bones: []
|
||||||
|
spriteID: 9c5347bdfa0951540849bd28ba7a5443
|
||||||
|
internalID: 0
|
||||||
|
vertices: []
|
||||||
|
indices:
|
||||||
|
edges: []
|
||||||
|
weights: []
|
||||||
|
secondaryTextures: []
|
||||||
|
spriteCustomMetadata:
|
||||||
|
entries: []
|
||||||
|
nameFileIdTable: {}
|
||||||
|
mipmapLimitGroupName:
|
||||||
|
pSDRemoveMatte: 0
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ed94cbf3a2dee724f9d20a2f51d124cc
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ae920956a7e616747a90f9aae8cf02d9
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,44 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
[RequireComponent(typeof(Animator))]
|
||||||
|
public class AnimatorLink : MonoBehaviour
|
||||||
|
{
|
||||||
|
Animator _animator;
|
||||||
|
bool _resetIKWeightsFlag = false;
|
||||||
|
|
||||||
|
public event System.Action OnAnimatorMoveEvent;
|
||||||
|
public event System.Action<int> OnAnimatorIKEvent;
|
||||||
|
|
||||||
|
public void ResetIKWeights() => _resetIKWeightsFlag = true;
|
||||||
|
|
||||||
|
#region Messages
|
||||||
|
|
||||||
|
void Awake()
|
||||||
|
{
|
||||||
|
_animator = GetComponent<Animator>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnAnimatorMove() => OnAnimatorMoveEvent?.Invoke();
|
||||||
|
|
||||||
|
void OnAnimatorIK(int layerIndex)
|
||||||
|
{
|
||||||
|
if (_resetIKWeightsFlag)
|
||||||
|
{
|
||||||
|
_resetIKWeightsFlag = false;
|
||||||
|
|
||||||
|
_animator.SetIKPositionWeight(AvatarIKGoal.LeftFoot, 0f);
|
||||||
|
_animator.SetIKPositionWeight(AvatarIKGoal.RightFoot, 0f);
|
||||||
|
_animator.SetIKPositionWeight(AvatarIKGoal.LeftHand, 0f);
|
||||||
|
_animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
OnAnimatorIKEvent?.Invoke(layerIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b24a8f06539258c41887e7e69f8b1754
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4f199f35221ef584d909e881238cba74
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,83 @@
|
|||||||
|
#if UNITY_EDITOR
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
[CustomEditor(typeof(CharacterActor))]
|
||||||
|
public class CharacterActorEditor : Editor
|
||||||
|
{
|
||||||
|
CharacterActor characterActor = null;
|
||||||
|
|
||||||
|
void OnEnable()
|
||||||
|
{
|
||||||
|
characterActor = target as CharacterActor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDisable()
|
||||||
|
{
|
||||||
|
Tools.hidden = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
if (characterActor.CharacterBody.Is2D)
|
||||||
|
{
|
||||||
|
if (Physics2D.simulationMode != SimulationMode2D.FixedUpdate)
|
||||||
|
EditorGUILayout.HelpBox("(Physics2D) Only FixedUpdate simulation mode is supported!", MessageType.Error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
if (Physics.simulationMode != SimulationMode.FixedUpdate)
|
||||||
|
EditorGUILayout.HelpBox("(Physics) Only FixedUpdate simulation mode is supported!", MessageType.Error);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUIUtility.labelWidth += 75;
|
||||||
|
DrawDefaultInspector();
|
||||||
|
EditorGUIUtility.labelWidth -= 75;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnSceneGUI()
|
||||||
|
{
|
||||||
|
if (!Application.isPlaying)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Tools.current == Tool.Move)
|
||||||
|
{
|
||||||
|
Tools.hidden = true;
|
||||||
|
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
|
||||||
|
Vector3 targetPosition = Handles.PositionHandle(characterActor.transform.position, characterActor.transform.rotation);
|
||||||
|
|
||||||
|
if (EditorGUI.EndChangeCheck())
|
||||||
|
{
|
||||||
|
Undo.RecordObject(characterActor, "Change character position");
|
||||||
|
characterActor.Teleport(targetPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Tools.current == Tool.Rotate)
|
||||||
|
{
|
||||||
|
Tools.hidden = true;
|
||||||
|
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
|
||||||
|
Quaternion targetRotation = Handles.RotationHandle(characterActor.transform.rotation, characterActor.transform.position);
|
||||||
|
|
||||||
|
if (EditorGUI.EndChangeCheck())
|
||||||
|
{
|
||||||
|
Undo.RecordObject(characterActor, "Change character rotation");
|
||||||
|
characterActor.Teleport(characterActor.Position, targetRotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Tools.hidden = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7f4079846e96c0f4380acc9c850361f7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,11 @@
|
|||||||
|
//#define CCP_DEBUG
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
public enum CharacterActorState
|
||||||
|
{
|
||||||
|
NotGrounded,
|
||||||
|
StableGrounded,
|
||||||
|
UnstableGrounded
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0839a4a1b32db1e46940552291b694b5
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,94 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
public enum CharacterBodyType
|
||||||
|
{
|
||||||
|
Sphere,
|
||||||
|
Capsule
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component exposes all the character body properties, such as width, height, body shape, physics, etc.
|
||||||
|
/// </summary>
|
||||||
|
[AddComponentMenu("Character Controller Pro/Core/Character Body")]
|
||||||
|
public class CharacterBody : MonoBehaviour
|
||||||
|
{
|
||||||
|
[HelpBox("This component will automatically assign a Rigidbody component and a CapsuleCollider component at runtime.", HelpBoxMessageType.Info)]
|
||||||
|
[SerializeField, BooleanButton("Physics", "3D", "2D", false)]
|
||||||
|
bool is2D = false;
|
||||||
|
|
||||||
|
[SerializeField, BreakVector2("Width", "Height")]
|
||||||
|
Vector2 bodySize = new Vector2(1f, 2f);
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
float mass = 50f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the character is governed by 2D Physics, false otherwise.
|
||||||
|
/// </summary>
|
||||||
|
public bool Is2D => is2D;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the RigidbodyComponent component associated to the character.
|
||||||
|
/// </summary>
|
||||||
|
public RigidbodyComponent RigidbodyComponent { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the ColliderComponent component associated to the character.
|
||||||
|
/// </summary>
|
||||||
|
public ColliderComponent ColliderComponent { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the mass of the character.
|
||||||
|
/// </summary>
|
||||||
|
public float Mass => mass;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the body size of the character (width and height).
|
||||||
|
/// </summary>
|
||||||
|
public Vector2 BodySize => bodySize;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the body properties and components.
|
||||||
|
/// </summary>
|
||||||
|
void Awake()
|
||||||
|
{
|
||||||
|
if (Is2D)
|
||||||
|
{
|
||||||
|
|
||||||
|
ColliderComponent = gameObject.AddComponent<CapsuleColliderComponent2D>();
|
||||||
|
RigidbodyComponent = gameObject.AddComponent<RigidbodyComponent2D>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ColliderComponent = gameObject.AddComponent<CapsuleColliderComponent3D>();
|
||||||
|
RigidbodyComponent = gameObject.AddComponent<RigidbodyComponent3D>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CharacterActor characterActor = null;
|
||||||
|
|
||||||
|
|
||||||
|
void OnValidate()
|
||||||
|
{
|
||||||
|
if (characterActor == null)
|
||||||
|
characterActor = GetComponent<CharacterActor>();
|
||||||
|
|
||||||
|
bodySize = new Vector2(
|
||||||
|
Mathf.Max(bodySize.x, 0f),
|
||||||
|
Mathf.Max(bodySize.y, bodySize.x + CharacterConstants.ColliderMinBottomOffset)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (characterActor != null)
|
||||||
|
characterActor.OnValidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 78cff8dc757190641a7708af786fcf21
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
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 Lightbug.Utilities;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.IMGUI.Controls;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
[CustomEditor(typeof(CharacterBody), true), CanEditMultipleObjects]
|
||||||
|
public class CharacterBodyEditor : Editor
|
||||||
|
{
|
||||||
|
SerializedProperty is2D = null;
|
||||||
|
SerializedProperty bodySize = null;
|
||||||
|
|
||||||
|
CharacterBody monoBehaviour;
|
||||||
|
|
||||||
|
void OnEnable()
|
||||||
|
{
|
||||||
|
monoBehaviour = (CharacterBody)target;
|
||||||
|
|
||||||
|
is2D = serializedObject.FindProperty("is2D");
|
||||||
|
bodySize = serializedObject.FindProperty("bodySize");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
serializedObject.Update();
|
||||||
|
|
||||||
|
DrawDefaultInspector();
|
||||||
|
|
||||||
|
if (monoBehaviour.transform.localScale != Vector3.one)
|
||||||
|
EditorGUILayout.HelpBox("Transform local scale must be <1,1,1> !!!", MessageType.Error);
|
||||||
|
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
CapsuleBoundsHandle capsuleHandle = new CapsuleBoundsHandle();
|
||||||
|
|
||||||
|
void OnSceneGUI()
|
||||||
|
{
|
||||||
|
if (monoBehaviour == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (is2D.boolValue)
|
||||||
|
{
|
||||||
|
Transform handlesTransform = monoBehaviour.transform;
|
||||||
|
|
||||||
|
// handlesTransform.rotation = Quaternion.identity;
|
||||||
|
Handles.matrix = handlesTransform.localToWorldMatrix;
|
||||||
|
|
||||||
|
capsuleHandle.radius = bodySize.vector2Value.x / 2f;
|
||||||
|
capsuleHandle.height = bodySize.vector2Value.y;
|
||||||
|
|
||||||
|
capsuleHandle.center = Vector3.up * capsuleHandle.height / 2f;
|
||||||
|
|
||||||
|
capsuleHandle.axes = PrimitiveBoundsHandle.Axes.X | PrimitiveBoundsHandle.Axes.Y;
|
||||||
|
|
||||||
|
capsuleHandle.heightAxis = CapsuleBoundsHandle.HeightAxis.Y;
|
||||||
|
capsuleHandle.DrawHandle();
|
||||||
|
|
||||||
|
Handles.matrix = Matrix4x4.identity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Handles.matrix = monoBehaviour.transform.localToWorldMatrix;
|
||||||
|
|
||||||
|
capsuleHandle.radius = bodySize.vector2Value.x / 2f;
|
||||||
|
capsuleHandle.height = bodySize.vector2Value.y;
|
||||||
|
|
||||||
|
capsuleHandle.center = Vector3.up * capsuleHandle.height / 2f;
|
||||||
|
|
||||||
|
capsuleHandle.axes = PrimitiveBoundsHandle.Axes.X | PrimitiveBoundsHandle.Axes.Y | PrimitiveBoundsHandle.Axes.Z;
|
||||||
|
|
||||||
|
|
||||||
|
capsuleHandle.heightAxis = CapsuleBoundsHandle.HeightAxis.Y;
|
||||||
|
capsuleHandle.DrawHandle();
|
||||||
|
|
||||||
|
Handles.matrix = Matrix4x4.identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 910f81d87065ee64c90d917647aa8feb
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,173 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This struct contains all the character info related to collision, that is, collision flags and external components. All the internal fields are updated frame by frame, and can
|
||||||
|
/// can be accessed by using public properties from the CharacterActor component.
|
||||||
|
/// </summary>
|
||||||
|
public struct CharacterCollisionInfo
|
||||||
|
{
|
||||||
|
// Ground
|
||||||
|
public Vector3 groundContactPoint;
|
||||||
|
public Vector3 groundContactNormal;
|
||||||
|
public Vector3 groundStableNormal;
|
||||||
|
public float groundSlopeAngle;
|
||||||
|
|
||||||
|
// Head
|
||||||
|
public bool headCollision;
|
||||||
|
public Contact headContact;
|
||||||
|
public float headAngle;
|
||||||
|
|
||||||
|
// Wall
|
||||||
|
public bool wallCollision;
|
||||||
|
public Contact wallContact;
|
||||||
|
public float wallAngle;
|
||||||
|
|
||||||
|
// Edge
|
||||||
|
public bool isOnEdge;
|
||||||
|
public float edgeAngle;
|
||||||
|
|
||||||
|
// Object
|
||||||
|
public GameObject groundObject;
|
||||||
|
public int groundLayer;
|
||||||
|
public Collider groundCollider3D;
|
||||||
|
public Collider2D groundCollider2D;
|
||||||
|
public Rigidbody groundRigidbody3D;
|
||||||
|
public Rigidbody2D groundRigidbody2D;
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets all the fields to default.
|
||||||
|
/// </summary>
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
ResetGroundInfo();
|
||||||
|
ResetWallInfo();
|
||||||
|
ResetHeadInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the wall contact related info.
|
||||||
|
/// </summary>
|
||||||
|
public void ResetWallInfo()
|
||||||
|
{
|
||||||
|
wallCollision = false;
|
||||||
|
wallContact = new Contact();
|
||||||
|
wallAngle = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetWallInfo(in Contact contact, CharacterActor characterActor)
|
||||||
|
{
|
||||||
|
wallCollision = true;
|
||||||
|
wallAngle = Vector3.Angle(characterActor.Up, contact.normal);
|
||||||
|
wallContact = contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the head contact related info.
|
||||||
|
/// </summary>
|
||||||
|
public void ResetHeadInfo()
|
||||||
|
{
|
||||||
|
headCollision = false;
|
||||||
|
headContact = new Contact();
|
||||||
|
headAngle = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetHeadInfo(in Contact contact, CharacterActor characterActor)
|
||||||
|
{
|
||||||
|
headCollision = true;
|
||||||
|
headAngle = Vector3.Angle(characterActor.Up, headContact.normal);
|
||||||
|
headContact = contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetGroundInfo(in CollisionInfo collisionInfo, CharacterActor characterActor)
|
||||||
|
{
|
||||||
|
if (collisionInfo.hitInfo.hit)
|
||||||
|
{
|
||||||
|
isOnEdge = collisionInfo.isAnEdge;
|
||||||
|
edgeAngle = collisionInfo.edgeAngle;
|
||||||
|
groundContactNormal = collisionInfo.contactSlopeAngle < 90f ? collisionInfo.hitInfo.normal : characterActor.Up;
|
||||||
|
groundContactPoint = collisionInfo.hitInfo.point;
|
||||||
|
groundStableNormal = characterActor.GetGroundSlopeNormal(collisionInfo);
|
||||||
|
groundSlopeAngle = Vector3.Angle(characterActor.Up, groundStableNormal);
|
||||||
|
|
||||||
|
groundObject = collisionInfo.hitInfo.transform.gameObject;
|
||||||
|
groundLayer = groundObject.layer;
|
||||||
|
groundCollider2D = collisionInfo.hitInfo.collider2D;
|
||||||
|
groundCollider3D = collisionInfo.hitInfo.collider3D;
|
||||||
|
groundRigidbody2D = collisionInfo.hitInfo.rigidbody2D;
|
||||||
|
groundRigidbody3D = collisionInfo.hitInfo.rigidbody3D;
|
||||||
|
|
||||||
|
// Ground contact
|
||||||
|
Vector3 pointVelocity = Vector3.zero;
|
||||||
|
if (collisionInfo.hitInfo.rigidbody2D != null)
|
||||||
|
pointVelocity = collisionInfo.hitInfo.rigidbody2D.GetPointVelocity(groundContactPoint);
|
||||||
|
else if (collisionInfo.hitInfo.rigidbody3D != null)
|
||||||
|
pointVelocity = collisionInfo.hitInfo.rigidbody3D.GetPointVelocity(groundContactPoint);
|
||||||
|
|
||||||
|
Vector3 relativeVelocity = characterActor.Velocity - pointVelocity;
|
||||||
|
Contact groundContact = new Contact(groundContactPoint, groundContactNormal, pointVelocity, relativeVelocity);
|
||||||
|
characterActor.GroundContacts.Add(groundContact);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ResetGroundInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetGroundContact(in CollisionInfo collisionInfo, CharacterActor characterActor)
|
||||||
|
{
|
||||||
|
if (!collisionInfo.hitInfo.hit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Vector3 point = collisionInfo.hitInfo.point;
|
||||||
|
Vector3 normal = collisionInfo.hitInfo.normal;
|
||||||
|
|
||||||
|
Vector3 pointVelocity = Vector3.zero;
|
||||||
|
|
||||||
|
if (collisionInfo.hitInfo.rigidbody2D != null)
|
||||||
|
pointVelocity = collisionInfo.hitInfo.rigidbody2D.GetPointVelocity(point);
|
||||||
|
else if (collisionInfo.hitInfo.rigidbody3D != null)
|
||||||
|
pointVelocity = collisionInfo.hitInfo.rigidbody3D.GetPointVelocity(point);
|
||||||
|
|
||||||
|
|
||||||
|
Vector3 relativeVelocity = characterActor.Velocity - pointVelocity;
|
||||||
|
Contact groundContact = new Contact(point, normal, pointVelocity, relativeVelocity);
|
||||||
|
characterActor.GroundContacts.Add(groundContact);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the ground contact related info.
|
||||||
|
/// </summary>
|
||||||
|
public void ResetGroundInfo()
|
||||||
|
{
|
||||||
|
groundContactPoint = Vector3.zero;
|
||||||
|
groundContactNormal = Vector3.up;
|
||||||
|
groundStableNormal = Vector3.up;
|
||||||
|
|
||||||
|
groundSlopeAngle = 0f;
|
||||||
|
|
||||||
|
isOnEdge = false;
|
||||||
|
edgeAngle = 0f;
|
||||||
|
|
||||||
|
groundObject = null;
|
||||||
|
groundLayer = 0;
|
||||||
|
groundCollider3D = null;
|
||||||
|
groundCollider2D = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c8a789e3f19e91c449f6528c60ddafc3
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,240 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
public abstract class CharacterCollisions : MonoBehaviour
|
||||||
|
{
|
||||||
|
public HitInfo[] HitsBuffer { get; protected set; } = new HitInfo[20];
|
||||||
|
|
||||||
|
protected CharacterActor CharacterActor { get; private set; }
|
||||||
|
public PhysicsComponent PhysicsComponent { get; protected set; }
|
||||||
|
|
||||||
|
readonly CollisionInfo _collisionInfo = new CollisionInfo();
|
||||||
|
|
||||||
|
float BackstepDistance => 2f * ContactOffset;
|
||||||
|
|
||||||
|
public abstract float ContactOffset { get; }
|
||||||
|
public abstract float CollisionRadius { get; }
|
||||||
|
protected Transform Transform;
|
||||||
|
|
||||||
|
public static CharacterCollisions CreateInstance(GameObject gameObject)
|
||||||
|
{
|
||||||
|
Rigidbody2D rigidbody2D = gameObject.GetComponent<Rigidbody2D>();
|
||||||
|
Rigidbody rigidbody3D = gameObject.GetComponent<Rigidbody>();
|
||||||
|
|
||||||
|
if (rigidbody2D != null)
|
||||||
|
return gameObject.GetOrAddComponent<CharacterCollisions2D>();
|
||||||
|
else if (rigidbody3D != null)
|
||||||
|
return gameObject.GetOrAddComponent<CharacterCollisions3D>();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks vertically for the ground using a CastSphere.
|
||||||
|
/// </summary>
|
||||||
|
public CollisionInfo CheckForGround(Vector3 position, float stepOffset, float stepDownDistance, in HitInfoFilter hitInfoFilter, HitFilterDelegate hitFilter = null)
|
||||||
|
{
|
||||||
|
float preDistance = stepOffset + BackstepDistance;
|
||||||
|
Vector3 displacement = CustomUtilities.Multiply(-CharacterActor.Up, Mathf.Max(CharacterConstants.GroundCheckDistance, stepDownDistance));
|
||||||
|
Vector3 origin = CharacterActor.GetBottomCenter(position, preDistance);
|
||||||
|
Vector3 castDisplacement = displacement + CustomUtilities.Multiply(Vector3.Normalize(displacement), preDistance + ContactOffset);
|
||||||
|
|
||||||
|
PhysicsComponent.SphereCast(
|
||||||
|
out HitInfo hitInfo,
|
||||||
|
origin,
|
||||||
|
CollisionRadius,
|
||||||
|
castDisplacement,
|
||||||
|
in hitInfoFilter,
|
||||||
|
false,
|
||||||
|
hitFilter
|
||||||
|
);
|
||||||
|
|
||||||
|
UpdateCollisionInfo(_collisionInfo, position, in hitInfo, castDisplacement, preDistance, true, in hitInfoFilter);
|
||||||
|
return _collisionInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks vertically for the ground using a CastRay.
|
||||||
|
/// </summary>
|
||||||
|
public CollisionInfo CheckForGroundRay(Vector3 position, in HitInfoFilter hitInfoFilter, HitFilterDelegate hitFilter = null)
|
||||||
|
{
|
||||||
|
float preDistance = CharacterActor.BodySize.x / 2f;
|
||||||
|
|
||||||
|
Vector3 origin = CharacterActor.GetBottomCenter(position);
|
||||||
|
Vector3 displacement = CustomUtilities.Multiply(-CharacterActor.Up, Mathf.Max(CharacterConstants.GroundCheckDistance, CharacterActor.stepDownDistance));
|
||||||
|
Vector3 castDisplacement = displacement + CustomUtilities.Multiply(Vector3.Normalize(displacement), preDistance);
|
||||||
|
|
||||||
|
PhysicsComponent.Raycast(
|
||||||
|
out HitInfo hitInfo,
|
||||||
|
origin,
|
||||||
|
castDisplacement,
|
||||||
|
in hitInfoFilter,
|
||||||
|
false,
|
||||||
|
hitFilter
|
||||||
|
);
|
||||||
|
|
||||||
|
UpdateCollisionInfo(_collisionInfo, position, in hitInfo, castDisplacement, preDistance, false, in hitInfoFilter);
|
||||||
|
return _collisionInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cast the current body shape a get the closest hit.
|
||||||
|
/// </summary>
|
||||||
|
public CollisionInfo CastBody(Vector3 position, Vector3 displacement, float bottomOffset, in HitInfoFilter hitInfoFilter, bool allowOverlaps = false, HitFilterDelegate hitFilter = null)
|
||||||
|
{
|
||||||
|
float preDistance = BackstepDistance;
|
||||||
|
Vector3 direction = Vector3.Normalize(displacement);
|
||||||
|
|
||||||
|
Vector3 bottom = CharacterActor.GetBottomCenter(position, bottomOffset);
|
||||||
|
Vector3 top = CharacterActor.GetTopCenter(position);
|
||||||
|
bottom -= CustomUtilities.Multiply(direction, preDistance);
|
||||||
|
top -= CustomUtilities.Multiply(direction, preDistance);
|
||||||
|
|
||||||
|
Vector3 castDisplacement = displacement + CustomUtilities.Multiply(Vector3.Normalize(displacement), preDistance + ContactOffset);
|
||||||
|
float radius = CharacterActor.BodySize.x / 2f;
|
||||||
|
|
||||||
|
PhysicsComponent.CapsuleCast(
|
||||||
|
out HitInfo hitInfo,
|
||||||
|
bottom,
|
||||||
|
top,
|
||||||
|
radius,
|
||||||
|
castDisplacement,
|
||||||
|
in hitInfoFilter,
|
||||||
|
allowOverlaps,
|
||||||
|
hitFilter
|
||||||
|
);
|
||||||
|
|
||||||
|
UpdateCollisionInfo(_collisionInfo, position, in hitInfo, castDisplacement, preDistance, false, in hitInfoFilter);
|
||||||
|
return _collisionInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs an overlap test at a given position.
|
||||||
|
/// </summary>
|
||||||
|
[System.Obsolete("Use CheckOverlap instead.")]
|
||||||
|
public bool CheckOverlapWithLayerMask(Vector3 position, float bottomOffset, in HitInfoFilter hitInfoFilter, HitFilterDelegate hitFilter = null) =>
|
||||||
|
CheckOverlap(position, bottomOffset, in hitInfoFilter, hitFilter);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs an overlap test at a given position.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="position">Target position.</param>
|
||||||
|
/// <param name="bottomOffset">Bottom offset of the capsule.</param>
|
||||||
|
/// <param name="hitInfoFilter">Overlap filter.</param>
|
||||||
|
/// <returns>True if the overlap test detects some obstacle.</returns>
|
||||||
|
public bool CheckOverlap(Vector3 position, float bottomOffset, in HitInfoFilter hitInfoFilter, HitFilterDelegate hitFilter = null)
|
||||||
|
{
|
||||||
|
Vector3 bottom = CharacterActor.GetBottomCenter(position, bottomOffset);
|
||||||
|
Vector3 top = CharacterActor.GetTopCenter(position);
|
||||||
|
float radius = CharacterActor.BodySize.x / 2f - CharacterConstants.SkinWidth;
|
||||||
|
|
||||||
|
bool overlap = PhysicsComponent.OverlapCapsule(
|
||||||
|
bottom,
|
||||||
|
top,
|
||||||
|
radius,
|
||||||
|
in hitInfoFilter,
|
||||||
|
hitFilter
|
||||||
|
);
|
||||||
|
|
||||||
|
return overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the character fits at a specific location.
|
||||||
|
/// </summary>
|
||||||
|
public bool CheckBodySize(Vector3 size, Vector3 position, in HitInfoFilter hitInfoFilter, HitFilterDelegate hitFilter = null)
|
||||||
|
{
|
||||||
|
Vector3 bottom = CharacterActor.GetBottomCenter(position, size);
|
||||||
|
float radius = size.x / 2f;
|
||||||
|
|
||||||
|
// BottomCenterToTopCenter = Up displacement
|
||||||
|
Vector3 castDisplacement = CharacterActor.GetBottomCenterToTopCenter(size);
|
||||||
|
|
||||||
|
PhysicsComponent.SphereCast(
|
||||||
|
out HitInfo hitInfo,
|
||||||
|
bottom,
|
||||||
|
radius,
|
||||||
|
castDisplacement,
|
||||||
|
in hitInfoFilter,
|
||||||
|
false,
|
||||||
|
hitFilter
|
||||||
|
);
|
||||||
|
|
||||||
|
bool overlap = hitInfo.hit;
|
||||||
|
return !overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the character fits in place.
|
||||||
|
/// </summary>
|
||||||
|
public bool CheckBodySize(Vector3 size, in HitInfoFilter hitInfoFilter, HitFilterDelegate hitFilter = null) => CheckBodySize(size, CharacterActor.Position, in hitInfoFilter, hitFilter);
|
||||||
|
|
||||||
|
|
||||||
|
public void UpdateCollisionInfo(
|
||||||
|
CollisionInfo collisionInfo,
|
||||||
|
Vector3 position,
|
||||||
|
in HitInfo hitInfo,
|
||||||
|
Vector3 castDisplacement,
|
||||||
|
float preDistance,
|
||||||
|
bool calculateEdge = true,
|
||||||
|
in HitInfoFilter hitInfoFilter = new HitInfoFilter())
|
||||||
|
{
|
||||||
|
if (hitInfo.hit)
|
||||||
|
{
|
||||||
|
Vector3 castDirection = Vector3.Normalize(castDisplacement);
|
||||||
|
|
||||||
|
float closestDistance = hitInfo.distance - preDistance - ContactOffset;
|
||||||
|
|
||||||
|
var displacement = castDirection * closestDistance;
|
||||||
|
|
||||||
|
if (calculateEdge)
|
||||||
|
{
|
||||||
|
Vector3 edgeCenterReference = CharacterActor.GetBottomCenter(position + displacement, 0f);
|
||||||
|
PerformEdgeDetectionRaycasts(in edgeCenterReference, in hitInfo.point, in hitInfoFilter, out HitInfo upperHitInfo, out HitInfo lowerHitInfo);
|
||||||
|
|
||||||
|
collisionInfo.SetData(in hitInfo, CharacterActor.Up, displacement, in upperHitInfo, in lowerHitInfo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
collisionInfo.SetData(in hitInfo, CharacterActor.Up, displacement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
collisionInfo.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PerformEdgeDetectionRaycasts(in Vector3 edgeCenterReference, in Vector3 contactPoint, in HitInfoFilter hitInfoFilter, out HitInfo upperHitInfo, out HitInfo lowerHitInfo)
|
||||||
|
{
|
||||||
|
Vector3 castDirection = Vector3.Normalize(contactPoint - edgeCenterReference);
|
||||||
|
Vector3 castDisplacement = CustomUtilities.Multiply(castDirection, CharacterConstants.EdgeRaysCastDistance);
|
||||||
|
Vector3 upperHitPosition = edgeCenterReference + CustomUtilities.Multiply(CharacterActor.Up, CharacterConstants.EdgeRaysSeparation);
|
||||||
|
Vector3 lowerHitPosition = edgeCenterReference - CustomUtilities.Multiply(CharacterActor.Up, CharacterConstants.EdgeRaysSeparation);
|
||||||
|
|
||||||
|
PhysicsComponent.Raycast(
|
||||||
|
out upperHitInfo,
|
||||||
|
upperHitPosition,
|
||||||
|
castDisplacement,
|
||||||
|
in hitInfoFilter
|
||||||
|
);
|
||||||
|
|
||||||
|
PhysicsComponent.Raycast(
|
||||||
|
out lowerHitInfo,
|
||||||
|
lowerHitPosition,
|
||||||
|
castDisplacement,
|
||||||
|
in hitInfoFilter
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Awake()
|
||||||
|
{
|
||||||
|
CharacterActor = GetComponent<CharacterActor>();
|
||||||
|
if (CharacterActor == null)
|
||||||
|
Debug.Log("CharacterCollisions: CharacterComponent missing");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d83fb70402062c54fb7df4da208f8c07
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,18 @@
|
|||||||
|
using Lightbug.Utilities;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
public class CharacterCollisions2D : CharacterCollisions
|
||||||
|
{
|
||||||
|
protected override void Awake()
|
||||||
|
{
|
||||||
|
base.Awake();
|
||||||
|
|
||||||
|
PhysicsComponent = gameObject.AddComponent<PhysicsComponent2D>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float ContactOffset => Physics2D.defaultContactOffset;
|
||||||
|
public override float CollisionRadius => CharacterActor.BodySize.x / 2f;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0ebd659de5ec4cb409f72a4d32922e72
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,18 @@
|
|||||||
|
using Lightbug.Utilities;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
public class CharacterCollisions3D : CharacterCollisions
|
||||||
|
{
|
||||||
|
protected override void Awake()
|
||||||
|
{
|
||||||
|
base.Awake();
|
||||||
|
|
||||||
|
PhysicsComponent = gameObject.AddComponent<PhysicsComponent3D>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float ContactOffset => Physics.defaultContactOffset;
|
||||||
|
public override float CollisionRadius => CharacterActor.BodySize.x / 2f;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9661c2503d7fe3a4c93582e96d9c6644
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,103 @@
|
|||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This class contain all the constants used for collision detection, steps detection, ground probing, etc. All the values were carefully chosen, this means that it is not recommended to modify these values at all,
|
||||||
|
/// however if you need to do it do so at your own risk (make a backup before).
|
||||||
|
/// </summary>
|
||||||
|
public class CharacterConstants
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Offset (towards the ground) applied to the ground trigger.
|
||||||
|
/// </summary>
|
||||||
|
public const float GroundTriggerOffset = 0.05f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This value represents the time (in seconds) that a jumping character can remain unstable while touching the ground. This becomes useful to prevent the character
|
||||||
|
/// to be stuck in this unstable state for too long.
|
||||||
|
/// </summary>
|
||||||
|
public const float MaxUnstableGroundContactTime = 0.25f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Distance between the origins of the upper and lower edge detection rays.
|
||||||
|
/// </summary>
|
||||||
|
public const float EdgeRaysSeparation = 0.005f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cast distance used for the raycasts in the edge detection algorithm.
|
||||||
|
/// </summary>
|
||||||
|
public const float EdgeRaysCastDistance = 2f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Space between the collider and the collision shape (used by physics queries).
|
||||||
|
/// </summary>
|
||||||
|
public const float SkinWidth = 0.005f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minimum offset applied to the bottom of the capsule (upwards) to avoid contact with the ground.
|
||||||
|
/// </summary>
|
||||||
|
public const float ColliderMinBottomOffset = 0.1f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minimum angle between upper and lower normals (from the edge detector) that defines an edge.
|
||||||
|
/// </summary>
|
||||||
|
public const float MinEdgeAngle = 0.5f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum angle between upper and lower normals (from the edge detector) that defines an edge.
|
||||||
|
/// </summary>
|
||||||
|
public const float MaxEdgeAngle = 170f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minimum angle between upper and lower normals (from the edge detector) that defines a step.
|
||||||
|
/// </summary>
|
||||||
|
public const float MinStepAngle = 85f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum angle between upper and lower normals (from the edge detector) that defines a step.
|
||||||
|
/// </summary>
|
||||||
|
public const float MaxStepAngle = 95f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base distance used for ground probing.
|
||||||
|
/// </summary>
|
||||||
|
public const float GroundCheckDistance = 0.1f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum number of iterations available for the collide and slide algorithm.
|
||||||
|
/// </summary>
|
||||||
|
public const int MaxSlideIterations = 3;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum number of iterations available for the collide and slide algorithm used after the simulation (dynamic ground processing).
|
||||||
|
/// </summary>
|
||||||
|
public const int MaxPostSimulationSlideIterations = 2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default gravity value used by the weight function.
|
||||||
|
/// </summary>
|
||||||
|
public const float DefaultGravity = 9.8f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minimum angle value considered when choosing the "head contact". The angle is measured between the contact normal and the "Up" vector.
|
||||||
|
/// The valid range goes from "MinHeadContactAngle" to 180 degrees.
|
||||||
|
/// </summary>
|
||||||
|
public const float HeadContactMinAngle = 100f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tolerance value considered when choosing the "wall contact". The angle is measured between the contact normal and the "Up" vector.
|
||||||
|
/// The valid range goes from 90 - "WallContactAngleTolerance" to 90 degrees.
|
||||||
|
/// </summary>
|
||||||
|
public const float WallContactAngleTolerance = 10f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Distance used to predict the ground below the character.
|
||||||
|
/// </summary>
|
||||||
|
public const float GroundPredictionDistance = 10f;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ca9a8d1e9f8176943ba18353b6d4618d
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,113 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This class is used for debug purposes, mainly to print information on screen about the collision flags, certain values and/or triggering events.
|
||||||
|
/// </summary>
|
||||||
|
[DefaultExecutionOrder(ExecutionOrder.CharacterActorOrder)]
|
||||||
|
[AddComponentMenu("Character Controller Pro/Core/Character Debug")]
|
||||||
|
public class CharacterDebug : MonoBehaviour
|
||||||
|
{
|
||||||
|
[SerializeField]
|
||||||
|
CharacterActor characterActor = null;
|
||||||
|
|
||||||
|
[Header("Character Info")]
|
||||||
|
[SerializeField]
|
||||||
|
Text text = null;
|
||||||
|
|
||||||
|
[Header("Events")]
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
bool printEvents = false;
|
||||||
|
|
||||||
|
[Header("Stability")]
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
Renderer stabilityIndicator;
|
||||||
|
|
||||||
|
[Condition("stabilityIndicator", ConditionAttribute.ConditionType.IsNotNull, ConditionAttribute.VisibilityType.NotEditable)]
|
||||||
|
[SerializeField]
|
||||||
|
Color stableColor = new Color(0f, 1f, 0f, 0.5f);
|
||||||
|
|
||||||
|
[Condition("stabilityIndicator", ConditionAttribute.ConditionType.IsNotNull, ConditionAttribute.VisibilityType.NotEditable)]
|
||||||
|
[SerializeField]
|
||||||
|
Color unstableColor = new Color(1f, 0f, 0f, 0.5f);
|
||||||
|
|
||||||
|
int colorID = Shader.PropertyToID("_Color");
|
||||||
|
float time = 0f;
|
||||||
|
|
||||||
|
void UpdateCharacterInfoText()
|
||||||
|
{
|
||||||
|
if (text == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (time > 0.2f)
|
||||||
|
{
|
||||||
|
text.text = characterActor.GetCharacterInfo();
|
||||||
|
time = 0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
time += Time.deltaTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnWallHit(Contact contact) => Debug.Log("OnWallHit");
|
||||||
|
void OnGroundedStateEnter(Vector3 localVelocity) => Debug.Log("OnEnterGroundedState, localVelocity : " + localVelocity.ToString("F3"));
|
||||||
|
void OnGroundedStateExit() => Debug.Log("OnExitGroundedState");
|
||||||
|
void OnStableStateEnter(Vector3 localVelocity) => Debug.Log("OnStableStateEnter, localVelocity : " + localVelocity.ToString("F3"));
|
||||||
|
void OnStableStateExit() => Debug.Log("OnStableStateExit");
|
||||||
|
void OnHeadHit(Contact contact) => Debug.Log("OnHeadHit");
|
||||||
|
void OnTeleportation(Vector3 position, Quaternion rotation) => Debug.Log("OnTeleportation, position : " + position.ToString("F3") + " and rotation : " + rotation.ToString("F3"));
|
||||||
|
|
||||||
|
#region Messages
|
||||||
|
void FixedUpdate()
|
||||||
|
{
|
||||||
|
if (characterActor == null)
|
||||||
|
{
|
||||||
|
enabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateCharacterInfoText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
if (stabilityIndicator != null)
|
||||||
|
stabilityIndicator.material.SetColor(colorID, characterActor.IsStable ? stableColor : unstableColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnEnable()
|
||||||
|
{
|
||||||
|
if (!printEvents)
|
||||||
|
return;
|
||||||
|
|
||||||
|
characterActor.OnHeadHit += OnHeadHit;
|
||||||
|
characterActor.OnWallHit += OnWallHit;
|
||||||
|
characterActor.OnGroundedStateEnter += OnGroundedStateEnter;
|
||||||
|
characterActor.OnGroundedStateExit += OnGroundedStateExit;
|
||||||
|
characterActor.OnStableStateEnter += OnStableStateEnter;
|
||||||
|
characterActor.OnStableStateExit += OnStableStateExit;
|
||||||
|
characterActor.OnTeleport += OnTeleportation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDisable()
|
||||||
|
{
|
||||||
|
if (!printEvents)
|
||||||
|
return;
|
||||||
|
|
||||||
|
characterActor.OnHeadHit -= OnHeadHit;
|
||||||
|
characterActor.OnWallHit -= OnWallHit;
|
||||||
|
characterActor.OnGroundedStateEnter -= OnGroundedStateEnter;
|
||||||
|
characterActor.OnGroundedStateExit -= OnGroundedStateExit;
|
||||||
|
characterActor.OnStableStateEnter += OnStableStateEnter;
|
||||||
|
characterActor.OnStableStateExit += OnStableStateExit;
|
||||||
|
characterActor.OnTeleport -= OnTeleportation;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d10147059bd4fd540bb9e250c0eb10ff
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,117 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This class contains the collision information gathered from of all the different physics queries (raycast, capsuleCast, etc). This information is very important
|
||||||
|
/// for movement prediction.
|
||||||
|
/// </summary>
|
||||||
|
public class CollisionInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The physics query data.
|
||||||
|
/// </summary>
|
||||||
|
public HitInfo hitInfo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The available displacement obtained as the result of the collision test. By adding this vector to the character position, the result will represent the closest possible position to the hit surface.
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 displacement;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The angle between the contact normal and the character up vector.
|
||||||
|
/// </summary>
|
||||||
|
public float contactSlopeAngle;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flag that indicates if the character is standing on an edge or not.
|
||||||
|
/// </summary>
|
||||||
|
public bool isAnEdge;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flag that indicates if the character is standing on an step or not.
|
||||||
|
/// </summary>
|
||||||
|
public bool isAStep;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Normal vector obtained from the edge detector upper ray.
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 edgeUpperNormal;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Normal vector obtained from the edge detector lower ray.
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 edgeLowerNormal;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Angle between the character up vector and the edge detector upper normal.
|
||||||
|
/// </summary>
|
||||||
|
public float edgeUpperSlopeAngle;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Angle between the character up vector and the edge detector lower normal.
|
||||||
|
/// </summary>
|
||||||
|
public float edgeLowerSlopeAngle;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Angle between the edge detector upper normal and the edge detector lower normal.
|
||||||
|
/// </summary>
|
||||||
|
public float edgeAngle;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets all the fields to their default values.
|
||||||
|
/// </summary>
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
this.hitInfo = default;
|
||||||
|
this.displacement = default;
|
||||||
|
this.contactSlopeAngle = default;
|
||||||
|
this.edgeUpperNormal = default;
|
||||||
|
this.edgeLowerNormal = default;
|
||||||
|
this.edgeUpperSlopeAngle = default;
|
||||||
|
this.edgeLowerSlopeAngle = default;
|
||||||
|
this.edgeAngle = default;
|
||||||
|
this.isAnEdge = default;
|
||||||
|
this.isAStep = default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the fields values based on the character movement.
|
||||||
|
/// </summary>
|
||||||
|
public void SetData(in HitInfo hitInfo, Vector3 upDirection, Vector3 displacement)
|
||||||
|
{
|
||||||
|
this.hitInfo = hitInfo;
|
||||||
|
this.displacement = displacement;
|
||||||
|
this.contactSlopeAngle = Vector3.Angle(upDirection, hitInfo.normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the fields values based on the character movement.
|
||||||
|
/// </summary>
|
||||||
|
public void SetData(
|
||||||
|
in HitInfo hitInfo,
|
||||||
|
Vector3 upDirection,
|
||||||
|
Vector3 displacement,
|
||||||
|
in HitInfo upperHitInfo,
|
||||||
|
in HitInfo lowerHitInfo
|
||||||
|
)
|
||||||
|
{
|
||||||
|
SetData(in hitInfo, upDirection, displacement);
|
||||||
|
|
||||||
|
this.edgeUpperNormal = upperHitInfo.normal;
|
||||||
|
this.edgeLowerNormal = lowerHitInfo.normal;
|
||||||
|
|
||||||
|
this.edgeUpperSlopeAngle = Vector3.Angle(edgeUpperNormal, upDirection);
|
||||||
|
this.edgeLowerSlopeAngle = Vector3.Angle(edgeLowerNormal, upDirection);
|
||||||
|
|
||||||
|
this.edgeAngle = Vector3.Angle(edgeUpperNormal, edgeLowerNormal);
|
||||||
|
|
||||||
|
this.isAnEdge = CustomUtilities.isBetween(edgeAngle, CharacterConstants.MinEdgeAngle, CharacterConstants.MaxEdgeAngle, true);
|
||||||
|
this.isAStep = CustomUtilities.isBetween(edgeAngle, CharacterConstants.MinStepAngle, CharacterConstants.MaxStepAngle, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 917a9bbab88628e40acfcae8c9a18e66
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 939c76a9b1746ed4ba9f3d184f7b544c
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,44 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The root abstract class for all the graphics-based components.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class CharacterGraphics : MonoBehaviour
|
||||||
|
{
|
||||||
|
protected CharacterActor CharacterActor { get; private set; }
|
||||||
|
protected CharacterBody CharacterBody => CharacterActor.CharacterBody;
|
||||||
|
|
||||||
|
protected virtual void OnValidate()
|
||||||
|
{
|
||||||
|
CharacterActor = this.GetComponentInBranch<CharacterActor>();
|
||||||
|
|
||||||
|
if (CharacterActor == null)
|
||||||
|
{
|
||||||
|
Debug.Log("Warning: No CharacterActor component detected in this hierarchy.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Awake()
|
||||||
|
{
|
||||||
|
CharacterActor = this.GetComponentInBranch<CharacterActor>();
|
||||||
|
|
||||||
|
if (CharacterActor == null)
|
||||||
|
{
|
||||||
|
Debug.Log("Warning: No CharacterActor component detected in this hierarchy.");
|
||||||
|
enabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//RootController = CharacterActor.GetComponentInChildren<CharacterGraphicsRootController>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 28b91e21fd19e4f409985c581cdd7b61
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,123 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component can be used to rotate a 2D character based on its forward direction. For 2D, characters usually have its forward direction pointing towards Vector3.forward (or negtive).
|
||||||
|
/// </summary>
|
||||||
|
[AddComponentMenu("Character Controller Pro/Core/Character Graphics/2D Rotator (Obsolete)")]
|
||||||
|
[DefaultExecutionOrder(ExecutionOrder.CharacterGraphicsOrder)]
|
||||||
|
public class CharacterGraphics2DRotator : CharacterGraphics
|
||||||
|
{
|
||||||
|
[HelpBox("This component is obsolete and has been replaced with the CharacterSpriteScaler component, which is a simplified version.", HelpBoxMessageType.Warning)]
|
||||||
|
[Tooltip("Scale: it will flip the sprite along the horizontal axis (localScale). This works only with sprites!\nRotation: it will rotate the object towards the facing direction.")]
|
||||||
|
public FacingDirectionMode facingDirectionMode = FacingDirectionMode.Rotation;
|
||||||
|
|
||||||
|
[Condition("facingDirectionMode", ConditionAttribute.ConditionType.IsEqualTo, ConditionAttribute.VisibilityType.Hidden, (int)FacingDirectionMode.Scale)]
|
||||||
|
[SerializeField]
|
||||||
|
VectorComponent scaleAffectedComponent = VectorComponent.X;
|
||||||
|
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
Vector3 initialScale = Vector3.zero;
|
||||||
|
Vector3 initialForward;
|
||||||
|
|
||||||
|
enum VectorComponent
|
||||||
|
{
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
Z
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The method used by the CharacterGraphics component to orient the graphics object towards the facing direction vector.
|
||||||
|
/// </summary>
|
||||||
|
public enum FacingDirectionMode
|
||||||
|
{
|
||||||
|
Rotation,
|
||||||
|
Scale
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
void HandleRotation(float dt)
|
||||||
|
{
|
||||||
|
if (facingDirectionMode == FacingDirectionMode.Scale)
|
||||||
|
{
|
||||||
|
transform.rotation = Quaternion.LookRotation(initialForward, CharacterActor.Up);
|
||||||
|
|
||||||
|
float signedAngle = Vector3.SignedAngle(CharacterActor.Forward, CharacterActor.Up, Vector3.forward);
|
||||||
|
bool shouldBeFacingRight = signedAngle > 0f;
|
||||||
|
|
||||||
|
switch (scaleAffectedComponent)
|
||||||
|
{
|
||||||
|
case VectorComponent.X:
|
||||||
|
|
||||||
|
transform.localScale = new Vector3(
|
||||||
|
shouldBeFacingRight ? initialScale.x : -initialScale.x,
|
||||||
|
transform.localScale.y,
|
||||||
|
transform.localScale.z
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case VectorComponent.Y:
|
||||||
|
|
||||||
|
transform.localScale = new Vector3(
|
||||||
|
transform.localScale.x,
|
||||||
|
shouldBeFacingRight ? initialScale.y : -initialScale.y,
|
||||||
|
transform.localScale.z
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case VectorComponent.Z:
|
||||||
|
|
||||||
|
transform.localScale = new Vector3(
|
||||||
|
transform.localScale.x,
|
||||||
|
transform.localScale.y,
|
||||||
|
shouldBeFacingRight ? initialScale.z : -initialScale.z
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnValidate()
|
||||||
|
{
|
||||||
|
base.OnValidate();
|
||||||
|
|
||||||
|
if (!CharacterBody.Is2D)
|
||||||
|
Debug.Log("Warning: CharacterBody is not 2D. This component is intended to be used with a 2D physics character.");
|
||||||
|
|
||||||
|
SkinnedMeshRenderer skinnedMeshRenderer = GetComponentInChildren<SkinnedMeshRenderer>();
|
||||||
|
if (skinnedMeshRenderer != null && facingDirectionMode == FacingDirectionMode.Scale)
|
||||||
|
Debug.Log("Warning: \"Scale\" facing direction mode is intended to work with sprites, not with humanoid characters, choose \"Rotation\" instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Awake()
|
||||||
|
{
|
||||||
|
base.Awake();
|
||||||
|
if (!CharacterBody.Is2D)
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
initialScale = transform.localScale;
|
||||||
|
initialForward = transform.forward;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LateUpdate()
|
||||||
|
{
|
||||||
|
float dt = Time.deltaTime;
|
||||||
|
HandleRotation(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b0530af9c2dd9364790ff3a6267906fc
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,174 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component is responsible for smoothing out the graphics-related elements (under the root object) based on the character movement and rotation.
|
||||||
|
/// </summary>
|
||||||
|
[AddComponentMenu("Character Controller Pro/Core/Character Graphics/Graphics Root Controller (obsolete)")]
|
||||||
|
[DefaultExecutionOrder(ExecutionOrder.CharacterGraphicsOrder)]
|
||||||
|
public class CharacterGraphicsRootController : CharacterGraphics
|
||||||
|
{
|
||||||
|
[HelpBox("This component is obsolete. It has been separated into two new components: Step Lerper and Rotation Lerper.", HelpBoxMessageType.Warning)]
|
||||||
|
[Tooltip("Whether or not interpolate the rotation of the character.")]
|
||||||
|
[SerializeField]
|
||||||
|
bool lerpRotation = false;
|
||||||
|
|
||||||
|
[Condition("lerpRotation", ConditionAttribute.ConditionType.IsTrue, ConditionAttribute.VisibilityType.NotEditable)]
|
||||||
|
[SerializeField]
|
||||||
|
float rotationLerpSpeed = 25f;
|
||||||
|
|
||||||
|
[Space(10f)]
|
||||||
|
|
||||||
|
[Tooltip("Whether or not to interpolate the vertical displacement change of the character. A vertical displacement happens everytime the character " +
|
||||||
|
"increase/decrease its vertical position (slopes, step up, step down, etc.). This feature does not work with rigidbodies (if this is required use the new VerticalDisplacementLerper component instead).")]
|
||||||
|
[SerializeField]
|
||||||
|
bool lerpVerticalDisplacement = true;
|
||||||
|
|
||||||
|
[Tooltip("How fast the step up interpolation is going to be.")]
|
||||||
|
[SerializeField]
|
||||||
|
float positiveDisplacementSpeed = 10f;
|
||||||
|
|
||||||
|
[Tooltip("How fast the step down interpolation is going to be.")]
|
||||||
|
[SerializeField]
|
||||||
|
float negativeDisplacementSpeed = 40f;
|
||||||
|
|
||||||
|
|
||||||
|
[Tooltip("Having a character that is being interpolated all the time is not ideal, especially when walking on slopes, being not grounded, or maybe using a moving platform. " +
|
||||||
|
"For those cases, the character should be allowed to smoothly go back to its original local position over time. This field represents the duration of this process (in seconds).")]
|
||||||
|
[SerializeField]
|
||||||
|
float recoveryDuration = 1f;
|
||||||
|
|
||||||
|
[Tooltip("The maximum speed used for the recovery process (see recoveryDuration tooltip).")]
|
||||||
|
[SerializeField]
|
||||||
|
float maxRecoverySpeed = 200f;
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
Vector3 previousPosition = default(Vector3);
|
||||||
|
Quaternion previousRotation = default(Quaternion);
|
||||||
|
|
||||||
|
Vector3 initialLocalForward = default(Vector3);
|
||||||
|
|
||||||
|
protected override void OnValidate()
|
||||||
|
{
|
||||||
|
base.OnValidate();
|
||||||
|
|
||||||
|
CustomUtilities.SetPositive(ref rotationLerpSpeed);
|
||||||
|
CustomUtilities.SetPositive(ref positiveDisplacementSpeed);
|
||||||
|
CustomUtilities.SetPositive(ref negativeDisplacementSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
initialLocalForward = CharacterActor.transform.InverseTransformDirection(transform.forward);
|
||||||
|
|
||||||
|
previousPosition = transform.position;
|
||||||
|
previousRotation = transform.rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void OnEnable()
|
||||||
|
{
|
||||||
|
CharacterActor.OnTeleport += OnTeleport;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDisable()
|
||||||
|
{
|
||||||
|
CharacterActor.OnTeleport -= OnTeleport;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool teleportFlag = false;
|
||||||
|
|
||||||
|
void OnTeleport(Vector3 position, Quaternion rotation)
|
||||||
|
{
|
||||||
|
teleportFlag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
if (CharacterActor == null)
|
||||||
|
{
|
||||||
|
this.enabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float dt = Time.deltaTime;
|
||||||
|
|
||||||
|
HandleRotation(dt);
|
||||||
|
HandleVerticalDisplacement(dt);
|
||||||
|
|
||||||
|
if (teleportFlag)
|
||||||
|
teleportFlag = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
float recoveryTimer = 0f;
|
||||||
|
|
||||||
|
void HandleVerticalDisplacement(float dt)
|
||||||
|
{
|
||||||
|
if (!lerpVerticalDisplacement)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (teleportFlag)
|
||||||
|
{
|
||||||
|
previousPosition = transform.position;
|
||||||
|
transform.position = CharacterActor.Position;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 planarDisplacement = Vector3.ProjectOnPlane(CharacterActor.transform.position - previousPosition, CharacterActor.Up);
|
||||||
|
Vector3 verticalDisplacement = Vector3.Project(CharacterActor.transform.position - previousPosition, CharacterActor.Up);
|
||||||
|
|
||||||
|
float groundProbingDisplacement = CharacterActor.transform.InverseTransformVectorUnscaled(CharacterActor.GroundProbingDisplacement).y;
|
||||||
|
|
||||||
|
if (Mathf.Abs(groundProbingDisplacement) < 0.01f)
|
||||||
|
recoveryTimer += dt;
|
||||||
|
else
|
||||||
|
recoveryTimer = 0f;
|
||||||
|
|
||||||
|
// Choose between positive and negative displacement speed based on the vertical displacement.
|
||||||
|
bool upwardsLerpDirection = CharacterActor.transform.InverseTransformVectorUnscaled(verticalDisplacement).y >= 0f;
|
||||||
|
float displacementTSpeed = upwardsLerpDirection ? positiveDisplacementSpeed : negativeDisplacementSpeed;
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate the lerp t speed as a function of the recovery timer.
|
||||||
|
float lerpTSpeedOutput = Mathf.Min(displacementTSpeed + ((maxRecoverySpeed - displacementTSpeed) / recoveryDuration) * recoveryTimer, maxRecoverySpeed);
|
||||||
|
|
||||||
|
transform.position = previousPosition + planarDisplacement + Vector3.Lerp(Vector3.zero, verticalDisplacement, lerpTSpeedOutput * dt);
|
||||||
|
|
||||||
|
previousPosition = transform.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HandleRotation(float dt)
|
||||||
|
{
|
||||||
|
if (!lerpRotation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (teleportFlag)
|
||||||
|
{
|
||||||
|
transform.localRotation = Quaternion.identity;
|
||||||
|
previousRotation = transform.rotation;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
transform.rotation = Quaternion.Slerp(previousRotation, CharacterActor.Rotation, rotationLerpSpeed * dt);
|
||||||
|
|
||||||
|
previousRotation = transform.rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f0d53e635ffddec4bb2ec7efd96e71b8
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,84 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component can be used to make a Transform change its scale based on the character actor height.
|
||||||
|
/// </summary>
|
||||||
|
[AddComponentMenu("Character Controller Pro/Core/Character Graphics/Scaler")]
|
||||||
|
[DefaultExecutionOrder(ExecutionOrder.CharacterGraphicsOrder + 1)]
|
||||||
|
public class CharacterGraphicsScaler : CharacterGraphics
|
||||||
|
{
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
VectorComponent scaleHeightComponent = VectorComponent.Y;
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
enum VectorComponent
|
||||||
|
{
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
Z
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 initialLocalScale = Vector3.one;
|
||||||
|
|
||||||
|
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
initialLocalScale = transform.localScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
if (!CharacterActor.enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Vector3 scale = Vector3.one;
|
||||||
|
|
||||||
|
switch (scaleHeightComponent)
|
||||||
|
{
|
||||||
|
case VectorComponent.X:
|
||||||
|
|
||||||
|
scale = new Vector3(
|
||||||
|
initialLocalScale.x * (CharacterActor.BodySize.y / CharacterActor.DefaultBodySize.y),
|
||||||
|
initialLocalScale.y * (CharacterActor.BodySize.x / CharacterActor.DefaultBodySize.x),
|
||||||
|
initialLocalScale.z * (CharacterActor.BodySize.x / CharacterActor.DefaultBodySize.x)
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case VectorComponent.Y:
|
||||||
|
|
||||||
|
scale = new Vector3(
|
||||||
|
initialLocalScale.x * (CharacterActor.BodySize.x / CharacterActor.DefaultBodySize.x),
|
||||||
|
initialLocalScale.y * (CharacterActor.BodySize.y / CharacterActor.DefaultBodySize.y),
|
||||||
|
initialLocalScale.z * (CharacterActor.BodySize.x / CharacterActor.DefaultBodySize.x)
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case VectorComponent.Z:
|
||||||
|
|
||||||
|
scale = new Vector3(
|
||||||
|
initialLocalScale.x * (CharacterActor.BodySize.x / CharacterActor.DefaultBodySize.x),
|
||||||
|
initialLocalScale.y * (CharacterActor.BodySize.x / CharacterActor.DefaultBodySize.x),
|
||||||
|
initialLocalScale.z * (CharacterActor.BodySize.y / CharacterActor.DefaultBodySize.y)
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
transform.localScale = scale;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5e93c8610dacb85428134b9b32dec22a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,76 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component can be used to smooth out the graphics object rotation.
|
||||||
|
/// </summary>
|
||||||
|
[AddComponentMenu("Character Controller Pro/Core/Character Graphics/Rotation Lerper")]
|
||||||
|
[DefaultExecutionOrder(ExecutionOrder.CharacterGraphicsOrder)]
|
||||||
|
public class CharacterRotationLerper : CharacterGraphics
|
||||||
|
{
|
||||||
|
[Condition("lerpRotation", ConditionAttribute.ConditionType.IsTrue, ConditionAttribute.VisibilityType.NotEditable)]
|
||||||
|
[SerializeField]
|
||||||
|
float rotationLerpSpeed = 25f;
|
||||||
|
|
||||||
|
Quaternion previousRotation = default;
|
||||||
|
bool teleportFlag = false;
|
||||||
|
|
||||||
|
#region Messages
|
||||||
|
protected override void OnValidate()
|
||||||
|
{
|
||||||
|
base.OnValidate();
|
||||||
|
|
||||||
|
CustomUtilities.SetPositive(ref rotationLerpSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
previousRotation = transform.rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnEnable() => CharacterActor.OnTeleport += OnTeleport;
|
||||||
|
void OnDisable() => CharacterActor.OnTeleport -= OnTeleport;
|
||||||
|
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
if (CharacterActor == null)
|
||||||
|
{
|
||||||
|
enabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float dt = Time.deltaTime;
|
||||||
|
|
||||||
|
HandleRotation(dt);
|
||||||
|
|
||||||
|
if (teleportFlag)
|
||||||
|
teleportFlag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
void OnTeleport(Vector3 position, Quaternion rotation) => teleportFlag = true;
|
||||||
|
|
||||||
|
void HandleRotation(float dt)
|
||||||
|
{
|
||||||
|
if (teleportFlag)
|
||||||
|
{
|
||||||
|
transform.localRotation = Quaternion.identity;
|
||||||
|
previousRotation = transform.rotation;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
transform.rotation = Quaternion.Slerp(previousRotation, CharacterActor.Rotation, rotationLerpSpeed * dt);
|
||||||
|
previousRotation = transform.rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 66d7fc6bc208f2c40a9211826ddc17f7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,104 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component can be used to rotate a 2D sprite based on the character forward direction.
|
||||||
|
/// </summary>
|
||||||
|
[AddComponentMenu("Character Controller Pro/Core/Character Graphics/Sprite Rotator")]
|
||||||
|
[DefaultExecutionOrder(ExecutionOrder.CharacterGraphicsOrder)]
|
||||||
|
public class CharacterSpriteRotator : CharacterGraphics
|
||||||
|
{
|
||||||
|
[SerializeField]
|
||||||
|
VectorComponent scaleAffectedComponent = VectorComponent.X;
|
||||||
|
|
||||||
|
enum VectorComponent
|
||||||
|
{
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
Z
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 initialScale;
|
||||||
|
Vector3 initialForward;
|
||||||
|
|
||||||
|
void HandleRotation(float dt)
|
||||||
|
{
|
||||||
|
transform.rotation = Quaternion.LookRotation(initialForward, CharacterActor.Up);
|
||||||
|
|
||||||
|
float signedAngle = Vector3.SignedAngle(CharacterActor.Forward, CharacterActor.Up, Vector3.forward);
|
||||||
|
bool shouldBeFacingRight = signedAngle > 0f;
|
||||||
|
|
||||||
|
switch (scaleAffectedComponent)
|
||||||
|
{
|
||||||
|
case VectorComponent.X:
|
||||||
|
|
||||||
|
transform.localScale = new Vector3(
|
||||||
|
shouldBeFacingRight ? initialScale.x : -initialScale.x,
|
||||||
|
transform.localScale.y,
|
||||||
|
transform.localScale.z
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case VectorComponent.Y:
|
||||||
|
|
||||||
|
transform.localScale = new Vector3(
|
||||||
|
transform.localScale.x,
|
||||||
|
shouldBeFacingRight ? initialScale.y : -initialScale.y,
|
||||||
|
transform.localScale.z
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case VectorComponent.Z:
|
||||||
|
|
||||||
|
transform.localScale = new Vector3(
|
||||||
|
transform.localScale.x,
|
||||||
|
transform.localScale.y,
|
||||||
|
shouldBeFacingRight ? initialScale.z : -initialScale.z
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Messages
|
||||||
|
|
||||||
|
protected override void OnValidate()
|
||||||
|
{
|
||||||
|
base.OnValidate();
|
||||||
|
|
||||||
|
if (!CharacterBody.Is2D)
|
||||||
|
Debug.Log("Warning: CharacterBody is not 2D. This component is intended to be used with a 2D physics character.");
|
||||||
|
|
||||||
|
SkinnedMeshRenderer skinnedMeshRenderer = GetComponentInChildren<SkinnedMeshRenderer>();
|
||||||
|
if (skinnedMeshRenderer != null)
|
||||||
|
Debug.Log("Warning: \"Scale\" facing direction mode is intended to work with sprites, not with humanoid characters, choose \"Rotation\" instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Awake()
|
||||||
|
{
|
||||||
|
base.Awake();
|
||||||
|
|
||||||
|
if (!CharacterBody.Is2D)
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
initialScale = transform.localScale;
|
||||||
|
initialForward = transform.forward;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LateUpdate()
|
||||||
|
{
|
||||||
|
float dt = Time.deltaTime;
|
||||||
|
HandleRotation(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1da741a4ebb943549aa33ebc211b3da7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,113 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component is responsible for smoothing out the graphics-related elements (under the root object) based on the character movement (CharacterActor).
|
||||||
|
/// It allows you to modify the position and rotation accordingly, producing a great end result.
|
||||||
|
/// </summary>
|
||||||
|
[AddComponentMenu("Character Controller Pro/Core/Character Graphics/Step Lerper")]
|
||||||
|
[DefaultExecutionOrder(ExecutionOrder.CharacterGraphicsOrder)]
|
||||||
|
public class CharacterStepLerper : CharacterGraphics
|
||||||
|
{
|
||||||
|
[Tooltip("How fast the step up interpolation is going to be.")]
|
||||||
|
[SerializeField]
|
||||||
|
float positiveDisplacementSpeed = 20f;
|
||||||
|
|
||||||
|
[Tooltip("How fast the step down interpolation is going to be.")]
|
||||||
|
[SerializeField]
|
||||||
|
float negativeDisplacementSpeed = 40f;
|
||||||
|
|
||||||
|
[Tooltip("Having a character that is being interpolated all the time is not ideal, especially when walking on slopes, being not grounded, or maybe using a moving platform. " +
|
||||||
|
"For those cases, the character should be allowed to smoothly go back to its original local position over time. This field represents the duration of this process (in seconds).")]
|
||||||
|
[SerializeField]
|
||||||
|
float recoveryDuration = 1f;
|
||||||
|
|
||||||
|
[Tooltip("The maximum speed used for the recovery process (see recoveryDuration tooltip).")]
|
||||||
|
[SerializeField]
|
||||||
|
float maxRecoverySpeed = 200f;
|
||||||
|
|
||||||
|
|
||||||
|
Vector3 previousPosition = default;
|
||||||
|
bool teleportFlag = false;
|
||||||
|
float recoveryTimer = 0f;
|
||||||
|
|
||||||
|
#region Messages
|
||||||
|
protected override void OnValidate()
|
||||||
|
{
|
||||||
|
base.OnValidate();
|
||||||
|
|
||||||
|
CustomUtilities.SetPositive(ref positiveDisplacementSpeed);
|
||||||
|
CustomUtilities.SetPositive(ref negativeDisplacementSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
previousPosition = transform.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnEnable() => CharacterActor.OnTeleport += OnTeleport;
|
||||||
|
void OnDisable() => CharacterActor.OnTeleport -= OnTeleport;
|
||||||
|
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
if (CharacterActor == null)
|
||||||
|
{
|
||||||
|
enabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float dt = Time.deltaTime;
|
||||||
|
|
||||||
|
HandleVerticalDisplacement(dt);
|
||||||
|
|
||||||
|
if (teleportFlag)
|
||||||
|
teleportFlag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
void OnTeleport(Vector3 position, Quaternion rotation) => teleportFlag = true;
|
||||||
|
|
||||||
|
void HandleVerticalDisplacement(float dt)
|
||||||
|
{
|
||||||
|
if (teleportFlag)
|
||||||
|
{
|
||||||
|
previousPosition = transform.position;
|
||||||
|
transform.position = CharacterActor.Position;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 planarDisplacement = Vector3.ProjectOnPlane(CharacterActor.transform.position - previousPosition, CharacterActor.Up);
|
||||||
|
Vector3 verticalDisplacement = Vector3.Project(CharacterActor.transform.position - previousPosition, CharacterActor.Up);
|
||||||
|
|
||||||
|
float groundProbingDisplacement = CharacterActor.transform.InverseTransformVectorUnscaled(CharacterActor.GroundProbingDisplacement).y;
|
||||||
|
|
||||||
|
if (Mathf.Abs(groundProbingDisplacement) < 0.01f)
|
||||||
|
recoveryTimer += dt;
|
||||||
|
else
|
||||||
|
recoveryTimer = 0f;
|
||||||
|
|
||||||
|
// Choose between positive and negative displacement speed based on the vertical displacement.
|
||||||
|
bool upwardsLerpDirection = CharacterActor.transform.InverseTransformVectorUnscaled(verticalDisplacement).y >= 0f;
|
||||||
|
float displacementTSpeed = upwardsLerpDirection ? positiveDisplacementSpeed : negativeDisplacementSpeed;
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate the lerp t speed as a function of the recovery timer.
|
||||||
|
float lerpTSpeedOutput = Mathf.Min(displacementTSpeed + ((maxRecoverySpeed - displacementTSpeed) / recoveryDuration) * recoveryTimer, maxRecoverySpeed);
|
||||||
|
|
||||||
|
transform.position = previousPosition + planarDisplacement + Vector3.Lerp(Vector3.zero, verticalDisplacement, lerpTSpeedOutput * dt);
|
||||||
|
previousPosition = transform.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ab0ce86077d908646bc157d9b2355fdf
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,811 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A physics-based actor that represents a custom 2D/3D interpolated rigidbody.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class PhysicsActor : MonoBehaviour
|
||||||
|
{
|
||||||
|
[Header("Rigidbody")]
|
||||||
|
|
||||||
|
[Tooltip("Interpolates the Transform component associated with this actor during Update calls. This is a custom implementation, the actor " +
|
||||||
|
"does not use Unity's default interpolation.")]
|
||||||
|
public bool interpolateActor = true;
|
||||||
|
|
||||||
|
[Tooltip("Whether or not to use continuous collision detection (rigidbody property). " +
|
||||||
|
"This won't affect character vs static obstacles interactions, but it will affect character vs dynamic rigidbodies.")]
|
||||||
|
public bool useContinuousCollisionDetection = true;
|
||||||
|
|
||||||
|
[Header("Root motion")]
|
||||||
|
|
||||||
|
[Tooltip("This option activates root motion for the character. With root motion enabled, position and rotation are handled exclusively by the animation system.")]
|
||||||
|
public bool UseRootMotion = false;
|
||||||
|
|
||||||
|
[Tooltip("Whether or not to transfer position data from the root motion animation to the character.")]
|
||||||
|
[Condition("UseRootMotion", ConditionAttribute.ConditionType.IsTrue, ConditionAttribute.VisibilityType.NotEditable)]
|
||||||
|
public bool UpdateRootPosition = true;
|
||||||
|
|
||||||
|
[Tooltip("How the root velocity data is going to be applied to the actor.")]
|
||||||
|
[Condition(
|
||||||
|
new string[] { "UpdateRootPosition", "UseRootMotion" },
|
||||||
|
new ConditionAttribute.ConditionType[] { ConditionAttribute.ConditionType.IsTrue, ConditionAttribute.ConditionType.IsTrue },
|
||||||
|
new float[] { 0f, 0f },
|
||||||
|
ConditionAttribute.VisibilityType.NotEditable)]
|
||||||
|
public RootMotionVelocityType rootMotionVelocityType = RootMotionVelocityType.SetVelocity;
|
||||||
|
|
||||||
|
[Tooltip("Whether or not to transfer rotation data from the root motion animation to the character.")]
|
||||||
|
[Condition("UseRootMotion", ConditionAttribute.ConditionType.IsTrue, ConditionAttribute.VisibilityType.NotEditable)]
|
||||||
|
public bool UpdateRootRotation = true;
|
||||||
|
|
||||||
|
[Tooltip("How the root velocity data is going to be applied to the actor.")]
|
||||||
|
// [Condition( "UpdateRootRotation" , ConditionAttribute.ConditionType.IsTrue , ConditionAttribute.VisibilityType.NotEditable )]
|
||||||
|
[Condition(
|
||||||
|
new string[] { "UpdateRootRotation", "UseRootMotion" },
|
||||||
|
new ConditionAttribute.ConditionType[] { ConditionAttribute.ConditionType.IsTrue, ConditionAttribute.ConditionType.IsTrue },
|
||||||
|
new float[] { 0f, 0f },
|
||||||
|
ConditionAttribute.VisibilityType.NotEditable)]
|
||||||
|
public RootMotionRotationType rootMotionRotationType = RootMotionRotationType.AddRotation;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines how the root velocity data is going to be applied to the actor.
|
||||||
|
/// </summary>
|
||||||
|
public enum RootMotionVelocityType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The root motion velocity will be applied as velocity.
|
||||||
|
/// </summary>
|
||||||
|
SetVelocity,
|
||||||
|
/// <summary>
|
||||||
|
/// The root motion velocity will be applied as planar velocity.
|
||||||
|
/// </summary>
|
||||||
|
SetPlanarVelocity,
|
||||||
|
/// <summary>
|
||||||
|
/// The root motion velocity will be applied as vertical velocity.
|
||||||
|
/// </summary>
|
||||||
|
SetVerticalVelocity,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines how the root rotation data is going to be applied to the actor.
|
||||||
|
/// </summary>
|
||||||
|
public enum RootMotionRotationType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The root motion rotation will override the current rotation.
|
||||||
|
/// </summary>
|
||||||
|
SetRotation,
|
||||||
|
/// <summary>
|
||||||
|
/// The root motion rotation will be added to the current rotation.
|
||||||
|
/// </summary>
|
||||||
|
AddRotation
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This event is called prior to the physics simulation.
|
||||||
|
/// </summary>
|
||||||
|
public event System.Action<float> OnPreSimulation;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This event is called after the physics simulation.
|
||||||
|
/// </summary>
|
||||||
|
public event System.Action<float> OnPostSimulation;
|
||||||
|
|
||||||
|
Vector3 startingPosition;
|
||||||
|
Vector3 targetPosition;
|
||||||
|
Quaternion startingRotation;
|
||||||
|
Quaternion targetRotation;
|
||||||
|
Coroutine postSimulationUpdateCoroutine;
|
||||||
|
AnimatorLink animatorLink = null;
|
||||||
|
bool wasInterpolatingActor = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the RigidbodyComponent component associated with the character.
|
||||||
|
/// </summary>
|
||||||
|
public abstract RigidbodyComponent RigidbodyComponent { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Animator component associated with the actor.
|
||||||
|
/// </summary>
|
||||||
|
public Animator Animator { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the rigidbody velocity.
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 Velocity
|
||||||
|
{
|
||||||
|
get => RigidbodyComponent.Velocity;
|
||||||
|
set => RigidbodyComponent.Velocity = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the rigidbody velocity projected onto a plane formed by its up direction.
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 PlanarVelocity
|
||||||
|
{
|
||||||
|
get => transform.TransformDirection(LocalPlanarVelocity);
|
||||||
|
set => LocalPlanarVelocity = transform.InverseTransformDirection(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the rigidbody velocity projected onto its up direction.
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 VerticalVelocity
|
||||||
|
{
|
||||||
|
get => transform.TransformDirection(LocalVerticalVelocity);
|
||||||
|
set => LocalVerticalVelocity = transform.InverseTransformDirection(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the rigidbody local velocity.
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 LocalVelocity
|
||||||
|
{
|
||||||
|
get => transform.InverseTransformDirection(RigidbodyComponent.Velocity);
|
||||||
|
set => RigidbodyComponent.Velocity = transform.TransformDirection(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the rigidbody local planar velocity.
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 LocalPlanarVelocity
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
Vector3 localVelocity = LocalVelocity;
|
||||||
|
localVelocity.y = 0f;
|
||||||
|
return localVelocity;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
value.y = 0f;
|
||||||
|
LocalVelocity = value + LocalVerticalVelocity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the rigidbody local vertical velocity.
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 LocalVerticalVelocity
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
Vector3 localVelocity = LocalVelocity;
|
||||||
|
localVelocity.x = localVelocity.z = 0f;
|
||||||
|
return localVelocity;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
value.x = value.z = 0f;
|
||||||
|
LocalVelocity = LocalPlanarVelocity + value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the character local vertical velocity is less than zero.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsFalling => LocalVelocity.y < 0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the character local vertical velocity is greater than zero.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAscending => LocalVelocity.y > 0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the CharacterBody component associated with this character actor.
|
||||||
|
/// </summary>
|
||||||
|
public bool Is2D => RigidbodyComponent.Is2D;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the current rigidbody position. This action will produce an "interpolation reset", meaning that (visually) the object will move instantly to the target.
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 Position
|
||||||
|
{
|
||||||
|
get => RigidbodyComponent.Position;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
RigidbodyComponent.Position = value;
|
||||||
|
targetPosition = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the current rigidbody rotation. This action will produce an "interpolation reset", meaning that (visually) the object will rotate instantly to the target.
|
||||||
|
/// </summary>
|
||||||
|
public Quaternion Rotation
|
||||||
|
{
|
||||||
|
get => transform.rotation;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
transform.rotation = value;
|
||||||
|
targetRotation = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool IsKinematic
|
||||||
|
{
|
||||||
|
get => RigidbodyComponent.IsKinematic;
|
||||||
|
set => RigidbodyComponent.IsKinematic = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the rigidbody velocity based on a target position. The same can be achieved by setting the velocity value manually.
|
||||||
|
/// </summary>
|
||||||
|
public void Move(Vector3 position) => RigidbodyComponent.Move(position);
|
||||||
|
|
||||||
|
public event System.Action<Vector3, Quaternion> OnTeleport;
|
||||||
|
public event System.Action OnAnimatorMoveEvent;
|
||||||
|
public event System.Action<int> OnAnimatorIKEvent;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the teleportation position.
|
||||||
|
/// The character will move/rotate internally using its own internal logic.
|
||||||
|
/// </summary>
|
||||||
|
public void Teleport(Vector3 position) => Teleport(position, Rotation);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the teleportation position and rotation using an external Transform reference.
|
||||||
|
/// The character will move/rotate internally using its own internal logic.
|
||||||
|
/// </summary>
|
||||||
|
public void Teleport(Transform reference) => Teleport(reference.position, reference.rotation);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the teleportation position and rotation.
|
||||||
|
/// The character will move/rotate internally using its own internal logic.
|
||||||
|
/// </summary>
|
||||||
|
public void Teleport(Vector3 position, Quaternion rotation)
|
||||||
|
{
|
||||||
|
Position = position;
|
||||||
|
Rotation = rotation;
|
||||||
|
|
||||||
|
ResetInterpolationPosition();
|
||||||
|
ResetInterpolationRotation();
|
||||||
|
|
||||||
|
OnTeleport?.Invoke(Position, Rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current up direction based on the rigidbody rotation (not necessarily transform.up).
|
||||||
|
/// </summary>
|
||||||
|
public virtual Vector3 Up
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Rotation * Vector3.up;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Quaternion deltaRotation = Quaternion.FromToRotation(Up, value);
|
||||||
|
Rotation = deltaRotation * Rotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the current forward direction based on the rigidbody rotation (not necessarily transform.forward).
|
||||||
|
/// </summary>
|
||||||
|
public virtual Vector3 Forward
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Is2D ? Rotation * Vector3.right : Rotation * Vector3.forward;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Quaternion deltaRotation = Quaternion.FromToRotation(Forward, value);
|
||||||
|
Rotation = deltaRotation * Rotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current up direction based on the rigidbody rotation (not necessarily transform.right)
|
||||||
|
/// </summary>
|
||||||
|
public virtual Vector3 Right
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Is2D ? Rotation * Vector3.forward : Rotation * Vector3.right;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Quaternion deltaRotation = Quaternion.FromToRotation(Right, value);
|
||||||
|
Rotation = deltaRotation * Rotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Rotation
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets a rotation based on "forward" and "up". This is equivalent to Quaternion.LookRotation.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void SetRotation(Vector3 forward, Vector3 up)
|
||||||
|
{
|
||||||
|
Rotation = Quaternion.LookRotation(forward, up);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotates the character by doing yaw rotation (around its "up" axis).
|
||||||
|
/// </summary>
|
||||||
|
public virtual void RotateAround(Quaternion deltaRotation, Vector3 pivot)
|
||||||
|
{
|
||||||
|
Vector3 preReferenceToPivot = pivot - Position;
|
||||||
|
Rotation = deltaRotation * Rotation;
|
||||||
|
Vector3 postReferenceToPivot = deltaRotation * preReferenceToPivot;
|
||||||
|
Position += preReferenceToPivot - postReferenceToPivot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotates the character by doing yaw rotation (around its "up" axis) based on a given "forward" vector.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="angle">The desired forward vector.</param>
|
||||||
|
public virtual void SetYaw(Vector3 forward)
|
||||||
|
{
|
||||||
|
Rotation = Quaternion.AngleAxis(Vector3.SignedAngle(Forward, forward, Up), Up) * Rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.Obsolete]
|
||||||
|
/// <summary>
|
||||||
|
/// Rotates the character by doing yaw rotation (around its "up" axis).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="angle">The angle in degrees.</param>
|
||||||
|
public void SetYaw(float angle)
|
||||||
|
{
|
||||||
|
Rotation = Quaternion.AngleAxis(angle, Up) * Rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotates the character by doing yaw rotation (around its "up" axis).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="angle">The angle in degrees.</param>
|
||||||
|
public virtual void RotateYaw(float angle)
|
||||||
|
{
|
||||||
|
Rotation = Quaternion.AngleAxis(angle, Up) * Rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotates the character by doing yaw rotation (around its "up" axis).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="angle">The angle in degrees.</param>
|
||||||
|
/// <param name="pivot">The rotation pivot in space.</param>
|
||||||
|
public virtual void RotateYaw(float angle, Vector3 pivot)
|
||||||
|
{
|
||||||
|
Quaternion deltaRotation = Quaternion.AngleAxis(angle, Up);
|
||||||
|
RotateAround(deltaRotation, pivot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotates the character by doing pitch rotation (around its "right" axis).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="angle">The angle in degrees.</param>
|
||||||
|
public virtual void RotatePitch(float angle)
|
||||||
|
{
|
||||||
|
Rotation = Quaternion.AngleAxis(angle, Right) * Rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotates the character by doing pitch rotation (around its "right" axis).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="angle">The angle in degrees.</param>
|
||||||
|
/// <param name="pivot">The rotation pivot in space.</param>
|
||||||
|
public virtual void RotatePitch(float angle, Vector3 pivot)
|
||||||
|
{
|
||||||
|
Quaternion deltaRotation = Quaternion.AngleAxis(angle, Right);
|
||||||
|
RotateAround(deltaRotation, pivot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotates the character by doing roll rotation (around its "forward" axis).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="angle">The angle in degrees.</param>
|
||||||
|
public virtual void RotateRoll(float angle)
|
||||||
|
{
|
||||||
|
Rotation = Quaternion.AngleAxis(angle, Forward) * Rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotates the character by doing roll rotation (around its "forward" axis).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="angle">The angle in degrees.</param>
|
||||||
|
/// <param name="pivot">The rotation pivot in space.</param>
|
||||||
|
public virtual void RotateRoll(float angle, Vector3 pivot)
|
||||||
|
{
|
||||||
|
Quaternion deltaRotation = Quaternion.AngleAxis(angle, Forward);
|
||||||
|
RotateAround(deltaRotation, pivot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotates the character by performing 180 degrees of yaw rotation (around its vertical axis). Also, interpolation (rotation) gets automatically reset
|
||||||
|
/// just to prevent weird visual artifacts.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="angle">The angle in degrees.</param>
|
||||||
|
public virtual void TurnAround()
|
||||||
|
{
|
||||||
|
ResetInterpolationRotation();
|
||||||
|
RotateYaw(180f);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configures all the animation-related components based on a given Animator component. The Animator provides root motion data along
|
||||||
|
/// </summary>
|
||||||
|
[System.Obsolete]
|
||||||
|
public void InitializeAnimation()
|
||||||
|
{
|
||||||
|
if (Animator == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if UNITY_2023_1_OR_NEWER
|
||||||
|
Animator.updateMode = AnimatorUpdateMode.Fixed;
|
||||||
|
#else
|
||||||
|
Animator.updateMode = AnimatorUpdateMode.AnimatePhysics;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!Animator.TryGetComponent(out animatorLink))
|
||||||
|
animatorLink = Animator.gameObject.AddComponent<AnimatorLink>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAnimator(Animator animator)
|
||||||
|
{
|
||||||
|
if (animator == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Animator = animator;
|
||||||
|
|
||||||
|
#if UNITY_2023_1_OR_NEWER
|
||||||
|
Animator.updateMode = AnimatorUpdateMode.Fixed;
|
||||||
|
#else
|
||||||
|
Animator.updateMode = AnimatorUpdateMode.AnimatePhysics;
|
||||||
|
#endif
|
||||||
|
if (!Animator.TryGetComponent(out animatorLink))
|
||||||
|
animatorLink = Animator.gameObject.AddComponent<AnimatorLink>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetIKWeights()
|
||||||
|
{
|
||||||
|
if (animatorLink != null)
|
||||||
|
animatorLink.ResetIKWeights();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void PreSimulationUpdate(float dt) { }
|
||||||
|
protected virtual void PostSimulationUpdate(float dt) { }
|
||||||
|
|
||||||
|
protected virtual void UpdateKinematicRootMotionPosition()
|
||||||
|
{
|
||||||
|
if (!UpdateRootPosition)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Position += Animator.deltaPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void UpdateKinematicRootMotionRotation()
|
||||||
|
{
|
||||||
|
if (!UpdateRootRotation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (rootMotionRotationType == RootMotionRotationType.AddRotation)
|
||||||
|
Rotation *= Animator.deltaRotation;
|
||||||
|
else
|
||||||
|
Rotation = Animator.rootRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void UpdateDynamicRootMotionPosition()
|
||||||
|
{
|
||||||
|
if (!UpdateRootPosition)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RigidbodyComponent.Move(Position + Animator.deltaPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void UpdateDynamicRootMotionRotation()
|
||||||
|
{
|
||||||
|
if (!UpdateRootRotation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (rootMotionRotationType == RootMotionRotationType.AddRotation)
|
||||||
|
Rotation *= Animator.deltaRotation;
|
||||||
|
else
|
||||||
|
Rotation = Animator.rootRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PreSimulationRootMotionUpdate()
|
||||||
|
{
|
||||||
|
if (RigidbodyComponent.IsKinematic)
|
||||||
|
{
|
||||||
|
if (UpdateRootPosition)
|
||||||
|
UpdateKinematicRootMotionPosition();
|
||||||
|
|
||||||
|
if (UpdateRootRotation)
|
||||||
|
UpdateKinematicRootMotionRotation();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (UpdateRootPosition)
|
||||||
|
UpdateDynamicRootMotionPosition();
|
||||||
|
|
||||||
|
if (UpdateRootRotation)
|
||||||
|
UpdateDynamicRootMotionRotation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void OnAnimatorIKLinkMethod(int layerIndex) => OnAnimatorIKEvent?.Invoke(layerIndex);
|
||||||
|
|
||||||
|
#region Interpolation
|
||||||
|
|
||||||
|
bool internalResetFlag = true;
|
||||||
|
|
||||||
|
bool IsReadyForInterpolation()
|
||||||
|
{
|
||||||
|
if (!interpolateActor)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Is2D)
|
||||||
|
{
|
||||||
|
return Physics2D.simulationMode == SimulationMode2D.FixedUpdate;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if UNITY_2022_2_OR_NEWER
|
||||||
|
return Physics.simulationMode == SimulationMode.FixedUpdate;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SyncBody()
|
||||||
|
{
|
||||||
|
if (!IsReadyForInterpolation())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!wasInterpolatingActor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Since the Transform component has been modified during Update calls due to the interpolation process, this will affect the body position/rotation (Rigidbody).
|
||||||
|
// It is important to re-define the rigidbody properties with the previous physics frame targets data.
|
||||||
|
Position = startingPosition = targetPosition;
|
||||||
|
Rotation = startingRotation = targetRotation;
|
||||||
|
|
||||||
|
if (internalResetFlag)
|
||||||
|
{
|
||||||
|
internalResetFlag = false;
|
||||||
|
resetPositionFlag = false;
|
||||||
|
resetRotationFlag = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void InterpolateBody()
|
||||||
|
{
|
||||||
|
if (!IsReadyForInterpolation())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (wasInterpolatingActor)
|
||||||
|
{
|
||||||
|
float interpolationFactor = (Time.time - Time.fixedTime) / Time.fixedDeltaTime;
|
||||||
|
|
||||||
|
transform.SetPositionAndRotation(
|
||||||
|
resetPositionFlag ? targetPosition : Vector3.Lerp(startingPosition, targetPosition, interpolationFactor),
|
||||||
|
resetRotationFlag ? targetRotation : Quaternion.Slerp(startingRotation, targetRotation, interpolationFactor)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else // interpolation has been enabled
|
||||||
|
{
|
||||||
|
ResetInterpolationPosition();
|
||||||
|
ResetInterpolationRotation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateInterpolationTargets()
|
||||||
|
{
|
||||||
|
if (!IsReadyForInterpolation())
|
||||||
|
return;
|
||||||
|
|
||||||
|
targetPosition = Position;
|
||||||
|
targetRotation = Rotation;
|
||||||
|
|
||||||
|
if (resetPositionFlag)
|
||||||
|
{
|
||||||
|
startingPosition = targetPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resetRotationFlag)
|
||||||
|
{
|
||||||
|
startingRotation = targetRotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool resetPositionFlag = false;
|
||||||
|
bool resetRotationFlag = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prevents the body from getting its position interpolated during one physics update.
|
||||||
|
/// </summary>
|
||||||
|
public void ResetInterpolationPosition() => resetPositionFlag = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prevents the body from getting its rotation interpolated during one physics update.
|
||||||
|
/// </summary>
|
||||||
|
public void ResetInterpolationRotation() => resetRotationFlag = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prevents the body from getting interpolated during one physics update.
|
||||||
|
/// </summary>
|
||||||
|
public void ResetInterpolation()
|
||||||
|
{
|
||||||
|
ResetInterpolationPosition();
|
||||||
|
ResetInterpolationRotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the Animator component associated with the character is valid or not. An Animator is valid if it
|
||||||
|
/// is active and its internal references are not null.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the Animator is valid, false otherwise.</returns>
|
||||||
|
public bool IsAnimatorValid()
|
||||||
|
{
|
||||||
|
if (Animator == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Animator.runtimeAnimatorController == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!Animator.gameObject.activeSelf)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Messages
|
||||||
|
|
||||||
|
public virtual void OnValidate() { }
|
||||||
|
|
||||||
|
protected virtual void Awake()
|
||||||
|
{
|
||||||
|
gameObject.GetOrAddComponent<PhysicsActorSync>();
|
||||||
|
|
||||||
|
var animator = this.GetComponentInBranch<CharacterActor, Animator>();
|
||||||
|
SetAnimator(animator);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnEnable()
|
||||||
|
{
|
||||||
|
postSimulationUpdateCoroutine ??= StartCoroutine(PostSimulationUpdate());
|
||||||
|
|
||||||
|
if (animatorLink != null)
|
||||||
|
{
|
||||||
|
animatorLink.OnAnimatorMoveEvent += OnAnimatorMoveLinkMethod;
|
||||||
|
animatorLink.OnAnimatorIKEvent += OnAnimatorIKLinkMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
startingPosition = targetPosition = transform.position;
|
||||||
|
startingRotation = targetRotation = transform.rotation;
|
||||||
|
|
||||||
|
ResetInterpolationPosition();
|
||||||
|
ResetInterpolationRotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnDisable()
|
||||||
|
{
|
||||||
|
if (postSimulationUpdateCoroutine != null)
|
||||||
|
{
|
||||||
|
StopCoroutine(postSimulationUpdateCoroutine);
|
||||||
|
postSimulationUpdateCoroutine = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animatorLink != null)
|
||||||
|
{
|
||||||
|
animatorLink.OnAnimatorMoveEvent -= OnAnimatorMoveLinkMethod;
|
||||||
|
animatorLink.OnAnimatorIKEvent -= OnAnimatorIKLinkMethod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Start()
|
||||||
|
{
|
||||||
|
RigidbodyComponent.ContinuousCollisionDetection = useContinuousCollisionDetection;
|
||||||
|
RigidbodyComponent.UseInterpolation = false;
|
||||||
|
|
||||||
|
// Interpolation
|
||||||
|
targetPosition = startingPosition = transform.position;
|
||||||
|
targetRotation = startingRotation = transform.rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
InterpolateBody();
|
||||||
|
|
||||||
|
wasInterpolatingActor = interpolateActor;
|
||||||
|
internalResetFlag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnAnimatorMoveLinkMethod()
|
||||||
|
{
|
||||||
|
if (!enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!UseRootMotion)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float dt = Time.deltaTime;
|
||||||
|
OnAnimatorMoveEvent?.Invoke();
|
||||||
|
|
||||||
|
PreSimulationRootMotionUpdate();
|
||||||
|
PreSimulationUpdate(dt);
|
||||||
|
OnPreSimulation?.Invoke(dt);
|
||||||
|
|
||||||
|
// 2D Physics (Box2D) requires transform.forward to be Vector3.forward/back, otherwise the simulation will ignore
|
||||||
|
// the body due to the thinness of it.
|
||||||
|
if (Is2D)
|
||||||
|
{
|
||||||
|
if (Right.z > 0f)
|
||||||
|
Right = Vector3.forward;
|
||||||
|
else
|
||||||
|
Right = Vector3.back;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manual sync in case the Transform component is "dirty".
|
||||||
|
transform.SetPositionAndRotation(Position, Rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FixedUpdate()
|
||||||
|
{
|
||||||
|
if (UseRootMotion)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float dt = Time.deltaTime;
|
||||||
|
|
||||||
|
PreSimulationUpdate(dt);
|
||||||
|
OnPreSimulation?.Invoke(dt);
|
||||||
|
|
||||||
|
// 2D Physics (Box2D) requires transform.forward to be Vector3.forward/back, otherwise the simulation will ignore
|
||||||
|
// the body due to the thinness of it.
|
||||||
|
if (Is2D)
|
||||||
|
{
|
||||||
|
if (Right.z > 0f)
|
||||||
|
Right = Vector3.forward;
|
||||||
|
else
|
||||||
|
Right = Vector3.back;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manual sync in case the Transform component is "dirty".
|
||||||
|
transform.SetPositionAndRotation(Position, Rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator PostSimulationUpdate()
|
||||||
|
{
|
||||||
|
YieldInstruction waitForFixedUpdate = new WaitForFixedUpdate();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
yield return waitForFixedUpdate;
|
||||||
|
|
||||||
|
float dt = Time.deltaTime;
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
PostSimulationUpdate(dt);
|
||||||
|
OnPostSimulation?.Invoke(dt);
|
||||||
|
UpdateInterpolationTargets();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 57c6002e3b235904ebe367aeb325538b
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,32 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component is responsible for initializing the interpolation data associated with the physics actor.
|
||||||
|
/// </summary>
|
||||||
|
[DefaultExecutionOrder(int.MinValue)]
|
||||||
|
[RequireComponent(typeof(PhysicsActor))]
|
||||||
|
public class PhysicsActorSync : MonoBehaviour
|
||||||
|
{
|
||||||
|
PhysicsActor physicsActor = null;
|
||||||
|
|
||||||
|
void Awake()
|
||||||
|
{
|
||||||
|
physicsActor = GetComponent<PhysicsActor>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FixedUpdate()
|
||||||
|
{
|
||||||
|
if (!physicsActor.enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// This instruction runs before anything else and it makes sure the rigidbody data is always in "sync" with the interpolation data (physics actor).
|
||||||
|
physicsActor.SyncBody();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1402a51aed7afa64ba143fdb9301713c
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,104 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
using UnityEditor;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
[System.Serializable]
|
||||||
|
public class VerticalAlignmentSettings
|
||||||
|
{
|
||||||
|
[Tooltip("By assigning this object, the character up direction will be automatically calculated based on it. " +
|
||||||
|
"A null value means that the character up direction will be the one defined in the \"alignment direction\" field")]
|
||||||
|
public Transform alignmentReference = null;
|
||||||
|
|
||||||
|
[Tooltip("The mode defines how the up direction is calculated (alignment reference not null).")]
|
||||||
|
public VerticalReferenceMode referenceMode = VerticalReferenceMode.Away;
|
||||||
|
|
||||||
|
[Tooltip("The desired up direction (null alignment reference).")]
|
||||||
|
public Vector3 alignmentDirection = Vector3.up;
|
||||||
|
|
||||||
|
public enum VerticalReferenceMode
|
||||||
|
{
|
||||||
|
Towards,
|
||||||
|
Away
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
|
||||||
|
[CustomPropertyDrawer(typeof(VerticalAlignmentSettings))]
|
||||||
|
public class VerticalAlignmentSettingsPropertyDrawer : PropertyDrawer
|
||||||
|
{
|
||||||
|
const float verticalSpaceMultiplier = 1.1f;
|
||||||
|
|
||||||
|
SerializedProperty alignmentDirection = null;
|
||||||
|
SerializedProperty alignmentReference = null;
|
||||||
|
SerializedProperty referenceMode = null;
|
||||||
|
|
||||||
|
void FindProperties(SerializedProperty property)
|
||||||
|
{
|
||||||
|
alignmentReference = property.FindPropertyRelative("alignmentReference");
|
||||||
|
alignmentDirection = property.FindPropertyRelative("alignmentDirection");
|
||||||
|
referenceMode = property.FindPropertyRelative("referenceMode");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||||
|
{
|
||||||
|
|
||||||
|
EditorGUI.BeginProperty(position, label, property);
|
||||||
|
|
||||||
|
FindProperties(property);
|
||||||
|
|
||||||
|
|
||||||
|
Rect fieldRect = position;
|
||||||
|
fieldRect.height = EditorGUIUtility.singleLineHeight;
|
||||||
|
|
||||||
|
property.isExpanded = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
EditorGUI.PropertyField(fieldRect, alignmentReference);
|
||||||
|
fieldRect.y += verticalSpaceMultiplier * fieldRect.height;
|
||||||
|
|
||||||
|
if (alignmentReference.objectReferenceValue != null)
|
||||||
|
{
|
||||||
|
EditorGUI.PropertyField(fieldRect, referenceMode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EditorGUI.PropertyField(fieldRect, alignmentDirection);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUI.EndProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||||
|
{
|
||||||
|
float output = 2f * verticalSpaceMultiplier * EditorGUIUtility.singleLineHeight;
|
||||||
|
|
||||||
|
// if( property.isExpanded )
|
||||||
|
// {
|
||||||
|
// FindProperties( property );
|
||||||
|
|
||||||
|
// if( alignmentReference.objectReferenceValue != null )
|
||||||
|
// {
|
||||||
|
// output += verticalSpaceMultiplier * EditorGUIUtility.singleLineHeight;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ebbf3da661610cb4eb71cb84d5d94bc9
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 872bdfb8908144a41bc0a2e31c77d828
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,121 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
[AddComponentMenu("Character Controller Pro/Core/Dynamic One Way Platform")]
|
||||||
|
public class DynamicOneWayPlatform : MonoBehaviour
|
||||||
|
{
|
||||||
|
public LayerMask characterLayerMask = -1;
|
||||||
|
|
||||||
|
protected Vector3 preSimulationPosition;
|
||||||
|
Coroutine postSimulationUpdateCoroutine = null;
|
||||||
|
protected Dictionary<Transform, CharacterActor> characters = new Dictionary<Transform, CharacterActor>();
|
||||||
|
ColliderComponent colliderComponent;
|
||||||
|
PhysicsComponent physicsComponent;
|
||||||
|
RigidbodyComponent rigidbodyComponent;
|
||||||
|
|
||||||
|
void Awake()
|
||||||
|
{
|
||||||
|
colliderComponent = ColliderComponent.CreateInstance(gameObject);
|
||||||
|
physicsComponent = PhysicsComponent.CreateInstance(gameObject);
|
||||||
|
rigidbodyComponent = RigidbodyComponent.CreateInstance(gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnEnable()
|
||||||
|
{
|
||||||
|
postSimulationUpdateCoroutine ??= StartCoroutine(PostSimulationUpdate());
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDisable()
|
||||||
|
{
|
||||||
|
if (postSimulationUpdateCoroutine != null)
|
||||||
|
{
|
||||||
|
StopCoroutine(PostSimulationUpdate());
|
||||||
|
postSimulationUpdateCoroutine = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected List<HitInfo> CastPlatformBody(Vector3 castDisplacement)
|
||||||
|
{
|
||||||
|
float backstepDistance = 0.1f;
|
||||||
|
float skinWidth = 0f;
|
||||||
|
Vector3 castDirection = castDisplacement.normalized;
|
||||||
|
castDisplacement += backstepDistance * skinWidth * castDirection;
|
||||||
|
Vector3 origin = preSimulationPosition + colliderComponent.Offset - castDirection * backstepDistance;
|
||||||
|
|
||||||
|
HitInfoFilter filter = new HitInfoFilter(characterLayerMask, false, true);
|
||||||
|
return physicsComponent.BoxCast(
|
||||||
|
origin,
|
||||||
|
colliderComponent.BoundsSize - Vector3.one * skinWidth,
|
||||||
|
castDisplacement,
|
||||||
|
rigidbodyComponent.Rotation,
|
||||||
|
in filter
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bool ValidateOWPCollision(CharacterActor characterActor, Vector3 contactPoint) =>
|
||||||
|
characterActor.CheckOneWayPlatformCollision(contactPoint, characterActor.Position);
|
||||||
|
|
||||||
|
void FixedUpdate() => preSimulationPosition = rigidbodyComponent.Position;
|
||||||
|
|
||||||
|
IEnumerator PostSimulationUpdate()
|
||||||
|
{
|
||||||
|
YieldInstruction waitForFixedUpdate = new WaitForFixedUpdate();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
yield return waitForFixedUpdate;
|
||||||
|
UpdatePlatform();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdatePlatform()
|
||||||
|
{
|
||||||
|
Vector3 castDisplacement = rigidbodyComponent.Position - preSimulationPosition;
|
||||||
|
var hitsList = CastPlatformBody(castDisplacement);
|
||||||
|
|
||||||
|
if (hitsList == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0; i < hitsList.Count; i++)
|
||||||
|
{
|
||||||
|
var hitInfo = physicsComponent.HitsBuffer[i];
|
||||||
|
|
||||||
|
if (hitInfo.distance == 0f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var characterActor = characters.GetOrRegisterValue(hitInfo.transform);
|
||||||
|
if (characterActor == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Ignore the character collider (hitInfo contains the collider information).
|
||||||
|
physicsComponent.IgnoreCollision(in hitInfo, true);
|
||||||
|
|
||||||
|
if (!characterActor.IsGrounded)
|
||||||
|
{
|
||||||
|
// Check if the collision is valid
|
||||||
|
bool isValidCollision = ValidateOWPCollision(characterActor, hitInfo.point);
|
||||||
|
|
||||||
|
// If so, then move the character
|
||||||
|
if (isValidCollision)
|
||||||
|
{
|
||||||
|
// How much the actor needs to move
|
||||||
|
Vector3 actorCastDisplacement = castDisplacement.normalized * (castDisplacement.magnitude - hitInfo.distance);
|
||||||
|
Vector3 destination = characterActor.Position + actorCastDisplacement;
|
||||||
|
|
||||||
|
// Set the collision filter
|
||||||
|
HitInfoFilter filter = new HitInfoFilter(characterActor.ObstaclesWithoutOWPLayerMask, false, true);
|
||||||
|
|
||||||
|
characterActor.SweepAndTeleport(destination, in filter);
|
||||||
|
characterActor.ForceGrounded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f172c59dacc5df345833c688e9d99c02
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 90dcb45485fb8f14ea8b9937e819ade1
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,29 @@
|
|||||||
|
#if UNITY_EDITOR
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
public class AboutWindow : CharacterControllerProWindow
|
||||||
|
{
|
||||||
|
const float Width = 200f;
|
||||||
|
const float Height = 100f;
|
||||||
|
|
||||||
|
protected override void OnEnable()
|
||||||
|
{
|
||||||
|
this.position = new Rect((Screen.width - Width) / 2f, (Screen.height - Height) / 2f, Width, Height);
|
||||||
|
this.maxSize = this.minSize = this.position.size;
|
||||||
|
this.titleContent = new GUIContent("About");
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnGUI()
|
||||||
|
{
|
||||||
|
EditorGUILayout.SelectableLabel("Version: 1.4.12", GUILayout.Height(15f));
|
||||||
|
EditorGUILayout.SelectableLabel("Author : Juan Sálice (Lightbug)", GUILayout.Height(15f));
|
||||||
|
EditorGUILayout.SelectableLabel("Email : lightbug14@gmail.com", GUILayout.Height(15f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 879d183da6048b64d83d436dedab1b00
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,24 @@
|
|||||||
|
#if UNITY_EDITOR
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
class CCPAssetPostprocessor : AssetPostprocessor
|
||||||
|
{
|
||||||
|
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
|
||||||
|
{
|
||||||
|
var rootPath = CharacterControllerProEditor.GetAssetRootFolder();
|
||||||
|
|
||||||
|
foreach (string importedAsset in importedAssets)
|
||||||
|
{
|
||||||
|
if (importedAsset.Equals(rootPath))
|
||||||
|
{
|
||||||
|
WelcomeWindow window = EditorWindow.GetWindow<WelcomeWindow>(true, "Welcome");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0dc05c2c35edf9741bf8e08d39251f40
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,234 @@
|
|||||||
|
#if UNITY_EDITOR
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Presets;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
public class CharacterControllerProEditor : Editor
|
||||||
|
{
|
||||||
|
public static string GetAssetRootFolder()
|
||||||
|
{
|
||||||
|
// Find the assembly definition file
|
||||||
|
string[] guids = AssetDatabase.FindAssets("com.lightbug.character-controller-pro");
|
||||||
|
|
||||||
|
if (guids.Length > 0)
|
||||||
|
{
|
||||||
|
// Look for a parent directory called "Character Controller Pro"
|
||||||
|
string asmdefFilePath = AssetDatabase.GUIDToAssetPath(guids[0]);
|
||||||
|
return GetParentPathByFile("Character Controller Pro", asmdefFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Utilities
|
||||||
|
|
||||||
|
public static string GetParentPathByFile(string targetFolderName, string initialFilePath)
|
||||||
|
{
|
||||||
|
// Start by finding the assembly definition file
|
||||||
|
string[] guids = AssetDatabase.FindAssets("com.lightbug.character-controller-pro");
|
||||||
|
|
||||||
|
if (guids.Length > 1)
|
||||||
|
{
|
||||||
|
Debug.Log("Multiple \"com.lightbug.character-controller-pro\" assembly definition files found.");
|
||||||
|
}
|
||||||
|
else if (guids.Length > 0)
|
||||||
|
{
|
||||||
|
// ──────────────────────────────────────────────────────────────────────────
|
||||||
|
// path = "FolderA/FolderB/file.txt"
|
||||||
|
// Path.GetFileName(path) --> "file.txt"
|
||||||
|
// Path.GetDirectoryName(path) --> "FolderA/FolderB"
|
||||||
|
// ──────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
string currentDirectory = Path.GetDirectoryName(initialFilePath);
|
||||||
|
|
||||||
|
while (!string.IsNullOrEmpty(currentDirectory))
|
||||||
|
{
|
||||||
|
string folderName = Path.GetFileName(currentDirectory);
|
||||||
|
|
||||||
|
if (folderName == targetFolderName)
|
||||||
|
return currentDirectory;
|
||||||
|
else
|
||||||
|
currentDirectory = Path.GetDirectoryName(currentDirectory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // No file? :(
|
||||||
|
{
|
||||||
|
Debug.Log("No assembly definition file found. Have you deleted the file?.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log($"Error: Parent folder \"{targetFolderName}\" not found");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void MoveFolderToFolder(string sourceFolderPath, string destinationFolderPath)
|
||||||
|
{
|
||||||
|
// Source folder
|
||||||
|
if (!Directory.Exists(sourceFolderPath))
|
||||||
|
{
|
||||||
|
Debug.Log($"Error: Source directory {sourceFolderPath} doesn't exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the meta file
|
||||||
|
string sourceMetaPath = sourceFolderPath + ".meta";
|
||||||
|
if (!File.Exists(sourceMetaPath))
|
||||||
|
{
|
||||||
|
Debug.Log($"Error: Meta file {sourceMetaPath} doesn't exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destination folder
|
||||||
|
if (!Directory.Exists(destinationFolderPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(destinationFolderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
Directory.Move(sourceFolderPath, $"{destinationFolderPath}/{Path.GetFileName(sourceFolderPath)}");
|
||||||
|
File.Move(sourceMetaPath, $"{destinationFolderPath}/{Path.GetFileName(sourceMetaPath)}");
|
||||||
|
|
||||||
|
AssetDatabase.Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void MoveFileToFolder(string sourceFilePath, string destinationFolderPath)
|
||||||
|
{
|
||||||
|
// Source folder
|
||||||
|
if (!File.Exists(sourceFilePath))
|
||||||
|
{
|
||||||
|
Debug.Log($"Error: Source file {sourceFilePath} doesn't exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the meta file
|
||||||
|
string sourceMetaPath = sourceFilePath + ".meta";
|
||||||
|
if (!File.Exists(sourceMetaPath))
|
||||||
|
{
|
||||||
|
Debug.Log($"Error: Meta file {sourceMetaPath} doesn't exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destination folder
|
||||||
|
if (!Directory.Exists(destinationFolderPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(destinationFolderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
File.Move(sourceFilePath, $"{destinationFolderPath}/{Path.GetFileName(sourceFilePath)}");
|
||||||
|
File.Move(sourceMetaPath, $"{destinationFolderPath}/{Path.GetFileName(sourceMetaPath)}");
|
||||||
|
|
||||||
|
AssetDatabase.Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
[MenuItem("Window/Character Controller Pro/Welcome", false, 0)]
|
||||||
|
public static void WelcomeMessage()
|
||||||
|
{
|
||||||
|
WelcomeWindow window = EditorWindow.GetWindow<WelcomeWindow>(true, "Welcome");
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem("Window/Character Controller Pro/Documentation", false, 1)]
|
||||||
|
public static void Documentation()
|
||||||
|
{
|
||||||
|
Application.OpenURL("https://lightbug14.gitbook.io/ccp/");
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem("Window/Character Controller Pro/API Reference", false, 2)]
|
||||||
|
public static void APIReference()
|
||||||
|
{
|
||||||
|
Application.OpenURL("https://lightbug14.github.io/lightbug-web/character-controller-pro/Documentation/html/index.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem("Window/Character Controller Pro/About", false, 100)]
|
||||||
|
public static void About()
|
||||||
|
{
|
||||||
|
EditorWindow.GetWindow<AboutWindow>(true, "About");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*public static void UseOldStructure(string rootPath)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists($"{rootPath}/Main"))
|
||||||
|
{
|
||||||
|
Debug.Log("Error: The current folder structure is the old one.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MoveFolderToFolder($"{rootPath}/Main/Core", $"{rootPath}");
|
||||||
|
MoveFolderToFolder($"{rootPath}/Main/Documentation", $"{rootPath}");
|
||||||
|
MoveFolderToFolder($"{rootPath}/Main/Implementation", $"{rootPath}");
|
||||||
|
MoveFolderToFolder($"{rootPath}/Main/Utilities", $"{rootPath}");
|
||||||
|
MoveFileToFolder($"{rootPath}/Main/com.lightbug.character-controller-pro.asmdef", $"{rootPath}");
|
||||||
|
Directory.Delete($"{rootPath}/Main");
|
||||||
|
File.Delete($"{rootPath}/Main.meta");
|
||||||
|
|
||||||
|
AssetDatabase.Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem("Window/Character Controller Pro/Use old (1.4.10 or lower) folder structure", false, 0)]
|
||||||
|
static void UseOldStructure()
|
||||||
|
{
|
||||||
|
if (!IsCurrentStructureNew())
|
||||||
|
{
|
||||||
|
EditorUtility.DisplayDialog(
|
||||||
|
"Old folder structure detected",
|
||||||
|
"The current folder structure your project is using corresponds to the old one",
|
||||||
|
"Ok"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = EditorUtility.DisplayDialog(
|
||||||
|
"Folder structure",
|
||||||
|
"This will" +
|
||||||
|
"\n\nFrom 1.4.11 onwards, all the demo content locates outside the main assembly by separating the asset into \"Main\" and \"Demo\". " +
|
||||||
|
"Do you want this tool to update this structure for you?",
|
||||||
|
"Yes (recommended)",
|
||||||
|
"No"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
var rootPath = GetAssetRootFolder();
|
||||||
|
UseOldStructure(rootPath);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*static void UseNewStructure(string rootPath)
|
||||||
|
{
|
||||||
|
if (Directory.Exists($"{rootPath}/Main"))
|
||||||
|
{
|
||||||
|
Debug.Log("Error: The current folder structure is the new one.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MoveFolderToFolder($"{rootPath}/Core", $"{rootPath}/Main");
|
||||||
|
MoveFolderToFolder($"{rootPath}/Documentation", $"{rootPath}/Main");
|
||||||
|
MoveFolderToFolder($"{rootPath}/Implementation", $"{rootPath}/Main");
|
||||||
|
MoveFolderToFolder($"{rootPath}/Utilities", $"{rootPath}/Main");
|
||||||
|
MoveFileToFolder($"{rootPath}/com.lightbug.character-controller-pro.asmdef", $"{rootPath}/Main");
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem("Window/Character Controller Pro/Use new (1.4.11 or higher) folder structure", false, 0)]
|
||||||
|
static void UseNewStructure()
|
||||||
|
{
|
||||||
|
var rootPath = GetAssetRootFolder();
|
||||||
|
UseNewStructure(rootPath);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public static bool IsCurrentStructureNew(string rootPath) => Directory.Exists($"{rootPath}/Main");
|
||||||
|
|
||||||
|
public static bool IsCurrentStructureNew() => IsCurrentStructureNew(GetAssetRootFolder());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d49a31f193f362d49aaa28c2af09a173
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,42 @@
|
|||||||
|
#if UNITY_EDITOR
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
public abstract class CharacterControllerProWindow : EditorWindow
|
||||||
|
{
|
||||||
|
protected GUIStyle titleStyle = new GUIStyle();
|
||||||
|
protected GUIStyle subtitleStyle = new GUIStyle();
|
||||||
|
protected GUIStyle descriptionStyle = new GUIStyle();
|
||||||
|
|
||||||
|
|
||||||
|
protected virtual void OnEnable()
|
||||||
|
{
|
||||||
|
titleStyle.fontSize = 50;
|
||||||
|
titleStyle.alignment = TextAnchor.MiddleCenter;
|
||||||
|
titleStyle.padding.top = 4;
|
||||||
|
titleStyle.padding.bottom = 4;
|
||||||
|
titleStyle.normal.textColor = EditorGUIUtility.isProSkin ? Color.white : Color.black;
|
||||||
|
|
||||||
|
subtitleStyle.fontSize = 18;
|
||||||
|
subtitleStyle.alignment = TextAnchor.MiddleCenter;
|
||||||
|
subtitleStyle.padding.top = 4;
|
||||||
|
subtitleStyle.padding.bottom = 4;
|
||||||
|
subtitleStyle.normal.textColor = EditorGUIUtility.isProSkin ? Color.white : Color.black;
|
||||||
|
|
||||||
|
descriptionStyle.fontSize = 15;
|
||||||
|
descriptionStyle.wordWrap = true;
|
||||||
|
descriptionStyle.padding.left = 10;
|
||||||
|
descriptionStyle.padding.right = 10;
|
||||||
|
descriptionStyle.padding.top = 4;
|
||||||
|
descriptionStyle.padding.bottom = 4;
|
||||||
|
descriptionStyle.richText = true;
|
||||||
|
descriptionStyle.normal.textColor = EditorGUIUtility.isProSkin ? Color.white : Color.black;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bd3896d355c4e6b4ba210c70c0152263
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,113 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using Lightbug.Utilities;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
public abstract class CharacterDetector : MonoBehaviour
|
||||||
|
{
|
||||||
|
protected Dictionary<Transform, CharacterActor> characters = new Dictionary<Transform, CharacterActor>();
|
||||||
|
protected List<int> onEnterDirtyTransforms = new List<int>();
|
||||||
|
protected List<int> onStayDirtyTransforms = new List<int>();
|
||||||
|
protected List<int> onExitDirtyTransforms = new List<int>();
|
||||||
|
|
||||||
|
protected virtual void ProcessEnterAction(CharacterActor characterActor) { }
|
||||||
|
protected virtual void ProcessStayAction(CharacterActor characterActor) { }
|
||||||
|
protected virtual void ProcessExitAction(CharacterActor characterActor) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of characters (CharacterActor) currently inside this trigger.
|
||||||
|
/// </summary>
|
||||||
|
public int CharactersNumber { get; private set; }
|
||||||
|
|
||||||
|
void FixedUpdate()
|
||||||
|
{
|
||||||
|
if (onEnterDirtyTransforms.Count != 0)
|
||||||
|
onEnterDirtyTransforms.Clear();
|
||||||
|
|
||||||
|
if (onStayDirtyTransforms.Count != 0)
|
||||||
|
onStayDirtyTransforms.Clear();
|
||||||
|
|
||||||
|
if (onExitDirtyTransforms.Count != 0)
|
||||||
|
onExitDirtyTransforms.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessAction(Transform transform, List<int> characterActorsIDList, System.Action<CharacterActor> Action)
|
||||||
|
{
|
||||||
|
if (!enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CharacterActor characterActor = characters.GetOrRegisterValue(transform);
|
||||||
|
|
||||||
|
if (characterActor == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// We don't want to trigger the logic more than once due to multiple colliders interacting with the trigger.
|
||||||
|
int characterActorID = characterActor.GetInstanceID();
|
||||||
|
if (characterActorsIDList.Contains(characterActorID))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// The actor is not registered, add the ID to the list.
|
||||||
|
characterActorsIDList.Add(characterActorID);
|
||||||
|
|
||||||
|
CharactersNumber++;
|
||||||
|
|
||||||
|
Action?.Invoke(characterActor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnTriggerEnter(Collider collider)
|
||||||
|
{
|
||||||
|
var characterRigidbody = collider.attachedRigidbody;
|
||||||
|
if (characterRigidbody == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ProcessAction(characterRigidbody.transform, onEnterDirtyTransforms, ProcessEnterAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnTriggerEnter2D(Collider2D collider)
|
||||||
|
{
|
||||||
|
var characterRigidbody = collider.attachedRigidbody;
|
||||||
|
if (characterRigidbody == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ProcessAction(characterRigidbody.transform, onEnterDirtyTransforms, ProcessEnterAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnTriggerStay(Collider collider)
|
||||||
|
{
|
||||||
|
var characterRigidbody = collider.attachedRigidbody;
|
||||||
|
if (characterRigidbody == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ProcessAction(characterRigidbody.transform, onStayDirtyTransforms, ProcessStayAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnTriggerStay2D(Collider2D collider)
|
||||||
|
{
|
||||||
|
var characterRigidbody = collider.attachedRigidbody;
|
||||||
|
if (characterRigidbody == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ProcessAction(characterRigidbody.transform, onStayDirtyTransforms, ProcessStayAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnTriggerExit(Collider collider)
|
||||||
|
{
|
||||||
|
var characterRigidbody = collider.attachedRigidbody;
|
||||||
|
if (characterRigidbody == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ProcessAction(characterRigidbody.transform, onExitDirtyTransforms, ProcessExitAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnTriggerExit2D(Collider2D collider)
|
||||||
|
{
|
||||||
|
var characterRigidbody = collider.attachedRigidbody;
|
||||||
|
if (characterRigidbody == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ProcessAction(characterRigidbody.transform, onExitDirtyTransforms, ProcessExitAction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0f39a8804db37df4a850d980740867ad
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,13 @@
|
|||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This class contains constant values related to execution order values. These values are used by the Core components to define its own execution order inside Unity.
|
||||||
|
/// </summary>
|
||||||
|
public static class ExecutionOrder
|
||||||
|
{
|
||||||
|
public const int CharacterActorOrder = 10;
|
||||||
|
public const int CharacterGraphicsOrder = CharacterActorOrder + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2988c4ba7fa538b45a474a53fc4ea0e9
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,95 @@
|
|||||||
|
#if UNITY_EDITOR
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace Lightbug.CharacterControllerPro.Core
|
||||||
|
{
|
||||||
|
public class WelcomeWindow : CharacterControllerProWindow
|
||||||
|
{
|
||||||
|
protected override void OnEnable()
|
||||||
|
{
|
||||||
|
base.OnEnable();
|
||||||
|
|
||||||
|
this.position = new Rect(10f, 10f, 700f, 700f);
|
||||||
|
this.maxSize = this.minSize = this.position.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem("Window/Character Controller Pro/Upgrade guide 1.4.x", false, 0)]
|
||||||
|
public static void OpenUpgradeGuide()
|
||||||
|
{
|
||||||
|
string[] results = AssetDatabase.FindAssets("Upgrade guide 1.4.x");
|
||||||
|
if (results.Length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
OpenProjectFile(results[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OpenProjectFile(string guid)
|
||||||
|
{
|
||||||
|
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||||
|
var projectPathWithoutAssets = Application.dataPath.Substring(0, Application.dataPath.Length - 6);
|
||||||
|
Application.OpenURL(projectPathWithoutAssets + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnGUI()
|
||||||
|
{
|
||||||
|
|
||||||
|
GUILayout.Label("Character Controller Pro", titleStyle);
|
||||||
|
|
||||||
|
GUILayout.Space(20f);
|
||||||
|
|
||||||
|
GUILayout.BeginVertical("Box");
|
||||||
|
|
||||||
|
|
||||||
|
GUILayout.Label("<b>Upgrade to 1.4.X</b>", subtitleStyle);
|
||||||
|
|
||||||
|
GUILayout.Label("Are you upgrading to 1.4.x?\nPlease read the <b>upgrade guide</b> (<i>Character Controller Pro/Documentation/Upgrade guide 1.4.0.pdf</i>)", descriptionStyle);
|
||||||
|
if (GUILayout.Button("Upgrade guide"))
|
||||||
|
OpenUpgradeGuide();
|
||||||
|
GUILayout.EndVertical();
|
||||||
|
|
||||||
|
GUILayout.Space(10f);
|
||||||
|
|
||||||
|
GUILayout.BeginVertical("Box");
|
||||||
|
GUILayout.Label("<b>Demo setup</b>", subtitleStyle);
|
||||||
|
|
||||||
|
GUILayout.Label(
|
||||||
|
"In order to play the demo scenes that come with the asset, you must include some specific inputs (old InputManager), " +
|
||||||
|
"tags and layers to your project. <b>This is required for demo purposes only. The character controller (core + implementation) does " +
|
||||||
|
"not require any previous setup to work.</b>", descriptionStyle);
|
||||||
|
|
||||||
|
GUILayout.Space(10f);
|
||||||
|
|
||||||
|
GUILayout.Label(
|
||||||
|
"1. Open the <b>Input manager settings</b>.\n" +
|
||||||
|
"2. Load <i><color=yellow>Preset_Inputs.preset</color></i>.\n" +
|
||||||
|
"3. Open the <b>Tags and Layers settings</b>.\n" +
|
||||||
|
"4. Load <i><color=yellow>Preset_TagsAndLayers.preset</color></i>.\n", descriptionStyle);
|
||||||
|
|
||||||
|
GUILayout.EndVertical();
|
||||||
|
|
||||||
|
GUILayout.Space(10f);
|
||||||
|
|
||||||
|
GUILayout.BeginVertical("Box");
|
||||||
|
GUILayout.Label("<b>Known issues (editor)</b>", subtitleStyle);
|
||||||
|
GUILayout.Label("Please check the \"Known issues\" section if you are experiencing " +
|
||||||
|
"problems while testing the demo content. These are (most of the time) issues related to the Unity editor itself.", descriptionStyle);
|
||||||
|
if (GUILayout.Button("Known issues", EditorStyles.miniButton))
|
||||||
|
{
|
||||||
|
Application.OpenURL("https://lightbug14.gitbook.io/ccp/package/known-issues");
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayout.EndVertical();
|
||||||
|
|
||||||
|
GUILayout.Space(10f);
|
||||||
|
|
||||||
|
GUILayout.Space(10f);
|
||||||
|
GUILayout.Label("You can open this window from the top menu: \n<i>Window/Character Controller Pro/Welcome</i>", descriptionStyle);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bf69c37e90467de48a81772dccce861a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 145fa8bb62a46f449a41f0a1ed96473a
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: da7a4f81de6c4464c8f6d99c1d02278a
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user