feat: Procedural staircase

This commit is contained in:
Alexandre Coirier
2026-06-01 16:16:41 +02:00
parent ef0f7e03c5
commit 3718b3b298
8 changed files with 3260 additions and 1908 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e5374f1162874334e9626041e06987fd
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1fdaf664472a0e841a14e54e372c3456
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,110 @@
fileFormatVersion: 2
guid: 471d04e939c6be84780b978dadd025c7
ModelImporter:
serializedVersion: 24200
internalIDToNameTable: []
externalObjects: {}
materials:
materialImportMode: 0
materialName: 0
materialSearch: 1
materialLocation: 1
animations:
legacyGenerateAnimations: 4
bakeSimulation: 0
resampleCurves: 1
optimizeGameObjects: 0
removeConstantScaleCurves: 0
motionNodeName:
animationImportErrors:
animationImportWarnings:
animationRetargetingWarnings:
animationDoRetargetingWarnings: 0
importAnimatedCustomProperties: 0
importConstraints: 0
animationCompression: 1
animationRotationError: 0.5
animationPositionError: 0.5
animationScaleError: 0.5
animationWrapMode: 0
extraExposedTransformPaths: []
extraUserProperties: []
clipAnimations: []
isReadable: 0
meshes:
lODScreenPercentages: []
globalScale: 1
meshCompression: 0
addColliders: 0
useSRGBMaterialColor: 1
sortHierarchyByName: 1
importPhysicalCameras: 1
importVisibility: 1
importBlendShapes: 1
importCameras: 1
importLights: 1
nodeNameCollisionStrategy: 1
fileIdsGeneration: 2
swapUVChannels: 0
generateSecondaryUV: 0
useFileUnits: 1
keepQuads: 0
weldVertices: 1
bakeAxisConversion: 0
preserveHierarchy: 0
skinWeightsMode: 0
maxBonesPerVertex: 4
minBoneWeight: 0.001
optimizeBones: 1
generateMeshLods: 0
meshLodGenerationFlags: 0
maximumMeshLod: -1
meshOptimizationFlags: -1
indexFormat: 0
secondaryUVAngleDistortion: 8
secondaryUVAreaDistortion: 15.000001
secondaryUVHardAngle: 88
secondaryUVMarginMethod: 1
secondaryUVMinLightmapResolution: 40
secondaryUVMinObjectScale: 1
secondaryUVPackMargin: 4
useFileScale: 1
strictVertexDataChecks: 0
tangentSpace:
normalSmoothAngle: 60
normalImportMode: 0
tangentImportMode: 3
normalCalculationMode: 4
legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
blendShapeNormalImportMode: 1
normalSmoothingSource: 0
referencedClips: []
importAnimation: 1
humanDescription:
serializedVersion: 3
human: []
skeleton: []
armTwist: 0.5
foreArmTwist: 0.5
upperLegTwist: 0.5
legTwist: 0.5
armStretch: 0.05
legStretch: 0.05
feetSpacing: 0
globalScale: 1
rootMotionBoneName:
hasTranslationDoF: 0
hasExtraRoot: 0
skeletonHasParents: 1
lastHumanDescriptionAvatarSource: {instanceID: 0}
autoGenerateAvatarMappingIfUnspecified: 1
animationType: 2
humanoidOversampling: 1
avatarSetup: 0
addHumanoidExtraRootOnlyWhenUsingAvatar: 1
importBlendShapeDeformPercent: 1
remapMaterialsIfMaterialImportModeIsNone: 0
additionalBone: 0
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a9c2565cc47c3ea4490b9d4ca9dc8f14
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff
+36 -15
View File
@@ -22,7 +22,7 @@ public class SpiralStaircase : MonoBehaviour
public class State
{
public bool PlayerInside;
public int Turns;
public int Quarters;
public float TotalAngle;
[Range(0, 1)] public float Progression;
[Range(0, 1)] public float TotalProgression;
@@ -33,6 +33,9 @@ public class SpiralStaircase : MonoBehaviour
{
public UniversalRendererData RendererData;
public GameObject Stairs;
public MeshFilter StairSource;
public GameObject WallTop;
public GameObject WallMiddle;
public DoorsPair[] Doors;
public GameObject[] Inside;
public GameObject[] Outside;
@@ -41,10 +44,11 @@ public class SpiralStaircase : MonoBehaviour
[System.Serializable]
public class Settings
{
public float Offset = -12.25f;
public float StartAngle = 450;
public float EndAngle = 720;
public float AdditionalTopAngle = 360;
//public float Offset = -12.25f;
//public float StartAngle = 450;
//public float EndAngle = 720;
[Tooltip("Must be pair")]
[Min(7)] public int HalfTurns = 7;
}
[System.Serializable]
@@ -72,12 +76,29 @@ public class SpiralStaircase : MonoBehaviour
private List<IEnumerator> _doorsCoroutine;
private float _entryAngle = 0f;
private float _stairHeight;
private float _startAngle;
private float _endAngle;
void Awake()
{
_doorsCoroutine = new List<IEnumerator>();
for (int i = 0; i < _references.Doors.Length; i++)
_doorsCoroutine.Add(null);
_stairHeight = 1.75f;// _references.StairSource.mesh.bounds.size.y;
_startAngle = 180 * 2.5f;
_endAngle = Mathf.Max(_startAngle + 180, (_settings.HalfTurns - 2.5f) * 180);
for (int i = 1; i < _settings.HalfTurns; i++)
{
GameObject obj = Instantiate(_references.StairSource.gameObject, _references.StairSource.transform.parent);
obj.transform.localPosition = _references.StairSource.transform.localPosition + Vector3.up * _stairHeight * i;
obj.transform.localRotation = _references.StairSource.transform.localRotation * Quaternion.Euler(0, i * -180, 0);
}
_references.WallTop.transform.localPosition = Vector3.up * _settings.HalfTurns * _stairHeight;
_references.WallMiddle.transform.localScale = new Vector3(1, _settings.HalfTurns - 3, 1);
}
void Start()
@@ -169,7 +190,7 @@ public class SpiralStaircase : MonoBehaviour
{
_state.Progression = 0;
_state.PlayerInside = true;
_state.Turns = (int)_settings.EndAngle / 90;
_state.Quarters = (int)_endAngle / 90;
Count();
ManageInside();
}
@@ -178,7 +199,7 @@ public class SpiralStaircase : MonoBehaviour
{
_state.Progression = 1;
_state.PlayerInside = true;
_state.Turns = 0;
_state.Quarters = 0;
Count();
ManageInside();
}
@@ -188,25 +209,25 @@ public class SpiralStaircase : MonoBehaviour
if (!OctoPlayer.Instance) return;
Vector2[] steps = new Vector2[4] { Vector2.up, Vector2.left, Vector2.down, Vector2.right };
Vector2 nextStep = steps[_state.Turns % steps.Length];
Vector2 nextStep = steps[_state.Quarters % steps.Length];
Vector3 relativePos3D = transform.InverseTransformPoint(OctoPlayer.Instance.transform.position);
Vector2 relativePos2D = new Vector2(relativePos3D.x, relativePos3D.z);
float quarterAngle = Vector2.Angle(nextStep, relativePos2D) * Mathf.Sign(Vector3.Cross(nextStep, relativePos2D).z);
_state.TotalAngle = Mathf.Max(0, _state.Turns * 90 + quarterAngle);
_state.TotalAngle = Mathf.Max(0, _state.Quarters * 90 + quarterAngle);
if (quarterAngle > 90 && quarterAngle < 100)
{
_state.Turns++;
_state.Quarters++;
}
else if (quarterAngle < 0 && _state.Turns > 0)
else if (quarterAngle < 0 && _state.Quarters > 0)
{
_state.Turns--;
_state.Quarters--;
}
float progression = Mathf.Clamp01(Mathf.InverseLerp(_settings.StartAngle, _settings.EndAngle, _state.TotalAngle));
float progression = Mathf.Clamp01(Mathf.InverseLerp(_startAngle, _endAngle, _state.TotalAngle));
if (progression >= .5f && _state.Progression < .5f)
{
@@ -220,7 +241,7 @@ public class SpiralStaircase : MonoBehaviour
_state.Progression = progression;
_state.TotalProgression = Mathf.Clamp01(
Mathf.InverseLerp(_entryAngle, _settings.EndAngle + _settings.AdditionalTopAngle, _state.TotalAngle)
Mathf.InverseLerp(_entryAngle, _endAngle + _settings.HalfTurns * 180, _state.TotalAngle)
);
foreach (var trigger in _events.HallucinationTriggers)
@@ -236,7 +257,7 @@ public class SpiralStaircase : MonoBehaviour
}
}
_references.Stairs.transform.localPosition = new Vector3(0, _state.Progression * _settings.Offset, 0);
_references.Stairs.transform.localPosition = new Vector3(0, _state.Progression * _settings.HalfTurns * -_stairHeight, 0);
}
private void ManageInside()