init
This commit is contained in:
4
Libraries/fish.scc/.bin/manifest.json
Normal file
4
Libraries/fish.scc/.bin/manifest.json
Normal file
@@ -0,0 +1,4 @@
|
||||
[
|
||||
"package.base",
|
||||
"package.fish.scc"
|
||||
]
|
||||
BIN
Libraries/fish.scc/.bin/package.fish.scc.cll
Normal file
BIN
Libraries/fish.scc/.bin/package.fish.scc.cll
Normal file
Binary file not shown.
313
Libraries/fish.scc/.bin/package.fish.scc.xml
Normal file
313
Libraries/fish.scc/.bin/package.fish.scc.xml
Normal file
@@ -0,0 +1,313 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>package.fish.scc</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.ManuallyUpdate">
|
||||
<summary>
|
||||
Manually update this by calling Move() or let it always be simulated
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.ScaleAgainstWalls">
|
||||
<summary>
|
||||
If pushing against a wall, scale the velocity based on the wall's angle (False is useful for NPCs that get stuck on corners)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.TraceWidth">
|
||||
<summary>
|
||||
Width of our trace
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.TraceHeight">
|
||||
<summary>
|
||||
Height of our trace
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.RotateWithGameObject">
|
||||
<summary>
|
||||
Rotate the trace with the gameobject
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.CylinderTrace">
|
||||
<summary>
|
||||
Use a cylinder trace instead of a box trace<br/>
|
||||
[WARNING] This is a PHYSICAL TRACE, so it's more expensive than the normal box trace
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.IgnoreTags">
|
||||
<summary>
|
||||
Which tags it should ignore
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.MaxBounces">
|
||||
<summary>
|
||||
Max amount of trace calls whenever the simulation doesn't reach its target (Slide and collide bounces)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.GroundAcceleration">
|
||||
<summary>
|
||||
How fast you accelerate while on the ground (Units per second)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.GroundDeceleration">
|
||||
<summary>
|
||||
How fast you decelerate while on the ground (Units per second)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.AirAcceleration">
|
||||
<summary>
|
||||
How fast you accelerate while in the air (Units per second)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.AirDeceleration">
|
||||
<summary>
|
||||
How fast you decelerate while in the air (Units per second)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.IgnoreGroundSurface">
|
||||
<summary>
|
||||
Do we ignore the friction of the surface you're standing on or not?
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.IgnoreZ">
|
||||
<summary>
|
||||
Is this MoveHelper meant for horizontal grounded movement? (false = For flying or noclip)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.IgnoreZWhenZero">
|
||||
<summary>
|
||||
Do we ignore Z when it's near 0 (So that gravity affects you when not moving)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.WallTolerance">
|
||||
<summary>
|
||||
Tolerance from a 90° surface before it's considered a wall (Ex. Tolerance 1 = Between 89° and 91° can be a wall, 0.1 = 89.9° to 90.1°)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.GripFactorReduction">
|
||||
<summary>
|
||||
Player feels like it's gripping walls too much? Try more Grip Factor Reduction!
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.GroundStickEnabled">
|
||||
<summary>
|
||||
Stick the MoveHelper to the ground (IsOnGround will default to false if disabled)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.MaxGroundAngle">
|
||||
<summary>
|
||||
How steep terrain can be for you to stand on without slipping
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.GroundStickDistance">
|
||||
<summary>
|
||||
How far from the ground the MoveHelper is going to stick (Useful for going down stairs!)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.StepsEnabled">
|
||||
<summary>
|
||||
Enable steps climbing (+1 Trace call)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.StepHeight">
|
||||
<summary>
|
||||
How high steps can be for you to climb on
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.StepDepth">
|
||||
<summary>
|
||||
How deep it checks for steps (Minimum depth)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.StepTolerance">
|
||||
<summary>
|
||||
Tolerance from a 90° surface before it's considered a valid step (Ex. Tolerance 1 = Between 89° and 91° can be a step, 0.1 = 89.9° to 90.1°)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.PseudoStepsEnabled">
|
||||
<summary>
|
||||
Enable to ability to walk on a surface that's too steep if it's equal or smaller than a step (+1 Trace call when on steep terrain)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.PushEnabled">
|
||||
<summary>
|
||||
Instead of colliding with these tags the MoveHelper will be pushed away (Make sure the tags are in IgnoreTags as well!)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.PushTagsWeight">
|
||||
<summary>
|
||||
Which tags will push this MoveHelper away and with how much force (Make sure they are also included in IgnoreTags!) (+1 Trace call)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.GravityEnabled">
|
||||
<summary>
|
||||
Apply gravity to this MoveHelper when not on the ground
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.UseSceneGravity">
|
||||
<summary>
|
||||
Use the scene's gravity or our own
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.UseVectorGravity">
|
||||
<summary>
|
||||
Use a Vector3 gravity instead of a single float (Use this if you want to use a custom gravity)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.Gravity">
|
||||
<summary>
|
||||
Units per second squared (Default is -850f)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.VectorGravity">
|
||||
<summary>
|
||||
Units per second squared (Default is 0f, 0f, -850f)<br/>
|
||||
Changes which way <see cref="P:ShrimpleCharacterController.ShrimpleCharacterController.GroundStickEnabled"/> sticks to the ground
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.UnstuckEnabled">
|
||||
<summary>
|
||||
Check if the MoveHelper is stuck and try to get it to unstuck (+Trace calls if stuck)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.MaxUnstuckTries">
|
||||
<summary>
|
||||
How many trace calls it will attempt to get the MoveHelper unstuck
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.WishVelocity">
|
||||
<summary>
|
||||
The simulated target velocity for our MoveHelper (Units per second, we apply Time.Delta inside)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.Velocity">
|
||||
<summary>
|
||||
The resulting velocity after the simulation is done (Units per second)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.IsOnGround">
|
||||
<summary>
|
||||
Is the MoveHelper currently touching the ground
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.GroundNormal">
|
||||
<summary>
|
||||
The current ground normal you're standing on (Always Vector3.Zero if IsOnGround false)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.GroundAngle">
|
||||
<summary>
|
||||
The current ground angle you're standing on (Always 0f if IsOnGround false)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.GroundSurface">
|
||||
<summary>
|
||||
The current surface you're standing on
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.GroundObject">
|
||||
<summary>
|
||||
The gameobject you're currently standing on
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.IsPushingAgainstWall">
|
||||
<summary>
|
||||
Is the MoveHelper currently pushing against a wall
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.WallNormal">
|
||||
<summary>
|
||||
The current wall normal you're pushing against (Always Vector3.Zero if IsPushingAgainstWall false)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.WallObject">
|
||||
<summary>
|
||||
The gameobject you're currently pushing on
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.IsSlipping">
|
||||
<summary>
|
||||
Is the MoveHelper standing on a terrain too steep to stand on (Always false if IsOnGround false)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.IsStuck">
|
||||
<summary>
|
||||
The MoveHelper is stuck and we can't get it out
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ShrimpleCharacterController.ShrimpleCharacterController.SkinWidth">
|
||||
<summary>
|
||||
To avoid getting stuck due to imprecision we shrink the bounds before checking and compensate for it later
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:ShrimpleCharacterController.ShrimpleCharacterController.Bounds">
|
||||
<summary>
|
||||
The bounds of this MoveHelper generated from the TraceWidth and TraceHeight
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:ShrimpleCharacterController.ShrimpleCharacterController.UnstuckTarget">
|
||||
<summary>
|
||||
If another MoveHelper moved at the same time and they're stuck, let this one know that the other already unstuck for us
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ShrimpleCharacterController.ShrimpleCharacterController.BuildTrace(BBox,Vector3,Vector3)">
|
||||
<summary>
|
||||
Casts the current bounds from to and returns the scene trace result
|
||||
</summary>
|
||||
<param name="bounds"></param>
|
||||
<param name="from"></param>
|
||||
<param name="to"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:ShrimpleCharacterController.ShrimpleCharacterController.Punch(Vector3@)">
|
||||
<summary>
|
||||
Detach the MoveHelper from the ground and launch it somewhere (Units per second)
|
||||
</summary>
|
||||
<param name="amount"></param>
|
||||
</member>
|
||||
<member name="M:ShrimpleCharacterController.ShrimpleCharacterController.Move(System.Boolean)">
|
||||
<summary>
|
||||
Apply the WishVelocity, update the Velocity and the Position of the GameObject by simulating the MoveHelper
|
||||
</summary>
|
||||
<param name="manualUpdate">Just calculate but don't update position</param>
|
||||
</member>
|
||||
<member name="M:ShrimpleCharacterController.ShrimpleCharacterController.Move(System.Single,System.Boolean)">
|
||||
<summary>
|
||||
Apply the WishVelocity, update the Velocity and the Position of the GameObject by simulating the MoveHelper
|
||||
</summary>
|
||||
<param name="delta">The time step</param>
|
||||
<param name="manualUpdate">Just calculate but don't update position</param>
|
||||
</member>
|
||||
<member name="T:ShrimpleCharacterController.ShrimpleCharacterController.MoveHelperResult">
|
||||
<summary>
|
||||
Sometimes we have to update only the position but not the velocity (Like when climbing steps or getting unstuck) so we can't have Position rely only on Velocity
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ShrimpleCharacterController.ShrimpleCharacterController.TestPosition(Vector3,System.String)">
|
||||
<summary>
|
||||
Debug don't use
|
||||
</summary>
|
||||
<param name="position"></param>
|
||||
<param name="title"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:ShrimpleCharacterController.Vector3Extensions.MoveTowards(Vector3,Vector3,System.Single)">
|
||||
<summary>
|
||||
Move a vector3 towards a goal by a fixed distance
|
||||
</summary>
|
||||
<param name="value"></param>
|
||||
<param name="target"></param>
|
||||
<param name="travelSpeed"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:ShrimpleCharacterController.Vector3Extensions.ProjectAndScale(Vector3,Vector3)">
|
||||
<summary>
|
||||
Project a vector along a plane (normal) and scale it back to its original length
|
||||
</summary>
|
||||
<param name="value"></param>
|
||||
<param name="normal"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
BIN
Libraries/fish.scc/.sbox/cloud.db
Normal file
BIN
Libraries/fish.scc/.sbox/cloud.db
Normal file
Binary file not shown.
67
Libraries/fish.scc/.sbox/project.json
Normal file
67
Libraries/fish.scc/.sbox/project.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"scene.lastopened": {
|
||||
"Value": "[\u0022scenes/walker_example.scene\u0022,\u0022prefabs/debug_world.prefab\u0022]",
|
||||
"Timeout": 1747778774,
|
||||
"DeleteAt": 0
|
||||
},
|
||||
"gizmo.settings": {
|
||||
"Value": "{\u0022EditMode\u0022:\u0022position\u0022,\u0022Selection\u0022:true,\u0022ViewMode\u0022:\u00223d\u0022,\u0022GizmosEnabled\u0022:true,\u0022GizmoScale\u0022:1,\u0022GridSpacing\u0022:8,\u0022SnapToGrid\u0022:true,\u0022SnapToAngles\u0022:true,\u0022AngleSpacing\u0022:15,\u0022GlobalSpace\u0022:false,\u0022DebugActionGraphs\u0022:false}",
|
||||
"Timeout": 1747778773,
|
||||
"DeleteAt": 0
|
||||
},
|
||||
"scenes/walker_example.scene.Viewport0": {
|
||||
"Value": "{\u0022CameraPosition\u0022:\u0022-99.46711,-362.8735,485.0559\u0022,\u0022CameraRotation\u0022:\u0022-0.3022594,0.2325998,0.7326022,0.5637646\u0022,\u0022CameraOrthoHeight\u0022:1000}",
|
||||
"Timeout": 1747780744,
|
||||
"DeleteAt": 0
|
||||
},
|
||||
"AssetBrowser.Map.HistoryIdx": {
|
||||
"Value": "2",
|
||||
"Timeout": 1736783981,
|
||||
"DeleteAt": 1745241658
|
||||
},
|
||||
"AssetBrowser.Map.History": {
|
||||
"Value": "[\u0022C:\\\\Users\\\\uberm\\\\Desktop\\\\Projects\\\\shrimple_character_controller\\\\Assets\u0022,\u0022C:\\\\Users\\\\uberm\\\\Desktop\\\\Projects\\\\shrimple_character_controller\\\\Assets\u0022,\u0022C:\\\\Users\\\\uberm\\\\Desktop\\\\Projects\\\\shrimple_character_controller\\\\Assets\u0022]",
|
||||
"Timeout": 1736783981,
|
||||
"DeleteAt": 1745241658
|
||||
},
|
||||
"prefabs/debug_world.prefab.Viewport0": {
|
||||
"Value": "{\u0022CameraPosition\u0022:\u0022-1075.94,-361.7078,194.5635\u0022,\u0022CameraRotation\u0022:\u00220.01240713,0.1013415,-0.1208866,0.9874019\u0022,\u0022CameraOrthoHeight\u0022:1000}",
|
||||
"Timeout": 1747780744,
|
||||
"DeleteAt": 0
|
||||
},
|
||||
".Viewport0": {
|
||||
"Value": "{\u0022CameraPosition\u0022:\u002264.7494,-611.3881,145.0907\u0022,\u0022CameraRotation\u0022:\u0022-0.00140108,0.3086819,0.004317207,0.9511545\u0022,\u0022CameraOrthoHeight\u0022:1000}",
|
||||
"Timeout": 1747780728,
|
||||
"DeleteAt": 0
|
||||
},
|
||||
"SceneView.Viewport0.Settings": {
|
||||
"Value": "{\u0022CameraPosition\u0022:\u0022-1075.94,-361.7078,194.5635\u0022,\u0022CameraRotation\u0022:\u00220.01240713,0.1013415,-0.1208866,0.9874019\u0022,\u0022View\u0022:0,\u0022RenderMode\u0022:0,\u0022WireframeMode\u0022:false,\u0022EnablePostProcessing\u0022:true,\u0022EnablePrefabLighting\u0022:true,\u0022ShowGrid\u0022:true,\u0022GridOpacity\u0022:0.2,\u0022GridAxis\u0022:0,\u0022CameraOrthoHeight\u0022:1000}",
|
||||
"Timeout": 1747780744,
|
||||
"DeleteAt": 0
|
||||
},
|
||||
"SceneView.Layout": {
|
||||
"Value": "{\u0022Layout\u0022:0,\u0022SplitterState\u0022:[]}",
|
||||
"Timeout": 1747780728,
|
||||
"DeleteAt": 0
|
||||
},
|
||||
"folder-metadata": {
|
||||
"Value": "{\u0022..\\\\..\\\\..\\\\..\\\\..\\\\Program Files (x86)\\\\Steam\\\\steamapps\\\\common\\\\sbox\\\\Recents\u0022:{\u0022Color\u0022:\u00220.46667,0.73333,1,1\u0022,\u0022Icon\u0022:\u0022\u0022},\u0022..\\\\..\\\\..\\\\..\\\\..\\\\Program Files (x86)\\\\Steam\\\\steamapps\\\\common\\\\sbox\\\\Everything\u0022:{\u0022Color\u0022:\u00220.46667,0.73333,1,1\u0022,\u0022Icon\u0022:\u0022\u0022},\u0022.\u0022:{\u0022Color\u0022:\u00220.46667,0.73333,1,1\u0022,\u0022Icon\u0022:\u0022\u0022},\u0022..\\\\..\\\\..\\\\..\\\\..\\\\Program Files (x86)\\\\Steam\\\\steamapps\\\\common\\\\sbox\\\\addons\\\\citizen\\\\assets\u0022:{\u0022Color\u0022:\u00220.46667,0.73333,1,1\u0022,\u0022Icon\u0022:\u0022\u0022},\u0022..\\\\..\\\\..\\\\..\\\\..\\\\Program Files (x86)\\\\Steam\\\\steamapps\\\\common\\\\sbox\\\\core\u0022:{\u0022Color\u0022:\u00220.46667,0.73333,1,1\u0022,\u0022Icon\u0022:\u0022\u0022},\u0022Assets\\\\prefabs\u0022:{\u0022Color\u0022:\u00220.46667,0.73333,1,1\u0022,\u0022Icon\u0022:\u0022\u0022},\u0022Assets\\\\scenes\u0022:{\u0022Color\u0022:\u00220.46667,0.73333,1,1\u0022,\u0022Icon\u0022:\u0022\u0022},\u0022Assets\u0022:{\u0022Color\u0022:\u00220.46667,0.73333,1,1\u0022,\u0022Icon\u0022:\u0022\u0022},\u0022code\u0022:{\u0022Color\u0022:\u00220.46667,0.73333,1,1\u0022,\u0022Icon\u0022:\u0022\u0022},\u0022Localization\u0022:{\u0022Color\u0022:\u00220.46667,0.73333,1,1\u0022,\u0022Icon\u0022:\u0022\u0022},\u0022ProjectSettings\u0022:{\u0022Color\u0022:\u00220.46667,0.73333,1,1\u0022,\u0022Icon\u0022:\u0022\u0022},\u0022code\\\\Examples\u0022:{\u0022Color\u0022:\u00220.46667,0.73333,1,1\u0022,\u0022Icon\u0022:\u0022\u0022},\u0022code\\\\Util\u0022:{\u0022Color\u0022:\u00220.46667,0.73333,1,1\u0022,\u0022Icon\u0022:\u0022\u0022}}",
|
||||
"Timeout": 1737811230,
|
||||
"DeleteAt": 1745241658
|
||||
},
|
||||
"AssetBrowser.History": {
|
||||
"Value": "[\u0022C:\\\\Users\\\\uberm\\\\Desktop\\\\Projects\\\\shrimple_character_controller\\\\Assets\u0022]",
|
||||
"Timeout": 1747778774,
|
||||
"DeleteAt": 0
|
||||
},
|
||||
"AssetBrowser.HistoryIdx": {
|
||||
"Value": "0",
|
||||
"Timeout": 1747778774,
|
||||
"DeleteAt": 0
|
||||
},
|
||||
"Window.SboxSceneEditor.Dock": {
|
||||
"Value": "{\u0022floatingWindows\u0022:[],\u0022mainWrapper\u0022:{\u0022geometry\u0022:\u0022AdnQywADAAAAAAAAAAAAAAAAB9AAAAPRAAAAAAAAAAAAAAfQAAAD0QAAAAAAAAAACAAAAAAAAAAAAAAAB9AAAAPR\u0022,\u0022splitter\u0022:{\u0022items\u0022:[{\u0022currentIndex\u0022:0,\u0022objects\u0022:[{\u0022data\u0022:null,\u0022managedType\u0022:\u0022SceneTreeWidget\u0022,\u0022name\u0022:\u0022Hierarchy\u0022},{\u0022data\u0022:null,\u0022managedType\u0022:\u0022PanelInspectorWidget\u0022,\u0022name\u0022:\u0022UI Panels\u0022}],\u0022type\u0022:\u0022area\u0022},{\u0022items\u0022:[{\u0022items\u0022:[{\u0022currentIndex\u0022:0,\u0022objects\u0022:[{\u0022data\u0022:null,\u0022managedType\u0022:\u0022\u0022,\u0022name\u0022:\u0022GameFrame\u0022},{\u0022data\u0022:null,\u0022managedType\u0022:\u0022SceneDock\u0022,\u0022name\u0022:\u0022SceneDock:scenes/walker_example.scene\u0022},{\u0022data\u0022:null,\u0022managedType\u0022:\u0022SceneDock\u0022,\u0022name\u0022:\u0022SceneDock:prefabs/debug_world.prefab\u0022},{\u0022data\u0022:null,\u0022managedType\u0022:\u0022SceneDock\u0022,\u0022name\u0022:\u0022SceneDock:untitled\u0022}],\u0022type\u0022:\u0022area\u0022},{\u0022currentIndex\u0022:0,\u0022objects\u0022:[{\u0022data\u0022:null,\u0022managedType\u0022:\u0022ConsoleWidget\u0022,\u0022name\u0022:\u0022Console\u0022},{\u0022data\u0022:null,\u0022managedType\u0022:\u0022MainAssetBrowser\u0022,\u0022name\u0022:\u0022Asset Browser\u0022},{\u0022data\u0022:null,\u0022managedType\u0022:\u0022LibraryManagerDock\u0022,\u0022name\u0022:\u0022Library Manager\u0022},{\u0022data\u0022:null,\u0022managedType\u0022:\u0022MixerDock\u0022,\u0022name\u0022:\u0022Mixer\u0022}],\u0022type\u0022:\u0022area\u0022}],\u0022state\u0022:\u0022AAAA/wAAAAEAAAACAAACuAAAAsoA/////wEAAAACAA==\u0022,\u0022type\u0022:\u0022splitter\u0022},{\u0022items\u0022:[{\u0022currentIndex\u0022:0,\u0022objects\u0022:[{\u0022data\u0022:null,\u0022managedType\u0022:\u0022Inspector\u0022,\u0022name\u0022:\u0022Inspector\u0022},{\u0022data\u0022:null,\u0022managedType\u0022:\u0022UndoDock\u0022,\u0022name\u0022:\u0022Undo\u0022}],\u0022type\u0022:\u0022area\u0022},{\u0022currentIndex\u0022:0,\u0022objects\u0022:[{\u0022data\u0022:null,\u0022managedType\u0022:\u0022PerformanceDock\u0022,\u0022name\u0022:\u0022Performance\u0022}],\u0022type\u0022:\u0022area\u0022}],\u0022state\u0022:\u0022AAAA/wAAAAEAAAACAAAC2wAAAOcA/////wEAAAACAA==\u0022,\u0022type\u0022:\u0022splitter\u0022}],\u0022state\u0022:\u0022AAAA/wAAAAEAAAACAAAE/AAAAckA/////wEAAAABAA==\u0022,\u0022type\u0022:\u0022splitter\u0022}],\u0022state\u0022:\u0022AAAA/wAAAAEAAAACAAABBgAABskA/////wEAAAABAA==\u0022,\u0022type\u0022:\u0022splitter\u0022}},\u0022toolWindowManagerStateFormat\u0022:1}",
|
||||
"Timeout": 1747778786,
|
||||
"DeleteAt": 0
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
1
Libraries/fish.scc/.version
Normal file
1
Libraries/fish.scc/.version
Normal file
@@ -0,0 +1 @@
|
||||
1.0.97283
|
||||
19349
Libraries/fish.scc/Assets/prefabs/debug_world.prefab
Normal file
19349
Libraries/fish.scc/Assets/prefabs/debug_world.prefab
Normal file
File diff suppressed because one or more lines are too long
BIN
Libraries/fish.scc/Assets/prefabs/shrimp.png
Normal file
BIN
Libraries/fish.scc/Assets/prefabs/shrimp.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 254 KiB |
121
Libraries/fish.scc/Assets/scenes/flyer_example.scene
Normal file
121
Libraries/fish.scc/Assets/scenes/flyer_example.scene
Normal file
@@ -0,0 +1,121 @@
|
||||
{
|
||||
"__guid": "e78370eb-4e25-4b7f-bbf8-89f0fcbaa68b",
|
||||
"GameObjects": [
|
||||
{
|
||||
"__guid": "048573b1-fa80-406a-a30d-93881e2b19c9",
|
||||
"Flags": 0,
|
||||
"Name": "debug_world",
|
||||
"Enabled": true,
|
||||
"__Prefab": "prefabs/debug_world.prefab",
|
||||
"__PrefabVariables": {}
|
||||
},
|
||||
{
|
||||
"__guid": "dad296d6-935e-4779-b5ae-67a3a0d28ab6",
|
||||
"Flags": 0,
|
||||
"Name": "Player",
|
||||
"Position": "-171.0225,-113.5377,171.9933",
|
||||
"Enabled": true,
|
||||
"Components": [
|
||||
{
|
||||
"__type": "ShrimpleCharacterController.ShrimpleCharacterController",
|
||||
"__guid": "fa127e8d-b05d-4e14-894d-d2977361591d",
|
||||
"AirAcceleration": 1500,
|
||||
"AirDeceleration": 700,
|
||||
"Gravity": -850,
|
||||
"GravityEnabled": false,
|
||||
"GroundAcceleration": 1000,
|
||||
"GroundDeceleration": 1500,
|
||||
"GroundStickDistance": 12,
|
||||
"GroundStickEnabled": false,
|
||||
"IgnoreGroundSurface": false,
|
||||
"IgnoreTags": "",
|
||||
"IgnoreZ": false,
|
||||
"IgnoreZWhenZero": true,
|
||||
"ManuallyUpdate": true,
|
||||
"MaxBounces": 5,
|
||||
"MaxGroundAngle": 60,
|
||||
"MaxUnstuckTries": 20,
|
||||
"PushEnabled": false,
|
||||
"PushTagsWeight": {
|
||||
"player": 1
|
||||
},
|
||||
"ScaleAgainstWalls": true,
|
||||
"StepDepth": 2,
|
||||
"StepHeight": 12,
|
||||
"StepsEnabled": false,
|
||||
"TraceHeight": 72,
|
||||
"TraceWidth": 16,
|
||||
"UnstuckEnabled": true,
|
||||
"UseSceneGravity": true
|
||||
},
|
||||
{
|
||||
"__type": "ShrimpleCharacterController.ShrimpleFlyer",
|
||||
"__guid": "e79bdc25-5a6f-4eb2-8a49-5f7aac27f8cd",
|
||||
"RunSpeed": 2400,
|
||||
"WalkSpeed": 800
|
||||
},
|
||||
{
|
||||
"__type": "Sandbox.Citizen.CitizenAnimationHelper",
|
||||
"__guid": "6bb6e1f8-1402-4b7b-9006-ea4866eb9e64",
|
||||
"BodyWeight": 1,
|
||||
"EyesWeight": 1,
|
||||
"HeadWeight": 1,
|
||||
"LookAtEnabled": false,
|
||||
"Target": {
|
||||
"_type": "component",
|
||||
"component_id": "75a0dedf-07bc-4a29-9027-9e88625f7ba0",
|
||||
"go": "768529ee-5ecc-4ddb-a81e-73fdb775baec",
|
||||
"component_type": "SkinnedModelRenderer"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Children": [
|
||||
{
|
||||
"__guid": "768529ee-5ecc-4ddb-a81e-73fdb775baec",
|
||||
"Flags": 0,
|
||||
"Name": "Model",
|
||||
"Position": "0,0,0",
|
||||
"Enabled": true,
|
||||
"Components": [
|
||||
{
|
||||
"__type": "Sandbox.SkinnedModelRenderer",
|
||||
"__guid": "75a0dedf-07bc-4a29-9027-9e88625f7ba0",
|
||||
"BodyGroups": 341,
|
||||
"CreateBoneObjects": false,
|
||||
"Model": "models/citizen/citizen.vmdl",
|
||||
"RenderType": "On",
|
||||
"Tint": "1,1,1,1",
|
||||
"UseAnimGraph": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"SceneProperties": {
|
||||
"FixedUpdateFrequency": 50,
|
||||
"MaxFixedUpdates": 5,
|
||||
"NetworkFrequency": 30,
|
||||
"NetworkInterpolation": true,
|
||||
"ThreadedAnimation": true,
|
||||
"TimeScale": 1,
|
||||
"UseFixedUpdate": true,
|
||||
"NavMesh": {
|
||||
"Enabled": false,
|
||||
"IncludeStaticBodies": true,
|
||||
"IncludeKeyframedBodies": true,
|
||||
"EditorAutoUpdate": true,
|
||||
"AgentHeight": 64,
|
||||
"AgentRadius": 16,
|
||||
"AgentStepSize": 18,
|
||||
"AgentMaxSlope": 40,
|
||||
"ExcludedBodies": "",
|
||||
"IncludedBodies": ""
|
||||
}
|
||||
},
|
||||
"Title": "walker_example",
|
||||
"Description": "",
|
||||
"ResourceVersion": 1,
|
||||
"__references": [],
|
||||
"__version": 1
|
||||
}
|
||||
146
Libraries/fish.scc/Assets/scenes/roller_example.scene
Normal file
146
Libraries/fish.scc/Assets/scenes/roller_example.scene
Normal file
@@ -0,0 +1,146 @@
|
||||
{
|
||||
"__guid": "e78370eb-4e25-4b7f-bbf8-89f0fcbaa68b",
|
||||
"GameObjects": [
|
||||
{
|
||||
"__guid": "048573b1-fa80-406a-a30d-93881e2b19c9",
|
||||
"Flags": 0,
|
||||
"Name": "debug_world",
|
||||
"Enabled": true,
|
||||
"__Prefab": "prefabs/debug_world.prefab",
|
||||
"__PrefabVariables": {}
|
||||
},
|
||||
{
|
||||
"__guid": "dad296d6-935e-4779-b5ae-67a3a0d28ab6",
|
||||
"Flags": 0,
|
||||
"Name": "Player",
|
||||
"Position": "0,-49.46404,176.2773",
|
||||
"Enabled": true,
|
||||
"Components": [
|
||||
{
|
||||
"__type": "ShrimpleCharacterController.ShrimpleCharacterController",
|
||||
"__guid": "fa127e8d-b05d-4e14-894d-d2977361591d",
|
||||
"AirAcceleration": 250,
|
||||
"AirDeceleration": 100,
|
||||
"Gravity": -850,
|
||||
"GravityEnabled": true,
|
||||
"GroundAcceleration": 1000,
|
||||
"GroundDeceleration": 2000,
|
||||
"GroundStickDistance": 12,
|
||||
"GroundStickEnabled": false,
|
||||
"IgnoreGroundSurface": false,
|
||||
"IgnoreTags": "",
|
||||
"IgnoreZ": true,
|
||||
"IgnoreZWhenZero": true,
|
||||
"ManuallyUpdate": true,
|
||||
"MaxBounces": 5,
|
||||
"MaxGroundAngle": 60,
|
||||
"MaxUnstuckTries": 20,
|
||||
"PushEnabled": false,
|
||||
"PushTagsWeight": {
|
||||
"player": 1
|
||||
},
|
||||
"ScaleAgainstWalls": true,
|
||||
"StepDepth": 2,
|
||||
"StepHeight": 12,
|
||||
"StepsEnabled": true,
|
||||
"TraceHeight": 64,
|
||||
"TraceWidth": 64,
|
||||
"UnstuckEnabled": true,
|
||||
"UseSceneGravity": true
|
||||
},
|
||||
{
|
||||
"__type": "ShrimpleCharacterController.ShrimpleRoller",
|
||||
"__guid": "c557f267-05dd-4185-be90-7d60757118ef",
|
||||
"JumpStrength": 350,
|
||||
"RunSpeed": 3000,
|
||||
"WalkSpeed": 1000
|
||||
}
|
||||
],
|
||||
"Children": [
|
||||
{
|
||||
"__guid": "768529ee-5ecc-4ddb-a81e-73fdb775baec",
|
||||
"Flags": 0,
|
||||
"Name": "Model",
|
||||
"Position": "0,0,32",
|
||||
"Enabled": true,
|
||||
"Components": [
|
||||
{
|
||||
"__type": "Sandbox.ModelRenderer",
|
||||
"__guid": "13202fec-761f-46b0-9517-21a8662c39f3",
|
||||
"BodyGroups": 18446744073709551615,
|
||||
"MaterialOverride": "materials/editor/black_grid_8_doublesided.vmat",
|
||||
"Model": "models/dev/sphere.vmdl",
|
||||
"RenderType": "On",
|
||||
"Tint": "1,1,1,1"
|
||||
},
|
||||
{
|
||||
"__type": "Sandbox.TrailRenderer",
|
||||
"__guid": "0c954483-095d-48f1-bb1c-47d90bbb6ae6",
|
||||
"BlendMode": "Normal",
|
||||
"CastShadows": false,
|
||||
"Color": {
|
||||
"color": [
|
||||
{
|
||||
"c": "1,1,1,0.5"
|
||||
},
|
||||
{
|
||||
"t": 1,
|
||||
"c": "1,1,1,0"
|
||||
}
|
||||
],
|
||||
"alpha": []
|
||||
},
|
||||
"LifeTime": 3,
|
||||
"MaxPoints": 256,
|
||||
"Opaque": false,
|
||||
"PointDistance": 4,
|
||||
"Texturing": {
|
||||
"WorldSpace": true,
|
||||
"UnitsPerTexture": 10,
|
||||
"Scale": 1
|
||||
},
|
||||
"Width": {
|
||||
"rangey": "0,64",
|
||||
"frames": [
|
||||
{
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"Wireframe": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"SceneProperties": {
|
||||
"FixedUpdateFrequency": 50,
|
||||
"MaxFixedUpdates": 5,
|
||||
"NetworkFrequency": 30,
|
||||
"NetworkInterpolation": true,
|
||||
"ThreadedAnimation": true,
|
||||
"TimeScale": 1,
|
||||
"UseFixedUpdate": true,
|
||||
"NavMesh": {
|
||||
"Enabled": false,
|
||||
"IncludeStaticBodies": true,
|
||||
"IncludeKeyframedBodies": true,
|
||||
"EditorAutoUpdate": true,
|
||||
"AgentHeight": 64,
|
||||
"AgentRadius": 16,
|
||||
"AgentStepSize": 18,
|
||||
"AgentMaxSlope": 40,
|
||||
"ExcludedBodies": "",
|
||||
"IncludedBodies": ""
|
||||
}
|
||||
},
|
||||
"Title": "walker_example",
|
||||
"Description": "",
|
||||
"ResourceVersion": 1,
|
||||
"__references": [],
|
||||
"__version": 1
|
||||
}
|
||||
185
Libraries/fish.scc/Assets/scenes/walker_example.scene
Normal file
185
Libraries/fish.scc/Assets/scenes/walker_example.scene
Normal file
@@ -0,0 +1,185 @@
|
||||
{
|
||||
"__guid": "e78370eb-4e25-4b7f-bbf8-89f0fcbaa68b",
|
||||
"GameObjects": [
|
||||
{
|
||||
"__guid": "4a794eac-df05-4fff-b80b-f4f40e6b4e9e",
|
||||
"Flags": 0,
|
||||
"Name": "Scene Information",
|
||||
"Enabled": true,
|
||||
"Components": [
|
||||
{
|
||||
"__type": "Sandbox.SceneInformation",
|
||||
"__guid": "f6aaec07-69f8-4387-b7d9-f94cbc0f362d",
|
||||
"Author": null,
|
||||
"Changes": null,
|
||||
"Description": "",
|
||||
"Group": null,
|
||||
"OnComponentDestroy": null,
|
||||
"OnComponentDisabled": null,
|
||||
"OnComponentEnabled": null,
|
||||
"OnComponentFixedUpdate": null,
|
||||
"OnComponentStart": null,
|
||||
"OnComponentUpdate": null,
|
||||
"SceneTags": "",
|
||||
"Title": "walker_example",
|
||||
"Version": null
|
||||
}
|
||||
],
|
||||
"Children": []
|
||||
},
|
||||
{
|
||||
"__guid": "048573b1-fa80-406a-a30d-93881e2b19c9",
|
||||
"Flags": 0,
|
||||
"Name": "debug_world",
|
||||
"Enabled": true,
|
||||
"__Prefab": "prefabs/debug_world.prefab",
|
||||
"__PrefabVariables": {}
|
||||
},
|
||||
{
|
||||
"__guid": "dad296d6-935e-4779-b5ae-67a3a0d28ab6",
|
||||
"Flags": 0,
|
||||
"Name": "Player",
|
||||
"Position": "-171.0225,-113.5377,171.9933",
|
||||
"Enabled": true,
|
||||
"Components": [
|
||||
{
|
||||
"__type": "ShrimpleCharacterController.ShrimpleCharacterController",
|
||||
"__guid": "fa127e8d-b05d-4e14-894d-d2977361591d",
|
||||
"__version": 1,
|
||||
"AirAcceleration": 300,
|
||||
"AirDeceleration": 0,
|
||||
"CylinderTrace": true,
|
||||
"Gravity": -850,
|
||||
"GravityEnabled": true,
|
||||
"GripFactorReduction": 1,
|
||||
"GroundAcceleration": 1000,
|
||||
"GroundDeceleration": 1500,
|
||||
"GroundStickDistance": 12,
|
||||
"GroundStickEnabled": true,
|
||||
"IgnoreGroundSurface": false,
|
||||
"IgnoreTags": "",
|
||||
"IgnoreZ": true,
|
||||
"IgnoreZWhenZero": true,
|
||||
"ManuallyUpdate": true,
|
||||
"MaxBounces": 5,
|
||||
"MaxGroundAngle": 60,
|
||||
"MaxUnstuckTries": 20,
|
||||
"OnComponentDestroy": null,
|
||||
"OnComponentDisabled": null,
|
||||
"OnComponentEnabled": null,
|
||||
"OnComponentFixedUpdate": null,
|
||||
"OnComponentStart": null,
|
||||
"OnComponentUpdate": null,
|
||||
"PseudoStepsEnabled": true,
|
||||
"PushEnabled": false,
|
||||
"PushTagsWeight": {
|
||||
"player": 1
|
||||
},
|
||||
"RotateWithGameObject": true,
|
||||
"ScaleAgainstWalls": true,
|
||||
"StepDepth": 2,
|
||||
"StepHeight": 12,
|
||||
"StepsEnabled": true,
|
||||
"StepTolerance": 1,
|
||||
"TraceHeight": 72,
|
||||
"TraceWidth": 24,
|
||||
"UnstuckEnabled": true,
|
||||
"UseSceneGravity": true,
|
||||
"UseVectorGravity": false,
|
||||
"VectorGravity": "0,0,-850",
|
||||
"WallTolerance": 1
|
||||
},
|
||||
{
|
||||
"__type": "ShrimpleCharacterController.ShrimpleWalker",
|
||||
"__guid": "21e48f2b-e808-42b7-83e6-83282972f187",
|
||||
"DuckSpeed": 50,
|
||||
"JumpStrength": 350,
|
||||
"OnComponentDestroy": null,
|
||||
"OnComponentDisabled": null,
|
||||
"OnComponentEnabled": null,
|
||||
"OnComponentFixedUpdate": null,
|
||||
"OnComponentStart": null,
|
||||
"OnComponentUpdate": null,
|
||||
"RunSpeed": 300,
|
||||
"WalkSpeed": 100
|
||||
}
|
||||
],
|
||||
"Children": [
|
||||
{
|
||||
"__guid": "768529ee-5ecc-4ddb-a81e-73fdb775baec",
|
||||
"Flags": 0,
|
||||
"Name": "Model",
|
||||
"Enabled": true,
|
||||
"Components": [
|
||||
{
|
||||
"__type": "Sandbox.SkinnedModelRenderer",
|
||||
"__guid": "75a0dedf-07bc-4a29-9027-9e88625f7ba0",
|
||||
"AnimationGraph": null,
|
||||
"BodyGroups": 341,
|
||||
"BoneMergeTarget": null,
|
||||
"CreateAttachments": false,
|
||||
"CreateBoneObjects": false,
|
||||
"MaterialGroup": null,
|
||||
"MaterialOverride": null,
|
||||
"Model": "models/citizen/citizen.vmdl",
|
||||
"Morphs": {},
|
||||
"OnComponentDestroy": null,
|
||||
"OnComponentDisabled": null,
|
||||
"OnComponentEnabled": null,
|
||||
"OnComponentFixedUpdate": null,
|
||||
"OnComponentStart": null,
|
||||
"OnComponentUpdate": null,
|
||||
"Parameters": {
|
||||
"bools": {},
|
||||
"ints": {},
|
||||
"floats": {},
|
||||
"vectors": {},
|
||||
"rotations": {}
|
||||
},
|
||||
"PlaybackRate": 1,
|
||||
"RenderOptions": {
|
||||
"GameLayer": true,
|
||||
"OverlayLayer": false,
|
||||
"BloomLayer": false,
|
||||
"AfterUILayer": false
|
||||
},
|
||||
"RenderType": "On",
|
||||
"Sequence": {
|
||||
"Name": null,
|
||||
"Looping": true
|
||||
},
|
||||
"Tint": "1,1,1,1",
|
||||
"UseAnimGraph": true
|
||||
}
|
||||
],
|
||||
"Children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"SceneProperties": {
|
||||
"NetworkInterpolation": true,
|
||||
"TimeScale": 1,
|
||||
"WantsSystemScene": true,
|
||||
"Metadata": {
|
||||
"Title": "walker_example"
|
||||
},
|
||||
"NavMesh": {
|
||||
"Enabled": false,
|
||||
"IncludeStaticBodies": true,
|
||||
"IncludeKeyframedBodies": true,
|
||||
"EditorAutoUpdate": true,
|
||||
"AgentHeight": 64,
|
||||
"AgentRadius": 16,
|
||||
"AgentStepSize": 18,
|
||||
"AgentMaxSlope": 40,
|
||||
"ExcludedBodies": "",
|
||||
"IncludedBodies": ""
|
||||
}
|
||||
},
|
||||
"ResourceVersion": 2,
|
||||
"Title": "walker_example",
|
||||
"Description": null,
|
||||
"__references": [],
|
||||
"__version": 2
|
||||
}
|
||||
21
Libraries/fish.scc/LICENSE
Normal file
21
Libraries/fish.scc/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Small Fish
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
34
Libraries/fish.scc/ProjectSettings/Collision.config
Normal file
34
Libraries/fish.scc/ProjectSettings/Collision.config
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"Defaults": {
|
||||
"solid": "Collide",
|
||||
"trigger": "Trigger",
|
||||
"ladder": "Ignore",
|
||||
"water": "Trigger"
|
||||
},
|
||||
"Pairs": [
|
||||
{
|
||||
"a": "solid",
|
||||
"b": "solid",
|
||||
"r": "Collide"
|
||||
},
|
||||
{
|
||||
"a": "trigger",
|
||||
"b": "playerclip",
|
||||
"r": "Ignore"
|
||||
},
|
||||
{
|
||||
"a": "trigger",
|
||||
"b": "solid",
|
||||
"r": "Trigger"
|
||||
},
|
||||
{
|
||||
"a": "playerclip",
|
||||
"b": "solid",
|
||||
"r": "Collide"
|
||||
}
|
||||
],
|
||||
"__guid": "3f8027f2-5728-4178-a563-2be1da260457",
|
||||
"__schema": "configdata",
|
||||
"__type": "CollisionRules",
|
||||
"__version": 1
|
||||
}
|
||||
194
Libraries/fish.scc/ProjectSettings/Input.config
Normal file
194
Libraries/fish.scc/ProjectSettings/Input.config
Normal file
@@ -0,0 +1,194 @@
|
||||
{
|
||||
"Actions": [
|
||||
{
|
||||
"Name": "Forward",
|
||||
"KeyboardCode": "W",
|
||||
"GamepadCode": "None",
|
||||
"GroupName": "Movement"
|
||||
},
|
||||
{
|
||||
"Name": "Backward",
|
||||
"KeyboardCode": "S",
|
||||
"GamepadCode": "None",
|
||||
"GroupName": "Movement"
|
||||
},
|
||||
{
|
||||
"Name": "Left",
|
||||
"KeyboardCode": "A",
|
||||
"GamepadCode": "None",
|
||||
"GroupName": "Movement"
|
||||
},
|
||||
{
|
||||
"Name": "Right",
|
||||
"KeyboardCode": "D",
|
||||
"GamepadCode": "None",
|
||||
"GroupName": "Movement"
|
||||
},
|
||||
{
|
||||
"Name": "Jump",
|
||||
"KeyboardCode": "space",
|
||||
"GamepadCode": "A",
|
||||
"GroupName": "Movement"
|
||||
},
|
||||
{
|
||||
"Name": "Run",
|
||||
"KeyboardCode": "shift",
|
||||
"GamepadCode": "LeftJoystickButton",
|
||||
"GroupName": "Movement"
|
||||
},
|
||||
{
|
||||
"Name": "Walk",
|
||||
"KeyboardCode": "alt",
|
||||
"GamepadCode": "None",
|
||||
"GroupName": "Movement"
|
||||
},
|
||||
{
|
||||
"Name": "Duck",
|
||||
"KeyboardCode": "ctrl",
|
||||
"GamepadCode": "B",
|
||||
"GroupName": "Movement"
|
||||
},
|
||||
{
|
||||
"Name": "attack1",
|
||||
"KeyboardCode": "mouse1",
|
||||
"GamepadCode": "RightTrigger",
|
||||
"GroupName": "Actions"
|
||||
},
|
||||
{
|
||||
"Name": "attack2",
|
||||
"KeyboardCode": "mouse2",
|
||||
"GamepadCode": "LeftTrigger",
|
||||
"GroupName": "Actions"
|
||||
},
|
||||
{
|
||||
"Name": "reload",
|
||||
"KeyboardCode": "r",
|
||||
"GamepadCode": "X",
|
||||
"GroupName": "Actions"
|
||||
},
|
||||
{
|
||||
"Name": "use",
|
||||
"KeyboardCode": "e",
|
||||
"GamepadCode": "Y",
|
||||
"GroupName": "Actions"
|
||||
},
|
||||
{
|
||||
"Name": "Slot1",
|
||||
"KeyboardCode": "1",
|
||||
"GamepadCode": "DpadWest",
|
||||
"GroupName": "Inventory"
|
||||
},
|
||||
{
|
||||
"Name": "Slot2",
|
||||
"KeyboardCode": "2",
|
||||
"GamepadCode": "DpadEast",
|
||||
"GroupName": "Inventory"
|
||||
},
|
||||
{
|
||||
"Name": "Slot3",
|
||||
"KeyboardCode": "3",
|
||||
"GamepadCode": "DpadSouth",
|
||||
"GroupName": "Inventory"
|
||||
},
|
||||
{
|
||||
"Name": "Slot4",
|
||||
"KeyboardCode": "4",
|
||||
"GamepadCode": "None",
|
||||
"GroupName": "Inventory"
|
||||
},
|
||||
{
|
||||
"Name": "Slot5",
|
||||
"KeyboardCode": "5",
|
||||
"GamepadCode": "None",
|
||||
"GroupName": "Inventory"
|
||||
},
|
||||
{
|
||||
"Name": "Slot6",
|
||||
"KeyboardCode": "6",
|
||||
"GamepadCode": "None",
|
||||
"GroupName": "Inventory"
|
||||
},
|
||||
{
|
||||
"Name": "Slot7",
|
||||
"KeyboardCode": "7",
|
||||
"GamepadCode": "None",
|
||||
"GroupName": "Inventory"
|
||||
},
|
||||
{
|
||||
"Name": "Slot8",
|
||||
"KeyboardCode": "8",
|
||||
"GamepadCode": "None",
|
||||
"GroupName": "Inventory"
|
||||
},
|
||||
{
|
||||
"Name": "Slot9",
|
||||
"KeyboardCode": "9",
|
||||
"GamepadCode": "None",
|
||||
"GroupName": "Inventory"
|
||||
},
|
||||
{
|
||||
"Name": "Slot0",
|
||||
"KeyboardCode": "0",
|
||||
"GamepadCode": "None",
|
||||
"GroupName": "Inventory"
|
||||
},
|
||||
{
|
||||
"Name": "SlotPrev",
|
||||
"KeyboardCode": "mouse4",
|
||||
"GamepadCode": "SwitchLeftBumper",
|
||||
"GroupName": "Inventory"
|
||||
},
|
||||
{
|
||||
"Name": "SlotNext",
|
||||
"KeyboardCode": "mouse5",
|
||||
"GamepadCode": "SwitchRightBumper",
|
||||
"GroupName": "Inventory"
|
||||
},
|
||||
{
|
||||
"Name": "View",
|
||||
"KeyboardCode": "C",
|
||||
"GamepadCode": "RightJoystickButton",
|
||||
"GroupName": "Other"
|
||||
},
|
||||
{
|
||||
"Name": "Voice",
|
||||
"KeyboardCode": "v",
|
||||
"GamepadCode": "None",
|
||||
"GroupName": "Other"
|
||||
},
|
||||
{
|
||||
"Name": "Drop",
|
||||
"KeyboardCode": "g",
|
||||
"GamepadCode": "None",
|
||||
"GroupName": "Other"
|
||||
},
|
||||
{
|
||||
"Name": "Flashlight",
|
||||
"KeyboardCode": "f",
|
||||
"GamepadCode": "DpadNorth",
|
||||
"GroupName": "Other"
|
||||
},
|
||||
{
|
||||
"Name": "Score",
|
||||
"KeyboardCode": "tab",
|
||||
"GamepadCode": "SwitchLeftMenu",
|
||||
"GroupName": "Other"
|
||||
},
|
||||
{
|
||||
"Name": "Menu",
|
||||
"KeyboardCode": "Q",
|
||||
"GamepadCode": "SwitchRightMenu",
|
||||
"GroupName": "Other"
|
||||
},
|
||||
{
|
||||
"Name": "Chat",
|
||||
"KeyboardCode": "enter",
|
||||
"GamepadCode": "None",
|
||||
"GroupName": "Other"
|
||||
}
|
||||
],
|
||||
"__guid": "2b0cbf43-3f45-425d-8560-9eaecf2ed2a3",
|
||||
"__schema": "configdata",
|
||||
"__type": "InputSettings",
|
||||
"__version": 1
|
||||
}
|
||||
41
Libraries/fish.scc/README.md
Normal file
41
Libraries/fish.scc/README.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Shrimple Character Controller
|
||||
|
||||
https://github.com/user-attachments/assets/374eea5b-7106-4c3e-8cb6-9bb56a1ff511
|
||||
|
||||
A shrimple yet versatile Character Controller/Move Helper that performs great.
|
||||
Performs 60%-200% better than standard Character Controller.
|
||||
|
||||
|
||||
You can find example scenes for the Walker, Roller, and Flyer here: [Controller Example Scenes](https://github.com/Small-Fish-Dev/shrimple_character_controller/tree/main/Assets/scenes)
|
||||
|
||||
Made from scratch using the classic [Collide and Slide](https://www.peroxide.dk/papers/collision/collision.pdf) method.
|
||||
|
||||
For any issues please report them here: [Github Issues](https://github.com/Small-Fish-Dev/shrimple_character_controller/issues)
|
||||
|
||||
# How to use
|
||||
You can find code examples for the Walker, Roller, and Flyer here: [Example Controllers](https://github.com/Small-Fish-Dev/shrimple_character_controller/tree/main/code/Examples)
|
||||
|
||||
It all boils down to:
|
||||
|
||||
```csharp
|
||||
Controller.WishVelocity = Vector3.Forward;
|
||||
Controller.Move();
|
||||
```
|
||||
|
||||
You'll have to call `.Move()` only if your Controller options "Manual Update" is set to true. Otherwise you can set it to false and it will always be simulated.
|
||||
|
||||
You are also able to manually update the GameObject's transform rather than letting the Controller do it:
|
||||
```csharp
|
||||
Controller.WishVelocity = wishDirection * wishSpeed;
|
||||
var controllerResult = Controller.Move( false );
|
||||
|
||||
if ( controllerResult.Position.z <= 999f ) // Out of bounds!
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
else
|
||||
{
|
||||
Transform.Position = controllerResult.Position;
|
||||
MyVelocity = controllerResult.Velocity;
|
||||
}
|
||||
```
|
||||
5
Libraries/fish.scc/code/Assembly.cs
Normal file
5
Libraries/fish.scc/code/Assembly.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
global using Sandbox;
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
||||
global using System.Linq;
|
||||
namespace ShrimpleCharacterController;
|
||||
68
Libraries/fish.scc/code/Examples/ShrimpleFlyer.cs
Normal file
68
Libraries/fish.scc/code/Examples/ShrimpleFlyer.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using Sandbox.Citizen;
|
||||
|
||||
namespace ShrimpleCharacterController;
|
||||
|
||||
[Hide]
|
||||
public sealed class ShrimpleFlyer : Component
|
||||
{
|
||||
[RequireComponent]
|
||||
public ShrimpleCharacterController Controller { get; set; }
|
||||
|
||||
[RequireComponent]
|
||||
public CitizenAnimationHelper AnimationHelper { get; set; }
|
||||
public SkinnedModelRenderer Renderer { get; set; }
|
||||
public GameObject Camera { get; set; }
|
||||
|
||||
[Property]
|
||||
[Range(400f, 1600f, 20f)]
|
||||
public float WalkSpeed { get; set; } = 800f;
|
||||
|
||||
[Property]
|
||||
[Range(800f, 4000f, 80f)]
|
||||
public float RunSpeed { get; set; } = 2400f;
|
||||
|
||||
public Angles EyeAngles { get; set; }
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
base.OnStart();
|
||||
|
||||
Renderer = AnimationHelper.Target;
|
||||
Camera = new GameObject(true, "Camera");
|
||||
Camera.SetParent(GameObject);
|
||||
var cameraComponent = Camera.Components.Create<CameraComponent>();
|
||||
cameraComponent.ZFar = 32768f;
|
||||
}
|
||||
|
||||
protected override void OnFixedUpdate()
|
||||
{
|
||||
base.OnFixedUpdate();
|
||||
|
||||
var isDucking = Input.Down("Duck");
|
||||
var isRunning = Input.Down("Run");
|
||||
var ascending = Input.Down("Jump") ? 1f : 0f;
|
||||
var descending = Input.Down("Duck") ? -1f : 0f;
|
||||
var wishSpeed = isRunning ? RunSpeed : WalkSpeed;
|
||||
var wishDirection = (Input.AnalogMove + Vector3.Up * (ascending + descending)).Normal * EyeAngles.ToRotation();
|
||||
|
||||
Controller.WishVelocity = wishDirection * wishSpeed;
|
||||
Controller.Move();
|
||||
|
||||
AnimationHelper.WithWishVelocity(Controller.WishVelocity);
|
||||
AnimationHelper.WithVelocity(Controller.Velocity);
|
||||
AnimationHelper.IsGrounded = Controller.IsOnGround;
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
base.OnUpdate();
|
||||
|
||||
EyeAngles += Input.AnalogLook;
|
||||
EyeAngles = EyeAngles.WithPitch(MathX.Clamp(EyeAngles.pitch, -10f, 40f));
|
||||
Renderer.WorldRotation = Rotation.Slerp(Renderer.WorldRotation, Rotation.FromYaw(EyeAngles.yaw), Time.Delta * 5f);
|
||||
|
||||
var cameraOffset = Vector3.Up * 70f + Vector3.Backward * 220f;
|
||||
Camera.WorldRotation = EyeAngles.ToRotation();
|
||||
Camera.LocalPosition = cameraOffset * Camera.WorldRotation;
|
||||
}
|
||||
}
|
||||
71
Libraries/fish.scc/code/Examples/ShrimpleRoller.cs
Normal file
71
Libraries/fish.scc/code/Examples/ShrimpleRoller.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
namespace ShrimpleCharacterController;
|
||||
|
||||
[Hide]
|
||||
public sealed class ShrimpleRoller : Component
|
||||
{
|
||||
[RequireComponent]
|
||||
public ShrimpleCharacterController Controller { get; set; }
|
||||
|
||||
public ModelRenderer Renderer { get; set; }
|
||||
public GameObject Camera { get; set; }
|
||||
|
||||
[Property]
|
||||
[Range(500f, 2000f, 100f)]
|
||||
public float WalkSpeed { get; set; } = 1000f;
|
||||
|
||||
[Property]
|
||||
[Range(1000f, 5000f, 200f)]
|
||||
public float RunSpeed { get; set; } = 3000f;
|
||||
|
||||
[Property]
|
||||
[Range(200f, 500f, 20f)]
|
||||
public float JumpStrength { get; set; } = 350f;
|
||||
|
||||
public Angles EyeAngles { get; set; }
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
base.OnStart();
|
||||
|
||||
Renderer = Components.Get<ModelRenderer>(FindMode.EnabledInSelfAndDescendants);
|
||||
|
||||
Camera = new GameObject(true, "Camera");
|
||||
Camera.SetParent(GameObject);
|
||||
var cameraComponent = Camera.Components.Create<CameraComponent>();
|
||||
cameraComponent.ZFar = 32768f;
|
||||
}
|
||||
|
||||
protected override void OnFixedUpdate()
|
||||
{
|
||||
base.OnFixedUpdate();
|
||||
|
||||
var wishDirection = Input.AnalogMove.Normal * Rotation.FromYaw(EyeAngles.yaw);
|
||||
var isDucking = Input.Down("Duck");
|
||||
var isRunning = Input.Down("Run");
|
||||
var wishSpeed = isRunning ? RunSpeed : WalkSpeed;
|
||||
|
||||
Controller.WishVelocity = wishDirection * wishSpeed;
|
||||
Controller.Move();
|
||||
|
||||
if (Input.Pressed("Jump") && Controller.IsOnGround)
|
||||
Controller.Punch(Vector3.Up * JumpStrength);
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
base.OnUpdate();
|
||||
|
||||
EyeAngles += Input.AnalogLook;
|
||||
EyeAngles = EyeAngles.WithPitch(MathX.Clamp(EyeAngles.pitch, -10f, 40f));
|
||||
|
||||
float pitchRotation = Controller.Velocity.x * Time.Delta;
|
||||
float rollRotation = -Controller.Velocity.y * Time.Delta;
|
||||
var ballPitch = Rotation.FromPitch(pitchRotation);
|
||||
var ballRoll = Rotation.FromRoll(rollRotation);
|
||||
Renderer.WorldRotation = ballPitch * ballRoll * Renderer.WorldRotation;
|
||||
|
||||
var cameraOffset = Vector3.Up * 70f + Vector3.Backward * 260f;
|
||||
Camera.WorldRotation = EyeAngles.ToRotation();
|
||||
Camera.LocalPosition = cameraOffset * Camera.WorldRotation;
|
||||
}
|
||||
}
|
||||
84
Libraries/fish.scc/code/Examples/ShrimpleWalker.cs
Normal file
84
Libraries/fish.scc/code/Examples/ShrimpleWalker.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using Sandbox.Citizen;
|
||||
|
||||
namespace ShrimpleCharacterController;
|
||||
|
||||
[Hide]
|
||||
public sealed class ShrimpleWalker : Component
|
||||
{
|
||||
[RequireComponent]
|
||||
public ShrimpleCharacterController Controller { get; set; }
|
||||
|
||||
[RequireComponent]
|
||||
public CitizenAnimationHelper AnimationHelper { get; set; }
|
||||
public SkinnedModelRenderer Renderer { get; set; }
|
||||
public GameObject Camera { get; set; }
|
||||
|
||||
[Property]
|
||||
[Range(50f, 200f, 10f)]
|
||||
public float WalkSpeed { get; set; } = 100f;
|
||||
|
||||
[Property]
|
||||
[Range(100f, 500f, 20f)]
|
||||
public float RunSpeed { get; set; } = 300f;
|
||||
|
||||
[Property]
|
||||
[Range(25f, 100f, 5f)]
|
||||
public float DuckSpeed { get; set; } = 50f;
|
||||
|
||||
[Property]
|
||||
[Range(200f, 500f, 20f)]
|
||||
public float JumpStrength { get; set; } = 350f;
|
||||
|
||||
public Angles EyeAngles { get; set; }
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
base.OnStart();
|
||||
|
||||
Renderer = Components.Get<SkinnedModelRenderer>(FindMode.EverythingInSelfAndDescendants);
|
||||
Camera = new GameObject(true, "Camera");
|
||||
Camera.SetParent(GameObject);
|
||||
var cameraComponent = Camera.Components.Create<CameraComponent>();
|
||||
cameraComponent.ZFar = 32768f;
|
||||
}
|
||||
|
||||
protected override void OnFixedUpdate()
|
||||
{
|
||||
base.OnFixedUpdate();
|
||||
|
||||
var wishDirection = Input.AnalogMove.Normal * Rotation.FromYaw(EyeAngles.yaw) * GameObject.WorldRotation;
|
||||
var isDucking = Input.Down("Duck");
|
||||
var isRunning = Input.Down("Run");
|
||||
var wishSpeed = isDucking ? DuckSpeed :
|
||||
isRunning ? RunSpeed : WalkSpeed;
|
||||
|
||||
Controller.WishVelocity = wishDirection * wishSpeed;
|
||||
Controller.Move();
|
||||
|
||||
if (Input.Pressed("Jump") && Controller.IsOnGround)
|
||||
{
|
||||
Controller.Punch(-Controller.AppliedGravity.Normal * JumpStrength);
|
||||
AnimationHelper?.TriggerJump();
|
||||
}
|
||||
|
||||
if (!AnimationHelper.IsValid()) return;
|
||||
|
||||
AnimationHelper.WithWishVelocity(Controller.WishVelocity);
|
||||
AnimationHelper.WithVelocity(Controller.Velocity);
|
||||
AnimationHelper.DuckLevel = isDucking ? 1f : 0f;
|
||||
AnimationHelper.IsGrounded = Controller.IsOnGround;
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
base.OnUpdate();
|
||||
|
||||
EyeAngles += Input.AnalogLook;
|
||||
EyeAngles = EyeAngles.WithPitch(MathX.Clamp(EyeAngles.pitch, -10f, 40f));
|
||||
// Renderer.WorldRotation = Rotation.Slerp(Renderer.WorldRotation, Rotation.FromYaw(EyeAngles.yaw), Time.Delta * 5f);
|
||||
|
||||
var cameraOffset = Vector3.Up * 70f + Vector3.Backward * 220f;
|
||||
Camera.LocalRotation = EyeAngles.ToRotation();
|
||||
Camera.LocalPosition = cameraOffset * Camera.LocalRotation;
|
||||
}
|
||||
}
|
||||
916
Libraries/fish.scc/code/ShrimpleCharacterController.cs
Normal file
916
Libraries/fish.scc/code/ShrimpleCharacterController.cs
Normal file
@@ -0,0 +1,916 @@
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace ShrimpleCharacterController;
|
||||
|
||||
[Icon("nordic_walking")]
|
||||
public class ShrimpleCharacterController : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Manually update this by calling Move() or let it always be simulated
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Group("Options")]
|
||||
public bool ManuallyUpdate { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// If pushing against a wall, scale the velocity based on the wall's angle (False is useful for NPCs that get stuck on corners)
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Group("Options")]
|
||||
public bool ScaleAgainstWalls { get; set; } = true;
|
||||
|
||||
[Sync]
|
||||
float _traceWidth { get; set; } = 16f;
|
||||
|
||||
/// <summary>
|
||||
/// Width of our trace
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Group("Trace")]
|
||||
[Range(1f, 64f, 1f, true, true)]
|
||||
public float TraceWidth
|
||||
{
|
||||
get => _traceWidth;
|
||||
set
|
||||
{
|
||||
_traceWidth = value;
|
||||
Bounds = BuildBounds();
|
||||
_shrunkenBounds = Bounds.Grow(-SkinWidth);
|
||||
}
|
||||
}
|
||||
|
||||
[Sync]
|
||||
float _traceHeight { get; set; } = 72f;
|
||||
|
||||
/// <summary>
|
||||
/// Height of our trace
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Group("Trace")]
|
||||
[Range(1f, 256f, 1f, true, true)]
|
||||
public float TraceHeight
|
||||
{
|
||||
get => _traceHeight;
|
||||
set
|
||||
{
|
||||
_traceHeight = value;
|
||||
Bounds = BuildBounds();
|
||||
_shrunkenBounds = Bounds.Grow(-SkinWidth);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotate the trace with the gameobject
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Group("Trace")]
|
||||
public bool RotateWithGameObject { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Use a cylinder trace instead of a box trace<br/>
|
||||
/// [WARNING] This is a PHYSICAL TRACE, so it's more expensive than the normal box trace
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Group("Trace")]
|
||||
public bool CylinderTrace { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Which tags it should ignore
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Group("Trace")]
|
||||
public TagSet IgnoreTags { get; set; } = new TagSet();
|
||||
|
||||
/// <summary>
|
||||
/// Max amount of trace calls whenever the simulation doesn't reach its target (Slide and collide bounces)
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Group("Trace")]
|
||||
[Range(1, 20, 1, true, true)]
|
||||
public int MaxBounces { get; set; } = 5;
|
||||
|
||||
/// <summary>
|
||||
/// How fast you accelerate while on the ground (Units per second)
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Group("Movement")]
|
||||
[Range(0f, 3000f, 10f, false)]
|
||||
[HideIf("GroundStickEnabled", false)]
|
||||
public float GroundAcceleration { get; set; } = 1000f;
|
||||
|
||||
/// <summary>
|
||||
/// How fast you decelerate while on the ground (Units per second)
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Group("Movement")]
|
||||
[Range(0f, 3000f, 10f, false)]
|
||||
[HideIf("GroundStickEnabled", false)]
|
||||
public float GroundDeceleration { get; set; } = 1500f;
|
||||
|
||||
/// <summary>
|
||||
/// How fast you accelerate while in the air (Units per second)
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Group("Movement")]
|
||||
[Range(0f, 3000f, 10f, false)]
|
||||
public float AirAcceleration { get; set; } = 300f;
|
||||
|
||||
/// <summary>
|
||||
/// How fast you decelerate while in the air (Units per second)
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Group("Movement")]
|
||||
[Range(0f, 3000f, 10f, false)]
|
||||
public float AirDeceleration { get; set; } = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// Do we ignore the friction of the surface you're standing on or not?
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Group("Movement")]
|
||||
public bool IgnoreGroundSurface { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Is this MoveHelper meant for horizontal grounded movement? (false = For flying or noclip)
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Group("Movement")]
|
||||
public bool IgnoreZ { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Do we ignore Z when it's near 0 (So that gravity affects you when not moving)
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Title("Ignore Z When Zero")]
|
||||
[Group("Movement")]
|
||||
[HideIf("IgnoreZ", true)]
|
||||
public bool IgnoreZWhenZero { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Tolerance from a 90° surface before it's considered a wall (Ex. Tolerance 1 = Between 89° and 91° can be a wall, 0.1 = 89.9° to 90.1°)
|
||||
/// </summary>
|
||||
[Group("Movement")]
|
||||
[Property]
|
||||
[Range(0f, 10f, 0.1f, false)]
|
||||
public float WallTolerance { get; set; } = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Player feels like it's gripping walls too much? Try more Grip Factor Reduction!
|
||||
/// </summary>
|
||||
[Group("Movement")]
|
||||
[Property]
|
||||
[Range(1f, 10f, 0.1f, true)]
|
||||
public float GripFactorReduction { get; set; } = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Stick the MoveHelper to the ground (IsOnGround will default to false if disabled)
|
||||
/// </summary>
|
||||
[FeatureEnabled("GroundStick")]
|
||||
[Property]
|
||||
public bool GroundStickEnabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// How steep terrain can be for you to stand on without slipping
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Feature("GroundStick")]
|
||||
[Range(0f, 89f, 1f, true, true)]
|
||||
public float MaxGroundAngle { get; set; } = 60f;
|
||||
|
||||
/// <summary>
|
||||
/// How far from the ground the MoveHelper is going to stick (Useful for going down stairs!)
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Feature("GroundStick")]
|
||||
[Range(1f, 32f, 1f, false)]
|
||||
public float GroundStickDistance { get; set; } = 12f;
|
||||
|
||||
/// <summary>
|
||||
/// Enable steps climbing (+1 Trace call)
|
||||
/// </summary>
|
||||
[FeatureEnabled("Steps")]
|
||||
[Property]
|
||||
public bool StepsEnabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// How high steps can be for you to climb on
|
||||
/// </summary>
|
||||
[Feature("Steps")]
|
||||
[Property]
|
||||
[Range(1f, 132f, 1f, false)]
|
||||
public float StepHeight { get; set; } = 12f;
|
||||
|
||||
/// <summary>
|
||||
/// How deep it checks for steps (Minimum depth)
|
||||
/// </summary>
|
||||
[Feature("Steps")]
|
||||
[Property]
|
||||
[Range(0.1f, 8f, 0.1f, false)]
|
||||
public float StepDepth { get; set; } = 2f;
|
||||
|
||||
/// <summary>
|
||||
/// Tolerance from a 90° surface before it's considered a valid step (Ex. Tolerance 1 = Between 89° and 91° can be a step, 0.1 = 89.9° to 90.1°)
|
||||
/// </summary>
|
||||
[Feature("Steps")]
|
||||
[Property]
|
||||
[Range(0f, 10f, 0.1f, false)]
|
||||
public float StepTolerance { get; set; } = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Enable to ability to walk on a surface that's too steep if it's equal or smaller than a step (+1 Trace call when on steep terrain)
|
||||
/// </summary>
|
||||
[Feature("Steps")]
|
||||
[Property]
|
||||
public bool PseudoStepsEnabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Instead of colliding with these tags the MoveHelper will be pushed away (Make sure the tags are in IgnoreTags as well!)
|
||||
/// </summary>
|
||||
[FeatureEnabled("Push")]
|
||||
[Property]
|
||||
public bool PushEnabled { get; set; } = false;
|
||||
|
||||
[Sync]
|
||||
Dictionary<string, float> _pushTagsWeight { get; set; } = new Dictionary<string, float>() { { "player", 1f } };
|
||||
|
||||
/// <summary>
|
||||
/// Which tags will push this MoveHelper away and with how much force (Make sure they are also included in IgnoreTags!) (+1 Trace call)
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Feature("Push")]
|
||||
public Dictionary<string, float> PushTagsWeight
|
||||
{
|
||||
get => _pushTagsWeight;
|
||||
set
|
||||
{
|
||||
_pushTagsWeight = value;
|
||||
_pushTags = BuildPushTags();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply gravity to this MoveHelper when not on the ground
|
||||
/// </summary>
|
||||
[FeatureEnabled("Gravity")]
|
||||
[Property]
|
||||
public bool GravityEnabled { get; set; } = true;
|
||||
|
||||
private bool _useSceneGravity = true;
|
||||
|
||||
/// <summary>
|
||||
/// Use the scene's gravity or our own
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Feature("Gravity")]
|
||||
public bool UseSceneGravity
|
||||
{
|
||||
get => _useSceneGravity;
|
||||
set
|
||||
{
|
||||
_useSceneGravity = value;
|
||||
_appliedGravity = BuildGravity();
|
||||
}
|
||||
}
|
||||
|
||||
private bool _useVectorGravity = false;
|
||||
|
||||
/// <summary>
|
||||
/// Use a Vector3 gravity instead of a single float (Use this if you want to use a custom gravity)
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Feature("Gravity")]
|
||||
[HideIf("UseSceneGravity", true)]
|
||||
public bool UseVectorGravity
|
||||
{
|
||||
get => _useVectorGravity;
|
||||
set
|
||||
{
|
||||
_useVectorGravity = value;
|
||||
_appliedGravity = BuildGravity();
|
||||
}
|
||||
}
|
||||
|
||||
private bool _usingFloatGravity => !UseVectorGravity && !UseSceneGravity;
|
||||
private bool _usingVectorGravity => UseVectorGravity && !UseSceneGravity;
|
||||
|
||||
private float _gravity = -850f;
|
||||
|
||||
/// <summary>
|
||||
/// Units per second squared (Default is -850f)
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Feature("Gravity")]
|
||||
[Range(-2000, 2000, 1, false)]
|
||||
[ShowIf("_usingFloatGravity", true)]
|
||||
public float Gravity
|
||||
{
|
||||
get => _gravity;
|
||||
set
|
||||
{
|
||||
_gravity = value;
|
||||
_appliedGravity = BuildGravity();
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 _vectorGravity = new Vector3(0f, 0f, -850f);
|
||||
|
||||
/// <summary>
|
||||
/// Units per second squared (Default is 0f, 0f, -850f)<br/>
|
||||
/// Changes which way <see cref="GroundStickEnabled"/> sticks to the ground
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Feature("Gravity")]
|
||||
[ShowIf("_usingVectorGravity", true)]
|
||||
public Vector3 VectorGravity
|
||||
{
|
||||
get => _vectorGravity;
|
||||
set
|
||||
{
|
||||
_vectorGravity = value;
|
||||
_appliedGravity = BuildGravity();
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 _appliedGravity;
|
||||
public Vector3 AppliedGravity => _appliedGravity;
|
||||
|
||||
/// <summary>
|
||||
/// Check if the MoveHelper is stuck and try to get it to unstuck (+Trace calls if stuck)
|
||||
/// </summary>
|
||||
[FeatureEnabled("Unstuck")]
|
||||
[Property]
|
||||
public bool UnstuckEnabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// How many trace calls it will attempt to get the MoveHelper unstuck
|
||||
/// </summary>
|
||||
[Property]
|
||||
[Feature("Unstuck")]
|
||||
[Range(1, 50, 1, false)]
|
||||
public int MaxUnstuckTries { get; set; } = 20;
|
||||
|
||||
/// <summary>
|
||||
/// The simulated target velocity for our MoveHelper (Units per second, we apply Time.Delta inside)
|
||||
/// </summary>
|
||||
[Sync] public Vector3 WishVelocity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The resulting velocity after the simulation is done (Units per second)
|
||||
/// </summary>
|
||||
[Sync] public Vector3 Velocity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is the MoveHelper currently touching the ground
|
||||
/// </summary>
|
||||
[Sync] public bool IsOnGround { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current ground normal you're standing on (Always Vector3.Zero if IsOnGround false)
|
||||
/// </summary>
|
||||
public Vector3 GroundNormal { get; private set; } = Vector3.Zero;
|
||||
|
||||
public Vector3 Up { get; set; } = Vector3.Up;
|
||||
|
||||
/// <summary>
|
||||
/// The current ground angle you're standing on (Always 0f if IsOnGround false)
|
||||
/// </summary>
|
||||
public float GroundAngle => Vector3.GetAngle(GroundNormal, Up);
|
||||
|
||||
/// <summary>
|
||||
/// The current surface you're standing on
|
||||
/// </summary>
|
||||
public Surface GroundSurface { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The gameobject you're currently standing on
|
||||
/// </summary>
|
||||
public GameObject GroundObject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is the MoveHelper currently pushing against a wall
|
||||
/// </summary>
|
||||
public bool IsPushingAgainstWall { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current wall normal you're pushing against (Always Vector3.Zero if IsPushingAgainstWall false)
|
||||
/// </summary>
|
||||
public Vector3 WallNormal { get; private set; } = Vector3.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// The gameobject you're currently pushing on
|
||||
/// </summary>
|
||||
public GameObject WallObject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is the MoveHelper standing on a terrain too steep to stand on (Always false if IsOnGround false)
|
||||
/// </summary>
|
||||
[Sync] public bool IsSlipping { get; private set; } // TODO IMPLEMENT
|
||||
|
||||
/// <summary>
|
||||
/// The MoveHelper is stuck and we can't get it out
|
||||
/// </summary>
|
||||
[Sync] public bool IsStuck { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// To avoid getting stuck due to imprecision we shrink the bounds before checking and compensate for it later
|
||||
/// </summary>
|
||||
public float SkinWidth;
|
||||
|
||||
public float AppliedWidth => TraceWidth / 2f * WorldScale.x; // The width of the MoveHelper in world units
|
||||
public float AppliedDepth => TraceWidth / 2f * WorldScale.y; // The depth of the MoveHelper in world units
|
||||
public float AppliedHeight => TraceHeight / 2f * WorldScale.z; // The height of the MoveHelper in world units
|
||||
private Vector3 _offset => (RotateWithGameObject ? WorldRotation.Up : Vector3.Up) * AppliedHeight; // The position of the MoveHelper in world units
|
||||
|
||||
/// <summary>
|
||||
/// The bounds of this MoveHelper generated from the TraceWidth and TraceHeight
|
||||
/// </summary>
|
||||
public BBox Bounds { get; set; }
|
||||
private BBox _shrunkenBounds;
|
||||
private string[] _pushTags;
|
||||
private Vector3 _lastVelocity;
|
||||
|
||||
/// <summary>
|
||||
/// If another MoveHelper moved at the same time and they're stuck, let this one know that the other already unstuck for us
|
||||
/// </summary>
|
||||
public ShrimpleCharacterController UnstuckTarget;
|
||||
|
||||
public override int ComponentVersion => 1;
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
SkinWidth = Math.Min(Math.Max(0.1f, TraceWidth * 0.05f), GroundStickDistance); // SkinWidth is 5% of the total width
|
||||
Bounds = BuildBounds();
|
||||
_shrunkenBounds = Bounds.Grow(-SkinWidth);
|
||||
_pushTags = BuildPushTags();
|
||||
}
|
||||
|
||||
protected override void DrawGizmos()
|
||||
{
|
||||
if (Gizmo.IsSelected)
|
||||
{
|
||||
Gizmo.GizmoDraw draw = Gizmo.Draw;
|
||||
draw.Color = Color.Blue;
|
||||
var bounds = BuildBounds();
|
||||
|
||||
if (CylinderTrace)
|
||||
draw.LineCylinder(Vector3.Zero, WorldRotation.Up * (bounds.Maxs.z - bounds.Mins.z), bounds.Maxs.x, bounds.Maxs.x, 24);
|
||||
else
|
||||
draw.LineBBox(bounds.Translate(Vector3.Up * TraceHeight / 2f * GameObject.WorldScale.z));
|
||||
}
|
||||
}
|
||||
|
||||
private BBox BuildBounds()
|
||||
{
|
||||
var x = GameObject.WorldScale.x;
|
||||
var y = GameObject.WorldScale.y;
|
||||
var z = GameObject.WorldScale.z;
|
||||
|
||||
var width = TraceWidth / 2f * x;
|
||||
var depth = TraceWidth / 2f * y;
|
||||
var height = TraceHeight / 2f * z;
|
||||
|
||||
return new BBox(new Vector3(-width, -depth, -height), new Vector3(width, depth, height));
|
||||
}
|
||||
|
||||
private Vector3 BuildGravity() => UseSceneGravity ? Scene.PhysicsWorld.Gravity : UseVectorGravity ? VectorGravity : new Vector3(0f, 0f, Gravity);
|
||||
|
||||
private string[] BuildPushTags()
|
||||
{
|
||||
return PushTagsWeight.Keys.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Casts the current bounds from to and returns the scene trace result
|
||||
/// </summary>
|
||||
/// <param name="bounds"></param>
|
||||
/// <param name="from"></param>
|
||||
/// <param name="to"></param>
|
||||
/// <returns></returns>
|
||||
public SceneTraceResult BuildTrace(BBox bounds, Vector3 from, Vector3 to)
|
||||
{
|
||||
SceneTrace builder = new SceneTrace(); // Empty trace builder
|
||||
|
||||
if (CylinderTrace)
|
||||
builder = Game.SceneTrace.Cylinder(bounds.Maxs.z - bounds.Mins.z, bounds.Maxs.x, from, to);
|
||||
else
|
||||
builder = Game.SceneTrace.Box(bounds, from, to);
|
||||
|
||||
builder = builder
|
||||
.IgnoreGameObjectHierarchy(GameObject)
|
||||
.WithoutTags(IgnoreTags);
|
||||
|
||||
if (RotateWithGameObject)
|
||||
builder = builder.Rotated(GameObject.WorldRotation);
|
||||
|
||||
return builder.Run();
|
||||
}
|
||||
|
||||
private SceneTraceResult BuildPushTrace(BBox bounds, Vector3 from, Vector3 to)
|
||||
{
|
||||
SceneTrace builder = new SceneTrace(); // Empty trace builder
|
||||
|
||||
if (CylinderTrace)
|
||||
builder = Game.SceneTrace.Cylinder(bounds.Maxs.z - bounds.Mins.z, bounds.Maxs.x, from, to);
|
||||
else
|
||||
builder = Game.SceneTrace.Box(bounds, from, to);
|
||||
|
||||
builder = builder
|
||||
.IgnoreGameObjectHierarchy(GameObject)
|
||||
.WithAnyTags(_pushTags); // Check for only the push tags
|
||||
|
||||
if (RotateWithGameObject)
|
||||
builder = builder.Rotated(GameObject.WorldRotation);
|
||||
|
||||
return builder.Run();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detach the MoveHelper from the ground and launch it somewhere (Units per second)
|
||||
/// </summary>
|
||||
/// <param name="amount"></param>
|
||||
public void Punch(in Vector3 amount)
|
||||
{
|
||||
IsOnGround = false;
|
||||
Velocity += amount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply the WishVelocity, update the Velocity and the Position of the GameObject by simulating the MoveHelper
|
||||
/// </summary>
|
||||
/// <param name="manualUpdate">Just calculate but don't update position</param>
|
||||
public MoveHelperResult Move(bool manualUpdate = false) => Move(Time.Delta, manualUpdate);
|
||||
|
||||
/// <summary>
|
||||
/// Apply the WishVelocity, update the Velocity and the Position of the GameObject by simulating the MoveHelper
|
||||
/// </summary>
|
||||
/// <param name="delta">The time step</param>
|
||||
/// <param name="manualUpdate">Just calculate but don't update position</param>
|
||||
public MoveHelperResult Move(float delta, bool manualUpdate = false)
|
||||
{
|
||||
var goalVelocity = CalculateGoalVelocity(delta); // Calculate the goal velocity using our Acceleration and Deceleration values
|
||||
|
||||
// KNOWN ISSUE: Velocity starts to build up to massive amounts when trying to climb terrain too steep?
|
||||
|
||||
// SIMULATE PUSH FORCES //
|
||||
if (PushEnabled)
|
||||
{
|
||||
var pushTrace = BuildPushTrace(Bounds, WorldPosition + _offset, WorldPosition); // Build a trace but using the Push tags instead of the Ignore tags
|
||||
|
||||
if (pushTrace.Hit) // We're inside any of the push tags
|
||||
{
|
||||
foreach (var tag in pushTrace.GameObject.Tags)
|
||||
{
|
||||
if (PushTagsWeight.TryGetValue(tag, out var tagWeight))
|
||||
{
|
||||
var otherPosition = pushTrace.GameObject.WorldPosition.WithZ(WorldPosition.z); // Only horizontal pushing
|
||||
var pushDirection = (otherPosition - WorldPosition).Normal;
|
||||
var pushVelocity = pushDirection * tagWeight * 50f; // I find 50 u/s to be a good amount to push if the weight is 1.0 (!!!)
|
||||
|
||||
goalVelocity -= pushVelocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var moveHelperResult = CollideAndSlide(goalVelocity, WorldPosition + _offset, delta); // Simulate the MoveHelper
|
||||
|
||||
var finalPosition = moveHelperResult.Position;
|
||||
var finalVelocity = moveHelperResult.Velocity;
|
||||
|
||||
// SIMULATE GRAVITY //
|
||||
if (GravityEnabled && Gravity != 0f)
|
||||
{
|
||||
if (!IsOnGround || IsSlipping || !GroundStickEnabled)
|
||||
{
|
||||
var gravity = AppliedGravity * delta;
|
||||
var gravityResult = CollideAndSlide(gravity, moveHelperResult.Position, delta, gravityPass: true); // Apply and simulate the gravity step
|
||||
|
||||
finalPosition = gravityResult.Position;
|
||||
finalVelocity += gravityResult.Velocity;
|
||||
}
|
||||
}
|
||||
|
||||
_lastVelocity = Velocity * delta;
|
||||
|
||||
if (!manualUpdate)
|
||||
{
|
||||
Velocity = finalVelocity;
|
||||
WorldPosition = finalPosition - _offset; // Actually updating the position is "expensive" so we only do it once at the end
|
||||
}
|
||||
|
||||
return new MoveHelperResult(finalPosition, finalVelocity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sometimes we have to update only the position but not the velocity (Like when climbing steps or getting unstuck) so we can't have Position rely only on Velocity
|
||||
/// </summary>
|
||||
public struct MoveHelperResult
|
||||
{
|
||||
public Vector3 Position;
|
||||
public Vector3 Velocity;
|
||||
|
||||
public MoveHelperResult(Vector3 position, Vector3 velocity)
|
||||
{
|
||||
Position = position;
|
||||
Velocity = velocity;
|
||||
}
|
||||
}
|
||||
|
||||
private MoveHelperResult CollideAndSlide(Vector3 velocity, Vector3 position, float delta, int depth = 0, bool gravityPass = false) =>
|
||||
CollideAndSlide(new MoveHelperResult(position, velocity), delta, depth, gravityPass);
|
||||
|
||||
private MoveHelperResult CollideAndSlide(MoveHelperResult current, float delta, int depth = 0, bool gravityPass = false)
|
||||
{
|
||||
if (depth >= MaxBounces)
|
||||
return current;
|
||||
|
||||
var velocity = current.Velocity * delta; // I like to set Velocity as units/second but we have to deal with units/tick here
|
||||
var position = current.Position;
|
||||
|
||||
// GROUND AND UNSTUCK CHECK //
|
||||
if (depth == 0) // Only check for the first step since it's impossible to get stuck on other steps
|
||||
{
|
||||
var groundTrace = BuildTrace(_shrunkenBounds, position, position + AppliedGravity.Normal * (GroundStickDistance + SkinWidth * 1.1f)); // Compensate for floating inaccuracy
|
||||
|
||||
if (groundTrace.StartedSolid)
|
||||
{
|
||||
IsStuck = true;
|
||||
if (UnstuckEnabled)
|
||||
{
|
||||
if (UnstuckTarget == null)
|
||||
{
|
||||
IsStuck = !TryUnstuck(position, out var result);
|
||||
|
||||
if (!IsStuck)
|
||||
{
|
||||
position = result; // Update the new position
|
||||
|
||||
if (groundTrace.GameObject != null)
|
||||
if (groundTrace.GameObject.Components.TryGet<ShrimpleCharacterController>(out var otherHelper))
|
||||
otherHelper.UnstuckTarget = this; // We already solved this, no need to unstuck the other helper
|
||||
}
|
||||
else
|
||||
{
|
||||
return new MoveHelperResult(position, Vector3.Zero); // Mission failed, bail out!
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UnstuckTarget = null; // Alright the other MoveHelper got us unstuck so just do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var hasLanded = !IsOnGround && Vector3.Dot(Velocity, AppliedGravity) >= 0f && groundTrace.Hit && groundTrace.Distance <= SkinWidth * 2f; // Wasn't on the ground and now is
|
||||
var isGrounded = IsOnGround && groundTrace.Hit; // Was already on the ground and still is, this helps stick when going down stairs
|
||||
|
||||
IsOnGround = hasLanded || isGrounded;
|
||||
GroundSurface = IsOnGround ? groundTrace.Surface : null;
|
||||
GroundNormal = IsOnGround ? groundTrace.Normal : -AppliedGravity.Normal;
|
||||
GroundObject = IsOnGround ? groundTrace.GameObject : null;
|
||||
IsSlipping = IsOnGround && GroundAngle > MaxGroundAngle;
|
||||
|
||||
if (IsSlipping && !gravityPass && Vector3.Dot(velocity, AppliedGravity) < 0f)
|
||||
velocity = velocity.WithZ(0f); // If we're slipping ignore any extra velocity we had
|
||||
|
||||
if (IsOnGround && GroundStickEnabled && !IsSlipping)
|
||||
{
|
||||
position = groundTrace.EndPosition + -AppliedGravity.Normal * SkinWidth; // Place on the ground
|
||||
velocity = Vector3.VectorPlaneProject(velocity, GroundNormal); // Follow the ground you're on without projecting Z
|
||||
}
|
||||
|
||||
IsStuck = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (velocity.IsNearlyZero(0.01f)) // Not worth continuing, reduces small stutter
|
||||
{
|
||||
return new MoveHelperResult(position, Vector3.Zero);
|
||||
}
|
||||
|
||||
var toTravel = velocity.Length + SkinWidth;
|
||||
var targetPosition = position + velocity.Normal * toTravel;
|
||||
var travelTrace = BuildTrace(_shrunkenBounds, position, targetPosition);
|
||||
|
||||
if (travelTrace.Hit)
|
||||
{
|
||||
var travelled = velocity.Normal * Math.Max(travelTrace.Distance - SkinWidth, 0f);
|
||||
|
||||
var leftover = velocity - travelled; // How much leftover velocity still needs to be simulated
|
||||
var angle = Vector3.GetAngle(-AppliedGravity.Normal, travelTrace.Normal);
|
||||
if (toTravel >= SkinWidth && travelTrace.Distance < SkinWidth)
|
||||
travelled = Vector3.Zero;
|
||||
|
||||
if (angle <= MaxGroundAngle) // Terrain we can walk on
|
||||
{
|
||||
if (gravityPass || !IsOnGround)
|
||||
leftover = Vector3.VectorPlaneProject(leftover, travelTrace.Normal); // Don't project the vertical velocity after landing else it boosts your horizontal velocity
|
||||
else
|
||||
leftover = leftover.ProjectAndScale(travelTrace.Normal); // Project the velocity along the terrain
|
||||
IsPushingAgainstWall = false;
|
||||
WallObject = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var climbedStair = false;
|
||||
|
||||
if (angle >= 90f - WallTolerance && angle <= 90f + WallTolerance) // Check for walls
|
||||
IsPushingAgainstWall = true; // We're pushing against a wall
|
||||
|
||||
if (true) //StepsEnabled
|
||||
{
|
||||
var isStep = angle >= 90f - StepTolerance && angle <= 90f + StepTolerance;
|
||||
// Log.Info($"Step? {isStep} — Angle: {angle:F2}, StepTolerance: {StepTolerance}");
|
||||
// Log.Info($"Step detected: angle={angle}, isStep={isStep}, PseudoStepsEnabled={PseudoStepsEnabled}");
|
||||
|
||||
|
||||
if (isStep || PseudoStepsEnabled)
|
||||
{
|
||||
if (IsOnGround)
|
||||
{
|
||||
var stepHorizontal = Vector3.VectorPlaneProject(velocity, AppliedGravity).Normal * StepDepth;
|
||||
var stepVertical = -AppliedGravity.Normal * (StepHeight + SkinWidth);
|
||||
var stepStart = travelTrace.EndPosition + stepHorizontal + stepVertical;
|
||||
var stepEnd = travelTrace.EndPosition + stepHorizontal;
|
||||
|
||||
// Log.Info($"StepTrace start: {stepStart}, end: {stepEnd}");
|
||||
|
||||
var stepTrace = BuildTrace(_shrunkenBounds, stepStart, stepEnd);
|
||||
|
||||
// Gizmo.Draw.Arrow(stepStart, stepEnd);
|
||||
|
||||
var stepAngle = Vector3.GetAngle(stepTrace.Normal, -AppliedGravity.Normal);
|
||||
// Log.Info($"StepTrace hit: {stepTrace.Hit}, angle: {stepAngle:F2}, startedSolid: {stepTrace.StartedSolid}");
|
||||
|
||||
if (!stepTrace.StartedSolid && stepTrace.Hit && stepAngle <= MaxGroundAngle)
|
||||
{
|
||||
if (isStep || (!IsSlipping && PseudoStepsEnabled))
|
||||
{
|
||||
var stepHeight = Vector3.Dot(stepTrace.EndPosition - travelTrace.EndPosition, Up);
|
||||
var absStepHeight = Math.Abs(stepHeight);
|
||||
|
||||
if(absStepHeight >= stepHeight)
|
||||
{
|
||||
var stepTravelled = Up * absStepHeight;
|
||||
position += stepTravelled;
|
||||
|
||||
climbedStair = true;
|
||||
IsPushingAgainstWall = false;
|
||||
WallObject = null;
|
||||
|
||||
}
|
||||
|
||||
// Log.Info($"Climbed stair! Height: {absStepHeight:F4}, New Pos: {position}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsPushingAgainstWall)
|
||||
{
|
||||
// Scale our leftover velocity based on the angle of approach relative to the wall
|
||||
// (Perpendicular = 0%, Parallel = 100%)
|
||||
var scale = ScaleAgainstWalls ? 1f - Vector3.Dot(-travelTrace.Normal.Normal / GripFactorReduction, velocity.Normal) : 1f;
|
||||
var wallLeftover = ScaleAgainstWalls ? Vector3.VectorPlaneProject(leftover, travelTrace.Normal.Normal) : leftover.ProjectAndScale(travelTrace.Normal.Normal);
|
||||
leftover = (wallLeftover * scale).WithZ(wallLeftover.z);
|
||||
|
||||
WallObject = travelTrace.GameObject;
|
||||
WallNormal = travelTrace.Normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!climbedStair)
|
||||
{
|
||||
var scale = IsSlipping ? 1f : 1f - Vector3.Dot(-travelTrace.Normal / GripFactorReduction, velocity.Normal);
|
||||
leftover = ScaleAgainstWalls ? Vector3.VectorPlaneProject(leftover, travelTrace.Normal) * scale : leftover.ProjectAndScale(travelTrace.Normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (travelled.Length <= 0.01f && leftover.Length <= 0.01f)
|
||||
return new MoveHelperResult(position + travelled, travelled / delta);
|
||||
|
||||
var newResult = CollideAndSlide(new MoveHelperResult(position + travelled, leftover / delta), delta, depth + 1, gravityPass); // Simulate another bounce for the leftover velocity from the latest position
|
||||
var currentResult = new MoveHelperResult(newResult.Position, travelled / delta + newResult.Velocity); // Use the new bounce's position and combine the velocities
|
||||
|
||||
return currentResult;
|
||||
}
|
||||
|
||||
if (depth == 0 && !gravityPass)
|
||||
{
|
||||
IsPushingAgainstWall = false;
|
||||
WallObject = null;
|
||||
}
|
||||
|
||||
return new MoveHelperResult(position + velocity, velocity / delta); // We didn't hit anything? Ok just keep going then :-)
|
||||
}
|
||||
|
||||
private float CalculateGoalSpeed(Vector3 wishVelocity, Vector3 velocity, Vector3 surfaceNormal, bool isAccelerating, float delta)
|
||||
{
|
||||
Vector3 wishDir = Vector3.VectorPlaneProject(wishVelocity, surfaceNormal).Normal;
|
||||
Vector3 currentDir = Vector3.VectorPlaneProject(velocity, surfaceNormal).Normal;
|
||||
|
||||
bool isSameDirection = velocity.IsNearlyZero(1f) || Vector3.Dot(wishDir, currentDir) >= 0f;
|
||||
|
||||
float acceleration = IsOnGround ? GroundAcceleration : AirAcceleration;
|
||||
float deceleration = IsOnGround ? GroundDeceleration : AirDeceleration;
|
||||
|
||||
float goalSpeed = isAccelerating
|
||||
? acceleration
|
||||
: (!isSameDirection ? Math.Max(acceleration, deceleration) : deceleration);
|
||||
|
||||
if (!IgnoreGroundSurface && GroundSurface != null)
|
||||
goalSpeed *= GroundSurface.Friction;
|
||||
|
||||
return goalSpeed * delta;
|
||||
}
|
||||
|
||||
|
||||
private Vector3 CalculateGoalVelocity(float delta)
|
||||
{
|
||||
Vector3 surfaceNormal = Up;
|
||||
|
||||
var wishVelocityProjected = Vector3.VectorPlaneProject(WishVelocity, surfaceNormal);
|
||||
var velocityProjected = Vector3.VectorPlaneProject(Velocity, surfaceNormal);
|
||||
|
||||
bool isAccelerating = wishVelocityProjected.Length >= velocityProjected.Length;
|
||||
|
||||
float goalSpeed = CalculateGoalSpeed(wishVelocityProjected, Velocity, surfaceNormal, isAccelerating, delta);
|
||||
Vector3 goalVelocity = Velocity.MoveTowards(wishVelocityProjected, goalSpeed);
|
||||
|
||||
return goalVelocity;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public bool TryUnstuck(Vector3 position, out Vector3 result)
|
||||
{
|
||||
if (_lastVelocity == Vector3.Zero)
|
||||
_lastVelocity = -AppliedGravity.Normal;
|
||||
|
||||
var velocityLength = _lastVelocity.Length + SkinWidth;
|
||||
var startPos = position - _lastVelocity.Normal * velocityLength; // Try undoing the last velocity 1st
|
||||
var endPos = position;
|
||||
|
||||
for (int i = 0; i < MaxUnstuckTries + 1; i++)
|
||||
{
|
||||
if (i == 1)
|
||||
startPos = position + -AppliedGravity.Normal * 2f; // Try going up 2nd
|
||||
|
||||
if (i > 1)
|
||||
startPos = position + Vector3.Random.Normal * ((float)i / 2f); // Start randomly checking 3rd
|
||||
|
||||
if (startPos - endPos == Vector3.Zero) // No difference!
|
||||
continue;
|
||||
|
||||
var unstuckTrace = BuildTrace(_shrunkenBounds, startPos, endPos);
|
||||
|
||||
if (!unstuckTrace.StartedSolid)
|
||||
{
|
||||
result = unstuckTrace.EndPosition - _lastVelocity.Normal * SkinWidth / 4f;
|
||||
_lastVelocity = Vector3.Zero;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
result = position;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debug don't use
|
||||
/// </summary>
|
||||
/// <param name="position"></param>
|
||||
/// <param name="title"></param>
|
||||
/// <returns></returns>
|
||||
private bool TestPosition(Vector3 position, string title)
|
||||
{
|
||||
var testTrace = BuildTrace(_shrunkenBounds, position, position);
|
||||
|
||||
if (testTrace.StartedSolid)
|
||||
{
|
||||
Log.Info($"[{RealTime.Now}]{title} {GameObject.Name} started solid at {position} against {testTrace.GameObject}");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void OnFixedUpdate()
|
||||
{
|
||||
base.OnFixedUpdate();
|
||||
|
||||
if (!ManuallyUpdate && Active)
|
||||
Move();
|
||||
}
|
||||
|
||||
[JsonUpgrader(typeof(ShrimpleCharacterController), 1)]
|
||||
private static void FloatGravityUpgrader(JsonObject json)
|
||||
{
|
||||
json.Remove("Gravity", out var newNode);
|
||||
json["_gravity"] = newNode;
|
||||
}
|
||||
}
|
||||
40
Libraries/fish.scc/code/Util/Extensions/Vector3Extensions.cs
Normal file
40
Libraries/fish.scc/code/Util/Extensions/Vector3Extensions.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
namespace ShrimpleCharacterController;
|
||||
|
||||
public static class Vector3Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Move a vector3 towards a goal by a fixed distance
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="travelSpeed"></param>
|
||||
/// <returns></returns>
|
||||
public static Vector3 MoveTowards( this Vector3 value, Vector3 target, float travelSpeed )
|
||||
{
|
||||
var difference = target - value;
|
||||
var distance = difference.Length;
|
||||
var normal = difference.Normal;
|
||||
|
||||
if ( distance <= travelSpeed || distance == 0f )
|
||||
{
|
||||
return target;
|
||||
}
|
||||
|
||||
return value + normal * travelSpeed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Project a vector along a plane (normal) and scale it back to its original length
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="normal"></param>
|
||||
/// <returns></returns>
|
||||
public static Vector3 ProjectAndScale( this Vector3 value, Vector3 normal )
|
||||
{
|
||||
var length = value.Length;
|
||||
value = Vector3.VectorPlaneProject( value, normal ).Normal;
|
||||
value *= length;
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
16
Libraries/fish.scc/scc.sbproj
Normal file
16
Libraries/fish.scc/scc.sbproj
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"Title": "Shrimple Character Controller",
|
||||
"Type": "library",
|
||||
"Org": "fish",
|
||||
"Ident": "scc",
|
||||
"Schema": 1,
|
||||
"IncludeSourceFiles": false,
|
||||
"Resources": null,
|
||||
"PackageReferences": [],
|
||||
"EditorReferences": null,
|
||||
"Mounts": null,
|
||||
"IsStandaloneOnly": false,
|
||||
"Metadata": {
|
||||
"CsProjName": ""
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user