557 lines
18 KiB
C#
557 lines
18 KiB
C#
using EasyInject.Attributes;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.Playables;
|
|
using UnityEngine.Timeline;
|
|
|
|
[GameObjectBean(ENameType.GameObjectName)]
|
|
public class StackerDevice : AbstractDevice
|
|
{
|
|
[SerializeField]
|
|
private StackerData stackerData;
|
|
private DeviceData deviceData;
|
|
[Header("前叉货叉光电描述")]
|
|
[SerializeField]
|
|
private string frontHasGoodsDesc;
|
|
|
|
|
|
[Autowired]
|
|
private LocationStorageManage storageManage;
|
|
[Autowired]
|
|
private ContainersManage containersManage;
|
|
[Autowired]
|
|
private StackerPopUI stackerPopUI;
|
|
[SerializeField]
|
|
private List<StackerForkActionBinding> forkActionBinding;
|
|
|
|
|
|
/// <summary>
|
|
/// 深浅伸叉动作映射
|
|
/// </summary>
|
|
[Header("深浅伸叉动作映射")]
|
|
[SerializeField]
|
|
private ForkActionMap forkActionMap;
|
|
/// <summary>
|
|
/// 上一次动作
|
|
/// </summary>
|
|
[SerializeField]
|
|
private StackerForkActionEnum lastforkActionEnum;
|
|
/// <summary>
|
|
/// 堆垛机移动的方向
|
|
/// </summary>
|
|
[SerializeField]
|
|
private Direction moveDirection = Direction.X;
|
|
[SerializeField]
|
|
private GameObject forkCargo;
|
|
[SerializeField]
|
|
private GameObject fork;
|
|
[SerializeField]
|
|
private Vector3 forkCargoOffset = Vector3.zero;
|
|
[Header("行走巷道内载货台高度偏移")]
|
|
[SerializeField]
|
|
private float isStorageforkCargoYOffset = 0.8f;
|
|
[Header("站台列载货台高度偏移")]
|
|
[SerializeField]
|
|
private float isDeviceforkCargoYOffset = -0.15f;
|
|
[SerializeField]
|
|
private float speed = 0.3f;
|
|
[SerializeField]
|
|
private float forkCargoUpOrDownSpeed = 0.3f;
|
|
|
|
[Header("载货台起升下降距离")]
|
|
[SerializeField]
|
|
private float LiftingAndLoweringDistance = 0.3f;
|
|
public override Transform Transform => forkCargo.transform;
|
|
public override string DeviceType => "STACKER";
|
|
public override string DeviceCode => name;
|
|
|
|
public override DeviceData DeviceData => deviceData;
|
|
|
|
private bool allowUpOrDown;
|
|
private float upOrDownSpeed;
|
|
|
|
private bool isOpenPop;
|
|
public enum Direction
|
|
{
|
|
Z,X
|
|
}
|
|
private PlayableDirector playableDirector;
|
|
/// <summary>
|
|
/// 所有动画轨道
|
|
/// </summary>
|
|
private List<TrackAsset> trackAssets = new();
|
|
private void Start()
|
|
{
|
|
playableDirector = transform.GetComponent<PlayableDirector>();
|
|
if(storageManage == null)
|
|
{
|
|
storageManage = ApplicationBoot.Instance.GetBean<LocationStorageManage>();
|
|
}
|
|
|
|
playableDirector.Stop();
|
|
StopActionClip();
|
|
|
|
var graph = playableDirector.playableAsset as TimelineAsset;
|
|
if (graph == null)
|
|
{
|
|
throw new Exception(name + ":未找到 TimelineAsset 资源");
|
|
}
|
|
trackAssets = new List<TrackAsset>(graph.GetRootTracks().ToArray());
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
|
|
//堆垛机本体移动
|
|
StackerBodyMove();
|
|
//载货台移动
|
|
ForkCargoVerticalMove();
|
|
//伸叉后起升或下降一段距离
|
|
ForkCargoUpOrDown();
|
|
|
|
//货叉动作执行
|
|
ExtendForkActionHandle();
|
|
}
|
|
|
|
private void ForkCargoUpOrDown()
|
|
{
|
|
if (!allowUpOrDown)
|
|
{
|
|
return;
|
|
}
|
|
forkCargo.transform.Translate(Vector3.up * upOrDownSpeed * forkCargoUpOrDownSpeed * Time.deltaTime);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 堆垛机主体移动
|
|
/// </summary>
|
|
private void StackerBodyMove()
|
|
{
|
|
//排列成层 有其一值为0则不处理
|
|
if(stackerData.frontRow == 0 || stackerData.special1 == 0 || stackerData.frontLayer == 0)
|
|
{
|
|
return;
|
|
}
|
|
//获取库位坐标
|
|
string row = stackerData.frontRow.ToString("D2");
|
|
string column = stackerData.special1.ToString("D2");
|
|
string layer = stackerData.frontLayer.ToString("D2");
|
|
//当取货或方法是站台列,直接目的地就是站台列
|
|
if(stackerData.toColumn >= 200)
|
|
{
|
|
column = stackerData.toColumn.ToString();
|
|
layer = stackerData.toLayer.ToString("D2");
|
|
}
|
|
|
|
string storageName = string.Format("{0}-{1}-{2}", row, column, layer);
|
|
|
|
GameObject storageObject = storageManage.GetStorageByName(storageName);
|
|
if (storageObject == null)
|
|
{
|
|
// throw new System.Exception(string.Format("【{1}】没有找到库位【{0}】坐标",storageName,name));
|
|
Debug.LogWarning(string.Format("【{1}】没有找到库位【{0}】坐标",storageName,name));
|
|
return;
|
|
}
|
|
//解析堆垛机可用坐标
|
|
Vector3 target = Vector3.zero;
|
|
if (moveDirection == Direction.X)
|
|
{
|
|
target = new Vector3(storageObject.transform.position.x + forkCargoOffset.x,transform.position.y,transform.position.z);
|
|
}
|
|
if (moveDirection == Direction.Z)
|
|
{
|
|
target = new Vector3(transform.position.x, transform.position.y, storageObject.transform.position.z+ forkCargoOffset.z);
|
|
}
|
|
if(target == Vector3.zero)
|
|
{
|
|
return;
|
|
}
|
|
//往目标点移动
|
|
transform.position = Vector3.MoveTowards(transform.position,target, speed * Time.deltaTime);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 载货台垂直移动
|
|
/// </summary>
|
|
private void ForkCargoVerticalMove()
|
|
{
|
|
//货叉动作是静止的才允许提升
|
|
if(StackerForkActionEnum.ForkRest == stackerData.frontForkAction )
|
|
{
|
|
//排列层 有其一值为0则不处理
|
|
if (stackerData.frontRow == 0 || stackerData.special1 == 0 || stackerData.frontLayer == 0)
|
|
{
|
|
return;
|
|
}
|
|
// if (stackerData.toRow == 0 || stackerData.toColumn == 0 || stackerData.toLayer == 0)
|
|
// {
|
|
// return;
|
|
// }
|
|
Vector3 target = ForkCargoTarget();
|
|
//往目标点移动
|
|
forkCargo.transform.position = Vector3.MoveTowards(forkCargo.transform.position, target, speed * Time.deltaTime);
|
|
}
|
|
|
|
}
|
|
|
|
private Vector3 ForkCargoTarget()
|
|
{
|
|
|
|
//获取库位坐标
|
|
string row = stackerData.frontRow.ToString("D2");
|
|
string column = stackerData.special1.ToString("D2");
|
|
string layer = stackerData.frontLayer.ToString("D2");
|
|
|
|
if(stackerData.toColumn >= 200)
|
|
{
|
|
column = stackerData.toColumn.ToString();
|
|
layer = stackerData.toLayer.ToString("D2");
|
|
}
|
|
string storageName = string.Format("{0}-{1}-{2}", row, column, layer);
|
|
|
|
GameObject storageObject = storageManage.GetStorageByName(storageName);
|
|
if (storageObject == null)
|
|
{
|
|
throw new System.Exception(string.Format("【{1}】没有找到库位【{0}】坐标", storageName, name));
|
|
}
|
|
//这里因为取货或者放货要保持抬起跟下降动作,增加额外值
|
|
float targetY = stackerData.frontForkHasGoods == true ? forkCargoOffset.y : 0;
|
|
float forkCargoBodyY = int.Parse(column) >= 200 ? isDeviceforkCargoYOffset : isStorageforkCargoYOffset;
|
|
//解析货叉可用坐标
|
|
Vector3 target = new Vector3(forkCargo.transform.position.x, storageObject.transform.position.y + forkCargoBodyY + targetY, forkCargo.transform.position.z);
|
|
return target;
|
|
}
|
|
/// <summary>
|
|
/// 货叉伸叉动作处理
|
|
/// </summary>
|
|
private void ExtendForkActionHandle()
|
|
{
|
|
//向左伸叉
|
|
if(stackerData.frontForkAction == StackerForkActionEnum.LeftExtendFork)
|
|
{
|
|
if(lastforkActionEnum != StackerForkActionEnum.LeftExtendFork)
|
|
{
|
|
//播放动画
|
|
PlayTrackGroup(GetForkActionName(StackerForkActionEnum.LeftExtendFork));
|
|
lastforkActionEnum = StackerForkActionEnum.LeftExtendFork;
|
|
}
|
|
|
|
}
|
|
|
|
//向右伸叉
|
|
if (stackerData.frontForkAction == StackerForkActionEnum.RightExtendFork)
|
|
{
|
|
if (lastforkActionEnum != StackerForkActionEnum.RightExtendFork)
|
|
{
|
|
//播放动画
|
|
string name = GetForkActionName(StackerForkActionEnum.RightExtendFork);
|
|
PlayTrackGroup(GetForkActionName(StackerForkActionEnum.RightExtendFork));
|
|
lastforkActionEnum = StackerForkActionEnum.RightExtendFork;
|
|
|
|
}
|
|
}
|
|
//向右缩叉
|
|
if (stackerData.frontForkAction == StackerForkActionEnum.RightRetractFork)
|
|
{
|
|
if (lastforkActionEnum != StackerForkActionEnum.RightRetractFork)
|
|
{
|
|
//缩动画播放之前,绑定容器
|
|
CheckAndBindContainer();
|
|
//继续播放
|
|
string name = GetForkActionName(StackerForkActionEnum.RightRetractFork);
|
|
PlayTrackGroup(name,false);
|
|
lastforkActionEnum = StackerForkActionEnum.RightRetractFork;
|
|
allowUpOrDown = true;
|
|
}
|
|
|
|
}
|
|
|
|
//向左缩叉
|
|
if (stackerData.frontForkAction == StackerForkActionEnum.LeftRetractFork)
|
|
{
|
|
if (lastforkActionEnum != StackerForkActionEnum.LeftRetractFork)
|
|
{
|
|
|
|
CheckAndBindContainer();
|
|
//继续播放
|
|
PlayTrackGroup(GetForkActionName(StackerForkActionEnum.LeftRetractFork), false);
|
|
lastforkActionEnum = StackerForkActionEnum.LeftRetractFork;
|
|
allowUpOrDown = true;
|
|
}
|
|
|
|
}
|
|
//清空货叉状态
|
|
if (stackerData.frontForkAction == StackerForkActionEnum.ForkRest)
|
|
{
|
|
if(lastforkActionEnum != StackerForkActionEnum.ForkRest)
|
|
{
|
|
lastforkActionEnum = StackerForkActionEnum.ForkRest;
|
|
//StopActionClip();
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
/// <summary>
|
|
/// 货叉缩叉动作完成处理(缩叉完成后自动触发)
|
|
/// </summary>
|
|
public void RetractForkActionFinishHandle()
|
|
{
|
|
//清空状态
|
|
//StopActionClip();
|
|
|
|
Debug.LogWarning("清理货叉状态");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 货叉缩叉动作处理(当伸叉到位后会自动触发)
|
|
/// </summary>
|
|
public void ForkActionStopHandle(float speed)
|
|
{
|
|
//劫持动画,让其暂停
|
|
|
|
upOrDownSpeed = stackerData.frontForkHasGoods ? -speed*2 : speed;
|
|
|
|
playableDirector.Pause();
|
|
}
|
|
public void ForkActionStartHandle()
|
|
{
|
|
//开始动画
|
|
allowUpOrDown = false;
|
|
//针对放货
|
|
if (stackerData.frontForkHasGoods)
|
|
{
|
|
ForkBindContainer();
|
|
}
|
|
}
|
|
public void StopActionClip()
|
|
{
|
|
playableDirector.time = 0;
|
|
playableDirector.Stop();
|
|
|
|
foreach (var track in trackAssets)
|
|
{
|
|
track.muted = true;
|
|
}
|
|
|
|
}
|
|
/// <summary>
|
|
/// 绑定容器到货叉
|
|
/// </summary>
|
|
private void CheckAndBindContainer()
|
|
{
|
|
if (!allowUpOrDown && stackerData.frontForkHasGoods)
|
|
{
|
|
return;
|
|
}
|
|
ForkBindContainer();
|
|
}
|
|
private void ForkBindContainer()
|
|
{
|
|
|
|
//直接获取容器
|
|
Container container = containersManage.GetContainerByCode(stackerData.frontContainerCode);
|
|
Debug.Log(string.Format("容器号 【{0},场景实例 【{1}】】", stackerData.frontContainerCode, container));
|
|
if (container != null)
|
|
{
|
|
if (stackerData.frontForkHasGoods == true)
|
|
{
|
|
//绑定库位
|
|
string storageName = string.Format("{0}-{1}-{2}", stackerData.toRow.ToString("D2"), stackerData.toColumn.ToString("D2"), stackerData.toLayer.ToString("D2"));
|
|
GameObject storage = storageManage.GetStorageByName(storageName);
|
|
if (storage == null)
|
|
{
|
|
throw new Exception(string.Format("设备【{1}】未找到库位【{0}】",storageName,name));
|
|
}
|
|
if(stackerData.toColumn >= 200)
|
|
{
|
|
//暂停代理
|
|
container.Agent.isStopped = false;
|
|
//启用
|
|
container.Agent.enabled = true;
|
|
}
|
|
container.transform.parent = storage.transform;
|
|
}
|
|
else
|
|
{
|
|
//暂停代理
|
|
container.Agent.isStopped = true;
|
|
//清空身上代理路径
|
|
container.Agent.ResetPath();
|
|
//关闭唤醒状态
|
|
container.isAwke = false;
|
|
container.Agent.enabled = false;
|
|
//绑定到货叉
|
|
container.transform.parent = fork.transform;
|
|
Debug.LogWarning(name + ":绑定容器 =" + container);
|
|
}
|
|
|
|
}
|
|
}
|
|
private string GetForkActionName(StackerForkActionEnum forkActionEnum)
|
|
{
|
|
string row = stackerData.toRow.ToString("D2");
|
|
//左伸
|
|
if (StackerForkActionEnum.LeftExtendFork == forkActionEnum || StackerForkActionEnum.RightRetractFork == forkActionEnum)
|
|
{
|
|
//左浅
|
|
if (string.Equals(forkActionMap.leftShaollow, row))
|
|
{
|
|
return stackerData.frontForkHasGoods == true ? ForkActionNameConstant.leftPutShaollw : ForkActionNameConstant.leftTakeShaollw;
|
|
}
|
|
//左深
|
|
if (string.Equals(forkActionMap.leftDeeps, row))
|
|
{
|
|
return stackerData.frontForkHasGoods == true ? ForkActionNameConstant.leftPutDeep : ForkActionNameConstant.leftTakeDeep;
|
|
}
|
|
}
|
|
//右伸
|
|
if (StackerForkActionEnum.RightExtendFork == forkActionEnum || StackerForkActionEnum.LeftRetractFork == forkActionEnum)
|
|
{
|
|
//右浅
|
|
if (string.Equals(forkActionMap.rightShaollow, row))
|
|
{
|
|
return stackerData.frontForkHasGoods == true ? ForkActionNameConstant.RightPutShaollw : ForkActionNameConstant.RightTakeShaollw;
|
|
}
|
|
|
|
//右深
|
|
if (string.Equals(forkActionMap.rightDeeps, row))
|
|
{
|
|
return stackerData.frontForkHasGoods == true ? ForkActionNameConstant.RightPutDeep : ForkActionNameConstant.RightTakeDeep;
|
|
}
|
|
}
|
|
throw new Exception(name + ":未配置伸叉映射");
|
|
}
|
|
|
|
public override void MouseSingleClick()
|
|
{
|
|
base.MouseSingleClick();
|
|
isOpenPop = !isOpenPop;
|
|
stackerPopUI.Open(this, isOpenPop);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取要播放动画名称
|
|
/// </summary>
|
|
/// <param name="actionEnum"></param>
|
|
/// <returns></returns>
|
|
private string GetActionAnimationName(StackerForkActionEnum actionEnum)
|
|
{
|
|
return forkActionBinding.Find(v => v.forkActionEnum == actionEnum).actionClipName;
|
|
}
|
|
public override void DataHandle(object data, object other = null)
|
|
{
|
|
|
|
//接收数据
|
|
stackerData = JsonConvert.DeserializeObject<StackerData>(JsonConvert.SerializeObject(data));
|
|
frontHasGoodsDesc = stackerData.frontForkHasGoods == true ? "前叉有货" : "无货";
|
|
deviceData = JsonConvert.DeserializeObject<DeviceData>(JsonConvert.SerializeObject(other));
|
|
}
|
|
|
|
public override void ProcessCompleted()
|
|
{
|
|
}
|
|
[System.Serializable]
|
|
public class StackerForkActionBinding
|
|
{
|
|
public StackerForkActionEnum forkActionEnum;
|
|
public string actionClipName;
|
|
}
|
|
/// <summary>
|
|
/// 播放分组
|
|
/// </summary>
|
|
private void PlayTrackGroup(string groupName, bool isRest = true)
|
|
{
|
|
var graph = playableDirector.playableAsset as TimelineAsset;
|
|
if (graph == null)
|
|
{
|
|
throw new Exception(name+":未找到 TimelineAsset 资源");
|
|
}
|
|
if (isRest)
|
|
{
|
|
List<TrackAsset> others = new List<TrackAsset>();
|
|
foreach (var track in trackAssets)
|
|
{
|
|
if (string.Equals(track.name, groupName))
|
|
{
|
|
track.muted = false;
|
|
|
|
foreach (var clip in track.GetClips())
|
|
{
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
others.Add(track);
|
|
}
|
|
}
|
|
//关闭其他动画
|
|
others.ForEach(v => v.muted = true);
|
|
playableDirector.Stop();
|
|
}
|
|
playableDirector.Play();
|
|
}
|
|
|
|
public override T DynamicData<T>()
|
|
{
|
|
return (T)(object)stackerData;
|
|
}
|
|
|
|
[System.Serializable]
|
|
public class ForkActionMap
|
|
{
|
|
public string leftShaollow;
|
|
public string leftDeeps;
|
|
public string rightShaollow;
|
|
public string rightDeeps;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 堆垛机动作动画名称常量
|
|
/// </summary>
|
|
private class ForkActionNameConstant
|
|
{
|
|
/// <summary>
|
|
/// 左浅取货
|
|
/// </summary>
|
|
public static string leftTakeShaollw = "Lef_take_shallow";
|
|
/// <summary>
|
|
/// 左深取货
|
|
/// </summary>
|
|
public static string leftTakeDeep = "Lef_take_deep";
|
|
/// <summary>
|
|
/// 左浅放货
|
|
/// </summary>
|
|
public static string leftPutShaollw = "Left_put_shallow";
|
|
/// <summary>
|
|
/// 左深放货
|
|
/// </summary>
|
|
public static string leftPutDeep = "Left_put_deep";
|
|
|
|
/// <summary>
|
|
/// 右浅取货
|
|
/// </summary>
|
|
public static string RightTakeShaollw = "Right_take_shallow";
|
|
/// <summary>
|
|
/// 右深取货
|
|
/// </summary>
|
|
public static string RightTakeDeep = "Right_take_deep";
|
|
/// <summary>
|
|
/// 右浅放货
|
|
/// </summary>
|
|
public static string RightPutShaollw = "Right_put_shallow";
|
|
/// <summary>
|
|
/// 右深放货
|
|
/// </summary>
|
|
public static string RightPutDeep = "Right_put_deep";
|
|
|
|
public static string ForkCargoUp = "载货台上升";
|
|
public static string ForkCargoDown = "载货台下降";
|
|
}
|
|
}
|