first commit

This commit is contained in:
lethanhsonvsp
2025-11-17 15:36:52 +07:00
commit 6f2eafa33c
14093 changed files with 1253472 additions and 0 deletions

8
Assets/Editor.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b8f01b30fae5b13418a2569db8043cd4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,83 @@
using UnityEngine;
using UnityEditor;
using UnityEngine.Splines;
using System.Linq;
[CustomEditor(typeof(MultiSplineFollower))]
public class MultiSplineFollowerEditor : Editor
{
public override void OnInspectorGUI()
{
// Vẽ inspector mặc định (hiện các trường routes, routes1, routes2, speed, rotationSpeed, ...)
base.OnInspectorGUI();
MultiSplineFollower follower = (MultiSplineFollower)target;
// Hiển thị từng nhóm route
DrawRouteGroup(follower.routes, "Routes (Nhóm 0)");
DrawRouteGroup(follower.routes1, "Routes1 (Nhóm 1)");
DrawRouteGroup(follower.routes2, "Routes2 (Nhóm 2)");
if (GUI.changed)
{
EditorUtility.SetDirty(follower);
}
}
private void DrawRouteGroup(SplineRoute[] routeArray, string groupLabel)
{
if (routeArray == null) return;
EditorGUILayout.Space();
EditorGUILayout.LabelField(groupLabel, EditorStyles.boldLabel);
for (int r = 0; r < routeArray.Length; r++)
{
var route = routeArray[r];
if (route == null) continue;
EditorGUILayout.BeginVertical("box");
EditorGUILayout.LabelField($"Route {r + 1}", EditorStyles.miniBoldLabel);
// START
if (route.splineStart != null)
{
int knotCount = route.splineStart.Spline?.Knots.Count() ?? 0;
if (knotCount > 0)
{
string[] options = Enumerable.Range(0, knotCount).Select(i => $"Knot {i}").ToArray();
route.startKnotIndex = EditorGUILayout.Popup("Start Knot", route.startKnotIndex, options);
}
else
{
EditorGUILayout.HelpBox("SplineStart không có knot nào.", MessageType.Warning);
}
}
else
{
EditorGUILayout.HelpBox("Chưa gán splineStart", MessageType.Info);
}
// END
if (route.splineEnd != null)
{
int knotCount = route.splineEnd.Spline?.Knots.Count() ?? 0;
if (knotCount > 0)
{
string[] options = Enumerable.Range(0, knotCount).Select(i => $"Knot {i}").ToArray();
route.endKnotIndex = EditorGUILayout.Popup("End Knot", route.endKnotIndex, options);
}
else
{
EditorGUILayout.HelpBox("SplineEnd không có knot nào.", MessageType.Warning);
}
}
else
{
EditorGUILayout.HelpBox("Chưa gán splineEnd", MessageType.Info);
}
EditorGUILayout.EndVertical();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1ffddca8b3c7373478b7fe510bc6dbf6

8
Assets/MTvsRB.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 56af2f4d77b09fb40a86e6dada50633d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,109 @@
fileFormatVersion: 2
guid: caf08c3793403bc48ba74cbf5e737aef
ModelImporter:
serializedVersion: 22200
internalIDToNameTable: []
externalObjects: {}
materials:
materialImportMode: 2
materialName: 0
materialSearch: 1
materialLocation: 1
animations:
legacyGenerateAnimations: 4
bakeSimulation: 0
resampleCurves: 1
optimizeGameObjects: 0
removeConstantScaleCurves: 0
motionNodeName:
rigImportErrors:
rigImportWarnings:
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
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:

Binary file not shown.

View File

@@ -0,0 +1,109 @@
fileFormatVersion: 2
guid: 17b5baefb35c2f748afeaaeeb9dae1fe
ModelImporter:
serializedVersion: 22200
internalIDToNameTable: []
externalObjects: {}
materials:
materialImportMode: 2
materialName: 0
materialSearch: 1
materialLocation: 1
animations:
legacyGenerateAnimations: 4
bakeSimulation: 0
resampleCurves: 1
optimizeGameObjects: 0
removeConstantScaleCurves: 0
motionNodeName:
rigImportErrors:
rigImportWarnings:
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
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:

BIN
Assets/MTvsRB/nn.fbx Normal file

Binary file not shown.

109
Assets/MTvsRB/nn.fbx.meta Normal file
View File

@@ -0,0 +1,109 @@
fileFormatVersion: 2
guid: 4df3875c0537a7c42bc2bb770b0fcc07
ModelImporter:
serializedVersion: 22200
internalIDToNameTable: []
externalObjects: {}
materials:
materialImportMode: 2
materialName: 0
materialSearch: 1
materialLocation: 1
animations:
legacyGenerateAnimations: 4
bakeSimulation: 0
resampleCurves: 1
optimizeGameObjects: 0
removeConstantScaleCurves: 0
motionNodeName:
rigImportErrors:
rigImportWarnings:
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
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:

8
Assets/Material.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a34a84e8d70220a4a8ba8a06e4780976
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

83
Assets/Material/B.mat Normal file
View File

@@ -0,0 +1,83 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: B
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _BumpScale: 1
- _Cutoff: 0.5
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _UVSec: 0
- _ZWrite: 1
m_Colors:
- _Color: {r: 0.121885024, g: 0.22150913, b: 0.7830189, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
m_BuildTextureStacks: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 38ba582044bb218469509f4a19eb8dd1
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

83
Assets/Material/G.mat Normal file
View File

@@ -0,0 +1,83 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: G
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _BumpScale: 1
- _Cutoff: 0.5
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _UVSec: 0
- _ZWrite: 1
m_Colors:
- _Color: {r: 0.022694906, g: 0.9622642, b: 0.055024367, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
m_BuildTextureStacks: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 035505eab6c86fe4bb2d04eb353c15fe
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,83 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Ground
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _BumpScale: 1
- _Cutoff: 0.5
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _UVSec: 0
- _ZWrite: 1
m_Colors:
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
m_BuildTextureStacks: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 79e1fb9ab2984984fa2b24d48d12b058
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

83
Assets/Material/Sl.mat Normal file
View File

@@ -0,0 +1,83 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Sl
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _BumpScale: 1
- _Cutoff: 0.5
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _UVSec: 0
- _ZWrite: 1
m_Colors:
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
m_BuildTextureStacks: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5796b43c03668174b93fdf9f95d6d997
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

83
Assets/Material/Y.mat Normal file
View File

@@ -0,0 +1,83 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Y
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _BumpScale: 1
- _Cutoff: 0.5
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _UVSec: 0
- _ZWrite: 1
m_Colors:
- _Color: {r: 0.9811321, g: 0.8973006, b: 0.14346743, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
m_BuildTextureStacks: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c69b86e0102069e429231bacccc1d799
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

8
Assets/Plugins.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 105277358663b34429b2eff35224ce2a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 86e5c3715256cd2418e8d81f9e03e2e5
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Plugins/MQTTnet.dll Normal file

Binary file not shown.

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: be41d36aacf33014c9c8e4822b0fbec0
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

8
Assets/Scenes.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a0f2f3c558cdb97498814583547437e6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: aea883fa2a6d7914b869e4de0b9b1487
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9fc0d4010bbf28b4594072e72b8655ab
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7aed28d9922a38a4b8d81c54b5078d1b
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 23800000
userData:
assetBundleName:
assetBundleVariant:

8
Assets/Script.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cb86729fa0fa7484682ccf5db8a0d3f4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,266 @@
using UnityEngine;
using UnityEngine.Splines;
using Unity.Mathematics;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
public class MultiSplineFollower : MonoBehaviour
{
[Header("Tuyến đường 1")]
public SplineRoute[] routes;
[Header("Tuyến đường 2")]
public SplineRoute[] routes1;
[Header("Tuyến đường 3")]
public SplineRoute[] routes2;
[Header("Cài đặt chuyển động")]
public float speed = 2f;
public float rotationSpeed = 180f;
public float angleThreshold = 30f;
[Header("Cài đặt quét TCIA")]
public float scanRadius = 0.5f; // bán kính quét đối tượng TCIA quanh follower
private int currentRouteIndex = 0;
private int currentRouteGroup = 0; // 0 = routes, 1 = routes1, 2 = routes2
private float t = 0f;
private bool onFirstSpline = true;
private bool isDelaying = false;
void Start()
{
if (GetActiveRoutes() == null || GetActiveRoutes().Length == 0) return;
var activeRoutes = GetActiveRoutes();
InitRoute(activeRoutes[0]);
t = activeRoutes[0].tStart;
transform.position = activeRoutes[0].splineStart.EvaluatePosition(0, t);
}
void Update()
{
var activeRoutes = GetActiveRoutes();
if (activeRoutes == null || activeRoutes.Length == 0) return;
if (currentRouteIndex >= activeRoutes.Length) return;
if (isDelaying) return;
SplineRoute route = activeRoutes[currentRouteIndex];
if (onFirstSpline)
MoveOnSpline(route.splineStart, ref t, route.tCommonA, true, route);
else
MoveOnSpline(route.splineEnd, ref t, route.tEnd, false, route);
}
SplineRoute[] GetActiveRoutes()
{
switch (currentRouteGroup)
{
case 0: return routes;
case 1: return routes1;
case 2: return routes2;
default: return null;
}
}
void InitRoute(SplineRoute route)
{
BezierKnot knotStart = route.splineStart.Spline.Knots.ElementAt(route.startKnotIndex);
BezierKnot knotEnd = route.splineEnd.Spline.Knots.ElementAt(route.endKnotIndex);
Vector3 knotX = route.splineStart.transform.TransformPoint((Vector3)knotStart.Position);
Vector3 knotY = route.splineEnd.transform.TransformPoint((Vector3)knotEnd.Position);
route.commonPoint = FindCommonPoint(route.splineStart, route.splineEnd);
float3 nearest;
SplineUtility.GetNearestPoint(route.splineStart.Spline,
(float3)route.splineStart.transform.InverseTransformPoint(knotX),
out nearest, out route.tStart);
SplineUtility.GetNearestPoint(route.splineStart.Spline,
(float3)route.splineStart.transform.InverseTransformPoint(route.commonPoint),
out nearest, out route.tCommonA);
SplineUtility.GetNearestPoint(route.splineEnd.Spline,
(float3)route.splineEnd.transform.InverseTransformPoint(route.commonPoint),
out nearest, out route.tCommonB);
SplineUtility.GetNearestPoint(route.splineEnd.Spline,
(float3)route.splineEnd.transform.InverseTransformPoint(knotY),
out nearest, out route.tEnd);
onFirstSpline = true;
}
void MoveOnSpline(SplineContainer spline, ref float t, float targetT, bool first, SplineRoute route)
{
Vector3 pos = spline.EvaluatePosition(0, t);
Vector3 tangent = Vector3.Normalize((Vector3)spline.EvaluateTangent(0, t));
if (route.reverseDirection) tangent = -tangent;
float angle = Vector3.Angle(transform.forward, tangent);
if (angle > angleThreshold)
{
Quaternion targetRot = Quaternion.LookRotation(tangent, Vector3.up);
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRot, rotationSpeed * Time.deltaTime);
return;
}
float dir = (targetT > t) ? 1f : -1f;
t += dir * (Time.deltaTime * speed / spline.CalculateLength(0));
if ((dir > 0 && t >= targetT) || (dir < 0 && t <= targetT))
t = targetT;
pos = spline.EvaluatePosition(0, t);
tangent = Vector3.Normalize((Vector3)spline.EvaluateTangent(0, t));
if (route.reverseDirection) tangent = -tangent;
transform.position = pos;
transform.rotation = Quaternion.LookRotation(tangent, Vector3.up);
if (first && Mathf.Approximately(t, targetT))
{
onFirstSpline = false;
t = route.tCommonB;
}
else if (!first && Mathf.Approximately(t, targetT))
{
if (route.delayAtEnd)
{
StartCoroutine(DelayAndNextRoute(route));
}
else
{
NextRoute();
}
}
}
IEnumerator DelayAndNextRoute(SplineRoute route)
{
isDelaying = true;
if (route.attachTCIAObjects)
{
Debug.Log($"[{route.splineStart.name}] attachTCIAObjects = TRUE → quét và gắn TCIA");
AttachTCIAChildren();
}
else
{
DetachTCIAChildren();
}
yield return new WaitForSeconds(2f);
isDelaying = false;
NextRoute();
}
void AttachTCIAChildren()
{
GameObject[] allObjects = Object.FindObjectsByType<GameObject>(FindObjectsSortMode.None);
foreach (GameObject obj in allObjects)
{
if (!obj.activeInHierarchy || obj == this.gameObject)
continue;
if (obj.name.ToUpper().Contains("TCIA"))
{
float distance = Vector3.Distance(transform.position, obj.transform.position);
if (distance <= scanRadius)
{
obj.transform.SetParent(this.transform, true);
}
}
}
}
void DetachTCIAChildren()
{
List<Transform> childrenToDetach = new List<Transform>();
foreach (Transform child in transform)
{
if (child.name.ToUpper().Contains("TCIA"))
{
childrenToDetach.Add(child);
}
}
foreach (Transform child in childrenToDetach)
{
child.SetParent(null, true);
}
}
void NextRoute()
{
var activeRoutes = GetActiveRoutes();
currentRouteIndex++;
if (activeRoutes != null && currentRouteIndex < activeRoutes.Length)
{
InitRoute(activeRoutes[currentRouteIndex]);
t = activeRoutes[currentRouteIndex].tStart;
transform.position = activeRoutes[currentRouteIndex].splineStart.EvaluatePosition(0, t);
}
else
{
// Hết nhóm hiện tại → chuyển sang nhóm tiếp theo
currentRouteGroup++;
currentRouteIndex = 0;
var nextGroupRoutes = GetActiveRoutes();
if (nextGroupRoutes != null && nextGroupRoutes.Length > 0)
{
Debug.Log($"Chuyển sang nhóm tuyến: {currentRouteGroup}");
InitRoute(nextGroupRoutes[0]);
t = nextGroupRoutes[0].tStart;
transform.position = nextGroupRoutes[0].splineStart.EvaluatePosition(0, t);
}
else
{
Debug.Log("Hoàn thành toàn bộ tuyến đường!");
}
}
}
Vector3 FindCommonPoint(SplineContainer s1, SplineContainer s2)
{
foreach (var knotA in s1.Spline.Knots)
{
Vector3 pA = s1.transform.TransformPoint((Vector3)knotA.Position);
foreach (var knotB in s2.Spline.Knots)
{
Vector3 pB = s2.transform.TransformPoint((Vector3)knotB.Position);
if (Vector3.Distance(pA, pB) < 0.01f)
return pA;
}
}
Debug.LogWarning("Không tìm thấy điểm chung!");
return Vector3.zero;
}
}
[System.Serializable]
public class SplineRoute
{
public SplineContainer splineStart;
public int startKnotIndex;
public SplineContainer splineEnd;
public int endKnotIndex;
public bool reverseDirection;
public bool delayAtEnd;
public bool attachTCIAObjects = true; // true = gắn TCIA, false = tách TCIA khi delay
[HideInInspector] public Vector3 commonPoint;
[HideInInspector] public float tStart;
[HideInInspector] public float tCommonA;
[HideInInspector] public float tCommonB;
[HideInInspector] public float tEnd;
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: d70a28c0bc38f874b90921a56348fa45

8
Assets/Script/mqtt.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e7dfee9ec7d58794ab85f959fe69a880
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,46 @@
using UnityEngine;
using MQTTnet;
using MQTTnet.Client;
using System.Threading.Tasks;
using System.Text;
public class MqttClientController : MonoBehaviour
{
public string mqttBrokerAddress = "broker.hivemq.com";
public int mqttPort = 1883;
public IMqttClient mqttClient { get; private set; }
public bool IsConnected => mqttClient?.IsConnected ?? false;
async void Start()
{
var factory = new MqttFactory();
mqttClient = factory.CreateMqttClient();
var options = new MqttClientOptionsBuilder()
.WithClientId("UnityClient")
.WithTcpServer(mqttBrokerAddress, mqttPort)
.WithCleanSession()
.Build();
mqttClient.ConnectedAsync += async e =>
{
Debug.Log("Connected to MQTT Broker.");
await Task.CompletedTask;
};
mqttClient.DisconnectedAsync += async e =>
{
Debug.Log("Disconnected from MQTT Broker.");
await Task.CompletedTask;
};
try
{
await mqttClient.ConnectAsync(options);
}
catch (System.Exception ex)
{
Debug.LogError($"MQTT connection failed: {ex.Message}");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b4a12d2d54e4c53428426127da4b9c51
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
using MQTTnet;
using MQTTnet.Protocol;
using UnityEngine;
public class MqttOJ : MonoBehaviour
{
public MqttClientController mqttClientController;
public string topic = "unity/position";
void Update()
{
if (mqttClientController != null && mqttClientController.IsConnected)
{
Vector3 position = transform.position;
string message = JsonUtility.ToJson(position);
var mqttMessage = new MqttApplicationMessageBuilder()
.WithTopic(topic)
.WithPayload(message)
.WithQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce)
.Build();
mqttClientController.mqttClient.PublishAsync(mqttMessage);
}
else
{
//Debug.LogWarning("MQTT client is not connected. Skipping publish.");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3925dfe133e555c4d8cd03541df378b5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,54 @@
using MQTTnet;
using MQTTnet.Client;
using System;
using System.Threading.Tasks;
using UnityEngine;
public class MqttUnityClient : MonoBehaviour
{
private IMqttClient _mqttClient;
private async void Start()
{
await ConnectAsync();
// Đăng ký chủ đề để nhận tin nhắn
await _mqttClient.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("unity/topic").Build());
}
private async Task ConnectAsync()
{
var factory = new MqttFactory();
_mqttClient = factory.CreateMqttClient();
var options = new MqttClientOptionsBuilder()
.WithClientId("UnityClient")
.WithTcpServer("broker.hivemq.com", 1883)
.WithCleanSession()
.Build();
_mqttClient.ApplicationMessageReceivedAsync += e =>
{
// Xử lý tin nhắn nhận được
var message = System.Text.Encoding.UTF8.GetString(e.ApplicationMessage.PayloadSegment);
Debug.Log($"Received: {message}");
return Task.CompletedTask;
};
await _mqttClient.ConnectAsync(options);
}
public async Task PublishAsync(string topic, string payload)
{
var message = new MqttApplicationMessageBuilder()
.WithTopic(topic)
.WithPayload(payload)
.WithQualityOfServiceLevel(MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce)
.Build();
if (_mqttClient.IsConnected)
{
await _mqttClient.PublishAsync(message);
Debug.Log($"Published: {payload} to {topic}");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6c7b03c5c34c4e840b9fcf3204cdb029
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: