1. 创建一个货物类,包含长、宽、高、重量、颜色、标签等属性,并定义一个列表用于存储所有货物对象。
public class Cargo {
public float length;
public float width;
public float height;
public float weight;
public Color color;
public string label;
public Cargo(float l, float w, float h, float m, Color c, string lbl) {
length = l;
width = w;
height = h;
weight = m;
color = c;
label = lbl;
}
}
List<Cargo> cargoes = new List<Cargo>();
2. 在UI界面中添加输入框和按钮,让用户输入货物参数和算法选择。
float length = float.Parse(lengthInput.text);
float width = float.Parse(widthInput.text);
float height = float.Parse(heightInput.text);
float weight = float.Parse(weightInput.text);
string label = labelInput.text;
Color color = colorPicker.color;
// 添加新货物到列表中
Cargo newCargo = new Cargo(length, width, height, weight, color, label);
cargoes.Add(newCargo);
// 计算最优摆放方案,使用选择的算法
if (algorithmDropdown.value == 0) {
// 贪心算法
} else if (algorithmDropdown.value == 1) {
// 回溯算法
} else if (algorithmDropdown.value == 2) {
// 遗传算法
}
3. 实现贪心算法来计算最优摆放方案,并在场景中绘制货物。
// 定义贪心算法函数
public void GreedyAlgorithm() {
float maxWidth = 20f;
float maxHeight = 10f;
float maxLength = 50f;
// 按照重量从大到小排序
cargoes.Sort((a, b) => b.weight.CompareTo(a.weight));
// 计算总体积和总重量,同时记录每个货物的位置和旋转角度
Vector3 pos = Vector3.zero;
Quaternion rot = Quaternion.identity;
float totalWeight = 0f;
float totalVolume = 0f;
foreach (Cargo cargo in cargoes) {
if (cargo.length <= maxLength && cargo.width <= maxWidth && cargo.height <= maxHeight) {
// 判断是否可以放入卡车
if (totalWeight + cargo.weight <= maxWeight && totalVolume + cargo.length * cargo.width * cargo.height <= maxVolume) {
totalWeight += cargo.weight;
totalVolume += cargo.length * cargo.width * cargo.height;
// 计算当前货物的位置和旋转角度
cargo.transform.position = pos;
cargo.transform.rotation = rot;
cargo.gameObject.SetActive(true);
// 更新下一个货物的位置和旋转角度
Vector3 nextPos = pos + new Vector3(cargo.length / 2f, cargo.height / 2f, -cargo.width / 2f);
if (nextPos.y > maxHeight) {
nextPos.y = 0f;
nextPos.x += maxLength;
}
pos = nextPos;
}
}
}
}
// 在场景中创建货物对象,设置位置和旋转角度,并添加到列表中
Cargo cargo1 = Instantiate(cargoPrefab).GetComponent<Cargo>();
cargo1.length = 5f;
cargo1.width = 2f;
cargo1.height = 3f;
cargo1.weight = 10f;
cargo1.color = Color.red;
cargo1.label = "Box 1";
cargo1.gameObject.SetActive(false);
cargoes.Add(cargo1);
// 绘制卡车模型,并计算最优摆放方案
CreateTruck();
GreedyAlgorithm();
4. 实现拖放事件和数据显示组件。
public class Cargo : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler {
public void OnBeginDrag(PointerEventData eventData) {
// 开始拖动货物时,记录初始位置和旋转角度
startPos = transform.position;
startRot = transform.rotation;
5. 实现摆放到卡车功能,并在UI界面中添加“装载”按钮。
public class Cargo : MonoBehaviour {
public void LoadToTruck() {
// 将货物设置为静态,禁止再次拖放
GetComponent<Rigidbody>().isKinematic = true;
// 设置货物父节点为卡车对象
transform.SetParent(truck.transform);
// 将货物加入已装载货物列表中
loadedCargoes.Add(this);
}
}
public void LoadCargoesToTruck() {
foreach (Cargo cargo in selectedCargoes) {
cargo.LoadToTruck();
}
// 计算已装载货物的总重量和总体积
float totalWeight = 0f;
float totalVolume = 0f;
foreach (Cargo cargo in loadedCargoes) {
totalWeight += cargo.weight;
totalVolume += cargo.length * cargo.width * cargo.height;
}
// 显示已装载货物的总重量和总体积
weightText.text = "Total weight: " + totalWeight.ToString("F2");
volumeText.text = "Total volume: " + totalVolume.ToString("F2");
}
6. 实现场景旋转、放大、拖动功能,并使用Unity自带的Camera类实现视角控制。
public class CameraController : MonoBehaviour {
public float moveSpeed = 10f;
public float rotateSpeed = 100f;
public float zoomSpeed = 10f;
private Camera camera;
void Start() {
camera = GetComponent<Camera>();
}
void Update() {
// 控制场景移动
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
float depth = Input.GetAxis("Depth");
transform.position += transform.right * horizontal * moveSpeed * Time.deltaTime;
transform.position += transform.up * vertical * moveSpeed * Time.deltaTime;
transform.position += transform.forward * depth * moveSpeed * Time.deltaTime;
// 控制场景旋转
float rotateHorizontal = Input.GetAxis("Mouse X");
float rotateVertical = Input.GetAxis("Mouse Y");
transform.Rotate(Vector3.up, rotateHorizontal * rotateSpeed * Time.deltaTime, Space.World);
transform.Rotate(Vector3.left, rotateVertical * rotateSpeed * Time.deltaTime, Space.World);
// 控制摄像机缩放
float zoom = Input.GetAxis("Mouse ScrollWheel");
camera.fieldOfView -= zoom * zoomSpeed;
camera.fieldOfView = Mathf.Clamp(camera.fieldOfView, 1f, 100f);
}
}
7. 在UI界面中添加“保存场景”按钮,并使用Unity自带的JsonUtility类将货物列表保存到本地文件。
public void SaveScene() {
// 将货物列表转换为JSON格式字符串
string json = JsonUtility.ToJson(cargoes);
// 将JSON字符串写入本地文件
string filePath = Application.dataPath + "/cargoes.json";
File.WriteAllText(filePath, json);
}
8. 在UI界面中添加“加载场景”按钮,并使用Unity自带的JsonUtility类从本地文件中读取货物列表。
public void LoadScene() {
// 从本地文件读取JSON字符串
string filePath = Application.dataPath + "/cargoes.json";
string json = File.ReadAllText(filePath);
// 将JSON字符串转换为货物对象列表
cargoes = JsonUtility.FromJson<List<Cargo>>(json);
// 在场景中创建每个货物对象,并设置其位置和旋转角度
foreach (Cargo cargo in cargoes) {
Cargo newCargo = Instantiate(cargoPrefab).GetComponent<Cargo>();
newCargo.length = cargo.length;
newCargo.width = cargo.width;
newCargo.height = cargo.height;
newCargo.weight = cargo.weight;
newCargo.color = cargo.color;
newCargo.label = cargo.label;
newCargo.transform.position = cargo.position;
newCargo.transform.rotation = cargo.rotation;
}
}
9. 在货物类中添加序列化属性,以便将货物对象保存到本地文件。
[System.Serializable]
public class Cargo {
public float length;
public float width;
public float height;
public float weight;
public Color color;
public string label;
// 序列化货物位置和旋转角度
public Vector3 position;
public Quaternion rotation;
public Cargo(float l, float w, float h, float m, Color c, string lbl) {
length = l;
width = w;
height = h;
weight = m;
color = c;
label = lbl;
}
}
10. 在货物类中添加Equals方法和GetHashCode方法,以便将相同属性的货物对象视为相等。
public override bool Equals(object obj) {
if (obj == null) return false;
Cargo other = obj as Cargo;
if (other == null) return false;
return length == other.length && width == other.width && height == other.height && weight == other.weight && color.Equals(other.color) && label.Equals(other.label);
}
public override int GetHashCode() {
return length.GetHashCode() ^ width.GetHashCode() ^ height.GetHashCode() ^ weight.GetHashCode() ^ color.GetHashCode() ^ label.GetHashCode();
}
11. 在摆放算法中实现相同货物尽量放置在一起的要求,并使用字典记录已放置的货物类型和数量。
// 定义贪心算法函数
public void GreedyAlgorithm() {
float maxWidth = 20f;
float maxHeight = 10f;
float maxLength = 50f;
// 按照重量从大到小排序
cargoes.Sort((a, b) => b.weight.CompareTo(a.weight));
// 计算总体积和总重量,同时记录每个货物的位置和旋转角度
Vector3 pos = Vector3.zero;
Quaternion rot = Quaternion.identity;
float totalWeight = 0f;
float totalVolume = 0f;
Dictionary<Cargo, int> cargoCount = new Dictionary<Cargo, int>();
foreach (Cargo cargo in cargoes) {
if (cargo.length <= maxLength && cargo.width <= maxWidth && cargo.height <= maxHeight) {
// 判断是否可以放入卡车
if (totalWeight + cargo.weight <= maxWeight && totalVolume + cargo.length * cargo.width * cargo.height <= maxVolume) {
// 判断是否需要新建一层
if (pos.y + cargo.height / 2f > maxHeight) {
pos.y = 0f;
pos.x += maxLength;
}
// 判断是否与上一个货物相同
bool sameCargo = false;
foreach (KeyValuePair<Cargo, int> item in cargoCount) {
if (item.Key.Equals(cargo)) {
sameCargo = true;
pos.z += item.Key.length / 2f + cargo.length / 2f;
break;
}
}
if (!sameCargo) {
cargoCount[cargo] = 1;
} else {
cargoCount[cargo]++;
}
// 更新当前货物的位置和旋转角度
cargo.transform.position = pos;
cargo.transform.rotation = rot;
cargo.gameObject.SetActive(true);
// 更新下一个货物的位置和旋转角度
pos += new Vector3(0f, cargo.height / 2f, cargo.width / 2f);
totalWeight += cargo.weight;
totalVolume += cargo.length * cargo.width * cargo.height;
}
}
}
}
12. 在摆放算法中实现最大化利用空间要求,根据卡车尺寸计算每层最大可用空间,并动态调整货物高度来最大化利用空间。
// 定义贪心算法函数
public void GreedyAlgorithm() {
float maxWidth = 20f;
float maxHeight = 10f;
float maxLength = 50f;
// 按照重量从大到小排序
cargoes.Sort((a, b) => b.weight.CompareTo(a.weight));
// 计算总体积和总重量,同时记录每个货物的位置和旋转角度
Vector3 pos = Vector3.zero;
Quaternion rot = Quaternion.identity;
float totalWeight = 0f;
float totalVolume = 0f;
Dictionary<Cargo, int> cargoCount = new Dictionary<Cargo, int>();
foreach (Cargo cargo in cargoes) {
if (cargo.length <= maxLength && cargo.width <= maxWidth && cargo.height <= maxHeight) {
// 判断是否可以放入卡车
if (totalWeight + cargo.weight <= maxWeight && totalVolume + cargo.length * cargo.width * cargo.height <= maxVolume) {
// 判断是否需要新建一层
if (pos.y + cargo.height / 2f > maxHeight) {
pos.y = 0f;
pos.x += maxLength;
}
// 判断是否与上一个货物相同
bool sameCargo = false;
foreach (KeyValuePair<Cargo, int> item in cargoCount) {
if (item.Key.Equals(cargo)) {
sameCargo = true;
pos.z += item.Key.length / 2f + cargo.length / 2f;
break;
}
}
if (!sameCargo) {
cargoCount[cargo] = 1;
} else {
cargoCount[cargo]++;
}
// 动态调整货物高度来最大化利用空间
float availableHeight = maxHeight - pos.y;
if (availableHeight < cargo.height) {
cargo.transform.localScale *= availableHeight / cargo.height;
cargo.height = availableHeight;
}
// 更新当前货物的位置和旋转角度
cargo.transform.position = pos;
cargo.transform.rotation = rot;
cargo.gameObject.SetActive(true);
// 更新下一个货物的位置和旋转角度
pos += new Vector3(0f, cargo.height / 2f, cargo.width / 2f);
totalWeight += cargo.weight;
totalVolume += cargo.length * cargo.width * cargo.height;
}
}
}
}
13. 在UI界面中添加“清空场景”按钮,并在点击后移除所有已放置的货物,并重置数据显示。
public void ClearScene() {
foreach (Cargo cargo in loadedCargoes) {
Destroy(cargo.gameObject);
}
loadedCargoes.Clear();
weightText.text = "Total weight: ";
volumeText.text = "Total volume: ";
}
14. 在UI界面中添加“退出应用程序”按钮,并在点击后退出应用程序。
public void QuitApplication() {
Application.Quit();
}
15. 在UI界面中添加“选择算法”下拉框,并在其中添加各种摆放算法选项。
public Dropdown algorithmDropdown;
void Start() {
// 在下拉框中添加选项
List<string> algorithms = new List<string>() { "Greedy Algorithm", "Genetic Algorithm", "Simulated Annealing" };
algorithmDropdown.AddOptions(algorithms);
}
16. 在UI界面中添加“摆放货物”按钮,并在点击后根据选定的算法进行货物摆放。
public void LoadCargoes() {
// 移除之前的货物
ClearScene();
// 根据选定的算法进行货物摆放
switch (algorithmDropdown.value) {
case 0:
GreedyAlgorithm();
break;
case 1:
GeneticAlgorithm();
break;
case 2:
SimulatedAnnealing();
break;
}
// 更新数据显示
weightText.text = "Total weight: " + loadedWeight.ToString("F2") + " tons";
volumeText.text = "Total volume: " + loadedVolume.ToString("F2") + " cubic meters";
}
17. 在UI界面中添加“摆放到卡车”按钮,并在点击后将货物摆放到卡车上。
public void PlaceCargoes() {
// 将货物摆放到卡车上
foreach (Cargo cargo in loadedCargoes) {
cargo.transform.SetParent(truck.transform);
}
}
18. 在UI界面中添加“拖动场景”按钮,并在点击后启用场景拖放功能。
public void EnableDrag() {
dragManager.enabled = true;
}
19. 在UI界面中添加“缩放场景”选框,并在选中后开启场景缩放功能。
public Toggle zoomToggle;
void Update() {
// 如果选中了缩放场景选框,则开启场景缩放功能
if (zoomToggle.isOn) {
float zoom = Input.GetAxis("Mouse ScrollWheel");
Camera.main.transform.position += Camera.main.transform.forward * zoom * zoomSpeed;
}
}
20. 在UI界面中添加“显示/隐藏方案”选框,并在选中后显示或隐藏货物摆放方案。
public Toggle planToggle;
void Update() {
// 如果选中了显示/隐藏方案选框,则显示或隐藏货物摆放方案
foreach (Cargo cargo in loadedCargoes) {
cargo.plan.SetActive(planToggle.isOn);
}
}
21. 在货物类中添加plan属性,并在创建货物时同时创建其对应的货物摆放方案。
public GameObject planPrefab;
public GameObject plan { get; private set; }
void Awake() {
plan = Instantiate(planPrefab, transform.position, transform.rotation, transform);
plan.SetActive(false);
}
22. 在卡车类中添加bounds属性,表示卡车所占用的空间范围,并在添加货物时更新该属性。
public Bounds bounds { get; private set; }
void Awake() {
bounds = new Bounds(transform.position, new Vector3(maxLength, maxHeight, maxWidth));
}
public bool AddCargo(Cargo cargo) {
// 判断是否可以放入卡车
if (loadedWeight + cargo.weight <= maxWeight && loadedVolume + cargo.length * cargo.width * cargo.height <= maxVolume) {
// 判断是否与上一个货物相同
bool sameCargo = false;
foreach (KeyValuePair<Cargo, int> item in cargoCount) {
if (item.Key.Equals(cargo)) {
sameCargo = true;
pos.z += item.Key.length / 2f + cargo.length / 2f;
break;
}
}
if (!sameCargo) {
cargoCount[cargo] = 1;
} else {
cargoCount[cargo]++;
}
// 更新当前货物的位置和旋转角度
cargo.transform.position = pos;
cargo.transform.rotation = rot;
cargo.gameObject.SetActive(true);
// 更新卡车的属性和下一个货物的位置和旋转角度
loadedCargoes.Add(cargo);
loadedWeight += cargo.weight;
loadedVolume += cargo.length * cargo.width * cargo.height;
bounds.Encapsulate(new Bounds(cargo.transform.position, new Vector3(cargo.length, cargo.height, cargo.width)));
pos += new Vector3(0f, cargo.height / 2f, cargo.width / 2f);
return true;
} else {
return false;
}
}
23. 在UI界面中添加“拖动货物”选框,并在选中后启用货物拖放功能。
public Toggle cargoDragToggle;
void Update() {
// 如果选中了拖动货物选框,则启用货物拖放功能
if (cargoDragToggle.isOn) {
foreach (Cargo cargo in loadedCargoes) {
cargo.gameObject.AddComponent<DragManager>();
}
}
}
标签:cargo,装车,weight,示例,C#,float,transform,public,货物 From: https://www.cnblogs.com/guangzhiruijie/p/17360878.html