add AI racer, race manager, checkpoint, finish line, respawn mechanism, avoidance logic
This commit is contained in:
parent
ecdb3f47d0
commit
f80fdc1649
246
Assets/Prefabs/AIRacer.prefab
Normal file
246
Assets/Prefabs/AIRacer.prefab
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &5373302305645060479
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 403226101183159382}
|
||||||
|
- component: {fileID: 7605148307958671168}
|
||||||
|
- component: {fileID: 7040049591731627265}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Racer
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &403226101183159382
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 5373302305645060479}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: -0.7071068, y: -0, z: -0, w: 0.7071068}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: -1.101}
|
||||||
|
m_LocalScale: {x: 50, y: 50, z: 50}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 713388573115023667}
|
||||||
|
m_LocalEulerAnglesHint: {x: -90, y: 90, z: -90}
|
||||||
|
--- !u!23 &7605148307958671168
|
||||||
|
MeshRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 5373302305645060479}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_CastShadows: 1
|
||||||
|
m_ReceiveShadows: 1
|
||||||
|
m_DynamicOccludee: 1
|
||||||
|
m_StaticShadowCaster: 0
|
||||||
|
m_MotionVectors: 1
|
||||||
|
m_LightProbeUsage: 1
|
||||||
|
m_ReflectionProbeUsage: 1
|
||||||
|
m_RayTracingMode: 2
|
||||||
|
m_RayTraceProcedural: 0
|
||||||
|
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||||
|
m_RayTracingAccelStructBuildFlags: 1
|
||||||
|
m_SmallMeshCulling: 1
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_RendererPriority: 0
|
||||||
|
m_Materials:
|
||||||
|
- {fileID: 2100000, guid: a8c192d1f2299e9429da6a6bbe7015b8, type: 2}
|
||||||
|
m_StaticBatchInfo:
|
||||||
|
firstSubMesh: 0
|
||||||
|
subMeshCount: 0
|
||||||
|
m_StaticBatchRoot: {fileID: 0}
|
||||||
|
m_ProbeAnchor: {fileID: 0}
|
||||||
|
m_LightProbeVolumeOverride: {fileID: 0}
|
||||||
|
m_ScaleInLightmap: 1
|
||||||
|
m_ReceiveGI: 1
|
||||||
|
m_PreserveUVs: 0
|
||||||
|
m_IgnoreNormalsForChartDetection: 0
|
||||||
|
m_ImportantGI: 0
|
||||||
|
m_StitchLightmapSeams: 1
|
||||||
|
m_SelectedEditorRenderState: 3
|
||||||
|
m_MinimumChartSize: 4
|
||||||
|
m_AutoUVMaxDistance: 0.5
|
||||||
|
m_AutoUVMaxAngle: 89
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingLayer: 0
|
||||||
|
m_SortingOrder: 0
|
||||||
|
m_AdditionalVertexStreams: {fileID: 0}
|
||||||
|
--- !u!33 &7040049591731627265
|
||||||
|
MeshFilter:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 5373302305645060479}
|
||||||
|
m_Mesh: {fileID: -1971573099692935037, guid: 9b10eb187f9523b48b3484ebce59fa25, type: 3}
|
||||||
|
--- !u!1 &6468720760632047264
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 713388573115023667}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: BankingObject
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &713388573115023667
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6468720760632047264}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 403226101183159382}
|
||||||
|
m_Father: {fileID: 2739604471974086380}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &9007727309090789879
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 2739604471974086380}
|
||||||
|
- component: {fileID: 7162886650759621711}
|
||||||
|
- component: {fileID: 6800183193855919764}
|
||||||
|
- component: {fileID: 4631925233965777590}
|
||||||
|
- component: {fileID: 8696968540172343143}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: AIRacer
|
||||||
|
m_TagString: Racer
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &2739604471974086380
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 9007727309090789879}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 713388573115023667}
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!54 &7162886650759621711
|
||||||
|
Rigidbody:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 9007727309090789879}
|
||||||
|
serializedVersion: 4
|
||||||
|
m_Mass: 1
|
||||||
|
m_Drag: 0
|
||||||
|
m_AngularDrag: 0.5
|
||||||
|
m_CenterOfMass: {x: 0, y: 0, z: 0}
|
||||||
|
m_InertiaTensor: {x: 1, y: 1, z: 1}
|
||||||
|
m_InertiaRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ImplicitCom: 1
|
||||||
|
m_ImplicitTensor: 1
|
||||||
|
m_UseGravity: 1
|
||||||
|
m_IsKinematic: 0
|
||||||
|
m_Interpolate: 0
|
||||||
|
m_Constraints: 0
|
||||||
|
m_CollisionDetection: 0
|
||||||
|
--- !u!65 &6800183193855919764
|
||||||
|
BoxCollider:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 9007727309090789879}
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_LayerOverridePriority: 0
|
||||||
|
m_IsTrigger: 0
|
||||||
|
m_ProvidesContacts: 0
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_Size: {x: 2, y: 0.75, z: 2.4}
|
||||||
|
m_Center: {x: 0, y: -0.1, z: -0.9}
|
||||||
|
--- !u!114 &4631925233965777590
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 9007727309090789879}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: c250747ddb036f14faf25789ceb28a34, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
hoverHeight: 3
|
||||||
|
positionAdjustmentSpeed: 5
|
||||||
|
raycastDistance: 10
|
||||||
|
terrainLayer:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
movementSpeed: 50
|
||||||
|
acceleration: 5
|
||||||
|
deceleration: 7
|
||||||
|
rotationSpeed: 100
|
||||||
|
waypoints: []
|
||||||
|
waypointThreshold: 5
|
||||||
|
enableRubberBanding: 1
|
||||||
|
rubberBandingCoefficient: 0.1
|
||||||
|
maxSpeedMultiplier: 1.5
|
||||||
|
minSpeedMultiplier: 0.8
|
||||||
|
--- !u!114 &8696968540172343143
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 9007727309090789879}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 80f1410edd2d20447b553914aa3c9c7f, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
currentCheckpointIndex: 0
|
||||||
|
lapCount: 0
|
7
Assets/Prefabs/AIRacer.prefab.meta
Normal file
7
Assets/Prefabs/AIRacer.prefab.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6651bdcbc08f8ed4384fe9587db0f16f
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -26,12 +26,12 @@ Transform:
|
|||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 5373302305645060479}
|
m_GameObject: {fileID: 5373302305645060479}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_LocalRotation: {x: -0.70710677, y: 0, z: 0, w: 0.70710677}
|
m_LocalRotation: {x: -0.7071068, y: -0, z: -0, w: 0.7071068}
|
||||||
m_LocalPosition: {x: -0, y: 0, z: -1.101}
|
m_LocalPosition: {x: 0, y: 0, z: -1.101}
|
||||||
m_LocalScale: {x: 50, y: 50, z: 50}
|
m_LocalScale: {x: 50, y: 50, z: 50}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 2739604471974086380}
|
m_Father: {fileID: 713388573115023667}
|
||||||
m_LocalEulerAnglesHint: {x: -90, y: 90, z: -90}
|
m_LocalEulerAnglesHint: {x: -90, y: 90, z: -90}
|
||||||
--- !u!23 &7605148307958671168
|
--- !u!23 &7605148307958671168
|
||||||
MeshRenderer:
|
MeshRenderer:
|
||||||
@ -86,6 +86,53 @@ MeshFilter:
|
|||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 5373302305645060479}
|
m_GameObject: {fileID: 5373302305645060479}
|
||||||
m_Mesh: {fileID: -1971573099692935037, guid: 9b10eb187f9523b48b3484ebce59fa25, type: 3}
|
m_Mesh: {fileID: -1971573099692935037, guid: 9b10eb187f9523b48b3484ebce59fa25, type: 3}
|
||||||
|
--- !u!1 &6468720760632047264
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 713388573115023667}
|
||||||
|
- component: {fileID: 6552287091957501518}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: BankingObject
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &713388573115023667
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6468720760632047264}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 403226101183159382}
|
||||||
|
m_Father: {fileID: 2739604471974086380}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &6552287091957501518
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6468720760632047264}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: f060abec37829be48a8165282e7c3aeb, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
bankingSpeed: 5
|
||||||
|
maxBankingAngle: 30
|
||||||
--- !u!1 &9007727309090789879
|
--- !u!1 &9007727309090789879
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@ -97,11 +144,11 @@ GameObject:
|
|||||||
- component: {fileID: 2739604471974086380}
|
- component: {fileID: 2739604471974086380}
|
||||||
- component: {fileID: 7162886650759621711}
|
- component: {fileID: 7162886650759621711}
|
||||||
- component: {fileID: 6800183193855919764}
|
- component: {fileID: 6800183193855919764}
|
||||||
- component: {fileID: 2566772842932132389}
|
|
||||||
- component: {fileID: 341120459158792421}
|
- component: {fileID: 341120459158792421}
|
||||||
|
- component: {fileID: 7105996084223619230}
|
||||||
m_Layer: 0
|
m_Layer: 0
|
||||||
m_Name: Player
|
m_Name: Player
|
||||||
m_TagString: Untagged
|
m_TagString: Racer
|
||||||
m_Icon: {fileID: 0}
|
m_Icon: {fileID: 0}
|
||||||
m_NavMeshLayer: 0
|
m_NavMeshLayer: 0
|
||||||
m_StaticEditorFlags: 0
|
m_StaticEditorFlags: 0
|
||||||
@ -119,7 +166,7 @@ Transform:
|
|||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 403226101183159382}
|
- {fileID: 713388573115023667}
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!54 &7162886650759621711
|
--- !u!54 &7162886650759621711
|
||||||
@ -170,21 +217,6 @@ BoxCollider:
|
|||||||
serializedVersion: 3
|
serializedVersion: 3
|
||||||
m_Size: {x: 2, y: 0.75, z: 2.4}
|
m_Size: {x: 2, y: 0.75, z: 2.4}
|
||||||
m_Center: {x: 0, y: -0.1, z: -0.9}
|
m_Center: {x: 0, y: -0.1, z: -0.9}
|
||||||
--- !u!114 &2566772842932132389
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 9007727309090789879}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: de1851cd35e729f4aa33011a49cd59fb, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
TurnInputName: Horizontal
|
|
||||||
AccelerateButtonName: Accelerate
|
|
||||||
BrakeButtonName: Brake
|
|
||||||
--- !u!114 &341120459158792421
|
--- !u!114 &341120459158792421
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@ -207,3 +239,17 @@ MonoBehaviour:
|
|||||||
acceleration: 3
|
acceleration: 3
|
||||||
deceleration: 2
|
deceleration: 2
|
||||||
rotationSpeed: 125
|
rotationSpeed: 125
|
||||||
|
--- !u!114 &7105996084223619230
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 9007727309090789879}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 80f1410edd2d20447b553914aa3c9c7f, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
currentCheckpointIndex: 0
|
||||||
|
lapCount: 0
|
||||||
|
8
Assets/Prefabs/RaceObjects.meta
Normal file
8
Assets/Prefabs/RaceObjects.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1e2afd01cab1aec41b5867293731f0b8
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
69
Assets/Prefabs/RaceObjects/Checkpoint.prefab
Normal file
69
Assets/Prefabs/RaceObjects/Checkpoint.prefab
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &4611779275587207245
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 170758284542595608}
|
||||||
|
- component: {fileID: 312733210285042010}
|
||||||
|
- component: {fileID: 6172101860559313244}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Checkpoint
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &170758284542595608
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 4611779275587207245}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: -0.0013773441, y: -0.0979718, z: -0.8798604}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!65 &312733210285042010
|
||||||
|
BoxCollider:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 4611779275587207245}
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_LayerOverridePriority: 0
|
||||||
|
m_IsTrigger: 1
|
||||||
|
m_ProvidesContacts: 0
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_Size: {x: 50, y: 40, z: 1}
|
||||||
|
m_Center: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &6172101860559313244
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 4611779275587207245}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 7c3aaa50cd9e11d49801b7daff0a21bf, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
checkpointIndex: 0
|
7
Assets/Prefabs/RaceObjects/Checkpoint.prefab.meta
Normal file
7
Assets/Prefabs/RaceObjects/Checkpoint.prefab.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 42174ef287c46c342845e8be9f640353
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
68
Assets/Prefabs/RaceObjects/Finish Line.prefab
Normal file
68
Assets/Prefabs/RaceObjects/Finish Line.prefab
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &4611779275587207245
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 170758284542595608}
|
||||||
|
- component: {fileID: 312733210285042010}
|
||||||
|
- component: {fileID: 5198925182810260566}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Finish Line
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &170758284542595608
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 4611779275587207245}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: -0.0013773441, y: -0.0979718, z: -0.8798604}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!65 &312733210285042010
|
||||||
|
BoxCollider:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 4611779275587207245}
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_LayerOverridePriority: 0
|
||||||
|
m_IsTrigger: 1
|
||||||
|
m_ProvidesContacts: 0
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_Size: {x: 50, y: 20, z: 1}
|
||||||
|
m_Center: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &5198925182810260566
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 4611779275587207245}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 9a4bc101ca357064ca138761e1319354, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
7
Assets/Prefabs/RaceObjects/Finish Line.prefab.meta
Normal file
7
Assets/Prefabs/RaceObjects/Finish Line.prefab.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b44d494d42ce6164dbaa9b9c298b9e1d
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
51
Assets/Prefabs/RaceObjects/RaceManager.prefab
Normal file
51
Assets/Prefabs/RaceObjects/RaceManager.prefab
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &2884735936553393805
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 6446736146779979254}
|
||||||
|
- component: {fileID: 8956791611276861029}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: RaceManager
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &6446736146779979254
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2884735936553393805}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: -0.0013773441, y: -0.0979718, z: -0.8798604}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &8956791611276861029
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2884735936553393805}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 18ac36268412d1946a31d8945cc6ac33, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
totalLaps: 3
|
||||||
|
numberOfCheckpoints: 0
|
||||||
|
finishLine: {fileID: 0}
|
||||||
|
raceFinished: 0
|
||||||
|
winnerName:
|
7
Assets/Prefabs/RaceObjects/RaceManager.prefab.meta
Normal file
7
Assets/Prefabs/RaceObjects/RaceManager.prefab.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3d3c243c1b15b8d47b49111dee600ae6
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
8
Assets/Resources.meta
Normal file
8
Assets/Resources.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a2203474888d52347830cc8c8f51e421
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
6866
Assets/Scenes/AITrack.unity
Normal file
6866
Assets/Scenes/AITrack.unity
Normal file
File diff suppressed because it is too large
Load Diff
7
Assets/Scenes/AITrack.unity.meta
Normal file
7
Assets/Scenes/AITrack.unity.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 79f34c11850512b418ac4060394f87ce
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -1232,7 +1232,7 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: 39e00ff0228389448a3e4fa61b925b10, type: 3}
|
m_Script: {fileID: 11500000, guid: 39e00ff0228389448a3e4fa61b925b10, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
scene_to_load: TestTrack
|
scene_to_load: AITrack
|
||||||
controlsPanel: {fileID: 1583355326}
|
controlsPanel: {fileID: 1583355326}
|
||||||
--- !u!1 &1397774624
|
--- !u!1 &1397774624
|
||||||
GameObject:
|
GameObject:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 933d22bf6aedba544849d3821a5d3a91
|
guid: 856adccddca4ccf42ae7e35ef8ad938e
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
|
322
Assets/Scripts/Kart/AIHovercarController.cs
Normal file
322
Assets/Scripts/Kart/AIHovercarController.cs
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class AIHovercarController : MonoBehaviour
|
||||||
|
{
|
||||||
|
[Header("Hover Settings")]
|
||||||
|
public float hoverHeight = 3.0f;
|
||||||
|
public float positionAdjustmentSpeed = 10.0f;
|
||||||
|
public float raycastDistance = 10.0f;
|
||||||
|
public LayerMask terrainLayer;
|
||||||
|
|
||||||
|
[Header("Movement Settings")]
|
||||||
|
public float movementSpeed = 10.0f; // Max speed
|
||||||
|
public float acceleration = 5.0f; // How quickly to accelerate
|
||||||
|
public float deceleration = 7.0f; // How quickly to decelerate
|
||||||
|
public float rotationSpeed = 100.0f;
|
||||||
|
|
||||||
|
[Header("Checkpoint Navigation")]
|
||||||
|
[Tooltip("Ordered list of checkpoints for the AI to follow.")]
|
||||||
|
public Transform[] checkpoints;
|
||||||
|
[Tooltip("Distance from a checkpoint at which the AI switches to the next one.")]
|
||||||
|
public float checkpointThreshold = 5.0f;
|
||||||
|
private int currentCheckpointIndex = 0;
|
||||||
|
|
||||||
|
[Header("Random Steering Settings")]
|
||||||
|
[Tooltip("Probability per second that a random steering offset is applied (0 = never, 1 = every second on average).")]
|
||||||
|
public float randomSteeringProbability = 0.2f;
|
||||||
|
[Tooltip("Maximum random steering offset added (in normalized input units; e.g., 0.2 means up to ±20% extra steering).")]
|
||||||
|
public float randomSteeringMaxOffset = 0.2f;
|
||||||
|
|
||||||
|
[Header("Slowdown Settings")]
|
||||||
|
[Tooltip("Distance before a checkpoint at which the AI begins to slow down.")]
|
||||||
|
public float slowdownDistance = 10f;
|
||||||
|
[Tooltip("Strength of the slowdown (0 = no slowdown, 1 = full slowdown to minimum throttle at the checkpoint).")]
|
||||||
|
public float slowdownStrength = 0.5f;
|
||||||
|
|
||||||
|
[Header("Reset Settings")]
|
||||||
|
[Tooltip("Time (in seconds) without track contact before resetting the vehicle.")]
|
||||||
|
public float timeBeforeReset = 3.0f;
|
||||||
|
|
||||||
|
[Header("Track Orientation Settings")]
|
||||||
|
[Tooltip("Distance to search downward for track (used to align the vehicle’s bottom).")]
|
||||||
|
public float trackRaycastDistance = 10.0f;
|
||||||
|
[Tooltip("Tag used on the track geometry.")]
|
||||||
|
public string trackTag = "Track";
|
||||||
|
|
||||||
|
[Header("Avoidance Settings")]
|
||||||
|
[Tooltip("Radius within which the AI will try to avoid other racers.")]
|
||||||
|
public float avoidanceRadius = 5.0f;
|
||||||
|
[Tooltip("Strength of the steering adjustment to avoid collisions.")]
|
||||||
|
public float avoidanceSteeringStrength = 0.5f;
|
||||||
|
[Tooltip("Throttle multiplier applied when avoiding other racers (0 to 1, where lower means more slowdown).")]
|
||||||
|
public float avoidanceSlowdownMultiplier = 0.5f;
|
||||||
|
[Tooltip("Tag used to identify other racers for avoidance.")]
|
||||||
|
public string racerTag = "Racer";
|
||||||
|
|
||||||
|
private float currentSpeed = 0.0f;
|
||||||
|
private Rigidbody rb;
|
||||||
|
|
||||||
|
// Timer for lost ground/track contact
|
||||||
|
private float noContactTimer = 0.0f;
|
||||||
|
// Flag indicating if the hover raycast hit the terrain/track this physics frame
|
||||||
|
private bool groundContact = false;
|
||||||
|
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
rb = GetComponent<Rigidbody>();
|
||||||
|
rb.useGravity = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FixedUpdate()
|
||||||
|
{
|
||||||
|
HandleHovering();
|
||||||
|
HandleMovement();
|
||||||
|
|
||||||
|
// If no ground/track contact is detected, count up the timer.
|
||||||
|
if (!groundContact)
|
||||||
|
{
|
||||||
|
noContactTimer += Time.fixedDeltaTime;
|
||||||
|
if (noContactTimer >= timeBeforeReset)
|
||||||
|
{
|
||||||
|
ResetToCheckpoint();
|
||||||
|
noContactTimer = 0.0f; // Reset timer after repositioning.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Reset the timer when ground/track contact is re-established.
|
||||||
|
noContactTimer = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hover logic: cast a ray downward, interpolate the hit point and normal on the terrain,
|
||||||
|
/// and adjust the vehicle's position and rotation so it hovers along the track.
|
||||||
|
/// Also sets the groundContact flag for reset timing.
|
||||||
|
/// </summary>
|
||||||
|
void HandleHovering()
|
||||||
|
{
|
||||||
|
RaycastHit hit;
|
||||||
|
Vector3 rayOrigin = transform.position;
|
||||||
|
|
||||||
|
if (Physics.Raycast(rayOrigin, -transform.up, out hit, raycastDistance, terrainLayer))
|
||||||
|
{
|
||||||
|
groundContact = true;
|
||||||
|
|
||||||
|
Mesh mesh = hit.collider.GetComponent<MeshFilter>().mesh;
|
||||||
|
int triangleIndex = hit.triangleIndex;
|
||||||
|
int vertex1Index = mesh.triangles[triangleIndex * 3 + 0];
|
||||||
|
int vertex2Index = mesh.triangles[triangleIndex * 3 + 1];
|
||||||
|
int vertex3Index = mesh.triangles[triangleIndex * 3 + 2];
|
||||||
|
|
||||||
|
Vector3 worldVertex1 = hit.collider.transform.TransformPoint(mesh.vertices[vertex1Index]);
|
||||||
|
Vector3 worldVertex2 = hit.collider.transform.TransformPoint(mesh.vertices[vertex2Index]);
|
||||||
|
Vector3 worldVertex3 = hit.collider.transform.TransformPoint(mesh.vertices[vertex3Index]);
|
||||||
|
|
||||||
|
Vector3 interpolatedPoint = worldVertex1 * hit.barycentricCoordinate.x +
|
||||||
|
worldVertex2 * hit.barycentricCoordinate.y +
|
||||||
|
worldVertex3 * hit.barycentricCoordinate.z;
|
||||||
|
|
||||||
|
Vector3 localNormal1 = mesh.normals[vertex1Index];
|
||||||
|
Vector3 localNormal2 = mesh.normals[vertex2Index];
|
||||||
|
Vector3 localNormal3 = mesh.normals[vertex3Index];
|
||||||
|
Vector3 worldNormal1 = hit.collider.transform.TransformDirection(localNormal1);
|
||||||
|
Vector3 worldNormal2 = hit.collider.transform.TransformDirection(localNormal2);
|
||||||
|
Vector3 worldNormal3 = hit.collider.transform.TransformDirection(localNormal3);
|
||||||
|
Vector3 interpolatedNormal = worldNormal1 * hit.barycentricCoordinate.x +
|
||||||
|
worldNormal2 * hit.barycentricCoordinate.y +
|
||||||
|
worldNormal3 * hit.barycentricCoordinate.z;
|
||||||
|
interpolatedNormal.Normalize();
|
||||||
|
|
||||||
|
Vector3 targetPosition = interpolatedPoint + interpolatedNormal * hoverHeight;
|
||||||
|
transform.position = Vector3.Lerp(transform.position, targetPosition, Time.fixedDeltaTime * positionAdjustmentSpeed);
|
||||||
|
|
||||||
|
Quaternion targetRotation = Quaternion.FromToRotation(transform.up, interpolatedNormal) * transform.rotation;
|
||||||
|
rb.rotation = Quaternion.Slerp(rb.rotation, targetRotation, Time.fixedDeltaTime * 5.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
groundContact = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Simulates input by computing throttle and steering based on the AI's orientation relative to the next checkpoint.
|
||||||
|
/// New additions:
|
||||||
|
/// - Random steering offset.
|
||||||
|
/// - Throttle reduction when turning sharply and when approaching a checkpoint.
|
||||||
|
/// - Avoidance: steer away from and slow down for nearby racers.
|
||||||
|
/// </summary>
|
||||||
|
void HandleMovement()
|
||||||
|
{
|
||||||
|
// Default simulated inputs.
|
||||||
|
float verticalInput = 1f; // full throttle by default
|
||||||
|
float horizontalInput = 0f;
|
||||||
|
|
||||||
|
if (checkpoints != null && checkpoints.Length > 0)
|
||||||
|
{
|
||||||
|
Transform targetCheckpoint = checkpoints[currentCheckpointIndex];
|
||||||
|
Vector3 toCheckpoint = targetCheckpoint.position - transform.position;
|
||||||
|
float distanceToCheckpoint = toCheckpoint.magnitude;
|
||||||
|
Vector3 toCheckpointNormalized = toCheckpoint.normalized;
|
||||||
|
|
||||||
|
// If the target checkpoint is behind the vehicle, switch to the next one immediately.
|
||||||
|
if (Vector3.Dot(transform.forward, toCheckpointNormalized) < 0)
|
||||||
|
{
|
||||||
|
currentCheckpointIndex = (currentCheckpointIndex + 1) % checkpoints.Length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Compute steering input based on the angle between the vehicle's forward and the direction to the checkpoint.
|
||||||
|
Vector3 projectedForward = Vector3.ProjectOnPlane(transform.forward, transform.up).normalized;
|
||||||
|
Vector3 projectedTarget = Vector3.ProjectOnPlane(toCheckpointNormalized, transform.up).normalized;
|
||||||
|
float angle = Vector3.SignedAngle(projectedForward, projectedTarget, transform.up);
|
||||||
|
horizontalInput = Mathf.Clamp(angle / 45f, -1f, 1f);
|
||||||
|
|
||||||
|
// Add a random steering offset occasionally.
|
||||||
|
if (Random.value < randomSteeringProbability * Time.fixedDeltaTime)
|
||||||
|
{
|
||||||
|
float randomOffset = Random.Range(-randomSteeringMaxOffset, randomSteeringMaxOffset);
|
||||||
|
horizontalInput += randomOffset;
|
||||||
|
horizontalInput = Mathf.Clamp(horizontalInput, -1f, 1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce throttle when turning sharply.
|
||||||
|
verticalInput = Mathf.Clamp(1f - (Mathf.Abs(horizontalInput) * 0.5f), 0f, 1f);
|
||||||
|
|
||||||
|
// Additional slowdown when approaching a checkpoint.
|
||||||
|
if (distanceToCheckpoint < slowdownDistance)
|
||||||
|
{
|
||||||
|
float slowdownFactor = Mathf.Lerp(1 - slowdownStrength, 1f, distanceToCheckpoint / slowdownDistance);
|
||||||
|
verticalInput *= slowdownFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch to the next checkpoint when close enough.
|
||||||
|
if (distanceToCheckpoint < checkpointThreshold)
|
||||||
|
{
|
||||||
|
currentCheckpointIndex = (currentCheckpointIndex + 1) % checkpoints.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Avoidance Logic ---
|
||||||
|
// Look for nearby racers and, if any are detected, adjust steering and throttle.
|
||||||
|
Collider[] nearbyColliders = Physics.OverlapSphere(transform.position, avoidanceRadius);
|
||||||
|
Vector3 avoidanceVector = Vector3.zero;
|
||||||
|
int avoidanceCount = 0;
|
||||||
|
foreach (Collider col in nearbyColliders)
|
||||||
|
{
|
||||||
|
if (col.gameObject != gameObject && col.CompareTag(racerTag))
|
||||||
|
{
|
||||||
|
Vector3 diff = transform.position - col.transform.position;
|
||||||
|
if (diff.magnitude > 0)
|
||||||
|
{
|
||||||
|
// Closer objects contribute more.
|
||||||
|
avoidanceVector += diff.normalized / diff.magnitude;
|
||||||
|
avoidanceCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (avoidanceCount > 0)
|
||||||
|
{
|
||||||
|
avoidanceVector /= avoidanceCount;
|
||||||
|
// Project onto the horizontal plane.
|
||||||
|
avoidanceVector = Vector3.ProjectOnPlane(avoidanceVector, transform.up).normalized;
|
||||||
|
// Determine steering adjustment from avoidance.
|
||||||
|
float avoidanceAngle = Vector3.SignedAngle(transform.forward, avoidanceVector, transform.up);
|
||||||
|
float avoidanceInput = Mathf.Clamp(avoidanceAngle / 45f, -1f, 1f) * avoidanceSteeringStrength;
|
||||||
|
horizontalInput += avoidanceInput;
|
||||||
|
horizontalInput = Mathf.Clamp(horizontalInput, -1f, 1f);
|
||||||
|
// Slow down throttle when avoiding.
|
||||||
|
verticalInput *= avoidanceSlowdownMultiplier;
|
||||||
|
}
|
||||||
|
// --- End Avoidance Logic ---
|
||||||
|
|
||||||
|
// Apply movement: accelerate/decelerate toward the target speed, then update velocity and angular velocity.
|
||||||
|
float targetSpeed = verticalInput * movementSpeed;
|
||||||
|
if (verticalInput != 0)
|
||||||
|
{
|
||||||
|
currentSpeed = Mathf.Lerp(currentSpeed, targetSpeed, Time.fixedDeltaTime * acceleration);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentSpeed = Mathf.Lerp(currentSpeed, 0, Time.fixedDeltaTime * deceleration);
|
||||||
|
}
|
||||||
|
|
||||||
|
rb.linearVelocity = transform.forward * currentSpeed;
|
||||||
|
float turn = horizontalInput * rotationSpeed;
|
||||||
|
rb.angularVelocity = transform.up * turn * Mathf.Deg2Rad;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the AI's position to the last checkpoint it passed and reorients it so that:
|
||||||
|
/// - Its front faces toward the nearest (other) checkpoint.
|
||||||
|
/// - Its bottom is aligned with the nearby track surface (determined via a raycast and track tag).
|
||||||
|
/// </summary>
|
||||||
|
void ResetToCheckpoint()
|
||||||
|
{
|
||||||
|
if (checkpoints == null || checkpoints.Length == 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("No checkpoints assigned in the Inspector.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the last checkpoint passed.
|
||||||
|
int lastCheckpointIndex = currentCheckpointIndex - 1;
|
||||||
|
if (lastCheckpointIndex < 0)
|
||||||
|
{
|
||||||
|
lastCheckpointIndex = checkpoints.Length - 1;
|
||||||
|
}
|
||||||
|
Transform lastCheckpoint = checkpoints[lastCheckpointIndex];
|
||||||
|
|
||||||
|
// Find the nearest other checkpoint (to set the forward direction).
|
||||||
|
Transform nearestOther = null;
|
||||||
|
float nearestDistance = Mathf.Infinity;
|
||||||
|
foreach (Transform cp in checkpoints)
|
||||||
|
{
|
||||||
|
if (cp == lastCheckpoint)
|
||||||
|
continue;
|
||||||
|
float d = Vector3.Distance(lastCheckpoint.position, cp.position);
|
||||||
|
if (d < nearestDistance)
|
||||||
|
{
|
||||||
|
nearestDistance = d;
|
||||||
|
nearestOther = cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine desired forward direction.
|
||||||
|
Vector3 desiredForward = (nearestOther != null)
|
||||||
|
? (nearestOther.position - lastCheckpoint.position).normalized
|
||||||
|
: transform.forward;
|
||||||
|
|
||||||
|
// Determine the track’s surface normal to align the vehicle’s bottom.
|
||||||
|
// Raycast downward from a point just above the checkpoint.
|
||||||
|
Vector3 desiredUp = Vector3.up; // Fallback
|
||||||
|
RaycastHit hit;
|
||||||
|
Vector3 rayOrigin = lastCheckpoint.position + Vector3.up * 1.0f;
|
||||||
|
if (Physics.Raycast(rayOrigin, -Vector3.up, out hit, trackRaycastDistance))
|
||||||
|
{
|
||||||
|
if (hit.collider.CompareTag(trackTag))
|
||||||
|
{
|
||||||
|
// Use the inverted hit normal so the vehicle’s bottom (–transform.up) is flush with the track.
|
||||||
|
desiredUp = -hit.normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust desired forward so that it is perpendicular to desired up.
|
||||||
|
desiredForward = Vector3.ProjectOnPlane(desiredForward, desiredUp).normalized;
|
||||||
|
|
||||||
|
Quaternion desiredRotation = Quaternion.LookRotation(desiredForward, desiredUp);
|
||||||
|
|
||||||
|
// Reset position and orientation.
|
||||||
|
transform.position = lastCheckpoint.position;
|
||||||
|
transform.rotation = desiredRotation;
|
||||||
|
|
||||||
|
// Clear any existing motion.
|
||||||
|
rb.linearVelocity = Vector3.zero;
|
||||||
|
rb.angularVelocity = Vector3.zero;
|
||||||
|
|
||||||
|
Debug.Log("AI reset to checkpoint: " + lastCheckpoint.name +
|
||||||
|
(nearestOther != null ? " with front facing: " + nearestOther.name : ""));
|
||||||
|
}
|
||||||
|
}
|
2
Assets/Scripts/Kart/AIHovercarController.cs.meta
Normal file
2
Assets/Scripts/Kart/AIHovercarController.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c250747ddb036f14faf25789ceb28a34
|
@ -1,86 +0,0 @@
|
|||||||
using System;
|
|
||||||
using UnityEngine;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine.VFX;
|
|
||||||
|
|
||||||
namespace SRL
|
|
||||||
{
|
|
||||||
public class ArcadeKart : MonoBehaviour
|
|
||||||
{
|
|
||||||
|
|
||||||
public InputData Input { get; private set; }
|
|
||||||
// the input sources that can control the kart
|
|
||||||
IInput[] m_Inputs;
|
|
||||||
|
|
||||||
void GatherInputs()
|
|
||||||
{
|
|
||||||
// reset input
|
|
||||||
Input = new InputData();
|
|
||||||
|
|
||||||
// gather nonzero input from our sources
|
|
||||||
for (int i = 0; i < m_Inputs.Length; i++)
|
|
||||||
{
|
|
||||||
Input = m_Inputs[i].GenerateInput();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[Header("Hover Settings")]
|
|
||||||
public float hoverHeight = 2.0f;
|
|
||||||
public float hoverForce = 100f;
|
|
||||||
public LayerMask groundLayer;
|
|
||||||
public float hoverDampening = 5f;
|
|
||||||
|
|
||||||
[Header("Movement Settings")]
|
|
||||||
public float forwardSpeed = 50f;
|
|
||||||
public float turnSpeed = 20f;
|
|
||||||
public float strafeSpeed = 15f;
|
|
||||||
public float drag = 2f;
|
|
||||||
|
|
||||||
|
|
||||||
private Rigidbody rb;
|
|
||||||
|
|
||||||
void Awake()
|
|
||||||
{
|
|
||||||
rb = GetComponent<Rigidbody>();
|
|
||||||
m_Inputs = GetComponents<IInput>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FixedUpdate()
|
|
||||||
{
|
|
||||||
GatherInputs();
|
|
||||||
Hover();
|
|
||||||
Move();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Hover()
|
|
||||||
{
|
|
||||||
// Raycast to ground to simulate hover
|
|
||||||
Ray ray = new Ray(transform.position, -transform.up);
|
|
||||||
if (Physics.Raycast(ray, out RaycastHit hit, hoverHeight * 2, groundLayer))
|
|
||||||
{
|
|
||||||
float hoverError = hoverHeight - hit.distance;
|
|
||||||
float upwardSpeed = rb.linearVelocity.y;
|
|
||||||
float appliedHoverForce = hoverError * hoverForce - upwardSpeed * hoverDampening;
|
|
||||||
|
|
||||||
rb.AddForce(Vector3.up * appliedHoverForce, ForceMode.Acceleration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Move()
|
|
||||||
{
|
|
||||||
// Forward movement
|
|
||||||
float forwardInput = Input.Accelerate ? 1f : 0f;
|
|
||||||
Vector3 forwardForce = transform.forward * forwardInput * forwardSpeed;
|
|
||||||
rb.AddForce(forwardForce, ForceMode.Acceleration);
|
|
||||||
|
|
||||||
// Turning (rotate around Y-axis)
|
|
||||||
float turnInput = Input.TurnInput;
|
|
||||||
rb.AddTorque(Vector3.up * turnInput * turnSpeed, ForceMode.Acceleration);
|
|
||||||
|
|
||||||
// Apply drag to reduce endless acceleration
|
|
||||||
rb.linearVelocity = Vector3.Lerp(rb.linearVelocity, Vector3.zero, drag * Time.fixedDeltaTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 438e8be3307824743b12d4e4f02825ea
|
|
@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 592688461ab994244b969670c11efe3f
|
|
@ -1,24 +0,0 @@
|
|||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace SRL
|
|
||||||
{
|
|
||||||
public struct InputData
|
|
||||||
{
|
|
||||||
public bool Accelerate;
|
|
||||||
public bool Brake;
|
|
||||||
public float TurnInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IInput
|
|
||||||
{
|
|
||||||
InputData GenerateInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class BaseInput : MonoBehaviour, IInput
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Override this function to generate an XY input that can be used to steer and control the car.
|
|
||||||
/// </summary>
|
|
||||||
public abstract InputData GenerateInput();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 4dbe12014e130b54daf317a2e6be5b65
|
|
@ -2,29 +2,71 @@ using UnityEngine;
|
|||||||
|
|
||||||
public class StableHovercarController : MonoBehaviour
|
public class StableHovercarController : MonoBehaviour
|
||||||
{
|
{
|
||||||
|
[Header("Hover Settings")]
|
||||||
public float hoverHeight = 3.0f;
|
public float hoverHeight = 3.0f;
|
||||||
public float positionAdjustmentSpeed = 10.0f;
|
public float positionAdjustmentSpeed = 10.0f;
|
||||||
public float raycastDistance = 10.0f;
|
public float raycastDistance = 10.0f;
|
||||||
public LayerMask terrainLayer;
|
public LayerMask terrainLayer;
|
||||||
|
|
||||||
|
[Header("Movement Settings")]
|
||||||
public float movementSpeed = 10.0f; // Max speed
|
public float movementSpeed = 10.0f; // Max speed
|
||||||
public float acceleration = 5.0f; // How quickly to accelerate
|
public float acceleration = 5.0f; // How quickly to accelerate
|
||||||
public float deceleration = 7.0f; // How quickly to decelerate
|
public float deceleration = 7.0f; // How quickly to decelerate
|
||||||
public float rotationSpeed = 100.0f;
|
public float rotationSpeed = 100.0f;
|
||||||
|
|
||||||
private float currentSpeed = 0.0f; // Speed that interpolates over time
|
[Header("Reset Settings")]
|
||||||
|
[Tooltip("Time (in seconds) without track contact before resetting the vehicle.")]
|
||||||
|
public float timeBeforeReset = 3.0f;
|
||||||
|
// Checkpoints are used to reposition the vehicle.
|
||||||
|
public Transform[] checkpoints;
|
||||||
|
|
||||||
|
[Header("Track Orientation Settings")]
|
||||||
|
[Tooltip("Distance to search downward for track (used to align the vehicle’s bottom).")]
|
||||||
|
public float trackRaycastDistance = 10.0f;
|
||||||
|
[Tooltip("Tag used on the track geometry.")]
|
||||||
|
public string trackTag = "Track";
|
||||||
|
|
||||||
|
private float currentSpeed = 0.0f;
|
||||||
private Rigidbody rb;
|
private Rigidbody rb;
|
||||||
|
private RacerProgress racerProgress;
|
||||||
|
|
||||||
|
// Timer for how long the raycast has failed to hit ground/track
|
||||||
|
private float noContactTimer = 0.0f;
|
||||||
|
// Flag that indicates whether a raycast hit was detected in this physics update.
|
||||||
|
private bool groundContact = false;
|
||||||
|
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
rb = GetComponent<Rigidbody>();
|
rb = GetComponent<Rigidbody>();
|
||||||
rb.useGravity = false; // Disable gravity for stability
|
rb.useGravity = false; // Disable gravity for hover stability
|
||||||
|
|
||||||
|
racerProgress = GetComponent<RacerProgress>();
|
||||||
|
if (racerProgress == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("No RacerProgress component found on this vehicle!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FixedUpdate()
|
void FixedUpdate()
|
||||||
{
|
{
|
||||||
HandleHovering();
|
HandleHovering();
|
||||||
HandleMovement();
|
HandleMovement();
|
||||||
|
|
||||||
|
// If we aren’t detecting ground/track contact, count up.
|
||||||
|
if (!groundContact)
|
||||||
|
{
|
||||||
|
noContactTimer += Time.fixedDeltaTime;
|
||||||
|
if (noContactTimer >= timeBeforeReset)
|
||||||
|
{
|
||||||
|
ResetToCheckpoint();
|
||||||
|
noContactTimer = 0.0f; // Reset timer after repositioning
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Reset the timer when ground/track is detected.
|
||||||
|
noContactTimer = 0.0f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleHovering()
|
void HandleHovering()
|
||||||
@ -32,23 +74,30 @@ public class StableHovercarController : MonoBehaviour
|
|||||||
RaycastHit hit;
|
RaycastHit hit;
|
||||||
Vector3 rayOrigin = transform.position;
|
Vector3 rayOrigin = transform.position;
|
||||||
|
|
||||||
// Cast a ray downward to detect the terrain
|
// Cast a ray downward to detect the terrain (or track geometry).
|
||||||
if (Physics.Raycast(rayOrigin, -transform.up, out hit, raycastDistance, terrainLayer))
|
if (Physics.Raycast(rayOrigin, -transform.up, out hit, raycastDistance, terrainLayer))
|
||||||
{
|
{
|
||||||
|
// We have ground contact.
|
||||||
|
groundContact = true;
|
||||||
|
|
||||||
|
// Determine the triangle on the mesh that was hit.
|
||||||
Mesh mesh = hit.collider.GetComponent<MeshFilter>().mesh;
|
Mesh mesh = hit.collider.GetComponent<MeshFilter>().mesh;
|
||||||
int triangleIndex = hit.triangleIndex;
|
int triangleIndex = hit.triangleIndex;
|
||||||
int vertex1Index = mesh.triangles[triangleIndex * 3 + 0];
|
int vertex1Index = mesh.triangles[triangleIndex * 3 + 0];
|
||||||
int vertex2Index = mesh.triangles[triangleIndex * 3 + 1];
|
int vertex2Index = mesh.triangles[triangleIndex * 3 + 1];
|
||||||
int vertex3Index = mesh.triangles[triangleIndex * 3 + 2];
|
int vertex3Index = mesh.triangles[triangleIndex * 3 + 2];
|
||||||
|
|
||||||
|
// Convert the triangle vertices to world space.
|
||||||
Vector3 worldVertex1 = hit.collider.transform.TransformPoint(mesh.vertices[vertex1Index]);
|
Vector3 worldVertex1 = hit.collider.transform.TransformPoint(mesh.vertices[vertex1Index]);
|
||||||
Vector3 worldVertex2 = hit.collider.transform.TransformPoint(mesh.vertices[vertex2Index]);
|
Vector3 worldVertex2 = hit.collider.transform.TransformPoint(mesh.vertices[vertex2Index]);
|
||||||
Vector3 worldVertex3 = hit.collider.transform.TransformPoint(mesh.vertices[vertex3Index]);
|
Vector3 worldVertex3 = hit.collider.transform.TransformPoint(mesh.vertices[vertex3Index]);
|
||||||
|
|
||||||
|
// Interpolate to find the hit point on the triangle.
|
||||||
Vector3 interpolatedPoint = worldVertex1 * hit.barycentricCoordinate.x +
|
Vector3 interpolatedPoint = worldVertex1 * hit.barycentricCoordinate.x +
|
||||||
worldVertex2 * hit.barycentricCoordinate.y +
|
worldVertex2 * hit.barycentricCoordinate.y +
|
||||||
worldVertex3 * hit.barycentricCoordinate.z;
|
worldVertex3 * hit.barycentricCoordinate.z;
|
||||||
|
|
||||||
|
// Similarly, interpolate the normals.
|
||||||
Vector3 localNormal1 = mesh.normals[vertex1Index];
|
Vector3 localNormal1 = mesh.normals[vertex1Index];
|
||||||
Vector3 localNormal2 = mesh.normals[vertex2Index];
|
Vector3 localNormal2 = mesh.normals[vertex2Index];
|
||||||
Vector3 localNormal3 = mesh.normals[vertex3Index];
|
Vector3 localNormal3 = mesh.normals[vertex3Index];
|
||||||
@ -60,37 +109,128 @@ public class StableHovercarController : MonoBehaviour
|
|||||||
worldNormal3 * hit.barycentricCoordinate.z;
|
worldNormal3 * hit.barycentricCoordinate.z;
|
||||||
interpolatedNormal.Normalize();
|
interpolatedNormal.Normalize();
|
||||||
|
|
||||||
|
// Compute the target hover position.
|
||||||
Vector3 targetPosition = interpolatedPoint + interpolatedNormal * hoverHeight;
|
Vector3 targetPosition = interpolatedPoint + interpolatedNormal * hoverHeight;
|
||||||
|
|
||||||
transform.position = Vector3.Lerp(transform.position, targetPosition, Time.fixedDeltaTime * positionAdjustmentSpeed);
|
transform.position = Vector3.Lerp(transform.position, targetPosition, Time.fixedDeltaTime * positionAdjustmentSpeed);
|
||||||
|
|
||||||
|
// Smoothly rotate the vehicle to align with the terrain.
|
||||||
Quaternion targetRotation = Quaternion.FromToRotation(transform.up, interpolatedNormal) * transform.rotation;
|
Quaternion targetRotation = Quaternion.FromToRotation(transform.up, interpolatedNormal) * transform.rotation;
|
||||||
rb.rotation = Quaternion.Slerp(rb.rotation, targetRotation, Time.fixedDeltaTime * 5.0f);
|
rb.rotation = Quaternion.Slerp(rb.rotation, targetRotation, Time.fixedDeltaTime * 5.0f);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No ground detected.
|
||||||
|
groundContact = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleMovement()
|
void HandleMovement()
|
||||||
{
|
{
|
||||||
// Get player input
|
// Get player input.
|
||||||
float input = Input.GetAxis("Vertical");
|
float input = Input.GetAxis("Vertical");
|
||||||
|
|
||||||
// Determine target speed based on input
|
// Calculate target speed.
|
||||||
float targetSpeed = input * movementSpeed;
|
float targetSpeed = input * movementSpeed;
|
||||||
|
|
||||||
|
// Smooth acceleration/deceleration.
|
||||||
if (input != 0)
|
if (input != 0)
|
||||||
{
|
{
|
||||||
// Smooth acceleration
|
|
||||||
currentSpeed = Mathf.Lerp(currentSpeed, targetSpeed, Time.fixedDeltaTime * acceleration);
|
currentSpeed = Mathf.Lerp(currentSpeed, targetSpeed, Time.fixedDeltaTime * acceleration);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Smooth deceleration when no input is present
|
|
||||||
currentSpeed = Mathf.Lerp(currentSpeed, 0, Time.fixedDeltaTime * deceleration);
|
currentSpeed = Mathf.Lerp(currentSpeed, 0, Time.fixedDeltaTime * deceleration);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply movement and rotation
|
// Apply forward movement.
|
||||||
rb.linearVelocity = transform.forward * currentSpeed;
|
rb.linearVelocity = transform.forward * currentSpeed;
|
||||||
|
|
||||||
|
// Apply rotation.
|
||||||
float turn = Input.GetAxis("Horizontal") * rotationSpeed;
|
float turn = Input.GetAxis("Horizontal") * rotationSpeed;
|
||||||
rb.angularVelocity = transform.up * turn * Mathf.Deg2Rad;
|
rb.angularVelocity = transform.up * turn * Mathf.Deg2Rad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the vehicle’s position to the last checkpoint reached (from RacerProgress) and orients it so that:
|
||||||
|
/// - Its front faces the nearest (other) checkpoint.
|
||||||
|
/// - Its bottom is aligned to the track (using a raycast and the specified track tag).
|
||||||
|
/// </summary>
|
||||||
|
void ResetToCheckpoint()
|
||||||
|
{
|
||||||
|
// Make sure we have checkpoints.
|
||||||
|
if (checkpoints == null || checkpoints.Length == 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("No checkpoints have been assigned in the Inspector.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (racerProgress == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("RacerProgress component is missing. Cannot reset to checkpoint.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int cpIndex = racerProgress.currentCheckpointIndex;
|
||||||
|
if (cpIndex < 0 || cpIndex >= checkpoints.Length)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("Invalid checkpoint index in RacerProgress!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position: use the checkpoint that the racer last reached.
|
||||||
|
Transform lastCheckpoint = checkpoints[cpIndex];
|
||||||
|
|
||||||
|
// Find the "other" checkpoint nearest to the last checkpoint.
|
||||||
|
// (This will be used to determine the forward direction.)
|
||||||
|
Transform nearestOther = null;
|
||||||
|
float nearestDistance = Mathf.Infinity;
|
||||||
|
foreach (Transform cp in checkpoints)
|
||||||
|
{
|
||||||
|
if (cp == lastCheckpoint)
|
||||||
|
continue;
|
||||||
|
float d = Vector3.Distance(lastCheckpoint.position, cp.position);
|
||||||
|
if (d < nearestDistance)
|
||||||
|
{
|
||||||
|
nearestDistance = d;
|
||||||
|
nearestOther = cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine desired forward:
|
||||||
|
// If we found another checkpoint, aim toward it.
|
||||||
|
// (Project the vector onto the plane defined by the desired up.)
|
||||||
|
Vector3 desiredForward = (nearestOther != null)
|
||||||
|
? (nearestOther.position - lastCheckpoint.position).normalized
|
||||||
|
: transform.forward;
|
||||||
|
|
||||||
|
// Determine the track’s surface normal so we can align the vehicle’s bottom.
|
||||||
|
// We cast a ray downward from a point just above the checkpoint.
|
||||||
|
Vector3 desiredUp = Vector3.up; // Fallback if no track is detected.
|
||||||
|
RaycastHit hit;
|
||||||
|
Vector3 rayOrigin = lastCheckpoint.position + Vector3.up * 1.0f;
|
||||||
|
if (Physics.Raycast(rayOrigin, -Vector3.up, out hit, trackRaycastDistance))
|
||||||
|
{
|
||||||
|
if (hit.collider.CompareTag(trackTag))
|
||||||
|
{
|
||||||
|
// To have the vehicle’s bottom (–transform.up) flush with the track,
|
||||||
|
// we set our desired up vector to be the inverse of the track’s normal.
|
||||||
|
desiredUp = -hit.normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now adjust the desired forward so that it is perpendicular to the desired up.
|
||||||
|
desiredForward = Vector3.ProjectOnPlane(desiredForward, desiredUp).normalized;
|
||||||
|
|
||||||
|
// Build the final rotation.
|
||||||
|
Quaternion desiredRotation = Quaternion.LookRotation(desiredForward, desiredUp);
|
||||||
|
|
||||||
|
// Reset position and orientation.
|
||||||
|
transform.position = lastCheckpoint.position;
|
||||||
|
transform.rotation = desiredRotation;
|
||||||
|
|
||||||
|
// Clear any existing motion.
|
||||||
|
rb.linearVelocity = Vector3.zero;
|
||||||
|
rb.angularVelocity = Vector3.zero;
|
||||||
|
|
||||||
|
Debug.Log("Vehicle reset to checkpoint: " + lastCheckpoint.name +
|
||||||
|
(nearestOther != null ? " with front facing: " + nearestOther.name : ""));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace SRL {
|
|
||||||
|
|
||||||
public class KeyboardInput : BaseInput
|
|
||||||
{
|
|
||||||
public string TurnInputName = "Horizontal";
|
|
||||||
public string AccelerateButtonName = "Accelerate";
|
|
||||||
public string BrakeButtonName = "Brake";
|
|
||||||
|
|
||||||
public override InputData GenerateInput() {
|
|
||||||
return new InputData
|
|
||||||
{
|
|
||||||
Accelerate = Input.GetButton(AccelerateButtonName),
|
|
||||||
Brake = Input.GetButton(BrakeButtonName),
|
|
||||||
TurnInput = Input.GetAxis("Horizontal")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: de1851cd35e729f4aa33011a49cd59fb
|
|
2
Assets/Scripts/Kart/ObjectBanking.cs.meta
Normal file
2
Assets/Scripts/Kart/ObjectBanking.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f060abec37829be48a8165282e7c3aeb
|
8
Assets/Scripts/RaceGameManager.meta
Normal file
8
Assets/Scripts/RaceGameManager.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 33bad5ae96b211b4ba79fa289a4eb6b9
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
24
Assets/Scripts/RaceGameManager/Checkpoint.cs
Normal file
24
Assets/Scripts/RaceGameManager/Checkpoint.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class Checkpoint : MonoBehaviour
|
||||||
|
{
|
||||||
|
[Tooltip("The order index of this checkpoint along the track.")]
|
||||||
|
public int checkpointIndex = 0;
|
||||||
|
|
||||||
|
private void OnTriggerEnter(Collider other)
|
||||||
|
{
|
||||||
|
RacerProgress progress = other.GetComponent<RacerProgress>();
|
||||||
|
if (progress != null && RaceManager.Instance != null)
|
||||||
|
{
|
||||||
|
// Only update if the racer is expecting this checkpoint next.
|
||||||
|
if (progress.currentCheckpointIndex == checkpointIndex)
|
||||||
|
{
|
||||||
|
int totalCheckpoints = RaceManager.Instance.numberOfCheckpoints;
|
||||||
|
progress.currentCheckpointIndex = (checkpointIndex + 1) % totalCheckpoints;
|
||||||
|
// If the racer just passed the final checkpoint, increment the lap count.
|
||||||
|
if (checkpointIndex == totalCheckpoints - 1)
|
||||||
|
progress.lapCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
Assets/Scripts/RaceGameManager/Checkpoint.cs.meta
Normal file
2
Assets/Scripts/RaceGameManager/Checkpoint.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7c3aaa50cd9e11d49801b7daff0a21bf
|
13
Assets/Scripts/RaceGameManager/FinishLine.cs
Normal file
13
Assets/Scripts/RaceGameManager/FinishLine.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class FinishLine : MonoBehaviour
|
||||||
|
{
|
||||||
|
private void OnTriggerEnter(Collider other)
|
||||||
|
{
|
||||||
|
RacerProgress progress = other.GetComponent<RacerProgress>();
|
||||||
|
if (progress != null && RaceManager.Instance != null)
|
||||||
|
{
|
||||||
|
RaceManager.Instance.CheckFinish(progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
Assets/Scripts/RaceGameManager/FinishLine.cs.meta
Normal file
2
Assets/Scripts/RaceGameManager/FinishLine.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9a4bc101ca357064ca138761e1319354
|
72
Assets/Scripts/RaceGameManager/RaceManager.cs
Normal file
72
Assets/Scripts/RaceGameManager/RaceManager.cs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
public class RaceManager : MonoBehaviour
|
||||||
|
{
|
||||||
|
public static RaceManager Instance;
|
||||||
|
|
||||||
|
[Header("Race Settings")]
|
||||||
|
[Tooltip("Total number of laps needed to finish the race.")]
|
||||||
|
public int totalLaps = 3;
|
||||||
|
[Tooltip("Total number of checkpoints in the race.")]
|
||||||
|
public int numberOfCheckpoints = 0; // Set this in the Inspector to match your track setup
|
||||||
|
|
||||||
|
[Header("Finish Line Settings")]
|
||||||
|
[Tooltip("Assign the finish line object (with a trigger collider) here.")]
|
||||||
|
public Transform finishLine;
|
||||||
|
|
||||||
|
private List<RacerProgress> racers = new List<RacerProgress>();
|
||||||
|
public bool raceFinished = false;
|
||||||
|
public string winnerName = "";
|
||||||
|
|
||||||
|
void Awake()
|
||||||
|
{
|
||||||
|
// Basic singleton setup.
|
||||||
|
if (Instance == null)
|
||||||
|
Instance = this;
|
||||||
|
else
|
||||||
|
Destroy(gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
// Optionally, automatically find all racers by tag.
|
||||||
|
GameObject[] racerObjects = GameObject.FindGameObjectsWithTag("Racer");
|
||||||
|
foreach (GameObject racer in racerObjects)
|
||||||
|
{
|
||||||
|
RacerProgress progress = racer.GetComponent<RacerProgress>();
|
||||||
|
if (progress != null)
|
||||||
|
racers.Add(progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the highest “progress value” among all racers.
|
||||||
|
/// (Calculated as: lap count * numberOfCheckpoints + current checkpoint index.)
|
||||||
|
/// </summary>
|
||||||
|
public float GetLeaderProgress()
|
||||||
|
{
|
||||||
|
float leaderProgress = 0f;
|
||||||
|
foreach (RacerProgress rp in racers)
|
||||||
|
{
|
||||||
|
float progressValue = rp.lapCount * numberOfCheckpoints + rp.currentCheckpointIndex;
|
||||||
|
if (progressValue > leaderProgress)
|
||||||
|
leaderProgress = progressValue;
|
||||||
|
}
|
||||||
|
return leaderProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Call this when a racer crosses the finish line.
|
||||||
|
/// </summary>
|
||||||
|
public void CheckFinish(RacerProgress rp)
|
||||||
|
{
|
||||||
|
if (rp.lapCount >= totalLaps && !raceFinished)
|
||||||
|
{
|
||||||
|
raceFinished = true;
|
||||||
|
winnerName = rp.gameObject.name;
|
||||||
|
Debug.Log("Race Finished! Winner: " + winnerName);
|
||||||
|
// Here you might trigger UI updates, stop all racers, etc.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
Assets/Scripts/RaceGameManager/RaceManager.cs.meta
Normal file
2
Assets/Scripts/RaceGameManager/RaceManager.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 18ac36268412d1946a31d8945cc6ac33
|
9
Assets/Scripts/RaceGameManager/RacerProgress.cs
Normal file
9
Assets/Scripts/RaceGameManager/RacerProgress.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class RacerProgress : MonoBehaviour
|
||||||
|
{
|
||||||
|
// The checkpoint index the racer is currently aiming for.
|
||||||
|
public int currentCheckpointIndex = 0;
|
||||||
|
// The current lap count.
|
||||||
|
public int lapCount = 0;
|
||||||
|
}
|
2
Assets/Scripts/RaceGameManager/RacerProgress.cs.meta
Normal file
2
Assets/Scripts/RaceGameManager/RacerProgress.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 80f1410edd2d20447b553914aa3c9c7f
|
@ -11,9 +11,12 @@ EditorBuildSettings:
|
|||||||
- enabled: 0
|
- enabled: 0
|
||||||
path: Assets/Scenes/SampleScene.unity
|
path: Assets/Scenes/SampleScene.unity
|
||||||
guid: 99c9720ab356a0642a771bea13969a05
|
guid: 99c9720ab356a0642a771bea13969a05
|
||||||
- enabled: 1
|
- enabled: 0
|
||||||
path: Assets/Scenes/TestTrack.unity
|
path: Assets/Scenes/TestTrackWithAI.unity
|
||||||
guid: 933d22bf6aedba544849d3821a5d3a91
|
guid: 933d22bf6aedba544849d3821a5d3a91
|
||||||
|
- enabled: 1
|
||||||
|
path: Assets/Scenes/AITrack.unity
|
||||||
|
guid: 79f34c11850512b418ac4060394f87ce
|
||||||
m_configObjects:
|
m_configObjects:
|
||||||
com.unity.input.settings.actions: {fileID: -944628639613478452, guid: 052faaac586de48259a63d0c4782560b, type: 3}
|
com.unity.input.settings.actions: {fileID: -944628639613478452, guid: 052faaac586de48259a63d0c4782560b, type: 3}
|
||||||
m_UseUCBPForAssetBundles: 0
|
m_UseUCBPForAssetBundles: 0
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
--- !u!78 &1
|
--- !u!78 &1
|
||||||
TagManager:
|
TagManager:
|
||||||
serializedVersion: 3
|
serializedVersion: 3
|
||||||
tags: []
|
tags:
|
||||||
|
- Racer
|
||||||
|
- Track
|
||||||
layers:
|
layers:
|
||||||
- Default
|
- Default
|
||||||
- TransparentFX
|
- TransparentFX
|
||||||
|
Loading…
x
Reference in New Issue
Block a user