【Unity】基于MVC模式的双肩包系统 UGUI实现

本文基于MVC模式,用UGUI初步实现了背包系统。

Control层包含了点击和拖拽两种逻辑。

 

博文首发:http://blog.csdn.net/duzixi

下载地址:https://github.com/duzixi/InventorySystem

 

一、工程准备(详见工程文件)

场景中Canvas上的对象:

 

  • Bag:用于显示背包内容
  • PickedItem:用于显示拾取道具的图片

 

资源中的预设体:

 

  • Item:生成背包的格子

 

 

二、源代码

 

Model 层

 

 
  1. using UnityEngine;

  2. using UnityEngine.UI;

  3. using System.Collections;

  4. using System.Collections.Generic;

  5. /// <summary>

  6. /// 脚本功能:MVC模式——Model层,定义物品结构,保存物品数据

  7. /// 添加对象:Bag 背包(Canvas下的空对象)

  8. /// 版权声明:Copyright (c) 2015 duzixi.com All Rights Reserved

  9. /// 创建日期:2015.5.8

  10. /// 知识要点:

  11. /// 1. MVC

  12. /// 2. 自定义类

  13. /// 3. 类的嵌套

  14. /// </summary>

  15. public class ItemModel : MonoBehaviour {

  16.  
  17. // 物品类的定义

  18. public class Item

  19. {

  20. public string name; // 物品名称

  21. public Sprite img; // 物品图片

  22.  
  23. // 构造器

  24. public Item(string name, Sprite img) {

  25. this.name = name;

  26. this.img = img;

  27. }

  28. }

  29.  
  30. public static List<Item> items; // 保存物品对象的集合

  31.  
  32. // 物品图片数组

  33. public int size = 16;

  34. Sprite[] sprites;

  35.  
  36. void Awake() // 数据初始化

  37. {

  38. items = new List<Item>(); // 初始化List<Item>

  39. sprites = new Sprite[size];

  40.  
  41. // 根据行列值初始化物品列表

  42. for (int i = 0; i < BagView.row; i++) {

  43. for (int j = 0; j < BagView.col; j++) {

  44. items.Add(new Item("", null));

  45. }

  46. }

  47.  
  48. // 【注意】实际开发中以下部分应由数据库代替

  49. for (int i = 0; i < size; i++) {

  50. string name = i < 9 ? "0" + (i + 1) : "" + (i + 1);

  51. sprites[i] = Resources.Load(name, typeof(Sprite)) as Sprite;

  52. items[i] = new Item(" ", sprites[i]);

  53. }

  54. }

  55. }

 

 

 

 

 

View 层

 

 

 
  1. using UnityEngine;

  2. using UnityEngine.UI;

  3. using System.Collections;

  4. /// <summary>

  5. /// 脚本功能:MVC模式 —— View视图,控制背包的显示方式

  6. /// 添加对象:Bag 背包 (Canvas下的空对象)

  7. /// 版权声明:Copyright (c) 2015 duzixi.com All Rights Reserved

  8. /// 创建时间:2015.05.08

  9. /// 修改记录:2015.05.18 添加编号

  10. /// 修改记录:2015.07.03 封装显示物品格子方法

  11. /// 知识要点:

  12. /// 1. MVC

  13. /// 2. UGUI

  14. /// </summary>

  15. public class BagView : MonoBehaviour {

  16. // 背包规格

  17. public static int row = 4; // 行

  18. public static int col = 5; // 列

  19.  
  20. // 背包格子

  21. public GameObject grid;

  22. float width; // 格子宽度

  23. float height; // 格子高度

  24.  
  25. // 根据格子预设体获取宽和高

  26. void Awake() {

  27. width = grid.GetComponent<RectTransform>().rect.width;

  28. height = grid.GetComponent<RectTransform>().rect.height;

  29. }

  30.  
  31. // 初始状态:平铺格子,创建背包

  32. void Start () {

  33. for (int i = 0; i < row; i++) {

  34. for (int j = 0; j < col; j++) {

  35. // 计算ID值(物品列表下标)

  36. int id = j + i * col;

  37.  
  38. // 实例化格子预设,按宽高布局

  39. GameObject itemGrid = Instantiate(grid, transform.position + new Vector3(j * width, -i * height, 0), Quaternion.identity) as GameObject;

  40. // 将实例化的格子对象设置为背包的子对象

  41. itemGrid.transform.SetParent(transform);

  42.  
  43. // 调用自定义方法:显示某个id的格子内容

  44. ShowItem(itemGrid.transform, id);

  45.  
  46. // 给格子 PickUpDrop 组件编号,拾取放下时用

  47. itemGrid.GetComponent<PickUpDrop>().gridID = id;

  48. }

  49. }

  50. }

  51.  
  52. // 重新刷新背包显示(物品位置发生变化时)

  53. public void ShowItems() {

  54. for (int i = 0; i < row * col; i++) {

  55. Transform itemGrid = transform.GetChild(i);

  56. ShowItem(itemGrid, i);

  57. }

  58. }

  59.  
  60. // 显示物品格子

  61. private void ShowItem(Transform itemGrid, int id) {

  62. // 显示物品名称

  63. Text txtUGUI = itemGrid.GetComponentInChildren<Text>();

  64. txtUGUI.text = ItemModel.items[id].name;

  65.  
  66. // 获取物品Icon的Image组件

  67. Image imageUGUI = itemGrid.GetChild(0).GetComponent<Image>();

  68.  
  69. // 如果有物品,就显示图片

  70. if (ItemModel.items[id].img != null) {

  71. imageUGUI.color = Color.white;

  72. } else { // 否则不显示

  73. imageUGUI.color = Color.clear;

  74. }

  75. imageUGUI.sprite = ItemModel.items[id].img;

  76. }

  77. }

 

 

 

 

 
  1. using UnityEngine;

  2. using UnityEngine.UI;

  3. using System.Collections;

  4. /// <summary>

  5. /// 脚本功能:让拾取的背包物品随鼠标移动

  6. /// 添加对象:PickedItem 拾取的物品

  7. /// 版权声明:Copyright (c) 2015 duzixi.com All Rights Reserved

  8. /// 创建日期:2015.05.18

  9. /// 修改记录:2015.07.03 添加射线忽略

  10. /// 知识要点:

  11. /// 1. UGUI RectTransform、锚点、中心点

  12. /// 2. 忽略射线接口 ICanvasRaycastFilter

  13. /// </summary>

  14.  
  15. public class MoveWithMouse : MonoBehaviour, ICanvasRaycastFilter {

  16. RectTransform rect; // 获取UGUI定位组件

  17.  
  18. Image icon; // 显示当前拾取物品的图标

  19.  
  20. void Awake() {

  21. rect = GetComponent<RectTransform>();

  22. // 【注意】图标对象是第0个子对象

  23. icon = transform.GetChild(0).GetComponent<Image>();

  24. }

  25.  
  26. void Update () {

  27. // 用鼠标位置给图标图片定位

  28. rect.anchoredPosition3D = Input.mousePosition;

  29. // 根据是否有图片确定透明度

  30. if (PickUpDrop.pickedItem.img != null) {

  31. icon.color = Color.white;

  32. } else {

  33. icon.color = Color.clear;

  34. }

  35. icon.sprite = PickUpDrop.pickedItem.img;

  36. }

  37.  
  38. // 忽略鼠标图标上的射线

  39. public bool IsRaycastLocationValid (Vector2 sp, Camera eventCamera) {

  40. return false;

  41. }

  42. }

 

 

 

 

Control 层

 

 
  1. using UnityEngine;

  2. using UnityEngine.EventSystems;

  3. using System.Collections;

  4. /// <summary>

  5. /// 脚本功能:MVC模式 —— Control控制,背包内物品摆放

  6. /// 添加对象:Item 物品格子预设体

  7. /// 版权声明:Copyright (c) 2015 duzixi.com All Rights Reserved

  8. /// 创建日期:2015.05.18 duzixi.com

  9. /// 修改记录:2015.07.03 添加射线忽略

  10. /// 知识要点:

  11. /// 1. UGUI、MVC设计模式

  12. /// </summary>

  13. public class PickUpDrop : MonoBehaviour, IDropHandler {

  14. public int gridID;

  15.  
  16. public static ItemModel.Item pickedItem; // 当前拾取的物品

  17.  
  18. void Start () {

  19. // 初始化当前拾取物品为空

  20. pickedItem = new ItemModel.Item("", null);

  21. }

  22.  
  23. // 背包核心逻辑:交换

  24. public static void SwapItem(int gridID)

  25. {

  26. // 交换背包中的物品和拾取物品

  27. ItemModel.Item temp = pickedItem;

  28. pickedItem = ItemModel.items[gridID];

  29. ItemModel.items[gridID] = temp;

  30.  
  31. // 刷新背包显示

  32. GameObject.Find("Bag").GetComponent<BagView>().ShowItems();

  33. }

  34.  
  35. // 当物品按钮被点下时(点击触发模式)

  36. public void Drop() {

  37. SwapItem(gridID);

  38. }

  39.  
  40. // 当物品放在格子中时(拖拽触发模式)

  41. public void OnDrop (PointerEventData eventData) {

  42. SwapItem(gridID);

  43. }

  44.  
  45. }

 

 

 
  1. using UnityEngine;

  2. using UnityEngine.UI;

  3. using UnityEngine.EventSystems;

  4. using System.Collections;

  5. /// <summary>

  6. /// 脚本功能:MVC模式 —— Control控制,操作逻辑,拖拽事件处理

  7. /// 添加对象:Bag 背包 (Canvas下的空对象)

  8. /// 版权声明:Copyright (c) 2015 duzixi.com All Rights Reserved

  9. /// 创建时间:2015.07.03

  10. /// 知识要点:

  11. /// 1. UnityEngine.EventSystem

  12. /// 2. IBeginDragHandlder, IDragHandler, IEndDragHander

  13. /// </summary>

  14. public class DragEvent : MonoBehaviour,IBeginDragHandler,IDragHandler,IEndDragHandler {

  15.  
  16. int gridID = 0; // 格子编号

  17.  
  18. void Start() {

  19. gridID = GetComponentInParent<PickUpDrop>().gridID; // 获取格子编号

  20. }

  21.  
  22. // 开始拖拽

  23. public void OnBeginDrag (PointerEventData eventData) {

  24. // 调用交换方法

  25. PickUpDrop.SwapItem(gridID);

  26. }

  27.  
  28. // 拖拽中

  29. public void OnDrag (PointerEventData eventData) {

  30. // 【注意】即使没有任何代码处理也要实现该接口,否则拖拽不成功

  31. }

  32.  
  33. // 结束拖拽

  34. public void OnEndDrag (PointerEventData eventData) {

  35. // 调用交换方法

  36. PickUpDrop.SwapItem(gridID);

  37. }

  38.  
  39. }

 

 

 

 

后语

目前还有点Bug,拖拽模式下当前物体拖拽会导致物品跟随。

另外屏幕适配还没有搞。