200 lines
7.4 KiB
C#
200 lines
7.4 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using DG.Tweening;
|
|
using UnityEditor;
|
|
|
|
public class DisassemblyAssembly : MonoBehaviour
|
|
{
|
|
public Camera cameraO;
|
|
public Transform[] modelParts; // 模型的各个部分
|
|
// 用于射线检测的层
|
|
public LayerMask clickableLayers;
|
|
public Vector3[] explodedPositions; // 记录爆炸后的目标位置
|
|
private Vector3[] originalPositions; // 记录模型各个部分的原始位置
|
|
private bool isAssembled = true; // 模型是否已组装
|
|
public GameObject moveObj;
|
|
public float snapThreshold = 0.5f; // 吸附阈值
|
|
public float explodeDistance = 5;
|
|
public Slider progressBar; // 进度条
|
|
public Material tipMaterial; // 高亮材质
|
|
private GameObject[] backupParts; // 备份对象
|
|
public Transform centerTran;
|
|
private Vector3 _offset;
|
|
private Vector3 _targetScreenPoint;
|
|
private Vector3 moveObjPrePosition;
|
|
private bool isDraging = false;
|
|
void Start()
|
|
{
|
|
// 记录模型各个部分的原始位置
|
|
originalPositions = new Vector3[modelParts.Length];
|
|
explodedPositions = new Vector3[modelParts.Length];
|
|
backupParts = new GameObject[modelParts.Length];
|
|
for (int i = 0; i < modelParts.Length; i++)
|
|
{
|
|
originalPositions[i] = modelParts[i].position;
|
|
explodedPositions[i] = modelParts[i].position + (modelParts[i].position - centerTran.position).normalized * explodeDistance;
|
|
// 创建备份对象
|
|
backupParts[i] = Instantiate(modelParts[i].gameObject, modelParts[i].position, modelParts[i].rotation, centerTran);
|
|
backupParts[i].GetComponent<Renderer>().material = tipMaterial;
|
|
Collider c = backupParts[i].GetComponent<Collider>();
|
|
Destroy(c);
|
|
backupParts[i].SetActive(false); // 初始时隐藏
|
|
}
|
|
|
|
// 监听滑动条的值变化
|
|
progressBar.onValueChanged.AddListener(OnSliderValueChanged);
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if (Input.GetKeyDown(KeyCode.I))
|
|
{
|
|
if (isAssembled)
|
|
{
|
|
ExplodeModel();
|
|
}
|
|
else
|
|
{
|
|
AssembleModel();
|
|
}
|
|
isAssembled = !isAssembled;
|
|
}
|
|
|
|
if (Input.GetMouseButtonDown(0))
|
|
{
|
|
Ray ray = cameraO.ScreenPointToRay(Input.mousePosition);
|
|
RaycastHit hit;
|
|
if (Physics.Raycast(ray, out hit, Mathf.Infinity, clickableLayers))
|
|
{
|
|
moveObj = hit.transform.gameObject;
|
|
if (moveObj)
|
|
{
|
|
isDraging = true;
|
|
_targetScreenPoint = cameraO.WorldToScreenPoint(moveObj.transform.position);
|
|
moveObjPrePosition = moveObj.transform.position;
|
|
_offset = moveObj.transform.position -
|
|
cameraO.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y,
|
|
_targetScreenPoint.z));
|
|
|
|
int de = System.Array.FindIndex(modelParts, t => t == moveObj.transform);
|
|
backupParts[de].SetActive(true);
|
|
}
|
|
}
|
|
}
|
|
if (isDraging)
|
|
{
|
|
var curScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, _targetScreenPoint.z);
|
|
Vector3 curWorldPoint = cameraO.ScreenToWorldPoint(curScreenSpace);
|
|
|
|
curWorldPoint.x = Mathf.Clamp(curWorldPoint.x, xMinValue, xMaxValue);
|
|
curWorldPoint.y = Mathf.Clamp(curWorldPoint.y, yMinValue, yMaxValue);
|
|
curWorldPoint.z = Mathf.Clamp(curWorldPoint.z, zMinValue, zMaxValue);
|
|
moveObj.transform.position = curWorldPoint + _offset;
|
|
}
|
|
if (isDraging && Input.GetMouseButtonUp(0))
|
|
{
|
|
isDraging = false;
|
|
if (moveObj)
|
|
{
|
|
/* if (moveObjPrePosition != moveObj.transform.position)
|
|
Singleton<SplitModel>.Instance.Splited = true;*/
|
|
int de = System.Array.FindIndex(modelParts, t => t == moveObj.transform);
|
|
backupParts[de].SetActive(false);
|
|
SnapToClosestPosition(moveObj.transform);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void ExplodeModel()
|
|
{
|
|
float duration = 1f; // 动画持续时间
|
|
for (int i = 0; i < modelParts.Length; i++)
|
|
{
|
|
modelParts[i].DOMove(explodedPositions[i], duration); // 移动每个部分到爆炸位置
|
|
}
|
|
}
|
|
|
|
void AssembleModel()
|
|
{
|
|
float duration = 1f; // 动画持续时间
|
|
for (int i = 0; i < modelParts.Length; i++)
|
|
{
|
|
modelParts[i].DOMove(originalPositions[i], duration); // 将每个部分移回原位
|
|
}
|
|
}
|
|
|
|
void SnapToClosestPosition(Transform part)
|
|
{
|
|
Vector3 closestPosition = Vector3.zero;
|
|
float closestDistance = float.MaxValue;
|
|
|
|
//Vector3[] targetPositions = isAssembled ? explodedPositions : originalPositions;
|
|
|
|
Vector3[] targetPositions = originalPositions;
|
|
int de = System.Array.FindIndex(modelParts, t => t == part);
|
|
|
|
float distance = Vector3.Distance(part.position, targetPositions[de]);
|
|
if (distance < closestDistance)
|
|
{
|
|
closestDistance = distance;
|
|
closestPosition = targetPositions[de];
|
|
}
|
|
|
|
|
|
if (closestDistance <= snapThreshold)
|
|
{
|
|
part.DOMove(closestPosition, 0.5f); // 吸附到最近的位置
|
|
}
|
|
}
|
|
|
|
void OnSliderValueChanged(float value)
|
|
{
|
|
for (int i = 0; i < modelParts.Length; i++)
|
|
{
|
|
Vector3 targetPosition = originalPositions[i] + (explodedPositions[i] - originalPositions[i]) * value;
|
|
modelParts[i].DOMove(targetPosition, 0.5f);
|
|
}
|
|
}
|
|
|
|
|
|
//是否限制活动范围
|
|
[SerializeField] private bool isRangeClamped = true;
|
|
//限制范围 当isRangeClamped为true时起作用
|
|
[SerializeField] private float xMinValue = -100f; //x最小值
|
|
[SerializeField] private float xMaxValue = 100f; //x最大值
|
|
[SerializeField] private float zMinValue = -100f; //z最小值
|
|
[SerializeField] private float zMaxValue = 100f; //z最大值
|
|
|
|
[SerializeField] private float yMinValue = 0f; //y最小值
|
|
[SerializeField] private float yMaxValue = 100; //y最大值
|
|
#if UNITY_EDITOR
|
|
private void OnDrawGizmosSelected()
|
|
{
|
|
//如果限制活动范围 将区域范围绘制出来
|
|
if (isRangeClamped)
|
|
{
|
|
Handles.color = Color.cyan;
|
|
Vector3[] points = new Vector3[8]
|
|
{
|
|
new Vector3(xMinValue, yMinValue, zMinValue),
|
|
new Vector3(xMaxValue, yMinValue, zMinValue),
|
|
new Vector3(xMaxValue, yMinValue, zMaxValue),
|
|
new Vector3(xMinValue, yMinValue, zMaxValue),
|
|
new Vector3(xMinValue, yMaxValue, zMinValue),
|
|
new Vector3(xMaxValue, yMaxValue, zMinValue),
|
|
new Vector3(xMaxValue, yMaxValue, zMaxValue),
|
|
new Vector3(xMinValue, yMaxValue, zMaxValue)
|
|
};
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
int start = i % 4;
|
|
int end = (i + 1) % 4;
|
|
Handles.DrawLine(points[start], points[end]);
|
|
Handles.DrawLine(points[start + 4], points[end + 4]);
|
|
Handles.DrawLine(points[start], points[i + 4]);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
} |