first commit
This commit is contained in:
266
Assets/Script/SplineMovement.cs
Normal file
266
Assets/Script/SplineMovement.cs
Normal 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;
|
||||
}
|
||||
2
Assets/Script/SplineMovement.cs.meta
Normal file
2
Assets/Script/SplineMovement.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d70a28c0bc38f874b90921a56348fa45
|
||||
8
Assets/Script/mqtt.meta
Normal file
8
Assets/Script/mqtt.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7dfee9ec7d58794ab85f959fe69a880
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
46
Assets/Script/mqtt/MqttClientController.cs
Normal file
46
Assets/Script/mqtt/MqttClientController.cs
Normal 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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Script/mqtt/MqttClientController.cs.meta
Normal file
11
Assets/Script/mqtt/MqttClientController.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4a12d2d54e4c53428426127da4b9c51
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
30
Assets/Script/mqtt/MqttOJ.cs
Normal file
30
Assets/Script/mqtt/MqttOJ.cs
Normal 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Script/mqtt/MqttOJ.cs.meta
Normal file
11
Assets/Script/mqtt/MqttOJ.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3925dfe133e555c4d8cd03541df378b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
54
Assets/Script/mqtt/MqttReceiver.cs
Normal file
54
Assets/Script/mqtt/MqttReceiver.cs
Normal 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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Script/mqtt/MqttReceiver.cs.meta
Normal file
11
Assets/Script/mqtt/MqttReceiver.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c7b03c5c34c4e840b9fcf3204cdb029
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user