Files
XRLib/Assets/Scripts/Simulator/Components/AGV/AGV.cs
2026-02-26 17:09:39 +09:00

218 lines
6.8 KiB
C#

using System;
using System.Collections.Generic;
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
using UVC.Data.Core;
namespace Simulator.Data.Transport
{
public enum AGVType
{
AGV,
AFL,
ForkLift
}
public class AGV : ComponentBase
{
private Vector3 targetPosition;
private Vector3 startPosition;
private Quaternion targetRotation;
private float moveSpeed;
private float t = 0f;
public GameObject entitySocket;
public List<Entity> possessEntities = new List<Entity>();
int index = 0;
public AGVData data;
bool getdata = false;
public event Action<AGVDataType,AGVDataType> onStateUpdated;
AGVDataType _dataType;
public AGVDataType dataType
{
get
{
return _dataType;
}
set
{
if (value != _dataType)
{
onStateUpdated?.Invoke(_dataType,value);
_dataType = value;
}
}
}
public void UpdatePosition(Vector3 position)
{
transform.position = position;
//FitCollider();
}
public void SetTargetPosition(DataObject agvData)
{
var datas = agvData.GetDataObject("data");
var timing = datas.GetDataObject("timing");
var duration = timing.GetDataObject("duration");
targetPosition = AGVNodeManager.Instance.GetNodePosition(datas.GetString("to_node"));
startPosition = AGVNodeManager.Instance.GetNodePosition(datas.GetString("from_node"));
moveSpeed = (float)duration.GetFloat("real_seconds");
t = 0f;
getdata = true;
transform.LookAt(targetPosition);
//Debug.Log($"{datas.GetDateTime("timestamp").ToString()}{index}{data.name},from:{datas.GetString("from_node")},to:{datas.GetString("to_node")}");
//Debug.Log($"move{agvData.GetString("component_id")}");
}
private void PlaceNext(Entity entity)
{
if (entity == null) return;
if (entitySocket == null)
{
Debug.LogWarning("[AGV] entitySocket 이 null 입니다. 배치를 건너뜁니다.");
return;
}
// 부모/로컬 트랜스폼 설정
entity.transform.SetParent(entitySocket.transform, worldPositionStays: false);
// Z 방향 적층(기존 로직 유지)
float stepY = EntityManager.Instance.ObjectSize.y;
entity.transform.localPosition = new Vector3(0f, stepY * index,0f);
entity.transform.localRotation = Quaternion.identity;
// 중복 방지 후 등록
if (!possessEntities.Contains(entity))
possessEntities.Add(entity);
index++;
}
public override void SetEntity(string key, string name = "")
{
PlaceNext(EntityManager.Instance.GetEntity(key, name));
}
private void OnEnable()
{
if (EntityManager.HasInstance)
EntityManager.Instance.OnEntityTransferred += HandleEntityTransferred;
}
private void OnDisable()
{
if (EntityManager.HasInstance)
EntityManager.Instance.OnEntityTransferred -= HandleEntityTransferred;
}
private void HandleEntityTransferred(Entity entity)
{
if (possessEntities.Contains(entity))
{
DecreaseEntity(entity);
}
}
public void LoadEntity(DataObject agvData)
{
var datas = agvData.GetDataObject("data");
var entity_Ids = datas.GetDataArray("entity_ids");
foreach (var entity in entity_Ids)
{
var id = entity.GetString("entity_id");
var name = entity.GetString("prefab_name");
SetEntity(id, name);
}
}
public void UnLoadEntity(DataObject agvData)
{
var data = agvData.GetDataObject("data");
var node = data.GetString("component");
var component = ComponentsManager.Instance.GetComponentData(node);
var entity_ids = data.GetDataArray("entity_ids");
foreach(var entity in entity_ids)
{
var entity_id = entity.GetString("entity_id");
component.SetEntity(entity_id);
}
}
public override void DecreaseEntity(Entity entity)
{
if (entity == null) return;
// 내부 리스트에서 제거(부모 변경/파괴 등 어떤 상태든 Remove는 안전)
possessEntities.Remove(entity);
// 재배치
ReflowEntities();
}
/// <summary>
/// 현재 보유 엔티티들을 0번 인덱스부터 다시 적층하여 빈칸 제거
/// 순회-수정 예외 방지를 위해 스냅샷을 만든 뒤, 원본을 비우고 다시 채움
/// </summary>
public void ReflowEntities()
{
// 위치 인덱스 초기화
index = 0;
// 스냅샷 생성 (null 제거)
var snapshot = new List<Entity>(possessEntities.Count);
foreach (var e in possessEntities)
{
if (e != null) snapshot.Add(e);
}
// 원본을 비운 뒤 스냅샷 기반으로 재배치
possessEntities.Clear();
foreach (var e in snapshot)
{
PlaceNext(e);
}
}
void Update()
{
if (getdata)
{
if (moveSpeed <= 0f) return;
t += Time.deltaTime / moveSpeed;
// 위치 업데이트
if (t <= 1f)
{
transform.position = Vector3.Lerp(startPosition, targetPosition, t);
}
else
{
transform.position = targetPosition;
getdata = false;
dataType = AGVDataType.Idle;
}
}
/*
// 회전 업데이트
if (isRotating)
{
float currentAngle = transform.eulerAngles.y;
float targetAngle = targetRotation.eulerAngles.y;
float newAngle = Mathf.SmoothDampAngle(currentAngle, targetAngle, ref angularVelocity, rotationSpeed, Mathf.Infinity, dampedTime);
transform.rotation = Quaternion.Euler(0, newAngle, 0);
}
else
{
transform.rotation = targetRotation;
angularVelocity = 0f;
}
*/
}
}
}