首页 > 编程语言 >C# 卡车装车示例(二)

C# 卡车装车示例(二)

时间:2023-04-28 09:01:14浏览次数:32  
标签:cargo 装车 weight 示例 C# float transform public 货物

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

相关文章

  • 论文阅读笔记《Residual Physics Learning and System Identification for Sim to rea
    ResidualPhysicsLearningandSystemIdentificationforSimtorealTransferofPoliciesonBuoyancyAssistedLeggedRobots发表于2023年。论文较新,未找到发表期刊。基于浮力辅助的足式机器人策略迁移的残差物理学习与系统识别SontakkeN,ChaeH,LeeS,etal.Resi......
  • NC25879 外挂
    题目链接题目题目描述我的就是我的,你也是我的,记住了,狐狸!​——韩信-白龙吟对于打赌输了的小T会遭受到制裁,小s修改了数据库使他可以派出许多军队来围攻小T.很不幸,小T与小s打赌打输了,现在小T遭受着枪林弹雨与十面埋伏,因为小T是神所以他......
  • 8. SELECT
    一.LIMIT和ORDERBY[[email protected]][employees]>select*fromemployeeslimit1;--从employees中随机取出一条数据,结果是不确定的+--------+------------+------------+-----------+--------+------------+|emp_no|birth_date|first_name|last_name|gender|......
  • 彻底明白Zigbee术语——群集(Cluster)、端点(EndPoint)等
      在学习zigbee协议栈的时候经常看到应用程序、zigbee设备对象(ZDO)、节点、设备、端点、群集、属性、绑定、寻址等一下zigbee术语,不知道这些zigbee术语是表示什么,是如何定义的,是如何区分的,是如何划分的以及他们之间有什么联系,一切的一切全不知道。网上也有很多zigbee术......
  • 打卡 C++类与对象定义一个日期类 N天以后 - C/C++ 操作符重载
    改造练习13-1(日复一日)中的Date类并提交,使其可以与一个整数n相加或相减,得到该日期N天后/前的日期。提示:请参考题目(日复一日)中的Date类实现;注意考虑闰月;整数n的取值范围为[1,10000]。裁判测试程序样例: #include<iostream>#include<string>#include<assert.h>usingn......
  • c/c++零基础坐牢第九天
    c/c++从入门到入土(9)开始时间2023-04-27 19:27:23结束时间2023-04-27 23:27:35前言:哈哈,今天是五一假期前的狂欢了?不少明天没课的同学都飞奔回家咯。咳咳,都来玩星穹铁道,不玩星穹铁道都是轨子,我铁道兵要来打轨子啦!经过几天的沉淀,对函数多少有些理解,咱们今天就来进行函数编程的相......
  • Mac M1(arm 系列芯片)如何安装 Chromium | Puppeteer
    最近写个脚本用到puppeteer,然后安装Chromium出现一点问题,这里记录一下解决方案。Puppeteer自动安装失败在Puppeteer安装时会自动安装Chromium,然而却总是报错502导致下载失败,直接下载可以下载,命令行wget也可以,猜测是因为Puppeteer开启了新的process来安装导致环境......
  • 菜鸟记录:c语言实现PAT甲级1005--Spell It Right
     非常简单的一题了,但还是交了两三次,原因:对数组的理解不足;对数字和字符之间的转换不够敏感。这将在下文中细说。Givenanon-negativeinteger N,yourtaskistocomputethesumofallthedigitsof N,andoutputeverydigitofthesuminEnglish.InputSpecificatio......
  • 【CPP】自定义排序--针对智能指针
    目录代码块代码块#include<iostream>#include<memory>#include<vector>#include<algorithm>usingnamespacestd;classBase{public:virtualvoidPrint(){std::cout<<"IamBase!\n";}};classDerived1:publi......
  • Docker-Compose部署xxl-job-admin
    Docker-Compose部署xxl-job-admin最近在探索微服务想做一个分布式任务调度中心,发现用之前.net的Quartz不太行Quartz作为开源作业调度中的佼佼者,是作业调度的首选。但是集群环境中Quartz采用API的方式对任务进行管理,从而可以避免上述问题,但是同样存在以下问题:问题一:调用API的的方......